2007-03-14
一个JBPM实现互斥撤回任务的例子
关键字: 一节点多任务实例
有一个需求是这个样子的:员工请假,填写好请假单后,提交申请.上级主管会有一个审核请假的任务,同时申请人有一个撤回的任务.这这两个任务互斥,也就是说两个任务有一个先执行.另一个任务取消.
曾经看过网上一篇文章使用分支节点创建两个任务节点.当一个任务节点执行后写一个action类负责结束另一个任务节点.达到互斥撤回的效果.本人试验过确实可以完成.
不过这不符合我们常规的流程定义方式(需要增加一对分支,联合节点).并且不符合jbpm关于节点描述.
jbpm认为一个节点代表流程中的一个等待状态.显然领导审核和员工撤销请假处于同一个等待状态,也应该处于一个节点中.使用一对分支,联合节点的方式虽然形式上处于一个等待状态.但这样的流程设计是不合适的.
可以这样设计这个互斥回撤节点
这个节点包含了我们刚才说的两个任务.我们知道当流传到这个节点的时候.这两个任务会同时创建并分配给各自的人员.有一个人完成任务后 节点向指定的节点转向.同时结束另一个任务. signal="first" 有一个任务结束节点就流转. end-tasks="true" 结束该节点的时候自动结束其他没有完成的任务.
这是个小例子没什么特别.可能早有高人知晓.在这我只是感觉到jbpm对节点是流程的一个等待状态这个含义,对我们设计流程有重要的意义.欢迎大家指正批评
完整的xml流程定义.如果你要部署这个流程.这里需要说明的是com.jbpmexample.jbpm.Assignment类是我自己的授权类.你自己写一个代替就好了, template="apply_1.ftl" 这样的属性是我自己加的 为了实现显示页面的定制.需要去掉.否则部署的时候会报错
曾经看过网上一篇文章使用分支节点创建两个任务节点.当一个任务节点执行后写一个action类负责结束另一个任务节点.达到互斥撤回的效果.本人试验过确实可以完成.
不过这不符合我们常规的流程定义方式(需要增加一对分支,联合节点).并且不符合jbpm关于节点描述.
jbpm认为一个节点代表流程中的一个等待状态.显然领导审核和员工撤销请假处于同一个等待状态,也应该处于一个节点中.使用一对分支,联合节点的方式虽然形式上处于一个等待状态.但这样的流程设计是不合适的.
可以这样设计这个互斥回撤节点
xml 代码
- <task-node name="审核" signal="first" end-tasks="true">
- <task name="审核员工请假" swimlane="boss" template="apply_2.ftl">
- <controller>
- <variable name="reason" access="read" mapped-name="reason"/>
- <variable name="day" access="read,write" mapped-name="day"/>
- <variable name="applyman" access="read" mapped-name="applyman"/>
- <variable name="decision" access="read,write" mapped-name="decision"/>
- controller>
- task>
- <task name="撤回请假单" swimlane="applyman" template="apply_3_new.ftl">
- <controller>
- <variable name="reason" access="read" mapped-name="reason"/>
- <variable name="day" access="read" mapped-name="day"/>
- <variable name="applyman" access="read" mapped-name="applyman"/>
- <variable name="decision" access="read,write" mapped-name="decision"/>
- controller>
- task>
- <transition name="结束" to="归档">transition>
- <transition name="撤销" to="请假结束">transition>
- <transition name="修改" to="修改">transition>
- task-node>
这个节点包含了我们刚才说的两个任务.我们知道当流传到这个节点的时候.这两个任务会同时创建并分配给各自的人员.有一个人完成任务后 节点向指定的节点转向.同时结束另一个任务. signal="first" 有一个任务结束节点就流转. end-tasks="true" 结束该节点的时候自动结束其他没有完成的任务.
这是个小例子没什么特别.可能早有高人知晓.在这我只是感觉到jbpm对节点是流程的一个等待状态这个含义,对我们设计流程有重要的意义.欢迎大家指正批评
完整的xml流程定义.如果你要部署这个流程.这里需要说明的是
xml 代码
- <?xml version="1.0" encoding="UTF-8"?>
- <process-definition
- xmlns="urn:jbpm.org:jpdl-3.1" name="新请假流程">
- <swimlane name="applyman" />
- <swimlane name="boss">
- <assignment class="com.jbpmexample.jbpm.Assignment">
- <swimlaneName>boss</swimlaneName>
- </assignment>
- </swimlane>
- <start-state name="请假开始">
- <task name="填写请假单" swimlane="applyman"
>template="apply_1.ftl" - <controller>
- <variable name="reason" access="read,write" mapped-name="reason"/>
- <variable name="day" access="read,write" mapped-name="day"/>
- <variable name="applyman" access="read,write" mapped-name="applyman"/>
- </controller>
- </task>
- <transition name="结束" to="审核"></transition>
- </start-state>
- <task-node name="审核" signal="first" end-tasks="true">
- <task name="审核员工请假" swimlane="boss" template="apply_2.ftl">
- <controller>
- <variable name="reason" access="read" mapped-name="reason"/>
- <variable name="day" access="read,write" mapped-name="day"/>
- <variable name="applyman" access="read" mapped-name="applyman"/>
- <variable name="decision" access="read,write" mapped-name="decision"/>
- </controller>
- </task>
- <task name="撤回请假单" swimlane="applyman" template="apply_3_new.ftl">
- <controller>
- <variable name="reason" access="read" mapped-name="reason"/>
- <variable name="day" access="read" mapped-name="day"/>
- <variable name="applyman" access="read" mapped-name="applyman"/>
- <variable name="decision" access="read,write" mapped-name="decision"/>
- </controller>
- </task>
- <transition name="结束" to="归档"></transition>
- <transition name="撤销" to="请假结束"></transition>
- <transition name="修改" to="修改"></transition>
- </task-node>
- <task-node name="归档">
- <task name="请假归档" swimlane="applyman" template="apply_4.ftl">
- <controller>
- <variable name="reason" access="read" mapped-name="reason"/>
- <variable name="day" access="read" mapped-name="day"/>
- <variable name="applyman" access="read" mapped-name="applyman"/>
- <variable name="decision" access="read" mapped-name="decision"/>
- </controller>
- </task>
- <transition name="结束" to="请假结束"></transition>
- </task-node>
- <end-state name="请假结束"></end-state>
- <task-node name="修改">
- <task name="修改" swimlane="applyman" template="apply_1.ftl">
- <controller>
- <variable name="reason" access="read,write" mapped-name="reason"/>
- <variable name="day" access="read,write" mapped-name="day"/>
- <variable name="applyman" access="read" mapped-name="applyman"/>
- </controller>
- </task>
- <transition name="结束" to="审核"></transition>
- </task-node>
- </process-definition>


评论
我也觉得是这样,我现在就碰到这种情况了,不知道怎么做,用fork join还有问题,在join那不知道怎么设置让有一路任务完成就向下执行,请问有没有什么好方法呀
另外似乎到了JBPM3.2.x,里面所带例子很少,单元测试也没有了,不知道是怎么回事?
如果审核的过程需要几个步骤,如部门主管审核,综合部审核,公司主管审核。。。,还能用你这种方法吗?不是还得用fork join
不过的确,因为我也要手动解析流程xml,得到特定任务列表(我在task-node那里用description做数字标识,可以用来排序),在它的规范下实在是无法用到xpath,不管怎么在网上找方法,都解决不了,最后只能用笨方法,在从流程库中取得xml文件後,转成string,然后用字符串替换方法,替换掉xmlns的内容。这样又可以用xpath查询了。
到目前为止,个人感觉jbpm很不成熟啊,它的javadoc很不值得称道;jpdl的扩展性不强,所有这些,让人用起来很不顺手。不过总比自己实现要来得好。
最近在处理jbpm在spring应用中的使用,网上的整合方法,有些搞不懂,总觉得不适合自己的架构,我现在就一直在解决整合jbpm後的事务问题,找不到合适的方法。
难道存在两个流程图文件,分别提供给UI使用,或是给jbpm使用
你可以在页面表现上写好。审核员工请假的任务有撤销,和结束两个转向,而撤回请假单有撤销一个转向。完全可以。我的流程任务是可以挂模板页面的。我想你说的那种是不需要模板页面的情况了。所有任务是一个页面了。
如果使用fork,join会很麻烦的,而且客户定制时会很不理解。我最早也这样。
如上面的的例子中,互斥任务中的“撤销”转向,仅仅只提供给申请人使用,而"结束"和"修改" 就提供给另外的任务使用。那么在程序中将如何挑选这些不同转向给互斥任务分别使用呢。我觉得上面的流程设计就很困难了。
后来在自己的项目中,为了解决互斥问题,就采用了fork,join,将互斥任务放在不同的分支,及不同的节点上,然后在节点上放入任务对应的转向。这样在UI上,就可根据任务的id得到可到达的转向了。
采用fork,join後,又有个重要问题出现了,不同分支是互斥的,当某个分支到达join後,将继续向下执行,目地达到了。但其他分支上的任务并没有结束。所以只好在不同分支的任务上,设立node-leave事件action,触发执行一个类,主动结束其他分支上创建的任务,以及分支Token。(Token要先于任务进行结束动作,不然,当结束任务时,会继续执行到下一节点。)
也就是在 task-node name="审核" 中怎么样转向不同的
transition name="结束"
transition name="撤销"
transition name="修改"
第一:我在做动态创建Task时(也是为了实现会签)task-node节点中只有一个任务,别且转入这个节点时不是流程创建的任务,是由node-enter事件的action类完成了创建n个相同的任务给不同的人.这个不知和你是否一样.
第二:我没有取消会签的任务(我看你的留言好像意思是有个取消会签的任务).如果需要这个任务我觉的这个任务应该单独有个事件action类.在这个类里面不但要task.end() 还要processInstance.signal("回退") 这样节点就流转了 至于其他会签任务 end-tasks="true" 在离开节点时,所有打开的任务将被结束.
对于第二点我没有试验过.
对没错,使用动态创建Task的时候是设置signal="last-wait",让所有的TaskInstance都完成了再到下一步。
但是在“会签”中,只要上一步任务一提交,会签的N个TaskInstance就已经创建,包括用来取消提交任务的TaskInstrance。这个时候,如果我们撤销提交,本来应该回到前一个节点,但是由于我们设置的是signal="last-wait",所以并不能像我们预期的一样,回到上一个节点。
signal属性可选值:
last:这是默认值。当最后一个任务实例完成时继续执行;当在节点入口处没有任务创建时,继续执行。
last-wait:当最后一个任务实例完成时继续执行;当在节点入口处没有任务创建时,执行在任务节点等待,直到任务被创建。
first:当第一个任务实例完成时继续执行;当在节点入口处没有任务创建时,继续执行。
first-wait:当第一个任务实例完成时继续执行;当在节点入口处没有任务创建时,执行在任务节点等待,直到任务被创建。
unsynchronized:总是继续执行,不管任务是否创建和完成。
never:执行不再继续,不管任务是否创建和完成。
其实我认为“动态创建Task”时应该设signal="last-wait" 因为这样就不会多创建一个多余的没有参与者的任务了(进入task-node会创建一个任务,但这个时候还没参与者)
不知道是否用springmodules整合过jbpm spring hibernate
如有 可否 谈谈看法?