Exceed基础框架使用手册... 2
1. 写在前面的话... 2
1.1 本文档的形成... 2
1.2 本文档面向的读者... 3
1.3 提示... 3
1.4 感谢... 3
2. 概述... 3
2.1 简单介绍... 3
2.2 系统适用环境... 3
2.3 相关第三方组件... 3
3. 快速上手... 4
3.1 部署应用程序... 4
3.2 我的第一个web应用... 4
3.2.1 JAVA代码部分... 4
3.2.2 jsp部分... 4
3.2.3 定义xml文件部分... 4
3.2.4 在hibernate.cfg文件中增加模型和表的映射关系... 4
4. 体系结构... 4
4.1 关键类说明... 5
4.1.1 WafAction(waf.action. WafAction) 5
4.1.2 DBAction. 5
4.1.3 ActionFilter(waf.action. ActionFilter) 7
4.1.4 DataManger(waf.db. DataManger) 7
4.1.5 WafMap(waf.db. WafMap) 8
4.1.6 WafModel(waf. WafModel) 9
4.1.7 WafForm(waf.action. WafForm) 10
4.1.8 DBUtil(waf. DBUtil) 10
4.1.9 SQLResult(waf.db.query. SQLResult) 10
4.1.10 LabelValueUtil(waf.db. LabelValueUtil) 11
4.1.11 DBUtil(waf.util. ParamUtil) 11
4.1.12 ObjectUtil(waf.util. ObjectUtil) 11
5. 系统配置... 12
6. 鑫路框架开发入门... 12
6.1 第一个Waf实体类... 12
6.2 第一个WafForm类... 13
6.3 第一DBAction类... 13
7. Waf开发进阶... 14
7.1 在列表页面上增加查询条件... 14
7.1.1 WAF查询说明... 15
7.1.2 多字段模糊搜索... 16
8. 其它重要功能... 16
8.1.1 文件上传功能... 16
8.1.2 Excel报表系统... 17
8.1.3 通用树组件... 17
9. 最佳实践... 19
9.1.1 关于Form定义的约定... 19
9.1.2 使用Model的业务验证机制... 19
9.1.3 扩展性的考虑... 19
9.1.4 基于baseproj来开始你的web项目... 19
9.1.5 异常处理... 20
10. 其它说明... 22
10.1 src_daf程序包... 22
10.2 exceed包... 23
10.3 bus包... 23
10.4 test 23
10.5 demo. 23
10.6 src. 23
11. 后记... 23
ExceedWeb基础框架使用手册
在java web开发中,有太多的的开发框架可供选择,
waf开发完成已经快1年了,但一直没有一个象样的手册,之前一直是自己在使用,也就觉得没有这个必要,知道2月初宋工说可能会在新项目中尝试使用,我才下定决心写一篇文档
java web程序员(最好是懒惰的):本框架的终极目标是将代码量降到最少,如果你不想再写那么多每完没了的机械代码,waf就适合你。
由于ExceedWeb还会有发展,所以本文档也会不断更新,当然waf的应用开发接口会向下兼容
Exceed基础框架的目的是为了解决我们在开发中经常反复制造类似轮子的问题,希望能最大限度减少重复开发的工作量,本版本的主要功能整合了数据访问,structs的简易封装,系统管理,手机短信,权限管理,文件上传、下载。经过资产和安全项目的实际应用,基础框架已具体较好的稳定性
项目 |
详细说明 |
应用服务器 |
在各个版本的tomcat都通过了测试,但未在其它应用服务器上测试过,理论上应该没问题 |
JAVA运行环境 |
基于JDK1.4.1开发,未在其它JDK版本上测试过 |
数据库 |
在DB2,SQLSERVER上都通过了测试,其它数据库没有测试过,因为数据访问层使用hibernate,所以理论上支持各种数据库 |
在此只说明几个关键的组件
组件名称 |
详细说明 |
Hibernate |
由于hibernate3.0不支持直接在sql语句中写中文,影响了WAF组装sql查询的功能,故waf使用hibernate2.7.1 |
Structs |
使用1.2,1.2.7也通过了测试,其它版本没测试过 |
Dwr |
0.6.1 |
Waf:exceedweb项目的核心功能包,本手册的展现内容
1、 访问wangxh//f$/ecipse/workspace/baseproj,拷贝baseproj工程目录到你的eclipse工程目录下
2、 建立或导入工程
3、 部署应用(以tomcat4.1.31为例子)修改 tomcat/conf/server.xml文件中第271行左右,改变应用的路径,
4、 启动应用程序
http://localhost:8080/baseproj/index.jsp,用户名adminc,密码:1111
下面我们以做一个操作手机短信组表(MessageGroup)的应用程序为例说明waf的使用过程
1、 建立实体类
MessageGroup,该需要继承自waf.WafModel
2、 建立Form类:MessageGroupForm 该类需要继承waf.action.WafForm
3、 建立Action MessageGroupAction 该类需要继承waf.action.DBAction,并需要实现getEntityBean()方法,以便让基类知道Action操作的实体类
1、 在web目录下建立messagegroup目录,存放对messagegroup表的列表,新增,修改页面,jsp文件的写法与一般的structs应用没有区别,所以就不详细描述了
与一般的structs应用没有区别,但因为MessageGroupAction 类继承自DBAction,所以需要定义约定好的fowardname名称,具体参考struts-config.xml文件,当然也需要同时在titles_def中定义jsp的配置
本图描述了Waf包的核心类结构及关系
执行具体的do方法,起到了一个分发器的作用,如果你的类不需要访问数据库,可以直接从该类继承
Waf系统的核心类,所有需要访问数据库的Action类都继承自该类,默认提供了数据表的增加,删除,修改,查询(多条件及模糊查询)功能
方法 |
详细说明 |
getEntityBean |
返回一个实体类的class对象,waf通过该方法知道需要操作那一个实体类,该方法为抽象方法,子类必须实现 |
getDataManager |
返回一个DataManger数据操作者对象,用户通过实现此方法,可以通知waf使用用户自定义的map类来进行数据维护,当然用户也可以在action的do方法中直接调用该类的方法,若用户不实现该类,waf将使用默认的数据管理类来完成数据维护工作,若你的map类中数据维护逻辑有特殊行为(比如操作多表),需要实现此方法 |
GetPageCond |
获得pagecond对象,可以在可插入方法中使用pagecond对象以控制显示的参数 |
要执行dolist方法,需要在设定act参数=list,提交后,系统将执行dolist方法
方法 |
详细说明 |
initListPage |
在执行dolist方法时,首先会调用initListPage方法,以便用户可以在打开list页面做一些自定义的动作,如设置下拉列表,设置查询条件的默认值等,你还可以通过设定pagecond对象属性的设置,在显示列表之前决定每页显示的条数,数字和日期的显示格式等
|
getListSql |
获得用于列表查询的sql语句,若不重载此方法,waf将使用默认的sql语句,查询该实体的全部记录 |
afterCreateFormBean |
在dolist方法的最后执行,此时waf已生成了formbean的结果集合,你可以改变list中的formbean的值,获得你期望的显示效果。 |
在打开新增页面之前,我们需要先调用doBeforeAdd方法,与dolist方法一样,需要在设置act参数为BeforeAdd
方法 |
详细说明 |
initAddPage |
初始化新增页面,在打开新增页面时调用,可以在此方法做一些设置下拉,设置默认值的工作 |
该页面在打开修改页面之前调用
要点:在执行doBeforeUpdate时,需要在参数中传入h_key标记需要修改的记录主键id号
方法 |
详细说明 |
initAddPage |
初始化新增页面,在打开修改页面时调用, |
getListSql |
执行dobeforeupdate的最初步骤时,需要调用此方法获得查询语句,若不实现此方法,waf将使用默认的查询语句,//TODO:若执行getlistsql语句取不断记录,系统将使用默认的sql语句,即获得该表的所有记录,再加上主键条件 |
beforeUpdate |
在生成修改页面内容后,若你还需要改变显示的内容,可以在此方法中改变form中的属性值 |
doaddnew方法执行记录的新增动作,默认情况下框架会根据当前页面上输入的值生成一个新对象,并将该对象插入。
方法 |
详细说明 |
afterCreateNewObj |
生成新的待插入对象前时调用此方法,系统会根据输入的参数自动生成新对象,但有时也需要修改部分对象属性,若需要修改部分对象属性,可重载此方法 |
afterAddnew |
AfterAddNew,有时需要控制执行完doaddnew后的动作,该方法较少用到 |
方法 |
详细说明 |
afterCreateUpdateObj |
生成新的待更新对象前时调用此方法,系统会根据输入的参数自动生成新对象,但有时也需要修改部分对象属性,若需要修改部分对象属性,可重载此方法 |
afterUpdate |
afterUpdate,有时需要控制执行完doaupdate后的动作,该方法较少用到 |
方法 |
详细说明 |
getObject |
获得当前页面操作的实体类的实例, |
|
|
1、命名约定:在
在执行DBAction的所有方法之前,DBAction会调用此接口的方法,这样用户可以在执行每一个do方法之前先做一些处理,比如进行权限验证等….
方法 |
详细说明 |
doFilter |
执行过滤器方法,可以定义该接口的实现类的方法,然后在waf.properties中配置 actionFilter=com.ifreeway.common.sysmgr.rights.PerimitFilter |
|
只能定义一个该接口的实现 |
数据操作接口,定义了新增,删除,修改的方法,DBAction需要操作此接口的方法
方法 |
详细说明 |
creat(Object obj) |
新增对象, |
update(Object obj) |
更新对象 |
delete(Object obj) |
删除对象 |
实现DataManger接口,系统中所有数据访问的DAO对象都需要继承此类,该类还提供了对事务处理方法的封装
方法 |
详细说明 |
BeforeNew(Object obj) |
在新增之前执行业务验证,如编码的唯一性,可以进行复杂的组合验证,具体定义方法见WafModel的说明, |
Create(Object obj) |
插入一个对象 |
Create(List lst) |
插入对象集合,默认使用了事务提交 |
createInTrans(Object obj) |
插入一个对象,在事务中使用,需要使用endTransaction(true),才能生效 |
CreateAndGetID(Object) |
插入对象后获得返回值,返回新对象的主键 |
…
|
|
其它说明 |
1、在插入新记录时,会生成新记录的插入时间为当前时间,精确到毫秒,如果表中没有create_time字段将不生效,其它请参考api说明 |
try{
//开始事务过程
this.beginTransaction();
//在事务中执行新增,所有在事务中使用的方法名都带有InTrans
this.createInTrans (org);
this. DeleteInTrans(user);
this. EndTransaction(true); //结束并提交事务
}catch(Exception e){
this.endTransaction(false);
// 抛出原始的异常信息
Exception ee = new Exception();
ee.setStackTrace(e.getStackTrace());
throw ee;
}
所有业务实体类对象的基类,要使用Waf的特性,所有实体类都必须继承自该类
方法 |
详细说明 |
GetDelFlagColumn() |
获得删除字段标记名,默认返回null,认为该表没有del_flag字段,若定义了del_flag字段,则waf执行删除时,将自动对其进行假删除,即将该字段值置为1,新增时,waf会自动设置该字段值为0 推荐将删除字段的名称定为del_flag |
GetOrderColumn() |
获得该表的排序字段,默认情况下在执行doList方法时,系统将根据该字段做降序排列,这样就保证了你总是可以在最前面看到新增或修改的记录 |
isDesc |
是否按照降序排列, |
getValidateUniqueFileds |
获得需要校验唯一性的字段,比如需要验证短信组名称的唯一性,就可以这样写mg_name:短信组名称,系统将会在新增,修改时候,验证该字段的唯一性, 定义规则: 字段名1:中文信息; 字段名2:中文信息,可以同时验证多个字段的唯一性 |
getComplexUniqueField |
复合验证,以短信组为例,需要验证相同帐号不能有相同的短信组名称,就可以使用此验证方法mg_name:短信组名称:account |
约束 |
1、主键必须是唯一的,而且必须是long型 |
最佳实践-表设计 |
1、 最好给大多数表定义del_flag字段,对记录做逻辑删除,这样可以更好的维护系统 2、 给每个表定义一个create_time(创建,更新时间),这样可以帮助你分析问题 |
最佳实践-类设计 |
1、如果你的系统决定使用waf,推荐你为你的系统定义一个基类,该类继承自WafModel,这样你可以统一控制实体对象的特性,也可以将来不依赖一某一组件 |
该类继承自ValidatorActionForm,系统中所有用于表现层的Form对象都要继承自该类
由于该类继承自ValidatorActionForm,所以WafForm中可以使用strcuts的验证方法
row_id:在list中显示的行号
数据类型:若实体类中某一字段的属性为double,float,date型,需要在form中将相应的属性定义为String
提供了一些常用的查询工具函数
方法 |
详细说明 |
execQuery(String sql) |
执行hibernate查询,返回结果集, |
findObjectWithQuery(String sql) |
这个方法得到查询语句的List里的第一个对象 |
getSQLResult |
获得一个SQLResult对象 |
其它方法请参考API说明 |
|
SQLResult主要是为了解决hibernate在执行多字段查询时不能按列名取值的缺陷而设计
使用传统的hibernate查询
String sql="select a.f1,b.f2from Hy_doc_deal_histModel a, Hy_doc_infoModel b //取得数据 Object value1=objs[0]; Object value2=objs[1]; |
如上所示,你必须记住每一个字段的位置,如果选择字段增加或者减少后改变了相对位置,队程序员来说简直是一场灾难,笔者曾因此问题调试了一个下午。
使用SQLResult可以像使用传统的JDBC ResultSet接口一样访问数据
sql = "select a.breed_id, count(a.breed_id) from EquipmentBreed a where a.mac_flag = 1 and a.report_flag = 1 and a.eq_type = '" + types[i] + "' group by a.breed_id"; SQLResult rs = DBUtil.getSQLResult(sql); while (rs.next()){ breedId = rs.getStrValue(“breed_id”); Long sCount = rs.getStrValue(2); //设备已安装总数 tmp = ((Double) ratingHt.get(breedId)).doubleValue() * sCount.longValue() * iDays; sCountHt.put(breedId, sCount); //单项设备累计工作总时数 ratingSumHt.put(breedId, new Double(tmp)); } |
你既可以通过字段的相对顺序访问结果集,也可以通过列名访问,与使用JDBC ResultSet的方式完全相同
提供了对于structs选择列表界面的完整解决方案
方法 |
详细说明 |
listLabelValues(String cate_name,boolean addSelectRow) |
获得下拉值集合,cate_name可以是systype中定义的类别名,也可以是一个hql语句 hql语句要求显示名称在前,值在后 |
getLabel(String value, List lst) |
根据值取得名称 |
方法 |
详细说明 |
execQuery(String sql) |
执行hibernate查询,返回结果集, |
findObjectWithQuery(String sql) |
这个方法得到查询语句的List里的第一个对象 |
ObjectUtil提供了一些系统级的方法,主要用于对象间交换数据
方法 |
详细说明 |
ObjectToFormBean(Class frmClass,List lst) |
转换一组实体类的对象到formbean对象 |
copyProperty(Object srcObj,Object targetObj) |
拷贝源对象属性到目标对象 |
cloneObject(Object srcObj) |
克隆对象 srcObj 需要克隆的对象 |
ExeGetMethod(Object obj,String methodName) |
在知道方法名称(不含get前缀)的情况下,执行对象的get方法 |
ExeSetMethod(Object obj,String methodName) |
执行set方法 |
#数据库连接提供者,默认使用
conn.provider=com.ifreeway.common.config.XinluConnector
#action过滤器(可选)
actionFilter=com.ifreeway.common.sysmgr.rights.PerimitFilter
我们以demo中的短信组为例子来讲述waf的基本使用方法,在后续的章节中我们将对该用例进行多次重构,通过这一过程,你可以一步步加深对Waf的理解
package com.ifreeway.safe.messagegroup; import waf.WafModel; public class MessageGroup extends WafModel { private Long mg_id; private String account; private String mg_name; private String accounts; private String tels; private String description; ----省去了get,set方法 |
Waf对用户定义的实体类没有特别的要求,只需要继承自WafModel类就行
package com.ifreeway.safe.messagegroup.form; import waf.action.WafForm; public class MessageGroupForm extends WafForm { private Long mg_id; private String account; private String mg_name; private String accounts; private String tels; private String description;
private String accounts_name; |
同样地,你可以像写普通Form类一样写,但也需要继承自WafForm
package com.ifreeway.safe.messagegroup.action; public class MessageGroupAction extends DBAction { /** * 获得该Action操作的实体类 */ public Class getEntityBean() { return MessageGroup.class; } } |
对于一个最简单的单表操作,全部代码就这些了,简单吧。
也许你也注意到了,讲了这么多,我们一直没有讲structs的配置,在使用waf的应用程序中,对于structs的配置与普通应用程序一样,只是对于有一下约定
type="com.ifreeway.safe.messagegroup.action.MessageGroupAction" name="MessageGroupForm" scope="request">
|
通过例子可以看出,各个页面的forward name都是约定好的,在以后的编码中遵守即可
经过前面一章的学习,你已经掌握了一个最简单WAF应用的编写方法,但WAF的优势远不至于此,从本章开始我们将开始接触waf的更多功能。
以用户管理为例,现在我们需要在用户列表页面上增加按照组织机构查询用户的功能,在传统的编程中,实现这个功能,我们需要编写代码,而且因为客户的需求变化会很大,所以需要经常需要查询代码。
我们首先看sysmgr/userinfo/userinfo_list.jsp的代码
所属机构:<html:select property="qd_int_org_id"> <html:options collection="belongtoorg_id_list" labelProperty="label" styleClass="sel-cel" property="value"/> html:select>
关键字: <input type="text" name="darkQuery[account,username]" class="fom-search3" size="25"/> <html:submit styleClass="button-search" value="查 询"/>
|
com.ifreeway.common.sysmgr.userinfo.action. UserInfoAction
/** * 初始化list页面时执行, */ protected void initListPage(ActionMapping mapping, ActionForm aform, HttpServletRequest req, HttpServletResponse res) throws Exception { WholeUserInfo user=BusFacade.getWholeUserInfo(req); String sql ="select a.org_id, a.orgname from OrgInfo a where a.del_flag = 0 and a.org_code like '"+user.getOrg_Code()+"%'"; //获得机构下拉列表 req.setAttribute("belongtoorg_id_list", LabelValueUtil.listLabelValues(sql, true)); }
|
我们可以看到,增加这样一个查询条件,我们没有编写任何与查询有关的代码就实现了查询需求,在使用waf的应用程序中,你可以同时定义多个查询条件,唯一的要求是你在页面上定义的查询字段需要符合waf规范
1、 精确查询,通过在页面上定义多个查询字段,waf可对多个查询做组合查询。查询定义格式:qd_字段类型_字段名称_tb_表别名_op_比较运算符,如qd_int_org_id
字段项目 |
说明 |
qd |
必需,标志这是一个精确查询字段 |
字段类型 |
必需 可以使用int,date,string 若是string类型,可以省略不写 若该字段是float,double,可认为是int类型 |
字段名称 |
必需 字段名称必须与实体类中定义的一致 |
tb |
可选 标记其后是一个表别名,若你的查询中涉及到多个表,需要填写其它表的别名,若省略此项,系统会默认使用aliaName为表别名,所以如果你只查询一个表,可以不使用该项目 |
表别名 |
使用你在查询中定义的表别名 |
op |
可选 一个操作符的开始标记,若使用等于操作符,可以不填写该项目 |
比较运算符 |
可选 可以使用的运算符 largeequal >= smallequal<= large > small < like like,若不定义该项,系统会默认使用= |
2、 同时使用多个查询字段
使用waf,你可以在页面上定义多个查询字段,系统会根据用户输入的结果生成相应的查询sql,这样就免去了判断逐一判断某一查询字段是否有值的问题,增加和减少查询条件也不需要修改任何业务代码
3、 一个查询字段的例子
假设在页面上定义了两个查询条件字段
qd_int_storage_id_op_largeequal_tb_aaaa 值为2,qd_name 值为abc。且Action中的getListSql返回的sql语句为 select aliaName ,aaa from table1 aliaName,table2 aaa ,生成的sql语句为
where aaa.storage_id=2 and aliaName.name=’abc’
为了降低用户使用的难度,waf还实现了多字段模糊搜索,可以对多个字段执行like匹配搜索
搜索字段定义:darkQuery[字段类型_字段名称_别名]
字段项目 |
说明 |
darkQuery |
必需,标志这是一个模糊搜索字段 |
字段类型 |
必需 可以使用int,date,string 若是string类型,可以省略不写 若该字段是float,double,可认为是int类型 |
字段名称 |
必需 字段名称必须与实体类中定义的一致,在此可以使用多个字段名称,中间用,号隔开 若[field1,field2,int|field2|aliaName, int|field2|aliaName] |
一个模糊搜索例子
darkQuery[account,username,operation_desc,org_name],在页面上定义此输入筐后,系统就能同时对这4个字段做模糊搜索,默认的表别名为aliaName
在没有waf的文件上传功能之前,所有的文件上传实现对我来说都是一个不小的挑战,在waf的应用中,文件上传变得很简单了。
1、 定义Action,该Action继承自waf.action. FileUploadAction
2、 在新增和修改页面中加入 a href="#" onClick="popNewWindow('/fileupload.do?act=list')">附件列表a>
点击此链接后就打开了弹出文件上传窗口,在此窗口中上传文件保存后就完成了文件上传
在waf系统中,树组件的显示使用htc控件,通过生成htc要求的xml数据来展现一颗树结构,树组件的结构定义如图所示
public List getTreeNodes() throws Exception { String sql=" select a from OrgInfo a where a.org_code like '" +this.getRootOrgCode()+"%'"; List nodes=new ArrayList(); List lst=new ArrayList(); for(int i=0;i OrgInfo org=(OrgInfo)lst.get(i);
DefaultNode node=new DefaultNode(); node.setId(org.getOrg_id().toString()); if(org.getBelongtoorg_id()==null) node.setParentId(null); else node.setParentId(org.getBelongtoorg_id().toString()); node.setLabel(org.getOrgname());
//获得机构的用户,只显示有手机号码的用户 String sql2=" select a from UserInfo a where a.del_flag=0 " + " and a.org_id="+org.getOrg_id(); List lst2=DBUtil.execQuery(sql2); for(int j=0;j
if(node.getParentId()==null) break; UserInfo user=(UserInfo)lst2.get(j);
DefaultNode userNode=new DefaultNode(); String nodeValue=user.getAccount()+"|"+user.getUsername(); userNode.setId(nodeValue); //userNode.setId(user.getAccount()); userNode.setParentId(node.getId()); userNode.setLabel(user.getUsername()); nodes.add(userNode); } nodes.add(node); } return nodes; } //是否是带checkbox的树 public boolean isCheckTree() { return true; } |
方法 |
详细说明 |
getTreeNodes() |
这是一个抽象方法,需要由子类实现,返回TreeNode的结果集合。 节点集定义规则:根节点的父节点为null,你只需要简单的将结果集全部输出,Xtree会根据节点和父节点的关系计算并输出树的xml表现 |
isCheckTree |
是否checkbox树 |
显示组织机构树的jsp页面请参考web/common/orgTree.jsp
本节介绍使用waf的一些最佳方法
数据类型:若实体类中某一字段的属性为double,float,date型,需要在form中将相应的属性定义为String
在新增、修改记录时候,经常需要验证某一个字段在表中是否唯一,此时可以使用WafModel的默认验证功能,可以仅仅简单定义条件,就完成业务功能
在一般情况下,用户一般不必重载doAddNew,doUpdate,doDelete方法,在确定需要重载这些方法之前,请先参考DBAction的说明部分,在95%的情况下,是不需要完全重载这些方法的。
为了最大限度减少waf的学习时间,建立一个baseproj工程,可以将该工程导入到eclipse直接使用,并在上面增加你的业务功能块。
异常可分为系统异常和业务异常,在waf中,不需要为每一种业务异常配置异常处理信息,而只需要简单的抛出即可
1、 业务层异常:有时候需要抛出一些业务层的异常,比如 要求用户至少上传一个文件,在使用structs的普通程序中,经常需要定义很多不同的异常类,在waf中你只要简单地抛出一个Exception异常,就能在异常页面上显示你需要的异常
2、 异常处理的一般原则:我们经常看到这样的异常处理
public WafModel findById(Class _class, Long key) throws BaseMapException { WafModel model = null; try { Session session = currentSession(); model = (WafModel) session.load(_class, key); closeSession(); } catch (Exception e) { closeSession(); throw new BaseMapException(); }finally{ closeSession(); } return model; } |
这段代码有什么问题吗?处理的很好啊,抛出了自己的异常,但这样的异常对于程序员的调试有帮助吗,非常遗憾,只会帮倒忙,因为它改变了异常的最初信息,你根本不知道发生了什么,只能在页面上看到
expired.BaseMapException=数据库出现故障,请和管理员联系!
Waf的异常处理推荐方法
1)保留原始的异常信息
public void creat(Object obj) throws Exception { WafModel model=(WafModel)obj; model.setCreate_time(new Date()); this.beforeNew(obj); Session session = this.beginTransaction();
Long id=null; try {
//获得刚插入对象的id id=(Long)session.save(obj);
//设置主键值 this.endTransaction(true);
} catch (Exception e) { // 回滚 this.endTransaction(false);
// 抛出原始的异常信息 Exception ee = new Exception(); ee.setStackTrace(e.getStackTrace()); throw ee; }
|
此段代码抛出了最本质的异常信息,在错误信息页面,点右肩查看html代码可以看到错误的堆栈信息
2)如果你不知道怎么办,就直接抛出去
sql = daf.util.SQLUtil.getSql(sql); List lst=new ArrayList(); //获得session Session session=SessionManager.currentSession(); try{
Query query=session.createQuery(sql);
lst=query.list(); }finally{ session.close(); }
return lst==null?new ArrayList():lst; |
本代码中,只是在finaly时关闭了session,并没有在catch块处理异常,因为你没有必要处理,是什么就是什么,不是更好吗
3)抛出业务异常
public void doActivate(Project proj,WholeUserInfo user)throws Exception{ //检查工程项目业主是否已设置,若没有设置,则不能激活项目 if(ParamUtil.isNull(proj.getOrg_code())){ throw new Exception("工程项目业主必须设置"); }
OrgInfo projOwner=proj.getOrgInfo();
//检查项目业主所在组织机构的默认帐号是否设置 if(ParamUtil.isNull(projOwner.getDefaultAccount())){ throw new Exception("项目业主所在单位必须设置默认帐号"); } //其它代码 …….. } |
throw new Exception("工程项目业主必须设置");这是一个典型的业务异常,你可以直接抛出,错误页面将获得这个message,而不需要再定义关于该exception的相应错误信息了。
2003年底,笔者参加了一个java web应用的开发,数据库操作层完全采用JDBC来完成,用过JDBC的同志们都知道,那一个个get,set方法真是把程序员的青春耗尽了。恰好笔者是一个懒惰的人,就萌发了一个编写一套数据访问框架daf(data access framework)的想法,也怪我孤陋寡闻,竟然不知道hibernate已大量使用了,完成了一个类似hibernate的数据访问框架,使用方法与hibernate基本一致,但不需要为每个实体类编写映射文件,而只需要设置每个表的主键,并约定实体类的属性名必须和表字段名称相同,这样的好处是增加,删除字段时,不需要修改映射文件。2004年底,笔者来到广州,因为新公司统一使用hibernate做数据访问层,也就停止了该项目的发展。如果你有兴趣,可以继续发展daf,完全不使用hibernate,也是一件很cool的事啊。
在java web开发中,经常需要使用excel来输出报表,传统的POI在写页眉,页脚时会出现中文乱码,笔者不得不使用jexcel来完成。但jexcel API的封装实在是很烂,没办法,笔者只好开发了一套excel数据访问接口。现在该接口的后台实现采用jexcel,但是也可以改为poi来完成后台实现,不会对接口得使用造成影响,详情可以看源码。
任何一个业务系统都需要用户管理,权限管理。笔者试图使这部分能实现最大限度的重用,但以笔者的开发经验,用户,机构表因为不同的业务场景会有很大的逻辑差异,重用的价值并不高,所以笔者建议你根据项目的实际情况修改此部分代码。就算是提供一个模板功能罢。
Bus包主要功能:权限管理,用户管理,系统参数配置,日志记录,短信、基础树,excel报表。
编写junit的测试用例包,抱歉,俺也很少写。
一个最简单的waf程序,看完后删掉吧。
搞了半天,你也该做点自己的事了,把业务代码都放进去吧(我没说不准你新建自己的源码包,没错,随你怎么贱,我都管不了)。
这是一份迟来的操作手册,因为以前一直在忙(也不知道在忙些什么)。当写下“后记”两字时,一种幸福感油然而生,不是吗?现在回过头来看看这些代码,这些文字,我觉得他们都是有生命的东西。就像自己的孩子,就算再难看,你还是最爱他。