泛普协同OA办公底层包开发指南
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系统filesystem2003 8A23143567.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方法是大家需要关注的方法。
- 1什么OA软件在功能比较好?泛普OA连JSP式样编写指南都开放了,你说好不好
- 2XX地产公司OA软件全面预算管理开发
- 3协同OA办公系统的预算相关系统表单开发
- 4泛普OA系统新增新的权限控制新功能的查看
- 5协同OA办公系统的二次开发经验总结
- 6OA系统关于需求,提供任务查询调整代码位置:
- 7泛普OA系统在企业的预算控制科目开关开发功能
- 8XX电网传媒OA软件客户模块定制开发测试
- 9泛普OA软件二次开发总结(史上最全的)
- 10OA软件目管理软件任务的行插入
- 11OA单点继承登陆设置:查看二次开发文档
- 12泛普OA协同办公系统的二次开发服务范围
- 13客户对OA办公自动化软件的开发需求描述
- 14OA办公自动化提供应用级二次开发功能与手段
- 15协同办公管理系统的HTML表单准备工作
- 16OA需求:对系统表单‘采购申请单’添加明细
- 17泛普OA一个JSP页面,一个JAVA程序的基本组成,如何阅读JSP页面
- 18OA办公系统可将通讯录以excel形式打开或保存至本地
- 19地产行业OA协同软件定制开发需求及实施方案
- 20协同OA软件按流程限制用户可选择的预算科目
- 21泛普协同OA办公底层包开发指南
- 22协同OA管理应用平台项目_OA与EAS系统集成方案
- 23OA软件系统二次开发培训文档,你值得一看
- 24OA协同软件工作日志开发方案
- 25XX建设公司协同管理软件流程二次开发
- 26泛普OA软件中的工作日志(微博)开发方案
- 27企业对协同OA系统中页面详细需求说明
- 28要做OA办公系统,找哪家系统开发公司比较好?泛普超专业二次开发方案
- 29什么是OA系统的二次开发功能呢?
- 30OA管理软件[资产采购]与[资产入库]自定义流程需求