oa_01:
1、建立机构管理的实体类,并映射【重点理解一对多双向关联映射的原理】(Organization.hbm.xml)
<!--一对多双向关联 -->
<many-to-one name="parent" column="pid"/>
<set name="children">
<key column="pid"/>
<one-to-many class="com.wlh.oa.model.Organization"/>
</set>
2、根据顺序图的分析,得到业务逻辑接口设计方案(OrgManager.java)
3、实现业务逻辑类(OrgManagerImpl.java)
4、编写测试单元对关键的接口(或没有把握的接口)进行测试,在测试中发现问题并修正(OrgManagerTest.java)
- 重点理解在SSH架构中,spring如何对事务和hibernate session进行管理
* spring通过AOP机制,在业务逻辑对象的方法上添加事务处理
* 需正确的配置事务的传播特性
每个模块的基本开发过程:
1、理解需求(用例分析),创建领域模型
2、细化领域模型,创建实体类,并映射实体类,测试映射的正确性(自动生成数据库表)
3、根据对用例的分析结果,创建业务逻辑接口以及方法,并实现以及测试
4、分析页面操作流程,根据MVC的想法,搞清楚都需要哪些JSP以及Action(可用状态图来分析)
5、逐步实现呈现层的各种内容
oa_02:
整合Spring和Hibernate之后,对于业务逻辑类的测试方法,可让测试类继承AbstractTransactionalSpringContextTests(
所在jar包:spring-mock.jar),
而不是直接继承TestCase,避免在测试单元中出现懒加载问题。如果数据应该保留在数据库中,
需要在测试方法中调用setComplete方法
- 重点理解为何会出现懒加载问题
AbstractTransactionalSpringContextTests
是一个针对需要在事务环境下执行测试的便利超类,通常会在每个测试完成时执行事务回滚。许多情况下,这是非常有用的,比如:
可以在不影响别的测试的情况下在数据库中插入或删除任何数据。
为任何要求事务的代码提供事务上下文。
如果数据应该保留在数据库中,需要在测试方法中调用setComplete方法。
可以调用startNewTransaction方法创建一个新的事务,前提是必须先调用endTransaction方法终止旧的事务。
事务行为要求在上下文中有一个实现PlatformTransactionManager接口的Bean实例,这将通过其超类的依赖注入机制自动注入,
如果需要使用超类的字段注入机制,那么Bean实例必须命名为transactionManager,这种机制允许上下文配置中存在一个或多个事务管理器实例的情况。
如果没有配置事务管理器,将不会使用事务管理,需要当心的是这可能会造成数据更改,一旦关闭超类的信赖检测将会启动此模式。
此类主要是通过重写AbstractSingleSpringContextTests超类提供的onSetUp和onTearDown方法,在相应的方法中创建和关闭事务来实现的。
AbstractTransactionalDataSourceSpringContextTests
此类给其超类添加了一些针对JDBC操作的便利方法,要求有一个javax.sql.DataSource实例定义在上下文中,
此类会暴露一个org.springframework.jdbc.core.JdbcTemplate实例,并提供了一些便利方法,如删除某个表中的数据,计算某个表的行数,执行数据库脚本等。
范例Springside框架就充分利用spring提供的工具类,简化测试工作量。比如springside提供一个DaoTestCase子类用于Hibernate的测试
,该类继承自AbstractTransactionalDataSourceSpringContextTests,只需要重写如下方法:
oa03:
增加/删除机构,以及返回操作:
=====================增加组织机构===========================
1.如果想将Action交给spring创建,则将Action的type类型为org.springframework.web.struts.DelegatingActionProxy,
然后将Action作为bean配到spring配置文件中, 而且该bean 没有id属性,而是有name属性,而且name属性的值前面加一个“/”;
2.节省Action的方法,是让一个类的的Action继承DispatchAction,然后将对该类的对象进行相关操作的方法都方法哦该Action中,
从而节省Action。注意 :该Action的action标签必须含有parameter属性例如:parameter="method",用于接收参数,
如果接收的到的请求为:'org.do?method=addInput',则调用该Action的addInput方法
3.当前项目着重看OrgAciton.java的方法:
protected ActionForward unspecified(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
因为该方法在进入主界面(默认会来到这里),此外不带参数?method="XXx",的org.do请求也都会进入这个方法
4.添加对象,将接收的表单信息拷贝到另外一个新的对象可以用:BeanUtils.copyProperties(object,object);
类OrgAciton.java:
public ActionForward add(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
OrgActionForm oaf=(OrgActionForm)form;
Organization org=new Organization();
BeanUtils.copyProperties(org,oaf);//拷贝属性
orgManager.addOrg(org, oaf.getParentId());
return mapping.findForward("add_success");
}
=====================删除组织机构========================
删除一个机构及其子机构:
public ActionForward del(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
OrgActionForm oaf=(OrgActionForm)form;
int orgId=oaf.getId();
int parentId=oaf.getParentId();
orgManager.delOrg(orgId);
//return mapping.findForward("del_success");
//=========自定义ActionForward,必须是重定向=======//
ActionForward forward=new ActionForward("/org.do?parentId="+parentId);
forward.setRedirect(true);
return forward;
}
//===============为了实现返回功能=======================//
int ppid=0;
if(parentId!=0){
Organization parent=orgManager.findOrg(parentId);
if( parent.getParent()!=null){
ppid=parent.getParent().getId();
}
}
request.setAttribute("ppid",ppid);
====================异常处理===========================
==修改==
a.加入SystemException.java继承自RunTimeException
b.加入SystemExceptionHandler.java继承子ExceptionHandler.java
c.在国际化资源文件中加入:
errors.org.hassuborg=Org[{0}] has {1} sub orgs
d.修改OrgManagerImpl.java的方法delOrg,抛出自定义异常SystemException
e.修改OrgAciton的方法del,不再捕捉业务层抛过来的异常,而是继续往上抛给Struts框架;
f.在Struts配置文件中添加异常配置:type属性表示指出异常类,handler表示指出处理异常的类
<global-exceptions>
<exception key="error.exception" type="com.wlh.oa.manager.SystemException" handler="com.wlh.oa.web.SystemExceptionHandler"/>
</global-exceptions>
==总结==:
参考代码:struts_autoexceptionhandle_login
a.自定义一个异常类:ErrorCodeException继承RunTimeException,该类含有属性错误码和占位符,构造方法可以接收错误码,和占位符
b.自定义一个异常处理类:ErrorCodeExceptionHandler继承自ExceptionHandler,
c.负责登录的Action不进行捕捉异常,而是继续晚上抛,由框架中的ExceptionHandler及其子类来处理异常,具体要要看Struts-config.xml文件中配置而定,在以下的配置中,则由ErrorCodeExceptionHandler复写了ExceptionHandler中的方法execute(),则由ErrorCodeExceptionHandler来处理异常:
例如:<!-- 全局exception -->
<global-exceptions>
<exception key="error.exception" type="com.wlh.exception.ErrorCodeException" handler="com.wlh.exception.handler.ErrorCodeExceptionHandler"/>
</global-exceptions>
d、ErrorCodeExceptionHandler的execute方法中从ErrorCodeException对象中得到错误码和占位符的填充值,然后就可以将异常信息添加到Globals.EXCEPTION_KEY
e.最后和手动异常处理一样,可以通过html:messages和html:errors得到错误和成功信息
oa04忽略。。
oa05分页处理
====================分页处理================================
==修改==
a.增加类:AbstractManager.java
b.修改类OrgManagerImpl中的方法 searchOrgs
/**
* 根据父机构Id查找子机构
*/
public PagerModel searchOrgs(int parentId,int offSet,int pageSize)
c.加入jar包pager-taglib.jar;
d.在common/common.jsp页面引入pager-taglib标签库 :
<%@ taglib prefix="pg" uri="http://jsptags.com/tags/navigation/pager" %>
e.修改org/index.jsp的机构的列表数据栏,改为pg标签分页;
==总结==
从现有的分页处理方案中,将ManagerImpl类中的抽象出AbstractManager,以便将分页逻辑进行封装处理,
使得分页处理更加简单(不需要拷贝分页逻辑);此外将一个页面的的数据封装到一个对象PageModel中;
- 重点理解抽象的概念(如何抽象?抽象哪些内容?)
仔细体会:
1.oa04中OrgManagerImpl.java是继承了HibernateDaoSupport.java的;
2.在oa05中,我们抽象出一个分页逻辑AbstractManager,让其继承了HibernateDaoSupport,
而让我们的类OrgManagerImpl,继承自AbstractManager,此时OrgManagerImpl也间接继承了AbstractManager,
OrgManagerImpl得到父类的父类HibernateDaoSupport的功能;
3. 一个类既实现了接口,又继承了一个类!则接口的的引用调用父类的方法时候,必须在接口中也声明父类的方法。
例如:OrgAction.java中的代码:
PagerModel pm=orgManager.searchOrgs(parentId,offset,pageSize);调用的searchOrgs并不是接口中的searchOrgs,
而是其父类AbstractManager中的,但是必须在接口中声明一个和父类中一样的接口,负责会出错!
利用ThreadLocal实现分页参数的透明传输(通过使用ThreadLocal能够避免在Manager的接口设计中添加分页参数)
- 重点理解ThreadLocal的基本原理以及实现方法
oa06:分页2
使用ThreadLocal分页参数透明传输
==修改==
1.添加封装pageSize和offSet的ThreadLocal的类SystemContext.java
2.添加一个过滤器类:PagerFilter,配置WEB.XML使得每个请求都可以访问该过滤器
而该过滤器就是向ThreadLocal中设置分页参数
3.修改OrgAciton中的方法unspecified中的代码,
PagerModel pm=orgManager.searchOrgs(parentId,offset,pageSize);
改为代码:-->PagerModel pm=orgManager.searchOrgs(parentId);
4.修改接口OrgManager和其实现类OrgManagerImpl的方法:
public PagerModel searchOrgs(int parentId,int offSet,int pageSize)改为
public PagerModel searchOrgs(int parentId)
5.在AbstractManager中添加一个方法:
public PagerModel searchPaginated(String hql){
return searchPaginated(hql,SystemContext.getOffset(),SystemContext.getPagesize());
}
oa07:Ant脚本:
使用ant脚本文件build.xml,生成Hibernate配置文件hibernate.cfg.xml和映射文件;
<?xml version="1.0" encoding="GBK"?>
<project name="OA系统构建脚本" default="生成Hibernate配置文件" basedir=".">
<property name="src.dir" value="${basedir}/"/>
<property name="build.dir" value="${basedir}/bin"/>
<property name="xdoclet.home" value="D:/代码库/BJSXT/xdoclet-plugins-1.0.3"/>
<!-- Build classpath -->
<path id="xdoclet.task.classpath">
<fileset dir="${xdoclet.home}/lib">
<include name="**/*.jar"/>
</fileset>
<fileset dir="${xdoclet.home}/plugins">
<include name="**/*.jar"/>
</fileset>
</path>
<taskdef
name="xdoclet"
classname="org.xdoclet.ant.XDocletTask"
classpathref="xdoclet.task.classpath"
/>
<target name="生成Hibernate配置文件">
<xdoclet>
<fileset dir="${src.dir}/com/wlh/oa/model">
<include name="**/*.java"/>
</fileset>
<component
classname="org.xdoclet.plugin.hibernate.HibernateConfigPlugin"
destdir="${src.dir}"
version="3.0"
hbm2ddlauto="update"
jdbcurl="jdbc:mysql://127.0.0.1/oa01"
jdbcdriver="com.mysql.jdbc.Driver"
jdbcusername="root"
jdbcpassword="bjsxt"
dialect="org.hibernate.dialect.MySQLDialect"
showsql="true"
/>
</xdoclet>
</target>
<target name="生成hibernate映射文件">
<xdoclet>
<fileset dir="${src.dir}/com/wlh/oa/model">
<include name="**/*.java"/>
</fileset>
<component
classname="org.xdoclet.plugin.hibernate.HibernateMappingPlugin"
version="3.0"
destdir="${src.dir}"
/>
</xdoclet>
</target>
</project>
oa09:添加:用户,角色,用户角色、模块、ACL类,及其映射文件:
1.用户类User对应组织机构中的类Person:使用了一对一唯一外键双向关联映射
2.访问控制列表ACL与User,Role,Module所关联:而Module使用了一对多双向关联映射
3.用户User和角色Role相互关联:user和Role使用了多对多双向映射
4.此处User和Role的多对多使用了第3个类UsersRoles,其实没必要UsersRoles也可以完成多对多映射双向映射
5.添加接口UserManager,RoleManager,personManager,ModuleManager,AClManager等以及实现类;
添加ActionForm和对应的Action
6.OrgAcitonForm中添加了一个属性select,如果是select,则弹出可选择机构的窗口
oa10:
DOM4J实现数据的导入 参考:InitSystemDatasImpl.java
oa11,oa12 :授权
主要是通过“用户管理”和“角色管理”中的“用户授权”和“角色授权”链接触发一个权限列表的窗口,在其中可以勾选或者取消复选框,从而修改ACl对象的持久化数据,从而进行权限管理.
a、版本oa11:只有对角色和用户做了普通授权,没有考虑继承的问题
b、版本oa12考虑了授权的继承的问题;
***ACL的状态为继承(即无效,判断的时候应该判断其所属角色的授权)***
***ACL的状态为不继承(即有效,判断的时候,直接根据aclState判断授权)***
继承与不继承的具体体现在什么地方?
答:体现在查找一个用户是否有操作某个模块的权限的时候,查找到相应的授权记录(也就是acl对象),然后查找acl的属性aclTriState(判断是否继承),
如果该用户的这个权限继承了角色,则授权中立,此时还得判断该用户的所有角色对该模块的权限,因为acl的状态为继承(即无效,判断的时候应该判断其所属角色的授权)
**请参考:AClManagerImpl.java中的方法:**
public boolean hasPermission(int userId, int moduleId, int permission)
public int getPermission(int permission)
如何更改主体对模块的访问权限的?
答: 主体(用户User或者角色Role)对模块Module的访问能力;
访问控制对象ACL是一个主体和模块的关联对象,其中包括User的Id或者Role的Id还有Module的Id,还有一个int类型的访问控制状态aclState(取值范围0~15),分别代表能否对模块进行C/R/U/D操作;
我们修改访问权限就是修改ACL对象中的属性aclState,将其的的二进制形式的某一位或者某几位修改为0或1。
1.只要点击user/index.jsp中的用户授权,则将所有的模块及其拥有的操作全部都列出来;
2.为什么AclAction中的方法很少呢?
答:因为使用的DWR,业务逻辑方法的调用转移到了页面的JS代码里;
3.HTML标签的自定义属性:
例如:acl/index.jsp中moduleId 和 permission都是自定义的属性;
<input type="checkbox" id="${module.id}_C" moduleId="${module.id}" permission="0" onclick="addOrUpdatePermission(this)">C
4.页面的js中也支持EL表达式:${}吗?
答:支持
5. dwr负责处理返回值的函数中,如何获得对某个页面元素对象的引用 ?
答:$(“元素的ID或名称”)
例如:acl/index.jsp
function initTable(){
..............
$(moduleId+"_C").checked=cState==0?false:true;
$(moduleId+"_R").checked=rState==0?false:true;
$(moduleId+"_U").checked=uState==0?false:true;
$(moduleId+"_D").checked=dState==0?false:true;
.................
}
中$(moduleId+"_C"),就是拿到一个复选框元素;
6.dwr是否支持spring?
答:支持
例如:dwr.xml文件中,是将Spring配置文件中的bean:aclManager动态生成一个js库,然后调用其中的方法;
<dwr>
<allow>
<create creator="spring" javascript="aclManager">
<param name="beanName" value="aclManager"/><!--Spring配置文件中的bean:aclManager -->
</create>
</allow>
</dwr>
7.dwr使用的时候要加入dwr.jar
8.
1).给用户和角色授权,共用了一个呈现页面/acl/index.jsp,呈现用户和角色对所有模块的访问权限
2).
学习:jstl的<c:forEach>两层嵌套标签显示父模块和子模块的信息,
3).
該版本讓我最遇到挫折的地方就是授权列表在点击角色授权的时候加载不上来:
解决的思路:
a.dwr客户端调用代码出错?经对比正确代码,发现没错误....
b.通过url:http://localhost:8080/oa_11/dwr 观察到:
Classes known to DWR:
aclManager ($Proxy19)点击进去,发现动态生成的js库中并没有查找授权列表的方法searchAclRecord....
问题在什么地方呢?清除work目录,重启服务,还是不管用,
c.最后才意识到,只是在实现类aclManagerImpl中添加了方法searchAclRecord及其实现,
但是没有在接口aclManager中添加方法的声明:
public List searchAclRecord(String principalType,int principalId);
然而,声明dwr.xml中声明的是接口spring的bean名称aclManager,接口中必须要有实现类总所有方法的声明。。。。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://getahead.org/dwr/dwr20.dtd">
<dwr>
<allow>
<create creator="spring" javascript="aclManager">
<param name="beanName" value="aclManager"/>
</create>
</allow>
</dwr>
oa12继承性授权
oa_12:
思路总结:
======从页面效果上看=========:
1.点击CRUD四个按钮的的任意一个,会将不继承按钮和启用按钮选中,
2.反选启用按钮,这一模块(一行)中所有的按钮将被取消选中,
======从业务逻辑的执行上看=====:
1.选中或者取消CRUD4个中的任意一个按钮:
a.则改变Acl对象的int型变量aclStrate,最低4位中的1位,表示是否允许CRUD操作
b.将不继承和启用按钮都选中
2.选中或者取消"不继承"按钮,则实质上就是将Acl对象的aclTriState属性设置为ACL_TRI_STATE_EXTENDS或者ACL_TRI_STATE_UNEXTENDS
3.选中或者取消"启用"按钮;
a.如果选中,则触发CRUD4个按钮的事件(包括选中和取消),然后还会触发继承事件(包括选中和取消),
b.如果取消选中,则:
(1).删除某条Acl记录
(2).将前面的CRUD按钮和不继承按钮全部反选,同时也触发各个按钮的事件(),
oa13:登录(重点)
实现登录功能
index.jsp-->login.do-->LoginAciton(如果不存在用户则转向index.jsp)-->
-->(登录成功)back_index.jsp-->(frameSet)index.do-->indexAction(继承BaseAction)-->outlook.jsp和main.jsp
-->在outlook.jsp中使用JSTL动态加载显示当前用户可以操作的各个模块;
===修改===
1. LoginAction
a.查找是否存在找个用户;
b.密码是否正确;
c.判断用户账号是否过期;
d.将当前用户纳入session管理:request.getSession().setAttribute("login", user);
2. 创建一个BaseAction [让其它所有需要登录之后才能执行的操作继承此Action]
3. 创建一个继承自BaseAction的IndexAction
a.IndexAction负责检查session中是否有用户;
代码:request.getSession().getAttribute("login");
b.如果有用户,则将当前用户的所有模块全部查询上来,然后放到request中;
List modules = aclManager.searchModules(user.getId());
request.setAttribute("modules", modules);
4.修改之前的outlook.html中模块显示部分代码为动态代码:
a.在头部加入<%@include file="/common/common.jsp" %>
b.修改中间部分,使用JSTL的<c:forEach>标签,动态加载并显示当前用户可以操作的各个模块;
5.添加一个日期类型转换器类:UtilDateConverter.java
6.添加一个InitServlet,主要是用来注册日期类型转换器(UtilDateConverter)
<servlet>
<servlet-name>initServlet</servlet-name>
<servlet-class>com.bjsxt.oa.web.InitServlet</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>
重点理解:
- Action的抽象(统一进行登录认证的控制),
本代码:IndexAciton继承自BaseAction,在调用IndexAction的时候先执行BaseAction中的execte方法,检查当前用户是否存在,即,session中是是否有用户
a.如果存在则调用 return super.execute(mapping, form, request, response), 让子类IndexAciton接着执行;
b.如果session中没有用户,则转向转向登陆页面
- 页面框架的运用:frameset
- javascript中的try{}catch(e){}的使用
oa14:利用JSTL自定义函数实现即时认证:
注意:授权和认证是一个组合,两者结合才是一个完整的权限管理,前面的版本做了授权,这里做认证
oa14:
利用JSTL自定义函数实现即时认证:
1.怎理解认证?
答:认证中判断用户的权限然后显示出对应的模块:
重点理解AClManagerImpl.java中的方法hasPermission和getPermission
***ACL的状态为继承(即无效,判断的时候应该判断其所属角色的授权)***
***ACL的状态为不继承(即有效,判断的时候,直接根据aclState判断授权)***
2.继承与不继承的具体体现在什么地方?
答:体现在查找一个用户是否有操作某个模块的权限的时候,查找到相应的授权记录(也就是acl对象),然后查找acl的属性aclTriState(判断是否继承),
如果该用户的这个权限继承了角色,则授权中立,此时还得判断该用户的所有角色对该模块的权限
**请参考:AClManagerImpl.java中的方法:**
public boolean hasPermission(int userId, int moduleId, int permission)
public int getPermission(int permission)
==修改==
a. 创建类:SecurityFunctions.java
/**
* JSTL函数,主要功能是可以完成权限的即时认证
* @author Administrator
*
*/
public class SecurityFunctions {
private static AclManager aclManager;
public static boolean hasPermission(int userId,String resourceSn,int permission){
return aclManager.hasPermissionByResourceSn(userId, resourceSn, permission);
}
//这个方法不能定义为static,因为这将导致spring无法注入
public void setAclManager(AclManager aclManager) {
SecurityFunctions.aclManager = aclManager;
}
}
b.在AclManager中添加
public boolean hasPermissionByResourceSn(int userId,String reourceSn,int permission);
接口,以便于在JSP中使用JSTL函数来进行即时认证
c.在AclManagerImpl中添加hasPermissionByResourceSn的实现:
public boolean hasPermissionByResourceSn(int userId, String resourceSn, int permission) {
String hql = "select m.id from Module m where m.sn = ? ";
return hasPermission(
userId,
(Integer)getSession().createQuery(hql).setParameter(0, resourceSn).uniqueResult(),
permission);
}
d.在spring配置文件中添加bean想认证函数中注入aclManager:
<!-- JSTL函数 -->
<bean id="sucurityFunctions" class="com.bjsxt.oa.web.SecurityFunctions">
<property name="aclManager" ref="aclManager"/>
</bean>
e.在WEB-INF/下添加文件my.tld
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<tlib-version>1.0</tlib-version><!--taglib的版本-->
<short-name>my</short-name><!--短名-->
<uri>http://www.bjsxt.com/oa/functions</uri>uri
<function>
<name>hasPermission</name><!--函数的调用名称-->
<function-class>com.bjsxt.oa.web.SecurityFunctions</function-class><!--类的全路径-->
<function-signature>boolean hasPermission(int, java.lang.String,int)</function-signature><!--函数名称和参数-->
</function>
</taglib>
f.在common/common.jsp中添加引入标签:
<%@ taglib prefix="my" uri="http://www.bjsxt.com/oa/functions" %>
g.在InitServlet中,将一些变量CREATE/READ/UPDATE/DELETE放入(getServletContext)application scope
以便于在JSP中使用它来表示操作类型,也就是person的index.jsp页面中的CREATE
h. 在人员管理页面添加人员,跟新,删除等地方加入认证标签:关键是test后面跟的JSTL自定义函数;
<c:if test="${my:hasPermission(login.id,'person',CREATE) }">
<a href="#" onclick="openWin('person.do?method=addInput','addperson',600,200);">添加人员信息</a>
</c:if>
备注:*******只要是放到request,session,application中的变量,在EL表达式中都可以拿到*****
test="${my:hasPermission(login.id,'person',CREATE) }
1.login.id是LoginAction放到session中的User对象的id;
2.person是模块的唯一表示;
3.CREATE是在InitServlet中,将一些变量CREATE/READ/UPDATE/DELETE放入(getServletContext)application scope;
oa15:根据公文流转领域模型创建相关的实体类,并使用xdoclet映射
1.用hibernate来映射byte[]类型的属性时,把它当成普通属性来映射,并指定type="binary" length="99999999"
例如:
公文类Document的属性,private byte[] content;
流程类workflow的属性,private byte[] processDef;
流程类workflow的属性,private byte[] processImage;
===============修改===============
1.根据领域模型,创建实体类Document,ApproveInfo,Workflow,修改User;
2.添加接口JbpmDelegate和 流程管理接口WorkflowManager;
oa_16:
根据顺序图的分析,创建流程管理接口以及JbpmDelegate接口
oa_17:集成JBPM到OA系统,并实现JbpmDelegate接口
- 第一步:创建数据库表
* 拷贝依赖包:bsh.jar/jcr-1.0.jar/jbpm-identity.jar/jbpm-jpdl.jar
* 修改hibernate.cfg.xml,添加JBPM的映射配置,以及缓存属性的配置
* 因为JBPM中的User类与OA系统中的User类在名称上有冲突,所以需要修改OA
系统中的User类的auto-import="false",并更改查询User对象的HQL语句,加上
全路径的类名进行查找,可以参考UserManagerImpl类。
- 第二步:与spring集成
* 集成spring与JBPM,需要用到第三方的类库:spring-modules-0.8.zip
* 将其中的spring-modules-jbpm31.jar拷贝到web-inf/lib下面即可
* 集成JBPM与spring的方法是:将JbpmConfiguration对象交给spring来创建
* 所以,需要在spring配置文件里面配置JbpmConfiguration对象的创建
<bean id="jbpmConfiguration" class="org.springmodules.workflow.jbpm31.LocalJbpmConfigurationFactoryBean">
<property name="configuration" value="classpath:jbpm.cfg.xml"></property>
</bean>
* 这个时候,需要拷贝jbpm.cfg.xml到类路径中
(可以从jbpm-jpdl-3.2.GA\src\jpdl\org\jbpm目录中拷贝(default.jbpm.cfg.xml)文件,
并重命名即可)
- 第三步:如何实现业务逻辑接口JbpmDelegate,实现类为JbpmDelegateImpl
* 用到jbpmConfiguration的时候,需要注入
所以在spring配置文件中加入:
<bean id="jbpmDelegate" class="com.wlh.oa.manager.impl.JbpmDelegateImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
<property name="jbpmConfiguration" ref="jbpmConfiguration"></property>
</bean>
* 当我们使用jbpmContext对象来操纵JBPM的时候,需要将JbpmContext内部的Hibernate session对象设置为当前的
hibernate session对象。
private JbpmContext getJbpmContext(){
JbpmContext context = jbpmConfiguration.createJbpmContext();
context.setSession(getSession());
return context;
}
* 当我们使用jbpmContext操纵JBPM数据结束的时候,注意不要关闭jbpmContext!!
oa_18:实现WorkflowManager接口,以及流程管理的界面
1.添加类workflowManagerImpl.java
2.添加workFlowAction和WorkflowActionForm
2.在spring配置文件applicationContext-beans.xml中加入:
<!-- 流程管理 -->
<bean id="workflowManager" class="com.wlh.oa.manager.impl.WorkflowManagerImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
<property name="jbpmDelegate" ref="jbpmDelegate"></property>
</bean>
3.在spring配置文件applicationContext-beans.xml中加入:
<bean name="/workflow" class="com.bjsxt.oa.web.actions.WorkflowAction" scope="prototype">
<property name="workflowManager" ref="workflowManager"></property>
</bean>
oa_19: 实现公文管理的业务逻辑类以及界面
实现公文管理的业务逻辑类以及界面
1.添加DocumentManagerImpl和DocumentManager;
还要JbpmDelegateImpl添加公文,删除公文,查找待审批的公文等方法;
2.spring配置文件中添加:
<!-- 公文管理 -->
<bean id="documentManager" class="com.bjsxt.oa.manager.impl.DocumentManagerImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
<property name="jbpmDelegate" ref="jbpmDelegate"></property>
</bean>
3.添加DocumentActionForm和DocumentAction
4.spring配置文件中添加action的配置:
<!-- 公文管理 -->
<bean name="/document" class="com.wlh.oa.web.actions.DocumentAction" scope="prototype">
<property name="documentManager" ref="documentManager"></property>
<property name="jbpmDelegate" ref="jbpmDelegate"></property>
<property name="workflowManager" ref="workflowManager"></property>
</bean>
5.
struts配置文件中添加:
(a).action配置
<!--公文管理 -->
<action
path="/document"
type="org.springframework.web.struts.DelegatingActionProxy"
name="documentForm"
scope="request"
parameter="method"
>
<forward name="index" path="/document/index.jsp"></forward>
<forward name="add_input" path="/document/add_input.jsp"></forward>
<forward name="approve_input" path="/document/approve_input.jsp"></forward>
<forward name="select_flow" path="/document/select_flow.jsp"></forward>
<forward name="submit_input" path="/document/submit_input.jsp"></forward>
<forward name="approved_list" path="/document/approved_list.jsp"/>
<forward name="approving_list" path="/document/approving_list.jsp"/>
<forward name="approve_history" path="/document/approve_history.jsp"/>
</action>
(b).actionForm配置
<form-bean name="documentForm" type="com.wlh.oa.web.forms.DocumentActionForm"></form-bean>
6. 4.webRoot下添加/document/..和相关页面
7.由于在User.hbm.xml中添加了:<hibernate-mapping auto-import="false">
所以需要在Document.hbm.xml中手动添加: <many-to-one name="creator"/>
8.修改生事务的传播特性:
要不然提交公文的时候就会出错(参考文章:http://blog.csdn.net/shendl/archive/2006/12/01/1423460.aspx)
<!-- 配置事务的传播特性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager" >
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>