Activiti 工作流会签开发设计思路
在流程业务管理中,任务是通常都是由一个人去处理的,而多个人同时处理一个任务,这种任务我们称之为会签任务。这种业务需求也很常见,如一个请款单,领导审批环节中,就需要多个部门领导签字。在流程业务中,我们可以把每个领导签字的环节都定义为任务,但若这样,这个流程业务有一点是固定的,就是签批人是固定的。而任务是由一个领导签完再到另一领导,当然也可以由多个领导同时签字。
传统的用流程业务来解决可以采用以下的做法:
串行会签
并行会签
前者在流程业务中,叫串行会签,也即是由一个领导签完再至另一领导签。后者我们称之为并行会签,表示几个领导同时进行签发,而不清楚最终是谁先签。
以上的解决方式有两大业务需求下是不能满足的,若会签的领导不是固定的,即可以由上一任务审批人提交前随意进行选择,另一种是对于会签业务中,要求若其中一部分领导审批通过,即直接往下走,不需要全部领导进行审批。另外,对于这种情况下,统计最终领导会签的结果也是比较困难的,即对审批单的意见是同意还是否决没有办法清楚。以上两种业务需求也是很常见的日常需求,但我们若采用了固定的流程节点,则不能实现。在这里,可以采用Activiti的节点多实例来处理,以上流程则可以简化为下:
何谓多任务实例节点?在Activiti5上的解析则为动态的多任务节点,可以根据传入的动态人员数进行动态生成任务。生成的任务数则不固定,可以进行并行会签,也可以进行串行会签。会签任务最终是否需要往下执行,由会签设置的规则来进行约束。如我们可以常规去设置“一票通过”、“一票否决”、“少数服务多数”等会签规则。因此,我们需要在会签节点上绑定我们的设计规则。会签规则设置界面如下:
通过会签设计规则,可以清楚最终会签人员的投票结果。其数据结构如下所示:
会签任务的定义本身已经由Activiti来实现了,但需要动态传入动态的人员数
- <userTask activiti:assignee="${assignee}" id="SignTask1" name="领导会签">
- <extensionElements>
- <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskSignCreateListener" event="create"/>
- <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskAssignListener" event="assignment"/>
- <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskCompleteListener" event="complete"/>
- </extensionElements>
- <multiInstanceLoopCharacteristics activiti:elementVariable="assignee" isSequential="false" activiti:collection="${taskUserAssignService.getSignUser(execution)}">
- <completionCondition>${signComplete.isComplete(execution)}</completionCondition>
- </multiInstanceLoopCharacteristics>
- </userTask>
<userTask activiti:assignee="${assignee}" id="SignTask1" name="领导会签">
<extensionElements>
<activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskSignCreateListener" event="create"/>
<activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskAssignListener" event="assignment"/>
<activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskCompleteListener" event="complete"/>
</extensionElements>
<multiInstanceLoopCharacteristics activiti:elementVariable="assignee" isSequential="false" activiti:collection="${taskUserAssignService.getSignUser(execution)}">
<completionCondition>${signComplete.isComplete(execution)}</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
其中,isSequential为true则为串行会签,若为false则为并行会签,而activiti:collection可以来自我们Spring容器中的接口及方法,表示获取会签用户集合,taskUserAssignService.getSignUser(execution)。其获取会签的用户值来自两个方面,一个在界面中指定的会签人员,另一个在后台会签节点上配置的人员。
后台会签节点人员设置
任务审批面上选择下一任务会签人员
<completeCondition>为完成会签的条件signComplete.isComplete(execution),可以在这里根据我们的会签规则及目前的会签情况,决定会签是否完成。其实现如下所示:
最终实现逻辑:
- @Override
- public boolean isComplete(ActivityExecution execution) {
-
- logger.debug("entert the SignComplete isComplete method...");
-
- String nodeId=execution.getActivity().getId();
- String actInstId=execution.getProcessInstanceId();
-
- ProcessDefinition processDefinition=bpmService.getProcessDefinitionByProcessInanceId(actInstId);
- //取得会签设置的规则
- BpmNodeSign bpmNodeSign=bpmNodeSignService.getByDefIdAndNodeId(processDefinition.getId(), nodeId);
- //完成会签的次数
- Integer completeCounter=(Integer)execution.getVariable("nrOfCompletedInstances");
- //总循环次数
- Integer instanceOfNumbers=(Integer)execution.getVariable("nrOfInstances");
- //计算投票结果。
- VoteResult voteResult=calcResult(bpmNodeSign, actInstId, nodeId, completeCounter,instanceOfNumbers);
-
- String signResult=voteResult.getSignResult();
- boolean isCompleted=voteResult.getIsComplete();
-
- /**
- * 会签完成做的动作。
- * 1.删除会签的流程变量。
- * 2.将会签数据更新为完成。
- * 3.设置会签结果变量。
- * 4.更新会签节点结果。
- * 5.清除会签用户。
- */
- if(isCompleted){
- //删除会签的变量。
- //删除 assignee,loopCounter变量。
- bpmService.delLoopAssigneeVars(execution.getId());
- logger.debug("set the sign result + " + signResult);
- //将会签数据更新为完成。
- taskSignDataService.batchUpdateCompleted(actInstId, nodeId);
- //设置会签的结果
- execution.setVariable("signResult_" + nodeId , signResult);
- //更新会签节点的状态。
- Short status=TaskOpinion.STATUS_PASSED;
- if(signResult.equals(SIGN_RESULT_REFUSE)){
- status=TaskOpinion.STATUS_NOT_PASSED;
- }
- //更新会签节点的状态。
- bpmProStatusDao.updStatus(actInstId, nodeId,status);
- //清除会签用户。
- taskUserAssignService.clearSignUser();
- }
-
- return isCompleted;
- }
-
- **
- * 根据会签规则计算投票结果。
- * <pre>
- * 1.如果会签规则为空,那么需要所有的人同意通过会签,否则不通过。
- * 2.否则按照规则计算投票结果。
- * </pre>
- * @param bpmNodeSign 会签规则
- * @param actInstId 流程实例ID
- * @param nodeId 节点id名称
- * @param completeCounter 循环次数
- * @param instanceOfNumbers 总的会签次数。
- * @return
- */
- private VoteResult calcResult(BpmNodeSign bpmNodeSign,String actInstId,String nodeId,Integer completeCounter,Integer instanceOfNumbers){
- VoteResult voteResult= new VoteResult();
- //没有会签实例
- if(instanceOfNumbers==0){
- return voteResult;
- }
- //投同意票数
- Integer agreeVotesCounts=taskSignDataService.getAgreeVoteCount(actInstId, nodeId);
- //没有设置会签规则
- //(那么得全部会签通过才通过,否则不通过)
- if(bpmNodeSign== null){
- //还没有完成可以退出。
- if(completeCounter<instanceOfNumbers){
- return voteResult;
- }
- else{
- //完成了 (全部同意才通过)
- if(agreeVotesCounts.equals(instanceOfNumbers)){
- return new VoteResult(SIGN_RESULT_PASS, true);
- }
- else{
- return new VoteResult(SIGN_RESULT_REFUSE, true);
- }
- }
- }
-
- //投反对票数
- Integer refuseVotesCounts=taskSignDataService.getRefuseVoteCount(actInstId, nodeId);
-
- //检查投票是否完成
- if(BpmNodeSign.VOTE_TYPE_PERCENT.equals(bpmNodeSign.getVoteType())){
- float percents=0;
- //按同意票数进行决定
- if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){
- percents=agreeVotesCounts/instanceOfNumbers;
- //投票同意票符合条件
- if(percents>=bpmNodeSign.getVoteAmount()){
- voteResult= new VoteResult(SIGN_RESULT_PASS, true);
- }
- //投票已经全部完成
- else if(completeCounter.equals(instanceOfNumbers)){
- voteResult= new VoteResult(SIGN_RESULT_REFUSE, true);
- }
- }
- //按反对票数进行决定
- else{
- percents=refuseVotesCounts/instanceOfNumbers;
- //投票
- if(percents>=bpmNodeSign.getVoteAmount()){
- voteResult= new VoteResult(SIGN_RESULT_REFUSE, true);
- }
- //投票已经全部完成
- else if(completeCounter.equals(instanceOfNumbers)){
- voteResult= new VoteResult(SIGN_RESULT_PASS, true);
- }
- }
- }
- //按绝对票数投票
- else{
- //按同意票数进行决定
- if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){
- //投票同意票符合条件
- if(agreeVotesCounts>=bpmNodeSign.getVoteAmount()){
- voteResult= new VoteResult(SIGN_RESULT_PASS, true);
- }
- //投票已经全部完成
- else if(completeCounter.equals(instanceOfNumbers)){
- voteResult= new VoteResult(SIGN_RESULT_REFUSE, true);
- }
- }
- //按反对票数进行决定
- else{
- //投票
- if(refuseVotesCounts>=bpmNodeSign.getVoteAmount()){
- voteResult= new VoteResult(SIGN_RESULT_REFUSE, true);
- }
- //投票已经全部完成
- else if(completeCounter.equals(instanceOfNumbers)){
- voteResult= new VoteResult(SIGN_RESULT_PASS, true);
- }
- }
- }
- return voteResult;
- }
@Override
public boolean isComplete(ActivityExecution execution) {
logger.debug("entert the SignComplete isComplete method...");
String nodeId=execution.getActivity().getId();
String actInstId=execution.getProcessInstanceId();
ProcessDefinition processDefinition=bpmService.getProcessDefinitionByProcessInanceId(actInstId);
//取得会签设置的规则
BpmNodeSign bpmNodeSign=bpmNodeSignService.getByDefIdAndNodeId(processDefinition.getId(), nodeId);
//完成会签的次数
Integer completeCounter=(Integer)execution.getVariable("nrOfCompletedInstances");
//总循环次数
Integer instanceOfNumbers=(Integer)execution.getVariable("nrOfInstances");
//计算投票结果。
VoteResult voteResult=calcResult(bpmNodeSign, actInstId, nodeId, completeCounter,instanceOfNumbers);
String signResult=voteResult.getSignResult();
boolean isCompleted=voteResult.getIsComplete();
/**
* 会签完成做的动作。
* 1.删除会签的流程变量。
* 2.将会签数据更新为完成。
* 3.设置会签结果变量。
* 4.更新会签节点结果。
* 5.清除会签用户。
*/
if(isCompleted){
//删除会签的变量。
//删除 assignee,loopCounter变量。
bpmService.delLoopAssigneeVars(execution.getId());
logger.debug("set the sign result + " + signResult);
//将会签数据更新为完成。
taskSignDataService.batchUpdateCompleted(actInstId, nodeId);
//设置会签的结果
execution.setVariable("signResult_" + nodeId , signResult);
//更新会签节点的状态。
Short status=TaskOpinion.STATUS_PASSED;
if(signResult.equals(SIGN_RESULT_REFUSE)){
status=TaskOpinion.STATUS_NOT_PASSED;
}
//更新会签节点的状态。
bpmProStatusDao.updStatus(actInstId, nodeId,status);
//清除会签用户。
taskUserAssignService.clearSignUser();
}
return isCompleted;
}
/**
* 根据会签规则计算投票结果。
* <pre>
* 1.如果会签规则为空,那么需要所有的人同意通过会签,否则不通过。
* 2.否则按照规则计算投票结果。
* </pre>
* @param bpmNodeSign 会签规则
* @param actInstId 流程实例ID
* @param nodeId 节点id名称
* @param completeCounter 循环次数
* @param instanceOfNumbers 总的会签次数。
* @return
*/
private VoteResult calcResult(BpmNodeSign bpmNodeSign,String actInstId,String nodeId,Integer completeCounter,Integer instanceOfNumbers){
VoteResult voteResult=new VoteResult();
//没有会签实例
if(instanceOfNumbers==0){
return voteResult;
}
//投同意票数
Integer agreeVotesCounts=taskSignDataService.getAgreeVoteCount(actInstId, nodeId);
//没有设置会签规则
//(那么得全部会签通过才通过,否则不通过)
if(bpmNodeSign==null){
//还没有完成可以退出。
if(completeCounter<instanceOfNumbers){
return voteResult;
}
else{
//完成了 (全部同意才通过)
if(agreeVotesCounts.equals(instanceOfNumbers)){
return new VoteResult(SIGN_RESULT_PASS,true);
}
else{
return new VoteResult(SIGN_RESULT_REFUSE,true);
}
}
}
//投反对票数
Integer refuseVotesCounts=taskSignDataService.getRefuseVoteCount(actInstId, nodeId);
//检查投票是否完成
if(BpmNodeSign.VOTE_TYPE_PERCENT.equals(bpmNodeSign.getVoteType())){
float percents=0;
//按同意票数进行决定
if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){
percents=agreeVotesCounts/instanceOfNumbers;
//投票同意票符合条件
if(percents>=bpmNodeSign.getVoteAmount()){
voteResult=new VoteResult(SIGN_RESULT_PASS, true);
}
//投票已经全部完成
else if(completeCounter.equals(instanceOfNumbers)){
voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);
}
}
//按反对票数进行决定
else{
percents=refuseVotesCounts/instanceOfNumbers;
//投票
if(percents>=bpmNodeSign.getVoteAmount()){
voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);
}
//投票已经全部完成
else if(completeCounter.equals(instanceOfNumbers)){
voteResult=new VoteResult(SIGN_RESULT_PASS, true);
}
}
}
//按绝对票数投票
else{
//按同意票数进行决定
if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){
//投票同意票符合条件
if(agreeVotesCounts>=bpmNodeSign.getVoteAmount()){
voteResult=new VoteResult(SIGN_RESULT_PASS, true);
}
//投票已经全部完成
else if(completeCounter.equals(instanceOfNumbers)){
voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);
}
}
//按反对票数进行决定
else{
//投票
if(refuseVotesCounts>=bpmNodeSign.getVoteAmount()){
voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);
}
//投票已经全部完成
else if(completeCounter.equals(instanceOfNumbers)){
voteResult=new VoteResult(SIGN_RESULT_PASS, true);
}
}
}
return voteResult;
}
最终实现效果,可以在线访问
http://www.jee-soft.cn:10080/bpm3/login.jsp
csx/1
可以通过访问流程管理体验效果
最终展示视频可以看以下链接:
http://www.jee-soft.cn/htsite/html/cpjfw/zxjc/bpmx3/index.html
已有
0 人发表留言,猛击->>
这里<<-参与讨论
ITeye推荐