监理公司管理系统 | 工程企业管理系统 | OA系统 | ERP系统 | 造价咨询管理系统 | 工程设计管理系统 | 甲方项目管理系统 | 签约案例 | 客户案例 | 在线试用
X 关闭
OA系统二次开发

当前位置:工程项目OA系统 > 泛普服务体系 > OA系统二次开发

泛普协同OA办公底层包开发指南

申请免费试用、咨询电话:400-8352-114

 
1.     引言... 4
1.1       概述... 4
1.2       定义... 4
2.     底层包应用及范例... 4
2.1       最基本的继承类... 4
2.2       怎样记录日志... 5
2.3       怎样获取属性文件的值... 8
2.4       怎样获取系统的运行目录... 10
2.5       怎样访问和运行数据库脚本... 11
2.6       如何上传一个文件... 15
2.7       如何访问已经上传的文件... 19
2.8       如何使用缓存提高系统效率... 20
2.9       其它底层类基本方法... 29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

1.    引言

 

1.1      概述

 
本文档为泛普协同OA商务系统(泛普OA系统)程序员开发指导文档,讲述了开发底层工具包的应用,常用功能的开发。
 
 

2.    底层包应用及范例

 
本章对泛普OA系统   OA系统的底层工具包进行讲解,开发人员可以从这里学到怎样利用底层的工具包进行开发
 
 

2.1      最基本的继承类

 
泛普OA管理系统中每一个java bean 都需要继承 泛普OA系统.general.BaseBean 类 。这个类实现了记录日志和获取属性文件值的方法。继承这两个类的其它类可直接应用这些方法来记录日志,获取属性文件某一个属性的值。方法的实现见后面的例子。
继承的例子如下:
 
java bean 的继承
 
public class ResourceComInfo extends BaseBean {
 
       public void doSomething() {          //某一个方法
              方法的处理………
              writeLog(s) ;       // 写日志
       }
}
 
 
 
 
 
 
 
 

2.2      泛普OA办公系统怎样记录日志

 
继承了泛普OA系统.general.BaseBean  ,可以直接使用 writeLog方法记录日志信息。注意这里是使用,而不是调用,因为这个方法是这两个被继承类中的方法。
 
注意writeLog 方法的使用:
/**
* 将某个对象写入Log文件
* @param obj 被写入的对象
*/
  public void writeLog(Object obj)
 
我们看到,可以被记入日志的是任意一个java对象。这些java对象将被自动转换成字符串对象(String)记入到日志文件中。日志文件将每天生成一个,以日志文件名称中的日期来区别,比如:泛普OA系统_20030812.log,代表2003年8月12日的日志。当天的日志为泛普OA系统.log。每一条日志的记录格式为 :
YYYY.MM.DD-HH:MM:SS 记录日志的类名 – 日志信息
比如:
2003.03.11-06:52:05 泛普OA系统.datacenter.OutReportResult - sql is  select ROUND(sum(F_sksr),5) from T_yyrb A , CRM_CustomerInfo where  CRM_CustomerInfo.id=A.crmid  and CRM_CustomerInfo.id in(5)  and A.reportdate >= '2004-01-10'  and A.reportdate <= '2004-03-10'  and A.inputstatus >= '0' and A.inputstatus<>'9'  and A.modtype='0'
 
日志的记录有两种模式,第一种为调试模式,第二种为在线模式。在第一种模式下,所有的java对象都会记录到日志文件中,包括调试信息,在第二种模式下,只有为Exception (异常)的对象才会记录到日志文件中。模式的设置在/泛普OA系统/WEB-INF/ log4jinit.properties 属性文件中的log4j.rootLogger 属性来指定,如下:
 
log4j.rootLogger = INFO,A2
 
#if you want to open the trace from open source,just add   #  ahead of line
log4j.logger.org = ERROR
log4j.logger.uk = ERROR
 
 
log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A2.DatePattern='_'yyyyMMdd'.log'
#don't modify the file property
log4j.appender.A2.File=@泛普OA系统
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p %c  - %m%n
上面的日志表明将所有的信息答应到文件日志文件中 ,其中日志的模式为:
#FATAL 0
#ERROR 3
#WARN 4  只有WARN,ERROR,FATAL输出
#INFO 6   所有的log都输出
#DEBUG 7
记录日志的例子如下:
public class ResourceComInfo extends BaseBean {
 
private void setResourceInfo() throws Exception{
   
try{
   
业务处理过程……….
 
String debugInfo = "This is test" ;
// 在调试模式下将会记入日志文件
                        writeLog("debug info is "+ debugInfo) ;          
                 }
                 catch(Exception e) {
                     // 在任何模式下出现异常,都将会记入日志文件
                      writeLog(e) ;
                      throw e ;
                 }
}
}
 
记录的日志文件形式为:
 
2007-10-15 16:51:50,125  DEBUG  泛普OA系统.hrm.resource. ResourceComInfo - debug info is This is test
 
如果有异常,将会记录为:
2007-10-15 16:51:50,125  ERROR  泛普OA系统.hrm.resource. ResourceComInfo - java.sql.SQLException: [Microsoft][SQLServer JDBC Driver][SQLServer]形式参数 '@id_1' 定义为 OUTPUT,但实际参数却未声明为 OUTPUT。
       at com.microsoft.jdbc.base.BaseExceptions.getException(Unknown Source)
       at com.microsoft.jdbc.sqlserver.tds.TDSRequest.processErrorToken(Unknown Source)
       at com.microsoft.jdbc.sqlserver.tds.TDSRequest.processReplyToken(Unknown Source)
       at com.microsoft.jdbc.sqlserver.tds.TDSRPCRequest.processReplyToken(Unknown Source)
       at com.microsoft.jdbc.sqlserver.tds.TDSRequest.processReply(Unknown Source)
       at com.microsoft.jdbc.sqlserver.SQLServerImplStatement.getNextResultType(Unknown Source)
       at com.microsoft.jdbc.base.BaseStatement.commonExecute(Unknown Source)
       at com.microsoft.jdbc.base.BaseStatement.executeInternal(Unknown Source)
       at com.microsoft.jdbc.base.BasePreparedStatement.execute(Unknown Source)
       at 泛普OA系统.conn.RecordSet.executeProc(RecordSet.java:155)
       at 泛普OA系统.conn.RecordSet.executeProc(RecordSet.java:109)
       at 泛普OA系统.hrm.resource. ResourceComInfo (ResourceComInfo.java:59)
       at com.caucho.jsp.JavaPage.service(JavaPage.java:87)
       at com.caucho.jsp.JavaPage.subservice(JavaPage.java:81)
       at com.caucho.jsp.Page.service(Page.java:410)
       at com.caucho.server.http.Invocation.service(Invocation.java:319)
       at com.caucho.server.http.RunnerRequest.handleRequest(RunnerRequest.java:333)
       at com.caucho.server.http.RunnerRequest.handleConnection(RunnerRequest.java:266)
       at com.caucho.server.TcpConnection.run(TcpConnection.java:140)
       at java.lang.Thread.run(Thread.java:484)
 
从上面的日志信息,可以看到ResourceComInfo类的59行代码运行的时候出现错误,这个错误是执行数据库操作的脚本错误,具体的错误信息是:形式参数 '@id_1' 定义为 OUTPUT,但实际参数却未声明为 OUTPUT。说明调用数据库脚本的时候参数的数量有出入。
 开发过程中请将日志级别设置为INFO,通过日志可检查程序在哪里出错了。

2.3      泛普办公平台怎样获取属性文件的值

 
继承了泛普OA系统.general.BaseBean  的类,可以直接使用getPropValue方法获取属性文件的值。注意这里是使用,而不是调用,因为这个方法是这两个被继承类中的方法。
 
注意getPropValue方法的使用:
/**
* 从配置文件中获取某个属性的值
* @param fname 属性文件名称
* @param key 值
* @return String 属性值
*/
  public String getPropValue(String fname , String key)
 
getPropValue 方法指定了从某一个属性文件fname 中获取键值key 的值。
 
这里的属性文件必须存放在系统运行目录下的WEB-INF/prop 目录下,文件名称为参数fname指定的文件名,不包括属性文件的后缀名,属性文件的后缀名必须为 .properties。
 
比如:
系统的运行目录为 d:泛普OA系统,那么属性文件必须放在d:泛普OA系统WEB-INFprop 目录下,取名为 thefilename.properties ,其中thefilename是任意的。
 
在属性文件中某一个键值的值用等号来赋值,等号后面的值必须放在一行,如果一行不够写(或者为了查看的方便),可以用 来链接多行。否则其它行的值不能被键值取得。等号左右都可以有空格,对键值和键值的值没有影响。
 
比如 :
thekeyname = thevalue
 
将键值的值放到多行:
thekeyname = thevalue1
              thevalue2
              thevalue3
              thevalue4                   
这时候thekeyname 的值为thevalue1thevalue2thevalue3 ,thevalue4 取不到,因为thevalue3后面没有
 
在程序中要取得上述属性文件中键值thekeyname的值,使用方法:
 
getPropValue(“thefilename” , “thekeyname”) ;
 
 
 
获取属性文件的值的例子如下:
 
public class ResourceComInfo extends BaseBean {
 
private void setResourceInfo() throws Exception{
   
业务处理过程……….
 
String keyValue = getPropValue(“thefilename” , “thekeyname”) ;
 
// 将键值thekeyname的值keyValue记入日志文件
                writeLog("keyvalue is "+ keyValue) ;          
                
}
}
 
系统的主属性文件 泛普OA系统.properties 的文件名“泛普OA系统” 作为系统常量放在泛普OA系统.general.GCONST 类中,可以使用getConfigFile() 方法来返回 “泛普OA系统 ”,在编程的过程中,如果需要用到泛普OA系统.properties属性文件中的键值,请用GCONST. getConfigFile() 来获取,当主属性文件名称因为需要改变得时候,不必改变所有用到这个属性文件的类,只需要改变GCONST类中常量的值
 
 

2.4      泛普OA系统怎样获取系统的运行目录

 
泛普OA系统.general.GCONST 类提供了一个静态方法getRootPath() ,返回系统的运行目录,比如系统的运行目录为d 盘的泛普OA系统目录,将返回d:泛普OA系统
 
获取系统的运行目录的例子如下:
 
public class TestBean extends BaseBean {
      
       import 泛普OA系统.general.GCONST ;
 
public void getSysRunPath(){
   
String sysRunPath = GCONST. GetRootPath() ;
 
// 将系统的运行目录sysRunPath的值记入日志文件
                writeLog("sysRunPath is "+ sysRunPath) ;        
                
}
}

2.5      泛普OA软件怎样访问和运行数据库脚本

 
在泛普OA系统系统中,大量的数据库访问,链接的建立和持续性,事务的处理,链接池的维护等问题都被封装在泛普OA系统.conn 包下面的各个类中,应用程序的实现者不需要去关心这些问题,而只需要调用泛普OA系统.conn.RecordSet 类来执行各种数据库操作。
 
泛普OA系统.conn.RecordSet 类实现了从数据库链接池中获取链接,执行指定的数据库脚本或者存储过程,并在脚本或者存储过程执行完毕后将链接及时地归还到链接池中。
 
泛普OA系统系统的链接池管理请参见 泛普OA系统.conn.ConnectionPool , 泛普OA系统.conn.DBConnectionPool ,泛普OA系统.conn.ConnCheckerTimer 类的API 文档,泛普OA系统.conn.ConnectionPool 用于管理泛普OA系统系统中的所有数据库链接池(泛普OA系统系统可以同时链接多个数据库,每一个数据库均有一个对应的数据库链接池,由泛普OA系统.conn.DBConnectionPool负责管理,而泛普OA系统.conn.ConnectionPool则是这些链接池的大管家,负责所有链接池的协调和统一对外接口),泛普OA系统.conn.DBConnectionPool用于建立和管理对某一个数据库的链接池,泛普OA系统.conn.ConnCheckerTimer用于监控各个链接池的状况,定期对数据库链接池中不符合要求的链接进行清理,并监视是否需要在某一链接池中建立新的链接。
 
调用泛普OA系统.conn.RecordSet,实现对数据的操作,下面进行详细的说明:
 
泛普OA系统.conn.RecordSet类采用 java.sql 中的 CallableStatement 和 Statement 执行数据库操作。客户端直接调用该类进行数据库操作。不需要考虑数据库链接的建立。其中客户端指所有调用该类进行数据库操作的应用程序,不特指用户的客户端。
 
RecordSet 执行数据库操作有两种形式,一种为调用存储过程,另一种为直接执行SQL语句。与ConnStatement不同 ,RecordSet 执行SQL语句不分查询和修改,都在一条语句中执行。RecordSet执行脚本的方式如下:
 
1、使用默认的链接池执行SQL语句:  
RecordSet rs = new RecordSet() ;
rs.executeSql(" select * from TB_Example ") ;
while( rs.next() ) {
String thename = rs.getString("name") ;
其它处理代码....……
}
在JSP页面中,可以通过以下方式应用
<%@ page import="泛普OA系统.general.Util" %>
<%@ page import="泛普OA系统.conn.*" %>
<%@ page import="java.util.*,java.sql.Timestamp" %>
<%@ page language="java" contentType="text/html; charset=GBK" %>
<%@ include file="/systeminfo/init.jsp" %>
<jsp:useBean id="rs" class="泛普OA系统.conn.RecordSet" scope="page" />
<%rs.execute(“”);   //执行SQL语句
while( rs.next() ) {
String thename = rs.getString("name") ;
其它处理代码....……
}
 
rs. executeProc (“存储过程名称”,para);   //执行存储过程
while( rs.next() ) {
String thename = rs.getString("name") ;
其它处理代码....……
}
 
 
%>
 
2、使用指定的链接池泛普OA系统test执行SQL语句
RecordSet rs = new RecordSet() ;
rs.executeSql(" update TB_Example set name = 'the new value' " , "泛普OA系统test" ) ;
 
 
 3、使用指定的链接池泛普OA系统test执行存储过程 PD_Example_UpdateById
存储过程PD_Example_UpdateById 如下:
CREATE  PROCEDURE [PD_Example_UpdateById]
                       (@name      varchar(100),
                        @id   int,
                        @flag integer output,
                        @msg varchar(80) output)
                   AS
                   update TB_Example set name = @name where id = @id
 
GO
 
 
RecordSet rs = new RecordSet() ;
 
String newname = ....... ;
String id = ...... ;
String procpara = newname + Util.getSeparator() + id ;
rs.executeProc( "PD_Example_UpdateById" , procpara , "泛普OA系统test" ) ;
 
procpara 是存储过程的参数值组成的字符串变量,多个参数值之间用 泛普OA系统.general.Util.getSeparator() 分开
 
 
4、在一个客户程序多个执行之间,查询结果可以保留到下一次查询
RecordSet rs = new RecordSet() ;
rs.executeSql(" select * from TB_Example ") ;
rs.executeSql(" update TB_Example set name = 'the new value '") ;
while( rs.next() ) {
String thename = rs.getString("name") ;  //得到修改前查询的值
其它处理代码....…….
}
 
rs.executeSql(" select * from TB_Example ") ;
while( rs.next() ) {
String thename = rs.getString("name") ;  //得到修改后查询的值
其它处理代码....……
 }
 
访问和运行数据库脚本的例子:
 
public class ResourceComInfo extends BaseBean {
 
private void setResourceInfo() throws Exception{
   
业务处理过程……….
 
String sqlStr = “select * from Hrmresorce” ;
RecordSet rt = new RecordSet() ;
rt.executeSql(sqlStr) ;
while(rt.next()){
        String id = Util.null2String(rt.getString("id"));
        String loginid = Util.null2String(rt.getString("loginid"));
        String lastname = Util.null2String(rt.getString("lastname"));
        // 将数据库的值记入日志文件
                        writeLog("id is "+ id) ;   
        writeLog("loginid is "+ loginid) ;
        writeLog("lastname is "+ lastname) ;      
}
                
}
}
 
 
 
 
其它关于系统数据库信息的管理
 
a)、泛普OA系统.conn.ConnectionPool 类的管理和设置:
 
所有的数据库链接池的集合,用链接池名称区别每一个链接池.支持对一个或多个由属性文件定义的数据库连接池的访问.客户程序可以调用getInstance()方法访问本类的唯一实例。
 
对于一个链接池集合来说,可以有多个链接池,分别链接不同的数据库。应用程序指定链接池的名称来调用不同的链接池。如果应用程序没有指定链接池的名称,将使用默认的链接池。默认链接池的指定有两种方式:
 
1、在Application Server设置的初始参数serverName的值 ,以Resin 为例:
<servlet servlet-name='InitServer' servlet-class='泛普OA系统.general.InitServer'>
      <init-param serverName='泛普OA系统'/>
<load-on-startup/>
</servlet>
 
2、如果Application Server没有相应设置,则系统使用属性文件(泛普OA系统.properties)中设置的默认链接池名称:
DefaultPoolName = 泛普OA系统
 
对于所有的链接池,系统需要加载相应的 JDBC Driver来建立与相应数据库的链接。这些 Driver 在属性文件(泛普OA系统.properties)中指定,多个Driver中间用空格隔开:
DriverClasses = com.microsoft.jdbc.sqlserver.SQLServerDriver
 
对于每一个链接池需要用到的参数在属性文件(泛普OA系统.properties)中指定,属性文件中参数的名称以链接池的名称开头,中间加入小数点,比如链接池 泛普OA系统 的参数指定为 :
 
泛普OA系统.url = jdbc:microsoft:sqlserver://10.1.1.205:1433;DatabaseName=泛普OA系统    //db url
泛普OA系统.user = sa                                                                     //db user name       
泛普OA系统.password = 123456                                                        //db user password
泛普OA系统.charset = ISO_1                                                          //db encode          
泛普OA系统.maxconn = 10                                                             //max conn in conn pool
泛普OA系统.minconn = 2                                                              //min conn in conn pool
泛普OA系统.maxusecount = 30              //the max use times of a conn           
泛普OA系统.maxidletime = 30            //the max unuse time of a conn (分)
泛普OA系统.maxalivetime = 2            //一个链接被调用后的最大未归回时间 (分)
泛普OA系统.checktime = 500                                                          //检查的频率 (秒)
 
 
 
b)、泛普OA系统.conn. DBConnectionPool类的管理和设置:
 
数据库链接池,所有创建的链接存放在链接池中,在客户端链接数据库时从链接池中取出链接,客户端在完成数据库操作后将链接返回链接池。
 
               
链接池创建链接需要用到的参数在属性文件(泛普OA系统.properties)中指定,属性文件中参数的名称以链接池的名称开头,中间加入小数点,比如链接池 泛普OA系统 的参数指定为 :
 
泛普OA系统.url = jdbc:microsoft:sqlserver://10.1.1.205:1433;DatabaseName=AIS2002    //db url
泛普OA系统.user = sa                                                                     //db user name       
泛普OA系统.password = 123456                                                        //db user password
泛普OA系统.charset = ISO_1                                                          //db encode          
泛普OA系统.maxconn = 10                                                             //max conn in conn pool
泛普OA系统.minconn = 2                                                              //min conn in conn pool
泛普OA系统.maxusecount = 30              //the max use times of a conn           
泛普OA系统.maxidletime = 30            //the max unuse time of a conn (分)
泛普OA系统.maxalivetime = 2            //一个链接被调用后的最大未归回时间 (分)
泛普OA系统.checktime = 500                                                          //检查的频率 (秒)
 
 
 

2.6      泛普OA办公如何上传一个文件

 
上传一个文件只需要调用泛普OA系统.file.FileUpload 类。泛普OA系统.file.FileUpload 类支持各种文件格式的上传,也支持多文件的上传。
 
B/S 架构的文件上传采用的是multipart/form-data 协议,而不是HTTP协议,采用这种协议上传的数据必须通过特殊的处理,而不能用常规的方法来获取,否则不能得到数据。泛普OA系统.file.FileUpload 封装了底层处理的代码,应用程序的实现者不需要关心这些细节!
 
泛普OA系统.file.FileUpload上传数据的方法有:
 
/**
* 进行上传一个文件的操作
* @param uploadname  需要上传的文件字段名称
* @return String   返回保存文件信息的imagefileid
*/
public String uploadFiles(String uploadname)
 
 
/**
* 进行上传一个文件的操作
* @param uploadnames需要上传的多个文件字段名称
* @return String[]   返回保存多个文件信息的imagefileid数组
*/
public String[] uploadFiles(String[] uploadnames)
 
 
这里,需要注意两点,一个是传给uploadFiles 方法的参数, 是上传文件字段的名称,而不是文件的名称(这个时候你并不知道文件的名称)。比如在jsp 或者html页面中文件浏览的字段代码为:
<input type=file size=70 name="accessory1">
那么这里的文件字段的名称为"accessory1"。  第二点是这个方法返回的信息是保存在数据库表 ImageFile 中关于这个文件信息的键值imagefileid ,这个表的结构如下:
Column(s) of "ImageFile" Table
Name Datatype Null Option Comment
imagefileid int NOT NULL 文件id
imagefilename varchar(200) NULL 文件名称
imagefiletype varchar(50) NULL 文件MIME类型
filerealpath varchar(255) NULL 文件存放目录
imagefileused int NULL 文件使用次数
iszip char(1) NULL 是否压缩
0:否
1:是
isencrypt char(1) NULL 是否加密
0:否
1:是
imagefile image NULL 文件(存在在数据库中的文件内容,现已不使用)
 
从表结构可以看出,我们得到了某一个文件信息的imagefileid,就可以从该表中得到相应的文件名称(这里指文件的实际名称,比如test.doc), 文件MIME类型(比如 txt,doc,gif等) ,文件存放目录(这里指在服务器中存放的实际路径信息,包括实际存放的文件名称,比如 e:泛普OA系统filesystem20038A23143567.zip)。通过这些信息,可以对文件进行操作,当然泛普OA系统.file.FileUpload 还提供了其它很多方法来获取文件相关的信息,不需要通过数据表的查询就能得到这些信息。存放在数据表中的信息只是供今后文件处理的时候使用!
 
上传文件的例子:
 
首先,我们要创建一个提交数据的页面,可以是jsp 的页面,也可以是html 的页面,我们将数据提交给 泛普OA系统.test.MutiFileUpload 的servlet 类来处理:
 
<HTML>
<HEAD>
<TITLE>文件上传</TITLE>
</HEAD>
<BODY>
<P>这是一个文件上传的例子</P>
<FORM id=泛普OA系统 name=泛普OA系统 action="/泛普OA系统/泛普OA系统.test.MutiFileUpload" method=post enctype="multipart/form-data"><!—注意,这里需要用enctype="multipart/form-data" 表明使用multipart/form-data 协议 -->
 
<input type="text" size="70" name="filedesc">
<input type="file" size="70" name="accessory1">
<input type="file" size="70" name="accessory2">
 
<input type="submit" name="提交">
</FORM>
</BODY>
</HTML>
 
将上面这段代码保存为一个html 文件FileUploadTest.htm,放在泛普OA系统运行目录下的/test/目录下。在这个页面中,有一个输入框和两个文件框可以输入信息。注意,在环境的配置中,需要告诉web服务器将 /泛普OA系统/ 的请求转给应用服务器作为servlet处理,关于配置的信息,请参考Apache 和Resin的配置文档。
 
 
下面我们来编写泛普OA系统.test.MutiFileUpload
 
package 泛普OA系统.test;
 
 
/**
 * Title:        多文件上传处理类
 * Description:  多文件上传测试
 
 * Copyright:    Copyright (c) 2001
 * Company:      泛普OA系统
 * @author liuyu
 * @version 1.0
 */
 
import javax.servlet.http.HttpServletRequest;
import 泛普OA系统.general.DynamicServlet;
import 泛普OA系统.file. FileUpload;
 
 
public class MutiFileUpload extends DynamicServlet {
 
public void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   
FileUpload fu = new FileUpload(request) ;
String fileDesc = fu.getParameter("filedesc") ;  /* 1*/
String[] fileFieldNames = {" accessory1"," accessory2"} ;
String[] fileIds = fu.uploadFiles(fileFieldNames) ;  /*2*/
String[] fileNames = fu.getFileNames() ;  /*3*/
 
 
// 将请求信息记入日志文件
                writeLog("fileDesc is "+ fileDesc) ;      
              for (int i=0; i< fileIds.length; i++) {
                     String fileId = fileIds[i] ;
                     If(fileId == null) continue ;
                     String fileName = fileNames[i] ;
                    
writeLog("fileId is "+ fileId) ;
writeLog("fileName is "+ fileName) ;  
}
 
response.sendRedirect("/test/FileUploadTest.htm");
}
}
 
以上代码需要注意的几个地方:
 
注释1:由于使用了multipart/form-data协议, 这里获取请求中的信息必须使用fu. getParameter()  方法,而不能使用 request.getParameter() 方法,否则不能得到filedesc的值!
 
注释2:使用uploadFiles方法上传accessory1和accessory2中的文件,同时返回保存在ImageFile 表中的文件基本信息的键值imagefileid,可以将这个imagefileid记录到其它地方以便今后调用。
 
注释3:使用getFileNames方法获取上传文件的真实名称(包括后缀名)
 
 
将代码保存到 /src/泛普OA系统/test/MutiFileUpload.java 文件中。访问FileUploadTest.htm 来测试一下,看看日志文件中的记录是否正确。页面提交,文件上传完毕后将再次返回FileUploadTest.htm页面。你可以查看ImageFile表来检查文件的具体存放位置等信息。
 
文件的存放位置在系统设置模块中设置,如果没有设置,将存放在系统运行目录下的 filesystem 目录下。
 

2.7      泛普OA办公自动化软件如何访问已经上传的文件

 
在jsp页面或者html页面中访问已经上传的文件非常简单,只需要调用泛普OA系统.file.FileDownload类,并传递需要访问的文件id ,这个文件id,就是在文件上传中返回的 imagefileid。
 
访问上传的文件有两种方式,一种是非下载方式,这种方式如果浏览器能够显示访问的文件类型,那么就会在浏览器中直接显示。另一种是下载方式,无论访问的文件是什么类型,都使用弹出下载窗口的形式下载。
 
对非下载方式的链接访问
<A href= "/泛普OA系统/泛普OA系统.file.FileDownload?fileid=<%=fileid%>">文件1</A>
 
对下载方式的链接访问
<A href= "/泛普OA系统/泛普OA系统.file.FileDownload?fileid=<%=fileid%>&download=1">文件1</A>
 
 
如果知道要访问的文件是图片,并需要在浏览页面中直接显示这个图片,可以使用下面的代码访问
<IMG SRC="/泛普OA系统/泛普OA系统.file.FileDownload?fileid=<%=fileid%>">
当然如果对于对应的文档,你没有权限,那么这个地址会让你返回到登录页面

2.8      泛普OA系统软件如何通过EXCEL导入数据

我们可以通过EXCEL导入一些数据实现系统的初始化,导入一个EXCEL需要用到泛普OA系统.file. ExcelParse,在THINKONE中导入一个EXCEL很简单,泛普OA系统.file. ExcelParse进行了封装,通过调用其中的方法:init(String filename)和getValue(String sheetname , String rownum , String columnnum)就可以实现
 
实例
<HTML>
<HEAD>
<TITLE>EXCEL导入</TITLE>
</HEAD>
<BODY>
<P>这是一个EXCEL导入的例子</P>
<FORM id=泛普OA系统 name=泛普OA系统 action="export.jsp" method=post enctype="multipart/form-data"><!—注意,这里需要用enctype="multipart/form-data" 表明使用multipart/form-data 协议 -->
 
<input type="text" size="70" name="filedesc">
<input type="file" size="70" name="accessory1">
<input type="file" size="70" name="accessory2">
 
<input type="submit" name="提交">
</FORM>
</BODY>
</HTML>
 
下面是export.jsp的例子
<%@ page import="泛普OA系统.general.Util,泛普OA系统.file.*,java.util.*" %>
<jsp:useBean id="ExcelParse" class="泛普OA系统.file.ExcelParse" scope="page" />
 
FileUploadToPath fu = new FileUploadToPath(request) ;    // 上传EXCEL文件
String filename = fu.uploadFiles("excelfile") ;    //获取EXCEL路径
ExcelParse.init( filename ) ;    //进行EXCEL文件初始化
  int recordercount = 0 ;
    while( true ) {
        recordercount ++ ;
      
//以下一行一行按列读取EXCEL中的数据getValue方法中的第一个参数不要变化,固定为1,第二个参数是行号,第三个参数是列号
 String workcode = Util.null2String( ExcelParse.getValue("1", ""+recordercount , "1" ) ).trim() ;
        String lastname = Util.null2String( ExcelParse.getValue("1", ""+recordercount , "2" ) ).trim() ;
        String sex = Util.null2String( ExcelParse.getValue("1", ""+recordercount , "3" ) ).trim() ;
        String department = Util.null2String( ExcelParse.getValue("1", ""+recordercount , "4" ) ).trim() ;
        String subcompany = Util.null2String( ExcelParse.getValue("1", ""+recordercount , "5" ) ).trim() ;
        String jobtitle = Util.null2String( ExcelParse.getValue("1", ""+recordercount , "6" ) ).trim() ;
        String manager = Util.null2String( ExcelParse.getValue("1", ""+recordercount , "7" ) ).trim() ;
        String status = Util.null2String( ExcelParse.getValue("1", ""+recordercount , "8" ) ).trim() ;
        String location = Util.null2String( ExcelParse.getValue("1", ""+recordercount , "9" ) ).trim() ;
        String loginid = Util.null2String( ExcelParse.getValue("1", ""+recordercount , "10" ) ).trim() ;
        String password = Util.null2String( ExcelParse.getValue("1", ""+recordercount , "11" ) ).trim() ;
        String seclevel = Util.null2String( ExcelParse.getValue("1", ""+recordercount , "12" ) ).trim() ;
        
        if( recordercount == 1 ) continue ;  //第一行为标题,一般不处理
 
        if( lastname.equals("") ) break ;   //表示已经是最后一行,处理结束
 
导入数据业务处理过程……….
 
}
//以上取出EXCEL文件中


 

2.9      泛普OA管理平台导出EXCEL文件

在实际应用在我们常常会把一些系统统计数据导出成EXCEL供进一步的分析,在THINKONE系统中提供了导出EXCEL文件的方法,泛普OA系统.file.ExcelFile,泛普OA系统.file.ExcelOut,泛普OA系统.file. ExcelSheet,泛普OA系统.file. ExcelRow进行了封装
实例
ExportExcelTest.jsp
<%@ page language="java" contentType="text/html; charset=GBK" %>
<%@ page import="泛普OA系统.file.*," %>
<jsp:useBean id="ExcelFile" class="泛普OA系统.file.ExcelFile" scope="session"/>
<iframe id="ExcelOut" name="ExcelOut" border=0 frameborder=no noresize=NORESIZE height="0%" width="0%"></iframe>
 
<%
  ExcelSheet es = new ExcelSheet() ;   // 初始化一个EXCEL的sheet对象
  ExcelRow er = es.newExcelRow () ;  //准备新增EXCEL中的一行
//以下为EXCEL添加多个列
er.addStringValue(“EXCEL第1列的值”) ; 
er.addStringValue(“EXCEL第2列的值”) ;
………. 
er.addStringValue(“EXCEL第n列的值”) ;
 
es.addExcelRow(er) ;   //加入一行
 
ExcelFile.init() ;
ExcelFile.setFilename(“导出EXCEL文件的名字”) ;
ExcelFile.addSheet(“sheet的名字”, es) ; //为EXCEL文件插入一个SHEET
 
%>
<a href=”/泛普OA系统/泛普OA系统.file.ExcelOut”>到处EXCEL文件</a>

2.10   泛普协同OA办公系统如何使用缓存提高系统效率

 
对于一些常用的信息,比如人员的名称,如果每次访问的时候都查询数据库来获取,将极大的影响系统的性能。我们可以将这些信息放到系统的缓存中,在用到的时候,从系统缓存中获取。(使用缓存是典型的用空间换时间的系统优化方式)
 
系统提供了 泛普OA系统.general.StaticObj 类来保存这些信息。泛普OA系统.general.StaticObj 类使用 HashTable 来管理缓存信息,其主要的方法如下:
 
StaticObj将数据库中常用的数据放入缓存中,以加快系统的反应速度。客户程序可以调用getInstance()方法访问本类的唯一实例。
 
StaticObj有两层缓存,分别为 mainKey - value 和 mainKey - subkey – value,由 mainKey 可以取得第一层的对象,由 mainKey - subkey 可以取得第二层的值,在第二层的值存在的情况下,第一层的值为 Hashtable。
 
 
 /**
 * 返回唯一实例.如果是第一次调用此方法,则创建实例
 *
 * @return StaticObj 唯一实例
 */
  public static StaticObj getInstance()
 
/**
 * 获取 mainKey 对应的第一层对象值
 *
 * @param key 主键名称
 * @return Object 对于的第一层对象值
 */
  public Object getObject(String key)
 
/**
 * 设置 mainKey 对应的第一层对象值
 *
 * @param key 主键名称
 * @param obj mainKey 对应的第一层对象值
 */
  public void putObject(String key, Object obj)
 
/**
 * 从缓存中清除 mainKey 对应的第一层对象值
 *
 * @param key 主键名称
 */
  public void removeObject(String key)
 
/**
 * 获取 mainKey - subkey 对应的第二层对象值
 *
 * @param HashKey 主键名称
 * @param RecKey  子主键名称
 * @return Object 对于的第二层对象值
 */
  public Object getRecordFromObj (String HashKey, String RecKey)
 
/**
 * 设置 mainKey - subkey 对应的第二层对象值
 *
 * @param HashKey 主键名称
 * @param RecKey  子主键名称
 * @param obj     mainKey - subkey对于的第二层对象值
 */
  public void putRecordToObj (String HashKey, String RecKey, Object obj)
 
 
/**
 * 从缓存中清除 mainKey - subkey 对应的第二层对象值
 *
 * @param HashKey 主键名称
 * @param RecKey  子主键名称
 */
  public void removeRecordFromObj (String HashKey, String RecKey)
 
 
/**
 * 从缓存中清除 所有对象值
 *
 */
  public void clearRecord() 
 
 
运用这些方法,我们可以构造所需要的缓存类,使用这些缓存类来对其它模块和功能提供缓存信息的接口,这些缓存类在系统中的命名为 XXXComInfo,其中XXX为相应缓存信息的名称。参考如下的人力资源缓存类:泛普OA系统.hrm.resource.ResourceComInfo。
 
ResourceComInfo 类主要提供人力资源信息中常用的一些信息的缓存,比如人员名称,所在部门。对于这些信息,都需要一个键值。常见的键值是这些信息在数据库表中的Primary Key,比如人力资源ID,其它模块和功能在关联人力资源信息的时候,只记录人力资源的ID,当需要获取人力资源的其它信息,如人员名称,所在部门的时候,从ResourceComInfo类提供的统一接口中获取。
 
 
泛普OA系统.hrm.resource.ResourceComInfo 的代码:
 
 
package 泛普OA系统.hrm.resource;
 
import java.util.*;
import 泛普OA系统.conn.*;
import 泛普OA系统.general.*;
 
 
/**
 * Title:        人力资源缓存信息接口类
 * Description:     对其它模块和功能提供统一的获取人力资源信息的接口
 * Copyright:    Copyright (c) 2002
 * Company:      泛普OA系统
 * @author liuyu
 * @version 1.0
 */
 
public class ResourceComInfo extends BaseBean {
 
    /* 1 */
    private ArrayList ids = null;               // 保存人力资源键值 ID 队列
    private ArrayList loginids = null;          // 保存人力资源登录名 队列
    private ArrayList lastnames = null;         // 保存人力资源名称 队列
    private ArrayList departmentids = null;     // 保存人力资源部门 队列
    private ArrayList seclevels = null;         // 保存人力资源安全级别 队列
    private ArrayList statuses = null;          // 保存人力资源状态 队列
 
   
    private StaticObj staticobj = null;         // 公共缓存类
 
    /* 2 */
    private int current_index = -1;             // 当前人力资源记录的指针
    private int array_size = 0;                 // 人力资源记录的数量
   
 
    /**
     * 人力资源缓存信息接口类构造方法
     * 构造方法中将获取公共缓存类的唯一实例,并调用getResourceInfo 方法获取缓存信息,
     * 同时赋值人力资源记录的数量
     *
     */
    public ResourceComInfo() throws Exception{
        staticobj = StaticObj.getInstance();  
        getResourceInfo() ;
        array_size = ids.size();
    }
 
 
 
    /**
     * 获取人力资源缓存信息方法
     * 检查是否有人力资源缓存信息,如果没有,将调用setResourceInfo 方法从数据库中获取人力资源信息并放入缓存中
     * 将缓存中的信息赋予相应的队列
     *
     */
private void getResourceInfo() throws Exception{
        /* 3 */
        if(staticobj.getObject("ResourceInfo") == null)
            setResourceInfo();
       
        // 将缓存中的信息赋予相应的队列
        ids = (ArrayList)(staticobj.getRecordFromObj("ResourceInfo", "ids"));
        loginids = (ArrayList)(staticobj.getRecordFromObj("ResourceInfo", "loginids"));
        lastnames = (ArrayList)(staticobj.getRecordFromObj("ResourceInfo", "lastnames"));
        departmentids = (ArrayList)(staticobj.getRecordFromObj("ResourceInfo", "departmentids"));
        seclevels = (ArrayList)(staticobj.getRecordFromObj("ResourceInfo", "seclevels"));
        statuses = (ArrayList)(staticobj.getRecordFromObj("ResourceInfo", "statuses"));
    }
 
 
    /**
     * 从数据库获取人力资源信息并放入缓存方法
     * 从数据库获取所需要的人力资源信息 (该类所提供的人力资源信息)
     * 将获取的信息放入缓存中
     *
     */
    private void setResourceInfo() throws Exception{
       
        // 生成队列实例
        ids = new ArrayList();
        loginids = new ArrayList();
        lastnames = new ArrayList();
        departmentids = new ArrayList();
        seclevels = new ArrayList();
        statuses = new ArrayList();
       
        // 查询数据库并赋值队列
        RecordSet rt = new RecordSet() ;
        rt.executeProc("HrmResource_SelectAll","") ;
        while(rt.next()){
            ids.add(Util.null2String(rt.getString("id")));
            loginids.add(Util.null2String(rt.getString("loginid")));
            lastnames.add(Util.null2String(rt.getString("lastname")));
            departmentids.add(""+Util.getIntValue(rt.getString("departmentid"),0));
            seclevels.add(Util.null2String(rt.getString("seclevel")));
            statuses.add(Util.null2String(rt.getString("status")));
        }
       
        /* 3 */
        // 将获取的信息放入缓存中, 缓存中的一级键值为 "ResourceInfo" , 二级键值为人力资源对应的队列名称
        staticobj.putRecordToObj("ResourceInfo", "ids", ids);
        staticobj.putRecordToObj("ResourceInfo", "loginids", loginids);
        staticobj.putRecordToObj("ResourceInfo", "lastnames", lastnames);
        staticobj.putRecordToObj("ResourceInfo", "departmentids", departmentids);
        staticobj.putRecordToObj("ResourceInfo", "seclevels", seclevels);
        staticobj.putRecordToObj("ResourceInfo", "statuses", statuses);
    }
 
 
    /**
     * 获取人力资源信息数量方法
     *
     * @return int 人力资源信息数量
     *
     */
    public int getResourceNum() {
        return array_size;
    }
 
    /* 2 */
    /**
     * 将当前人力资源信息指针指向下一个人力资源信息
     *
     * @return boolean 如果有下一个人力资源信息,返回true, 否则返回false,并将当前人力资源信息指针置为初始值(初始值在第一条记录之前)
     *
     */
    public boolean next(){
 
        while((current_index+1) < array_size){
            current_index++;
            return true;
        }
 
        current_index = -1;
        return false;
    }
 
 
    /* 2 */
    /**
     * 将当前人力资源信息指针指向初始值(初始值在第一条记录之前)
     *
     */
    public void setTofirstRow(){
        current_index = -1;
    }
 
    /* 2 */
    /**
     * 获取当前人力资源信息指针指向的人力资源记录的id
     *
     * @return String 当前人力资源信息指针指向的人力资源记录的id
     */
    public String getResourceid(){
        return (String)(ids.get(current_index));
    }
 
    /* 2 */
    /**
     * 获取当前人力资源信息指针指向的人力资源记录的名称
     *
     * @return String 当前人力资源信息指针指向的人力资源记录的名称
     */
    public String getLastname(){
        return ((String)(lastnames.get(current_index))).trim() ;
    }
 
 
    /* 2 */
    /**
     * 获取当前人力资源信息指针指向的人力资源记录的部门id
     *
     * @return String 当前人力资源信息指针指向的人力资源记录的部门id
     */
    public String getDepartmentID(){
        return ((String)(departmentids.get(current_index))).trim() ;
    }
 
   
    /**
     * 获取人力资源id对应的人力资源名称信息
     *
     * @param key 人力资源id  (为人力资源信息的键值)
     * @return String 人力资源id对应的人力资源名称信息
     */
    public String getResourcename(String key) {
        int index=ids.indexOf(key);
        if(index!=-1) return ((String)lastnames.get(index)).trim();
        else return "";
    }
 
    /**
     * 获取人力资源id对应的人力资源登录名信息
     *
     * @param key 人力资源id  (为人力资源信息的键值)
     * @return String 人力资源id对应的人力资源登录名信息
     */
    public String getLoginID(String key) {
        int index=ids.indexOf(key);
        if(index!=-1) return ((String)loginids.get(index)).trim() ;
        else return "";
    }
 
   
   
    /**
     * 获取人力资源id对应的人力资源部门信息
     *
     * @param key 人力资源id  (为人力资源信息的键值)
     * @return String 人力资源id对应的人力资源部门信息
     */
    public String getDepartmentID(String key) {
        int index=ids.indexOf(key);
        if(index!=-1) return ((String)departmentids.get(index)).trim() ;
        else return "";
    }
 
   
    /**
     * 获取人力资源id对应的人力资源安全级别信息
     *
     * @param key 人力资源id  (为人力资源信息的键值)
     * @return String 人力资源id对应的人力资源安全级别信息
     */
    public String getSeclevel(String key) {
        int index=ids.indexOf(key);
        if(index!=-1) return ((String)seclevels.get(index)).trim() ;
        else return "";
    }
 
 
    /**
     * 获取人力资源id对应的人力资源状态信息
     *
     * @param key 人力资源id  (为人力资源信息的键值)
     * @return String 人力资源id对应的人力资源状态信息
     */
    public String getStatus(String key) {
        int index=ids.indexOf(key);
        if(index!=-1) return ((String)statuses.get(index)).trim() ;
        else return "";
    }
 
    /* 4 */
    /**
     * 清除人力资源缓存信息
     *
     */
    public void removeResourceCache() {
        /* 3 */
        staticobj.removeObject("ResourceInfo");
}
 
      /**
     * 删除指定缓存信息
     * @param key 指定缓存
     */
    public void deleteResourceInfoCache(String key) {
        int index = ids.indexOf(key);
        if (index != -1) {
            ids.remove(index);
            loginids.remove(index);
            lastnames.remove(index);
            sexs.remove(index);
      
        }
        array_size = ids.size();
    }
 
 
 
/**
     * 更新指定缓存信息
     * @param key  指定缓存
     */
    public void updateResourceInfoCache(String key) {
        int index = ids.indexOf(key);
        if (index != -1) {
            RecordSet rs = new RecordSet();
            rs.executeSql("select * from HrmResource where id = " + key);
            if (rs.next()) {
                ids.set(index, Util.null2String(rs.getString("id")));
                loginids.set(index, Util.null2String(rs.getString("loginid")));
                lastnames.set(index, Util.null2String(rs.getString("lastname")));
                sexs.set(index, Util.null2String(rs.getString("sex")));
                emails.set(index, Util.null2String(rs.getString("email")));
                msg.setAction(CacheManager.ACTION_UPDATE);
                msg.setCacheType("ResourceInfo");
                msg.setRowKey("ids");
                msg.setRow(ht);
                staticobj.sendNotification(msg);
                }
            }
        }
    }
}
 
 
 
以上代码需要注意的几个地方:
 
注释1:这里所定义的队列,用于依次存放人力资源的所需信息。所需信息是根据我们的需要来确定的,但是必须明确一点,只有那些经常用到的信息采放到缓存中,否则将会造成缓存的臃余。
 
 
注释2:这里的指针和方法用于一些程序遍历人力资源的所有信息。比如如下在jsp页面中的应用:
 
<select name="resourceinfo">
<%
while(ResourceComInfo.next()) {
%>
<option value="<%= ResourceComInfo .getResourceid()%>"><%=ResourceComInfo .getLastname ()%></option>
<%
}
%>
</select>
 
 
注释3:缓存中的一级键值设置为相应的类名,根据这个键值来判断缓存中是否有相应的信息,或者清除缓存中的该信息。需要注意的是,缓存中的键值信息必须唯一,不能重复!
 
注释4:在不是必须的时候,更新人力资源的时候一定要使用更新指定的缓存的方式,而不要把缓存清空,等待下一次使用到该缓存的时候在重新初始化该缓存。
 
注释5:对数据更新频率不高,使用频率确相对较高数据请尽量使用缓存的方式存取数据,而不是直接从数据库中读取。
 

2.11   泛普OA办公平台其它底层类基本方法

 
THINKONE中,还有一些常用的工具类,是在开发中基本都会使用到的,大家还需要看看如下几个类的API 文档:
 
泛普OA系统.general.Util    :
提供了大量基本的工具方法(其中提供了对字符,数据等的处理),其中null2String方法,fromScreen方法,toScreen 方法,TokenizerString ,toHtml方法是大家需要关注的方法。
 
泛普OA系统.general.TimeUtil    :
提供对日期操作的工具方法,如:日期转化,日期加减
 
泛普OA系统.general. SendMail :
提供了邮件发送的基本方法,其中send方法,sendhtml方法,sendMiltipartText方法是大家需要关注的方法。
 
泛普OA系统.sms. SMSManager
提供了发送短信的基本方法,其中sendDBSMS方法,发送短信后会在OA的数据库中存放一条发送记录,sendSMS只发送短信,不记录信息
 
泛普OA系统.file.FileManage :
提供了文件处理的工具方法。其中createDir方法,copy方法,moveFileTo方法,DeleteFile方法,extractFileName方法,extractFileExt方法,extractFilePath方法是大家需要关注的方法。
发布:2006-04-24 16:03    编辑:泛普软件 · admin    [打印此页]    [关闭]
相关文章:

泛普OA系统二次开发其他应用

泛普OA商务合同 泛普OA需求调研 泛普OA实施方案 泛普OA项目启动 泛普网络硬件配置 泛普OA部署安装 泛普流程模板表单 OA系统二次开发 泛普常见问题解决 泛普OA操作手册 泛普软件项目验收 泛普培训推广上线 泛普OA售后服务 泛普新闻 泛普期刊 泛普博客