Ecology系统程序员开发指南 下载本文

Ecology系统程序员开发指南

文件编号: 生效日期: FFPD-0100- JSWD- 001 2003-08-25 密级: 版次:1.1 总页数 正文 编制:杨国生 审核:刘煜 受控编号: FFPD-0100- JSWD- 001 修改状态: 附录 批准:刘煜

文件修改控制

修改记录编号 A1 修改 状态 新建V1.0 修改页码及条款 修改人 审核人 批准人 杨国生 刘煜 刘煜 修改日期 2003-08-25

2 泛微网络有限公司 www.weaver.com.cn

目 录

1. 引言........................................................................................................................ 4 1.1 概述................................................................................................................ 4 1.2 定义................................................................................................................ 4 1.3 参考资料........................................................................................................ 4 2. 开发规范................................................................................................................ 5 3. 底层包应用及范例................................................................................................ 7 3.1 最基本的继承类............................................................................................ 7 3.2 怎样记录日志................................................................................................ 8 3.3 怎样获取属性文件的值.............................................................................. 11 3.4 怎样获取系统的运行目录.......................................................................... 13 3.5 怎样访问和运行数据库脚本...................................................................... 14 3.6 如何上传一个文件...................................................................................... 18 3.7 如何访问已经上传的文件.......................................................................... 22 3.8 如何使用缓存提高系统效率...................................................................... 23 3.9 其它底层类基本方法.................................................................................. 32

3 泛微网络有限公司 www.weaver.com.cn

1. 引言

1.1 概述

本需求文档为泛微协同商务系统(Ecology)程序员开发指导文档,讲述了开发的规范,底层工具包的应用,常用功能的开发。通过本文档,开发人员应掌握

1.2 定义

1.3 参考资料

书籍资料 编号 资料名称 简介 1 Thinking in java Java 思想-一本很不错的书 2 Java Servlet Programing Java Servlet 编程 3 J2EE 大全 J2EE 的一本学习书

Intenet上杂志、专业著作、技术标准以及他们的网址。 网址 简介 Java.sun.com SUN 的java 网站 www.java-cn.net java 中文站 (较多的书籍, 代码) www.javastudy.org java 学习网

4 泛微网络有限公司 www.weaver.com.cn

2. 开发规范

程序文件头部加上文件描述,包括标题,描述,公司,作者,版本,创建日期,修改记录,如下: /**

* Title: 数据库链接池集合

* Description: 所有的数据库链接池的集合,用链接池名称区别每一个 * 链接池 * Company: 泛微软件 * @author : 杨国生 * @version 1.0

* create date : 2001-10-23 * modify log:

* 2002-09-13 杨国生 增加链接池Encode参数 * * */

各个明显部分间加空行,各方法间加空行,方法前面加方法的注释,遵从JavaDoc规范,与所释方法间不加空行。注释用中文给出: /**

* 从指定名称的链接池中获得一个可用连接.若没有可用连接,且已有连接 * 数小于最大连接数限制, 则创建并返回新连接.否则, 在指定的时间内等 * 待其它线程释放连接.如指定的时间内没有链接返回,则返回空。 *

* @param name 连接池名字

* @param time 以毫秒计的等待时间

* @return WeaverConnection 可用连接或null */

public WeaverConnection getConnection(String name, int time) {

DBConnectionPool pool = (DBConnectionPool) pools.get( name ) ; if (pool == null) pool = createPools( name ) ; if (pool != null) { clients ++ ; return pool.getConnection( time ) ; } return null; }

泛微网络有限公司 www.weaver.com.cn

5

大括号{ 不换行, } 需要换行。当中代码要缩进。缩进为4个空格,必须以空格代替Tab键。

圆括号()与前面的方法名间留一个空格,括号内的每个参数前留一个空格,最后一个参数后也留一个空格。

逗号后面,分号前面,运算符号和赙值符号的前后,留一个空格。

类、接口名大写字母开头,后面单词首字母大写。尽量不用下划线。如UserGroup(Class)。

对象实例、变量小写字母开头,后面单词大写。如userSQLBean(UserSQL对象的实例) , locationName(变量)。

方法名小写字母开头,首单词一般为动词,后面单词大写开头。如User.getUserName,UserSQLBean.formatSQLSearch。

开发代码不能使用当前开发环境已经不建议使用的方法。在开发环境升级的时候,需要重新编译原有系统的代码,如发现原有系统存在升级的环境中不建议使用的方法,应进行更新。

6 泛微网络有限公司 www.weaver.com.cn

3. 底层包应用及范例

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

3.1 最基本的继承类

每一个java bean 都需要继承 weaver.general.BaseBean 类 ,每一个 servlet 都需要继承weaver.general. DynamicServlet。这两个类都实现了记录日志和获取属性文件值的方法。继承这两个类的其它类可直接应用这些方法来记录日志,获取属性文件某一个属性的值。方法的实现见后面的例子。继承了weaver.general. DynamicServlet类的servlet已经是一个servlet了,只需要实现weaver.general. DynamicServlet类的抽象方法doProcess就可以实现 doGet 和doPost 方法了。

继承的例子如下:

java bean 的继承

public class ResourceComInfo extends BaseBean { public void doSomething() { //某一个方法 方法的处理……… writeLog(s) ; // 写日志 } }

servlet 的继承

public class HelloServlet extends DynamicServlet {

public void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

对请求的处理……….. } }

7 泛微网络有限公司 www.weaver.com.cn

3.2 怎样记录日志

继承了weaver.general.BaseBean 或weaver.general. DynamicServlet的类,可以直接使用 writeLog方法记录日志信息。注意这里是使用,而不是调用,因为这个方法是这两个被继承类中的方法。

注意writeLog 方法的使用: /**

* 将某个对象写入Log文件 * @param obj 被写入的对象 */

public void writeLog(Object obj)

我们看到,可以被记入日志的是任意一个java对象。这些java对象将被自动转换成字符串对象(String)记入到日志文件中。日志文件将每天生成一个,以日志文件名称中的日期来区别,比如:ecology20030812.log,代表2003年8月12日的日志。每一条日志的记录格式为 :

YYYY.MM.DD-HH:MM:SS 记录日志的类名 – 日志信息 比如:

2003.03.11-06:52:05 weaver.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 (异常)的对象才会记录到日志文件中。模式的设置在weaver.properties 属性文件中的DEBUG_MODE 属性来指定,如下:

DEBUG_MODE = true // 为调试模式 DEBUG_MODE = false // 为在线模式

正式上线的系统需要将模式设置为在线模式。

记录日志的例子如下:

public class ResourceComInfo extends BaseBean {

private void setResourceInfo() throws Exception{

try{

业务处理过程……….

String debugInfo = \

8 泛微网络有限公司 www.weaver.com.cn

}

// 在调试模式下将会记入日志文件

writeLog(\ }

catch(Exception e) { // 在任何模式下出现异常,都将会记入日志文件 writeLog(e) ; throw e ; }

}

记录的日志文件形式为:

2003.03.11-06:52:05 weaver.hrm.resource. ResourceComInfo - debug info is This is test

如果有异常,将会记录为:

2003.03.11-06:52:05 weaver.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 weaver.conn.RecordSet.executeProc(RecordSet.java:155) at weaver.conn.RecordSet.executeProc(RecordSet.java:109) at weaver.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)

9 泛微网络有限公司 www.weaver.com.cn

从上面的日志信息,可以看到ResourceComInfo类的59行代码运行的时候出现错误,这个错误是执行数据库操作的脚本错误,具体的错误信息是:形式参数 '@id_1' 定义为 OUTPUT,但实际参数却未声明为 OUTPUT。说明调用数据库脚本的时候参数的数量有出入。

定期检查日志文件,可以发现代码中的各种错误。

泛微网络有限公司www.weaver.com.cn 10

3.3 怎样获取属性文件的值

继承了weaver.general.BaseBean 或weaver.general. DynamicServlet的类,可以直接使用getPropValue方法获取属性文件的值。注意这里是使用,而不是调用,因为这个方法是这两个被继承类中的方法。

注意getPropValue方法的使用: /**

* 从配置文件中获取某个属性的值 * @param fname 属性文件名称 * @param key 值

* @return String 属性值 */

public String getPropValue(String fname , String key)

getPropValue 方法指定了从某一个属性文件fname 中获取键值key 的值。

这里的属性文件必须存放在系统运行目录下的prop 目录下,文件名称为参数fname指定的文件名,不包括属性文件的后缀名,属性文件的后缀名必须为 .properties。

比如:

系统的运行目录为 d:\\ecology\\,那么属性文件必须放在d:\\ecology\\prop\\ 目录下,取名为 thefilename.properties ,其中thefilename是任意的。

在属性文件中某一个键值的值用等号来赋值,等号后面的值必须放在一行,如果一行不够写(或者为了查看的方便),可以用 \\ 来链接多行。否则其它行的值不能被键值取得。等号左右都可以有空格,对键值和键值的值没有影响。

比如 :

thekeyname = thevalue

将键值的值放到多行: thekeyname = thevalue1 \\ thevalue2 \\ thevalue3 thevalue4

这时候thekeyname 的值为thevalue1thevalue2thevalue3 ,thevalue4 取不到,因为thevalue3后面没有 \\

在程序中要取得上述属性文件中键值thekeyname的值,使用方法:

getPropValue(―thefilename‖ , ―thekeyname‖) ;

11 泛微网络有限公司 www.weaver.com.cn

获取属性文件的值的例子如下:

public class ResourceComInfo extends BaseBean {

private void setResourceInfo() throws Exception{

业务处理过程……….

String keyValue = getPropValue(―thefilename‖ , ―thekeyname‖) ;

// 将键值thekeyname的值keyValue记入日志文件

writeLog(\

}

}

小密密:

系统的主属性文件 weaver.properties 的文件名“weaver” 作为系统常量放在weaver.general.GCONST 类中,可以使用getConfigFile() 方法来返回

“weaver ”,在编程的过程中,如果需要用到weaver.properties属性文件中的键值,请用GCONST. getConfigFile() 来获取,当主属性文件名称因为需要改变得时候,不必改变所有用到这个属性文件的类,只需要改变GCONST类中常量的值

12 泛微网络有限公司 www.weaver.com.cn

3.4 怎样获取系统的运行目录

weaver.general.GCONST 类提供了一个静态方法getRootPath() ,返回系统的运行目录,比如系统的运行目录为d 盘的ecology目录,将返回d:\\ecology\\

获取系统的运行目录的例子如下:

public class TestBean extends BaseBean { import weaver.general.GCONST ;

public void getSysRunPath(){

String sysRunPath = GCONST. GetRootPath() ;

// 将系统的运行目录sysRunPath的值记入日志文件

writeLog(\

}

}

泛微网络有限公司 www.weaver.com.cn 13

3.5 怎样访问和运行数据库脚本

这是所有编程人员都关心的一个问题。在ecology系统中,大量的数据库访问,链接的建立和持续性,事务的处理,链接池的维护等问题都被封装在weaver.conn 包下面的各个类中,应用程序的实现者不需要去关心这些问题, 而只需要调用weaver.conn.RecordSet 类来执行各种数据库操作。

weaver.conn.RecordSet 类实现了从数据库链接池中获取链接,执行指定的数据库脚本或者存储过程,并在脚本或者存储过程执行完毕后将链接及时地归还到链接池中。

Ecology系统的链接池管理请参见 weaver.conn.ConnectionPool ,

weaver.conn.DBConnectionPool ,weaver.conn.ConnCheckerTimer 类的API 文档,weaver.conn.ConnectionPool 用于管理ecology系统中的所有数据库链接池(ecology系统可以同时链接多个数据库,每一个数据库均有一个对应的数据库链接池,由weaver.conn.DBConnectionPool负责管理,而

weaver.conn.ConnectionPool则是这些链接池的大管家,负责所有链接池的协调和统一对外接口),weaver.conn.DBConnectionPool用于建立和管理对某一个数据库的链接池,weaver.conn.ConnCheckerTimer用于监控各个链接池的状况,定期对数据库链接池中不符合要求的链接进行清理,并监视是否需要在某一链接池中建立新的链接。

调用weaver.conn.RecordSet,实现对数据的操作,下面进行详细的说明:

weaver.conn.RecordSet类采用 java.sql 中的 CallableStatement 和 Statement 执行数据库操作。客户端直接调用该类进行数据库操作。不需要考虑数据库链接的建立。其中客户端指所有调用该类进行数据库操作的应用程序,不特指用户的客户端。

RecordSet 执行数据库操作有两种形式,一种为调用存储过程,另一种为直接执行SQL语句。与ConnStatement不同 ,RecordSet 执行SQL语句不分查询和修改,都在一条语句中执行。RecordSet执行脚本的方式如下:

1、使用默认的链接池执行SQL语句: RecordSet rs = new RecordSet() ;

rs.executeSql(\while( rs.next() ) {

String thename = rs.getString(\其它处理代码....……

}

2、使用指定的链接池ecologytest执行SQL语句 RecordSet rs = new RecordSet() ;

rs.executeSql(\

14 泛微网络有限公司 www.weaver.com.cn

3、使用指定的链接池ecologytest执行存储过程 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( \

procpara 是存储过程的参数值组成的字符串变量,多个参数值之间用 weaver.general.Util.getSeparator() 分开

4、在一个客户程序多个执行之间,查询结果可以保留到下一次查询 RecordSet rs = new RecordSet() ;

rs.executeSql(\

rs.executeSql(\while( rs.next() ) {

String thename = rs.getString(\得到修改前查询的值 其它处理代码....…….

}

rs.executeSql(\while( rs.next() ) {

String thename = rs.getString(\得到修改后查询的值 其它处理代码....……

}

访问和运行数据库脚本的例子:

public class ResourceComInfo extends BaseBean {

泛微网络有限公司 www.weaver.com.cn 15

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(\

String loginid = Util.null2String(rt.getString(\ String lastname = Util.null2String(rt.getString(\ // 将数据库的值记入日志文件 writeLog(\

writeLog(\

writeLog(\ }

}

其它关于系统数据库信息的管理

a)、weaver.conn.ConnectionPool 类的管理和设置:

所有的数据库链接池的集合,用链接池名称区别每一个链接池.支持对一个或多个由属性文件定义的数据库连接池的访问.客户程序可以调用getInstance()方法访问本类的唯一实例。

对于一个链接池集合来说,可以有多个链接池,分别链接不同的数据库。应用程序指定链接池的名称来调用不同的链接池。如果应用程序没有指定链接池的名称,将使用默认的链接池。默认链接池的指定有两种方式:

1、在Application Server设置的初始参数serverName的值 ,以Resin 为例:

2、如果Application Server没有相应设置,则系统使用属性文件(weaver.properties)中设置的默认链接池名称: DefaultPoolName = ecology

16 泛微网络有限公司 www.weaver.com.cn

对于所有的链接池,系统需要加载相应的 JDBC Driver来建立与相应数据库的链接。这些 Driver 在属性文件(weaver.properties)中指定,多个Driver中间用空格隔开:

DriverClasses = com.microsoft.jdbc.sqlserver.SQLServerDriver

对于每一个链接池需要用到的参数在属性文件(weaver.properties)中指定,属性文件中参数的名称以链接池的名称开头,中间加入小数点,比如链接池 ecology 的参数指定为 :

ecology.url = jdbc:microsoft:sqlserver://10.1.1.205:1433;DatabaseName=AIS2002 //db url

ecology.user = sa //db user name ecology.password = 123456 //db user password ecology.charset = ISO_1 //db encode ecology.maxconn = 10 //max conn in conn pool ecology.minconn = 2 //min conn in conn pool ecology.maxusecount = 30 //the max use times of a conn ecology.maxidletime = 30 //the max unuse time of a conn (分)

ecology.maxalivetime = 2 //一个链接被调用后的最大未归回时间 (分) ecology.checktime = 500 //检查的频率 (秒)

b)、weaver.conn. DBConnectionPool类的管理和设置:

数据库链接池,所有创建的链接存放在链接池中,在客户端链接数据库时从链接池中取出链接,客户端在完成数据库操作后将链接返回链接池。

链接池创建链接需要用到的参数在属性文件(weaver.properties)中指定,属性文件中参数的名称以链接池的名称开头,中间加入小数点,比如链接池 ecology 的参数指定为 :

ecology.url = jdbc:microsoft:sqlserver://10.1.1.205:1433;DatabaseName=AIS2002 //db url

ecology.user = sa //db user name ecology.password = 123456 //db user password ecology.charset = ISO_1 //db encode ecology.maxconn = 10 //max conn in conn pool ecology.minconn = 2 //min conn in conn pool ecology.maxusecount = 30 //the max use times of a conn ecology.maxidletime = 30 //the max unuse time of a conn (分)

ecology.maxalivetime = 2 //一个链接被调用后的最大未归回时间 (分) ecology.checktime = 500 //检查的频率 (秒)

17 泛微网络有限公司 www.weaver.com.cn

3.6 如何上传一个文件

上传一个文件只需要调用weaver.file.FileUpload 类。weaver.file.FileUpload 类支持各种文件格式的上传,也支持多文件的上传。

B/S 架构的文件上传采用的是multipart/form-data 协议,而不是HTTP协议,采用这种协议上传的数据必须通过特殊的处理,而不能用常规的方法来获取,否则不能得到数据。weaver.file.FileUpload 封装了底层处理的代码,应用程序的实现者不需要关心这些细节!

weaver.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页面中文件浏览的字段代码为:

那么这里的文件字段的名称为\。 第二点是这个方法返回的信息是保存在数据库表 ImageFile 中关于这个文件信息的键值imagefileid ,这个表的结构如下: Column(s) of \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:是 18 泛微网络有限公司 www.weaver.com.cn

Column(s) of \Name Datatype isencrypt char(1) Null Option NULL Comment 是否加密 0:否 1:是 文件(存在在数据库中的文件内容,现已不使用) imagefile image NULL 从表结构可以看出,我们得到了某一个文件信息的imagefileid,就可以从该表中得到相应的文件名称(这里指文件的实际名称,比如test.doc), 文件MIME类型(比如 txt,doc,gif等) ,文件存放目录(这里指在服务器中存放的实际路径信息,包括实际存放的文件名称,比如

e:\\ecologyfilesystem\\2003\\08\\A\\23143567.zip)。通过这些信息,可以对文件进行操作,当然weaver.file.FileUpload 还提供了其它很多方法来获取文件相关的信息,不需要通过数据表的查询就能得到这些信息。存放在数据表中的信息只是供今后文件处理的时候使用!

上传文件的例子:

首先,我们要创建一个提交数据的页面,可以是jsp 的页面,也可以是html 的页面,我们将数据提交给 weaver.test.MutiFileUpload 的servlet 类来处理:

文件上传

这是一个文件上传的例子

将上面这段代码保存为一个html 文件FileUploadTest.htm,放在ecology运行目录下的/test/目录下。在这个页面中,有一个输入框和两个文件框可以输入信息。注意,在环境的配置中,需要告诉web服务器将 /weaver/ 的请求转给应用

19 泛微网络有限公司 www.weaver.com.cn

服务器作为servlet处理,关于配置的信息,请参考Apache 和Resin的配置文档。

下面我们来编写weaver.test.MutiFileUpload

package weaver.test; /**

* Title: 多文件上传处理类 * Description: 多文件上传测试

* Copyright: Copyright (c) 2001 * Company: weaver * @author liuyu * @version 1.0 */

import javax.servlet.http.HttpServletRequest; import weaver.general.DynamicServlet; import weaver.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(\String[] fileFieldNames = {\String[] fileIds = fu.uploadFiles(fileFieldNames) ; /*2*/ String[] fileNames = fu.getFileNames() ; /*3*/

// 将请求信息记入日志文件

writeLog(\ for (int i=0; i< fileIds.length; i++) { String fileId = fileIds[i] ; If(fileId == null) continue ; String fileName = fileNames[i] ;

writeLog(\

writeLog(\

}

response.sendRedirect(\

}

泛微网络有限公司 www.weaver.com.cn 20

}

以上代码需要注意的几个地方:

注释1:由于使用了multipart/form-data协议, 这里获取请求中的信息必须使用fu. getParameter() 方法,而不能使用 request.getParameter() 方法,否则不能得到filedesc的值!

注释2:使用uploadFiles方法上传accessory1和accessory2中的文件,同时返回保存在ImageFile 表中的文件基本信息的键值imagefileid,可以将这个imagefileid记录到其它地方以便今后调用。

注释3:使用getFileNames方法获取上传文件的真实名称(包括后缀名)

将代码保存到 /src/weaver/test/MutiFileUpload.java 文件中。访问

FileUploadTest.htm 来测试一下,看看日志文件中的记录是否正确。页面提交,文件上传完毕后将再次返回FileUploadTest.htm页面。你可以查看ImageFile表来检查文件的具体存放位置等信息。

小秘密:

文件的存放位置在系统设置模块中设置,如果没有设置,将存放在系统运行目录下的 filesystem 目录下。

21 泛微网络有限公司 www.weaver.com.cn

3.7 如何访问已经上传的文件

在jsp页面或者html页面中访问已经上传的文件非常简单,只需要调用

weaver.file.FileDownload类,并传递需要访问的文件id ,这个文件id,就是在文件上传中返回的 imagefileid。

访问上传的文件有两种方式,一种是非下载方式,这种方式如果浏览器能够显示访问的文件类型,那么就会在浏览器中直接显示。另一种是下载方式,无论访问的文件是什么类型,都使用弹出下载窗口的形式下载。

对非下载方式的链接访问

对下载方式的链接访问

如果知道要访问的文件是图片,并需要在浏览页面中直接显示这个图片,可以使用下面的代码访问

22 泛微网络有限公司 www.weaver.com.cn

3.8 如何使用缓存提高系统效率

对于一些常用的信息,比如人员的名称,如果每次访问的时候都查询数据库来获取,将极大的影响系统的性能。我们可以将这些信息放到系统的缓存中,在用到的时候,从系统缓存中获取。

系统提供了 weaver.general.StaticObj 类来保存这些信息。

weaver.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)

23 泛微网络有限公司 www.weaver.com.cn

/**

* 获取 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为相应缓存信息的名称。参考如下的人力资源缓存类:weaver.hrm.resource.ResourceComInfo。

ResourceComInfo 类主要提供人力资源信息中常用的一些信息的缓存,比如人员名称,所在部门。对于这些信息,都需要一个键值。常见的键值是这些信息在数据库表中的Primary Key,比如人力资源ID,其它模块和功能在关联人力资源信息的时候,只记录人力资源的ID,当需要获取人力资源的其它信息,如人员名称,所在部门的时候,从ResourceComInfo类提供的统一接口中获取。

24 泛微网络有限公司 www.weaver.com.cn

weaver.hrm.resource.ResourceComInfo 的代码:

package weaver.hrm.resource;

import java.util.*; import weaver.conn.*; import weaver.general.*; /**

* Title: 人力资源缓存信息接口类

* Description: 对其它模块和功能提供统一的获取人力资源信息的接口 * Copyright: Copyright (c) 2002 * Company: weaver * @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() ;

25 泛微网络有限公司 www.weaver.com.cn

array_size = ids.size(); }

/**

* 获取人力资源缓存信息方法

* 检查是否有人力资源缓存信息,如果没有,将调用setResourceInfo 方法从

数据库中获取人力资源信息并放入缓存中 * 将缓存中的信息赋予相应的队列 * */

private void getResourceInfo() throws Exception{ /* 3 */

if(staticobj.getObject(\ setResourceInfo();

// 将缓存中的信息赋予相应的队列

ids = (ArrayList)(staticobj.getRecordFromObj(\

loginids = (ArrayList)(staticobj.getRecordFromObj(\ lastnames = (ArrayList)(staticobj.getRecordFromObj(\\

departmentids = (ArrayList)(staticobj.getRecordFromObj(\\

seclevels = (ArrayList)(staticobj.getRecordFromObj(\\

statuses = (ArrayList)(staticobj.getRecordFromObj(\ }

/**

* 从数据库获取人力资源信息并放入缓存方法

* 从数据库获取所需要的人力资源信息 (该类所提供的人力资源信息) * 将获取的信息放入缓存中 * */

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() ;

26 泛微网络有限公司 www.weaver.com.cn

rt.executeProc(\ while(rt.next()){

ids.add(Util.null2String(rt.getString(\

loginids.add(Util.null2String(rt.getString(\ lastnames.add(Util.null2String(rt.getString(\

departmentids.add(\ seclevels.add(Util.null2String(rt.getString(\ statuses.add(Util.null2String(rt.getString(\ }

/* 3 */

// 将获取的信息放入缓存中, 缓存中的一级键值为 \, 二级键值为人力资源对应的队列名称

staticobj.putRecordToObj(\

staticobj.putRecordToObj(\ staticobj.putRecordToObj(\

staticobj.putRecordToObj(\ staticobj.putRecordToObj(\ staticobj.putRecordToObj(\ }

/**

* 获取人力资源信息数量方法 *

* @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;

27 泛微网络有限公司 www.weaver.com.cn

}

/* 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 (为人力资源信息的键值)

泛微网络有限公司 www.weaver.com.cn 28

* @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 \ }

泛微网络有限公司 www.weaver.com.cn 29

/**

* 获取人力资源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(\ } }

以上代码需要注意的几个地方:

注释1:这里所定义的队列,用于依次存放人力资源的所需信息。所需信息是根据我们的需要来确定的,但是必须明确一点,只有那些经常用到的信息采放到缓存中,否则将会造成缓存的臃余。

注释2:这里的指针和方法用于一些程序遍历人力资源的所有信息。比如如下在jsp页面中的应用:

30 泛微网络有限公司 www.weaver.com.cn

注释3:缓存中的一级键值设置为相应的类名,根据这个键值来判断缓存中是否有相应的信息,或者清除缓存中的该信息。需要注意的是,缓存中的键值信息必须唯一,不能重复!

注释4:清理缓存信息,其目的是在下一次获取缓存信息的时候,必须重新从数据库中读取一次在放入缓存中。在什么时候需要清理缓存信息呢?当然是在人力资源信息有所改变的时候,比如新建了人力资源,删除了人力资源,修改了人力资源信息(这里如果能判断修改的信息是否为缓存中的信息,比如人力资源姓名,当是的时候才清理,不是的时候就不清理,是最好的!)。

对于清理缓存,如果能改为新的处理方式,即在数据库信息改变的同时,只改变对应的缓存信息,而不是清理缓存信息后重新读取数据库,将对程序的性能起到很好的改进!

31 泛微网络有限公司 www.weaver.com.cn

3.9 其它底层类基本方法

在开始编程之前,大家还需要看看如下几个类的API 文档:

weaver.general.Util :

提供了大量基本的工具方法,其中null2String方法,fromScreen方法,toScreen 方法,TokenizerString 方法是大家需要关注的方法。

weaver.general. SendMail :

提供了邮件发送的基本方法,其中send方法,sendhtml方法,sendMiltipartText方法是大家需要关注的方法。

weaver.file.FileManage :

提供了文件处理的工具方法。其中createDir方法,copy方法,moveFileTo方法,DeleteFile方法,extractFileName方法,extractFileExt方法,extractFilePath方法是大家需要关注的方法。

weaver.file.GraphFile weaver.file.GraphOut

提供了图形处理的方法。具体的使用和实例请参见 《ecology图片API及实例文档》

weaver.file.ExcelFile weaver.file.ExcelOut weaver.file.ExcelParse weaver.file.ExcelRow weaver.file.ExcelSheet weaver.file.ExcelStyle

提供了Excel文件的生成和处理的方法。具体的使用和实例请参见 《ecology Excel API及实例文档》

32 泛微网络有限公司 www.weaver.com.cn