Activiti会签结束之后的流程流转控制

首先上一下流程图:

Activiti会签结束之后的流程流转控制_第1张图片

其次上一下流程设计xml源码:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
  <process id="smartProcess" name="智能会签流程">
    <startEvent id="startevent1" name="Start" activiti:initiator="initiator"></startEvent>
    <endEvent id="endevent1" name="End"></endEvent>
    <userTask id="submitApp" name="提交申请" activiti:assignee="${initiator}"></userTask>
    <userTask id="countersign" name="部门会签" activiti:candidateUsers="${countersignCandidateUser}">
      <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="countersignCandidateUsers" activiti:elementVariable="countersignCandidateUser"></multiInstanceLoopCharacteristics>
    </userTask>
    <exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway>
    <userTask id="countersignFail" name="会签不通过" activiti:candidateUsers="20000"></userTask>
    <userTask id="countersignSuccess" name="全票通过" activiti:candidateUsers="10000"></userTask>
    <sequenceFlow id="flow1" name="" sourceRef="startevent1" targetRef="submitApp"></sequenceFlow>
    <sequenceFlow id="flow2" name="" sourceRef="submitApp" targetRef="countersign"></sequenceFlow>
    <sequenceFlow id="flow5" name="" sourceRef="countersign" targetRef="exclusivegateway1"></sequenceFlow>
    <sequenceFlow id="flow6" name="" sourceRef="exclusivegateway1" targetRef="countersignFail">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${countersignYes!=countersignSize}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow7" name="" sourceRef="exclusivegateway1" targetRef="countersignSuccess">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${countersignYes==countersignSize}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow8" name="" sourceRef="countersignSuccess" targetRef="endevent1"></sequenceFlow>
    <sequenceFlow id="flow9" name="" sourceRef="countersignFail" targetRef="endevent1"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_smartProcess">
    <bpmndi:BPMNPlane bpmnElement="smartProcess" id="BPMNPlane_smartProcess">
      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
        <omgdc:Bounds height="35" width="35" x="50" y="50"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
        <omgdc:Bounds height="35" width="35" x="670" y="50"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="submitApp" id="BPMNShape_submitApp">
        <omgdc:Bounds height="55" width="105" x="110" y="40"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="countersign" id="BPMNShape_countersign">
        <omgdc:Bounds height="55" width="105" x="260" y="40"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="exclusivegateway1" id="BPMNShape_exclusivegateway1">
        <omgdc:Bounds height="40" width="40" x="400" y="47"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="countersignFail" id="BPMNShape_countersignFail">
        <omgdc:Bounds height="55" width="105" x="490" y="110"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="countersignSuccess" id="BPMNShape_countersignSuccess">
        <omgdc:Bounds height="55" width="105" x="490" y="-7"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="85" y="67"></omgdi:waypoint>
        <omgdi:waypoint x="110" y="67"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
        <omgdi:waypoint x="215" y="67"></omgdi:waypoint>
        <omgdi:waypoint x="260" y="67"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5">
        <omgdi:waypoint x="365" y="67"></omgdi:waypoint>
        <omgdi:waypoint x="400" y="67"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6">
        <omgdi:waypoint x="420" y="87"></omgdi:waypoint>
        <omgdi:waypoint x="542" y="110"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7">
        <omgdi:waypoint x="440" y="67"></omgdi:waypoint>
        <omgdi:waypoint x="542" y="48"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8">
        <omgdi:waypoint x="595" y="20"></omgdi:waypoint>
        <omgdi:waypoint x="687" y="50"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow9" id="BPMNEdge_flow9">
        <omgdi:waypoint x="542" y="110"></omgdi:waypoint>
        <omgdi:waypoint x="687" y="85"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

其次,再上一下我的测试类代码:

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.spring.impl.test.SpringActivitiTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.xyzq.gipms.domain.bpm.ProcessBusinessParam;
import com.xyzq.gipms.services.bpm.ProcessBusinessService;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:applicationContext-dataSource_h2.xml","classpath:applicationContext-common.xml"})
//@ContextConfiguration(locations={"classpath:applicationContext-dataSource_mysql.xml","classpath:applicationContext-common.xml"})
//@ContextConfiguration(locations={"classpath:applicationContext-dataSource_oracle.xml","classpath:applicationContext-common.xml"})
@SuppressWarnings("unused")
public class SmartProcessTest extends SpringActivitiTestCase {
	@Autowired
	private RepositoryService repositoryService;
	@Autowired
	private RuntimeService runtimeService;
	@Autowired
	private TaskService taskService;
	@Autowired
	private HistoryService historyService;
	@Autowired
	private IdentityService identityService;
	
	@Autowired
	private ProcessBusinessService processBusinessService;

	@Test
	public void testNativeProcess(){
		List<String> nextStepCandidateUsers = new ArrayList<String>();
		nextStepCandidateUsers.add("3130");
		nextStepCandidateUsers.add("3131");
		nextStepCandidateUsers.add("3132");
		
		Map<String,Object> variables = new HashMap<String,Object>();
		variables.put("countersignSize", nextStepCandidateUsers.size()); //设置全局流程变量
		variables.put("countersignCandidateUsers", nextStepCandidateUsers);//设置会签环节任务指派
		
		//启动流程
		String currentSessionUserId = "721";
		identityService.setAuthenticatedUserId(currentSessionUserId);
		String processInstanceId = runtimeService.startProcessInstanceByKey("smartProcess", variables).getId();
		System.out.println("当前执行流程实例Id:"+processInstanceId );
		
		//提交申请
		String taskId = taskService.createTaskQuery().processInstanceId(processInstanceId).taskAssignee(currentSessionUserId).singleResult().getId();
		taskService.complete(taskId);
		
		//会签1
		currentSessionUserId = "3130";
		taskId = taskService.createTaskQuery().processInstanceId(processInstanceId).taskCandidateUser(currentSessionUserId).singleResult().getId();
		setVariable(processInstanceId, true);
		taskService.complete(taskId);
		
		//会签2
		currentSessionUserId = "3131";
		taskId = taskService.createTaskQuery().processInstanceId(processInstanceId).taskCandidateUser(currentSessionUserId).singleResult().getId();
		setVariable(processInstanceId, false);
		taskService.complete(taskId);
		
		//会签3
		currentSessionUserId = "3132";
		taskId = taskService.createTaskQuery().processInstanceId(processInstanceId).taskCandidateUser(currentSessionUserId).singleResult().getId();
		setVariable(processInstanceId, true);
		taskService.complete(taskId);
		
		//会签结束判断流程走向
		long count1 = taskService.createTaskQuery().processInstanceId(processInstanceId).taskCandidateUser("10000").count();  //[通过] 判断是否有待办
		long count2 = taskService.createTaskQuery().processInstanceId(processInstanceId).taskCandidateUser("20000").count();  //[未通过] 判断是否有待办
		System.out.println("通过节点待办数量: "+count1+", 未通过节点待办数量: "+count2);
		System.out.println("按照全票通过的策略来判定会签是否通过:"+(count1>count2));
	}
	
	private void setVariable(String executionId, boolean isPass){
		final String YES_KEY = "countersignYes";
		final String NO_KEY = "countersignNo";
		
		//取出流程实例中存储的自定义变量值
		Object countersignYes = runtimeService.getVariable(executionId, YES_KEY);
		Object countersignNo = runtimeService.getVariable(executionId, NO_KEY);
		int _countersignYes = countersignYes==null?0:Integer.parseInt(countersignYes.toString());
		int _countersignNo = countersignNo==null?0:Integer.parseInt(countersignNo.toString());
		
		//设置新值
		_countersignYes = isPass?(_countersignYes+1) : _countersignYes;
		_countersignNo = isPass?(_countersignNo) : (_countersignNo+1);
		System.out.println("_countersignYes:"+(_countersignYes) +", _countersignNo:"+(_countersignNo));
		
		runtimeService.setVariable(executionId, YES_KEY, _countersignYes);
		runtimeService.setVariable(executionId, NO_KEY, _countersignNo);
	}
}


最后简要简述一下实现过程:

会签活动节点默认包含三个流程变量

nrOfInstances 实例总数

nrOfActiveInstances 当前还没有完成的实例

nrOfCompletedInstances 已经完成的实例个数

要完成包含业务意义的同意/不同意,通过/不通过等组合的会签结果判定走哪一条后续路径,这个就需要自己定义变量。我一共定义了三个变量:

countersignSize  本次会签的参与人数
countersignYes   本次会签给与通过的人数
countersignNo    本次会签给与不通过的人数

最终可以通过这几个变量组合形成多种会签结果判定策略。最后提一点这个跟会签(多实例里边的)completionCondition配置有所区分,两者可以组合使用。

 <completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.6}</completionCondition>

当然上述仅仅是一个简单的测试示例,真正能形成强大的业务支撑平台还需要多一些考虑,本文仅当抛砖引玉。

你可能感兴趣的:(Activiti,工作流,流程会签)