今日继续讲解jbpm框架,早上汤老师领着大家把昨天的内容复习了一下,然后做了总结。总结之后十分清晰。
一、昨日回顾
1. 部署流程定义:“deployProcessDefinition”向“jbpm_processdefinition” 表中添加新的流程定义记录,同时向其子表添加详细信息。
2. 创建流程实例:“findLatestProcessDefinition”到“jbpm_processdefinition”表中获取指定名称的流程定义。“createProcessInstance”创建的流程实例被保存到“jbpm_ processinstance”表中。“pi.getRootToken().signal()”中的Token指向当前任务(游标),signal发出一个信号到达下一个任务节点,同时向“jbpm_ taskinstance” 表中添加一个任务节点。“pi.getRootToken().signal()”为到达第一个任务节点。
3. 获取任务实例列表:“getTaskList”根据指定的actorId到“jbpm_ taskinstance”表中获取对应的任务列表。
4. 开始任务:“getTaskInstance”到“jbpm_ taskinstance”表中获取指定的任务实例。“start”向“jbpm_ taskinstance”表中对应的记录添加任务起始时间。
5. 结束任务:“getTaskInstance”到“jbpm_ taskinstance”表中获取指定的任务实例。“end”向“jbpm_ taskinstance”表中对应的记录添加任务结束时间。“end”内部调用“taskIns.getToken().signal();”指向下一个任务节点。
今日新内容主要为四点,流程定义文档、节点、动作与事件、任务分配。突然的感觉到事件在JavaEE中被广泛应用,看来事件驱动还是十分重要的。
二、流程定义文档(PAR)
1.打包流程文档时必须使用zip格式。
2.在根目录中或zip压缩文件中,包含如下文件:
i. processdefinition.xml(必须,jbpm的流程配置文件。)
ii. processimage.jpg(可选,流程设计器生成的图片文件。)
iii. gpd.xml(可选,流程设计器中图元的坐标等信息。)
iv. classes/(可选,存放用到的java类。)
3.eclipse的jbpm插件可以打包和部署流程,在设计页面的标签的旁边“Deployment”页面。在“Files and Floders”与“Java Classes and Resources”中,选择将要打包或部署的文件。“Local Save Settings”打包到…。“Deployment Server Settings”发布到JBOSS WEB容器,此时必须走动JBOSS WEB容器,采取默认设置即可。
4.更新的问题(版本)
我们每次部署流程时,JBOSSWEB容器都会为流程设置一个新的版本,而不会去覆盖之前部署的应用。使用之前的应用与对应的版本保留,不会造成数据出错。所以每次应该重新部署应用,也不要删除以前的应用。
如果被删除或覆盖,新部署的流程相比以前的流程。多了或少了几个任务节点,那使用之前的数据访问就会出错。
三、节点
1.预定义节点
1) Start-state:开始状态节点。
2) End-state:结束状态节点。
3) Task-Node:任务节点,非常重要,昨天已经学习过。
4) Decision:决策分支节点,此节点的handler委托类(delegation)必须实现DecisionHandler接口。如:
| Start-state |
需要为Decision的handler页面的delegation属性添加一个实现“DecisionHandler”接口的类。 此类返回一个String类型,用于指定decision节点执行哪个分支。 |
实现“DecisionHandler”接口的类:
package cn.itcast.cc.jbpm.node.decision; import org.jbpm.graph.exe.ExecutionContext; import org.jbpm.graph.node.Decision; import org.jbpm.graph.node.DecisionHandler; public class DecisionNodeTest extends Decision implements DecisionHandler { private static final long serialVersionUID = 1L; @Override public String decide(ExecutionContext arg0) throws Exception { //ExecutionContext节点的执行环境,通过这个参数可以获取所有信息。 return "t2";//执行transition名为“t2”的分支。 } } |
5) Fork/join:分叉与合并结点,可以把Fork/join看作是一个大节点。内部包含多条并行的子节点流程。
| Start-state |
fork |
两个分支是并行关系。直接两个分支全部执行完成,才会到达join。此处自动生成transition名称,tq和t3。如果没有,重新连接即可。必须具有transition名称。 |
Join,选择到此处时不全停留,直接到达end-state。 |
End-state |
6) State:状态节点,当流程执行到此节点时会暂停,直到调用token的signal方法时才会继续向下执行。(没有别的用处)
2.自定义节点
自定义节点的实现需要使用普通“Node”节点,与节点Action动作相配合。以实现预定义节点所不能完成的功能。
Node + action示例:
| Start-state |
Node |
End-state |
为node1的action->details属性页面的Handler添加一个实现了“ActionHandler”接口的类(必须选中页面中的“Configuration Action”),我为在此类中打印一条语语句:
package cn.itcast.cc.jbpm.node.customize; import org.jbpm.graph.def.ActionHandler; import org.jbpm.graph.exe.ExecutionContext; public class CustomizeAction implements ActionHandler { private static final long serialVersionUID = 1L; @Override public void execute(ExecutionContext executionContext) throws Exception { //ExecutionContext节点的执行环境,通过这个参数可以获取所有信息。 System.out.println("*****CustomizeAction*****"); } } |
四、动作与事件
动作我们在第三部分末尾已经介绍过,Jbpm的的节点包含三类事件(共7个事件)。Jbpm7个事件的执行顺序:
| node-leave:离开start-state1节点,可通过插件配置。 |
Transition:从start-sate1过渡到task-node1的事件,可通过插件配置。 |
node-enter:进入task-node1节点,可通过插件配置。 task-create:创建任务事件,需要插件/手动配置。 task-assign:分配任务事件,需要插件/手动配置。 task-start:任务开始事件,需要插件/手动配置。 task-end:任务结束事件,需要插件/手动配置。 |
… |
… |
上表中的事件是jbpm流程中比较常用的事件,事件不影响流程的执行。
让我们为上面的流程添加7个,表中对应的事件。事件处理统一使用一个实现了“ActionHandler”接口的类:
package cn.itcast.cc.jbpm.node.event; import org.jbpm.graph.def.ActionHandler; import org.jbpm.graph.exe.ExecutionContext; public class NodeEventTest implements ActionHandler { private static final long serialVersionUID = 1L; @Override public void execute(ExecutionContext executionContext) throws Exception { // 打印事件类型 System.out.println(executionContext.getEvent().getEventType()); } } |
processdefinition.xml文件内容为:
<?xml version="1.0" encoding="UTF-8"?> <process-definition xmlns="" name="NodeEvent"> <start-state name="start-state1"> <transition to="task-node1"></transition> <event type="node-leave"> <action class="cn.itcast.cc.jbpm.node.event.NodeEventTest" name="printNodeEventType"></action> </event> </start-state> <task-node name="task-node1"> <task name="下订单"> <assignment actor-id="客户"></assignment> <event type="task-create"> <action ref-name="printNodeEventType" /> </event> <event type="task-assign"> <action ref-name="printNodeEventType" /> </event> <event type="task-start"> <action ref-name="printNodeEventType" /> </event> <event type="task-end"> <action ref-name="printNodeEventType" /> </event> </task> <event type="node-enter"> <action ref-name="printNodeEventType"></action> </event> <transition to="end-state1"></transition> </task-node> <end-state name="end-state1"> <event type=""></event> </end-state> </process-definition> |
如果 task-node中包含多个task。将event放在task外部,task-node的内部,所有的task将共用同一个事件处理类。如果将event放在task内部,task将使用各自内部的事件处理类。
将流程发布到JBOSSWEB容器中(注意将类“NodeEventTest”一同发布),一步步执行查看控制台的输出。
五、任务分配
1.个人任务(推模型)
个人任务属于个人,只有个人能看到,必须由个人完成。个人任务的分配方式:
1) 手动添加,通过设计器设置task的Actor属性值。
2) Actor:通过设计器使用表达式将Actor设置为#{customer},在事件处理函数中通过“executionContext.getContextInstance().setTransientVariable(name, value)”设置变量值,动态更改actor。
3) 为Task的“Assignment->Handler”添加一个实现了AssignmentHandler接口的类,在“assign”方法中调用“assignable.setActorId(actor);”方法设置Actor属性值。
4) 可以在程序的任何位置使用“TaskInstance.setActorId(actor)”设置Actor的值。
2.组任务(拉/竞争模型)
组任务属于小组,只有小组成员可以查看,但必须仅有一个人来完成。组任务的分配试:
1) 手动添加,通过设计器设置task的PooledActors属性值,使用“,”分隔。
2) PooledActors:通过设计器使用表达式将PooledActors属性设置为#{actors},在事件处理函数中通过“executionContext.getContextInstance().setTransientVariable(name, value)”设置变量值,动态更改actor。
3) 为Task的“Assignment->Handler”添加一个实现了AssignmentHandler接口的类,在“assign”方法中调用“assignable. setPooleActors (actors);”方法设置PooleActors属性值。
4) 可以在程序的任何位置使用“taskInstance.setPooledActors(actors)”,设置PooledActors的值。
3.查询
1) 个人任务:jbpmContext.getTaskMgmtSession().findTaskInstances (actorId)。
2) 组任务:jbpmContext.getTaskMgmtSession().findPooledTaskInstances(actorId)。
actorId可以屏蔽pooledActors
4.Swimlane(泳道)
汤兄弟今天只是简单介绍了一下泳道,这个功能并不常用。
泳道图:
OK,今天的内容到此结束。明天就开始我们的OA系统了,主要使用struts+hibernate+jbpm开发!
哈哈,加油!