Activiti 工作流会签开发设计思路
在流程业务管理中,任务是通常都是由一个人去处理的,而多个人同时处理一个任务,这种任务我们称之为会签任务。这种业务需求也很常见,如一个请款单,领导审批环节中,就需要多个部门领导签字。在流程业务中,我们可以把每个领导签字的环节都定义为任务,但若这样,这个流程业务有一点是固定的,就是签批人是固定的。而任务是由一个领导签完再到另一领导,当然也可以由多个领导同时签字。
传统的用流程业务来解决可以采用以下的做法:
串行会签
并行会签
前者在流程业务中,叫串行会签,也即是由一个领导签完再至另一领导签。后者我们称之为并行会签,表示几个领导同时进行签发,而不清楚最终是谁先签。
以上的解决方式有两大业务需求下是不能满足的,若会签的领导不是固定的,即可以由上一任务审批人提交前随意进行选择,另一种是对于会签业务中,要求若其中一部分领导审批通过,即直接往下走,不需要全部领导进行审批。另外,对于这种情况下,统计最终领导会签的结果也是比较困难的,即对审批单的意见是同意还是否决没有办法清楚。以上两种业务需求也是很常见的日常需求,但我们若采用了固定的流程节点,则不能实现。在这里,可以采用Activiti的节点多实例来处理,以上流程则可以简化为下:
何谓多任务实例节点?在Activiti5上的解析则为动态的多任务节点,可以根据传入的动态人员数进行动态生成任务。生成的任务数则不固定,可以进行并行会签,也可以进行串行会签。会签任务最终是否需要往下执行,由会签设置的规则来进行约束。如我们可以常规去设置“一票通过”、“一票否决”、“少数服务多数”等会签规则。因此,我们需要在会签节点上绑定我们的设计规则。会签规则设置界面如下:
通过会签设计规则,可以清楚最终会签人员的投票结果。其数据结构如下所示:
会签任务的定义本身已经由Activiti来实现了,但需要动态传入动态的人员数
Java代码
1.<userTask activiti:assignee="${assignee}" id="SignTask1" name="领导会签">
2.<extensionElements>
3.<activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskSignCreateListener" event="create"/>
4.<activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskAssignListener" event="assignment"/>
5.<activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskCompleteListener" event="complete"/>
6.</extensionElements>
7.<multiInstanceLoopCharacteristics activiti:elementVariable="assignee" isSequential="false" activiti:collection="${taskUserAssignService.getSignUser(execution)}">
8.<completionCondition>${signComplete.isComplete(execution)}</completionCondition>
9.</multiInstanceLoopCharacteristics>
10.</userTask>
其中,isSequential为true则为串行会签,若为false则为并行会签,而activiti:collection可以来自我们Spring容器中的接口及方法,表示获取会签用户集合,taskUserAssignService.getSignUser(execution)。其获取会签的用户值来自两个方面,一个在界面中指定的会签人员,另一个在后台会签节点上配置的人员。
后台会签节点人员设置
任务审批面上选择下一任务会签人员
<completeCondition>为完成会签的条件signComplete.isComplete(execution),可以在这里根据我们的会签规则及目前的会签情况,决定会签是否完成。其实现如下所示:
最终实现逻辑:
Java代码
1.@Override
2.public boolean isComplete(ActivityExecution execution) {
3.
4. logger.debug("entert the SignComplete isComplete method...");
5.
6. String nodeId=execution.getActivity().getId();
7. String actInstId=execution.getProcessInstanceId();
8.
9. ProcessDefinition processDefinition=bpmService.getProcessDefinitionByProcessInanceId(actInstId);
10. //取得会签设置的规则
11. BpmNodeSign bpmNodeSign=bpmNodeSignService.getByDefIdAndNodeId(processDefinition.getId(), nodeId);
12. //完成会签的次数
13. Integer completeCounter=(Integer)execution.getVariable("nrOfCompletedInstances");
14. //总循环次数
15. Integer instanceOfNumbers=(Integer)execution.getVariable("nrOfInstances");
16. //计算投票结果。
17. VoteResult voteResult=calcResult(bpmNodeSign, actInstId, nodeId, completeCounter,instanceOfNumbers);
18.
19. String signResult=voteResult.getSignResult();
20. boolean isCompleted=voteResult.getIsComplete();
21.
22. /**
23. * 会签完成做的动作。
24. * 1.删除会签的流程变量。
25. * 2.将会签数据更新为完成。
26. * 3.设置会签结果变量。
27. * 4.更新会签节点结果。
28. * 5.清除会签用户。
29. */
30. if(isCompleted){
31. //删除会签的变量。
32. //删除 assignee,loopCounter变量。
33. bpmService.delLoopAssigneeVars(execution.getId());
34. logger.debug("set the sign result + " + signResult);
35. //将会签数据更新为完成。
36. taskSignDataService.batchUpdateCompleted(actInstId, nodeId);
37. //设置会签的结果
38. execution.setVariable("signResult_" + nodeId , signResult);
39. //更新会签节点的状态。
40. Short status=TaskOpinion.STATUS_PASSED;
41. if(signResult.equals(SIGN_RESULT_REFUSE)){
42. status=TaskOpinion.STATUS_NOT_PASSED;
43. }
44. //更新会签节点的状态。
45. bpmProStatusDao.updStatus(actInstId, nodeId,status);
46. //清除会签用户。
47. taskUserAssignService.clearSignUser();
48. }
49.
50. return isCompleted;
51.}
52.
53.**
54. * 根据会签规则计算投票结果。
55. * <pre>
56. * 1.如果会签规则为空,那么需要所有的人同意通过会签,否则不通过。
57. * 2.否则按照规则计算投票结果。
58. * </pre>
59. * @param bpmNodeSign 会签规则
60. * @param actInstId 流程实例ID
61. * @param nodeId 节点id名称
62. * @param completeCounter 循环次数
63. * @param instanceOfNumbers 总的会签次数。
64. * @return
65. */
66.private VoteResult calcResult(BpmNodeSign bpmNodeSign,String actInstId,String nodeId,Integer completeCounter,Integer instanceOfNumbers){
67. VoteResult voteResult=new VoteResult();
68. //没有会签实例
69. if(instanceOfNumbers==0){
70. return voteResult;
71. }
72. //投同意票数
73. Integer agreeVotesCounts=taskSignDataService.getAgreeVoteCount(actInstId, nodeId);
74. //没有设置会签规则
75. //(那么得全部会签通过才通过,否则不通过)
76. if(bpmNodeSign==null){
77. //还没有完成可以退出。
78. if(completeCounter<instanceOfNumbers){
79. return voteResult;
80. }
81. else{
82. //完成了 (全部同意才通过)
83. if(agreeVotesCounts.equals(instanceOfNumbers)){
84. return new VoteResult(SIGN_RESULT_PASS,true);
85. }
86. else{
87. return new VoteResult(SIGN_RESULT_REFUSE,true);
88. }
89. }
90. }
91.
92. //投反对票数
93. Integer refuseVotesCounts=taskSignDataService.getRefuseVoteCount(actInstId, nodeId);
94.
95. //检查投票是否完成
96. if(BpmNodeSign.VOTE_TYPE_PERCENT.equals(bpmNodeSign.getVoteType())){
97. float percents=0;
98. //按同意票数进行决定
99. if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){
100. percents=agreeVotesCounts/instanceOfNumbers;
101. //投票同意票符合条件
102. if(percents>=bpmNodeSign.getVoteAmount()){
103. voteResult=new VoteResult(SIGN_RESULT_PASS, true);
104. }
105. //投票已经全部完成
106. else if(completeCounter.equals(instanceOfNumbers)){
107. voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);
108. }
109. }
110. //按反对票数进行决定
111. else{
112. percents=refuseVotesCounts/instanceOfNumbers;
113. //投票
114. if(percents>=bpmNodeSign.getVoteAmount()){
115. voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);
116. }
117. //投票已经全部完成
118. else if(completeCounter.equals(instanceOfNumbers)){
119. voteResult=new VoteResult(SIGN_RESULT_PASS, true);
120. }
121. }
122. }
123. //按绝对票数投票
124. else{
125. //按同意票数进行决定
126. if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){
127. //投票同意票符合条件
128. if(agreeVotesCounts>=bpmNodeSign.getVoteAmount()){
129. voteResult=new VoteResult(SIGN_RESULT_PASS, true);
130. }
131. //投票已经全部完成
132. else if(completeCounter.equals(instanceOfNumbers)){
133. voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);
134. }
135. }
136. //按反对票数进行决定
137. else{
138. //投票
139. if(refuseVotesCounts>=bpmNodeSign.getVoteAmount()){
140. voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);
141. }
142. //投票已经全部完成
143. else if(completeCounter.equals(instanceOfNumbers)){
144. voteResult=new VoteResult(SIGN_RESULT_PASS, true);
145. }
146. }
147. }
148. return voteResult;
149.}
最终实现效果,可以在线访问
http://www.jee-soft.cn:10080/bpm3/login.jsp
csx/1
可以通过访问流程管理体验效果
最终展示视频可以看以下链接:
http://www.jee-soft.cn/htsite/html/cpjfw/zxjc/bpmx3/index.html
分享到:
相关推荐
Activity工作流会签demo
在用activiti的时候经常遇到取会签人员的问题,这个文档解决怎么获取会签人员。
Activiti 是一个开源的工作流和业务自动化引擎,广泛应用于企业级流程管理。在这个主题中,"activiti 会签投票统计" 涉及到 Activiti 的特定功能,特别是会签(Parallel Multi-instance)和自定义事件监听器,用于...
【标题】"Activiti多实例任务实现会签"是指在Activiti工作流引擎中,如何配置和使用多实例任务来实现会签功能。在企业级应用中,会签常常用于决策过程,要求多个参与者共同审批,只有当所有参与者都完成审批后,流程...
Activiti 是一个非常流行的开源工作流引擎,它提供了丰富的API和强大的图形化建模工具,使得开发者能够轻松地在应用中集成工作流功能。本篇将围绕"Activiti-5.4中实现会签"这一主题展开,探讨如何在Activiti 5.4版本...
本项目"基于JAVA的工作流引擎开发框架源码"可能是对其中一个或多个这样的框架的实现或扩展,适用于毕业设计或教学实践,旨在帮助学习者深入理解工作流引擎的工作原理和Java编程技术。 工作流引擎的核心概念包括: ...
- **关于设计约束的说明**:这些规则是为了避免工作流设计中的常见问题,并确保流程能够顺利执行。 #### 四、顺序、分支、汇聚 - **顺序业务流程**:指按既定顺序依次执行的流程。例如,员工入职流程中的“提交...
FixFlow不仅支持常见的工作流功能,如加签、会签、回退等“中国式工作流”,而且提供了更为友好的用户界面和更完善的本地化支持。 #### 五、总结 综上所述,JBPM与Activiti各有千秋,在不同的应用场景下展现出不同...
总的来说,Activiti为开发人员提供了一整套工作流自动化解决方案,通过合理设计和使用Activiti数据库中的表结构,可以有效地实现企业级流程自动化的需求。对于开发者而言,理解Activiti数据库表结构对于优化工作流程...
Activiti 是一个开源的工作流引擎,它被广泛用于企业级应用中来管理业务流程。本学习笔记主要聚焦在开始活动节点以及如何判断流程是否结束,同时涵盖了查询历史流程实例的相关内容。 一、开始活动节点(Start Event...
### 使用Fire-WorkFlow开发工作流举例说明书 #### 一、Example展示的FireWorkflow特性 在本章节中,我们将深入探讨使用FireWorkflow的实际案例——**Example**,它以一个具体的J2ee小项目形式,展示了如何按照官方...
【集成jeecg-boot-activiti1】是一个关于在Jeecg Boot项目中整合Activiti工作流引擎的教程。本文档详细介绍了如何将Activiti 5.22.0版本集成到Jeecg Boot 2.4.2的环境中,以实现业务流程自动化管理。 1. **目标**:...
这可能是基于某些条件(如金额、部门等)或者根据工作流中的事件(如异常情况)来决定。在代码中,加签可能涉及对现有审批流的修改,添加新的审批节点,并更新流程实例的状态,确保所有参与者都能接收到通知并进行...
OsWorkflow是一款强大的工作流管理工具,适用于Java开发环境,能够帮助开发者实现复杂业务流程的自动化管理。以下是该文档中涵盖的关键知识点: 1. **工作流概念**:OsWorkflow首先介绍了工作流的基本概念,包括...
工作流 activiti 5.22 退回代码实现。 activiti在设计的时候没有回退相关的操作,回退是中国特有的特色。这里写一个比较简单的回退。不支持回退到并行网关前面节点,虽然回退到前面节点不会报错 但会导致任务无法...