绘制流程图:
具体的xml代码如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:tns="http://www.activiti.org/testm1539766523202" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1539766523202" name=""
targetNamespace="http://www.activiti.org/testm1539766523202" typeLanguage="http://www.w3.org/2001/XMLSchema">
<process id="bingxingleveal" isClosed="false" isExecutable="true" processType="None">
<startEvent id="_2" name="StartEvent"/>
<userTask activiti:exclusive="true" id="shenqing" name="提交申请"/>
<parallelGateway gatewayDirection="Unspecified" id="_4" name="ParallelGateway"/>
<userTask activiti:exclusive="true" id="shenpiA" name="审批A"/>
<userTask activiti:exclusive="true" id="shenpiB" name="审批B"/>
<userTask activiti:exclusive="true" id="shenpiC" name="审批C"/>
<exclusiveGateway gatewayDirection="Unspecified" id="_8" name="ExclusiveGateway"/>
<parallelGateway gatewayDirection="Unspecified" id="_9" name="ParallelGateway"/>
<userTask activiti:exclusive="true" id="_10" name="最终审批"/>
<endEvent id="_11" name="EndEvent"/>
<sequenceFlow id="_12" sourceRef="_2" targetRef="shenqing"/>
<sequenceFlow id="_13" sourceRef="shenqing" targetRef="_4"/>
<sequenceFlow id="_14" sourceRef="_4" targetRef="shenpiB">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${bingxing.submit==true}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="_15" sourceRef="_4" targetRef="shenpiA">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${bingxing.submit==true}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="_16" sourceRef="shenpiB" targetRef="_9"/>
<sequenceFlow id="_18" sourceRef="shenpiC" targetRef="_8"/>
<sequenceFlow id="_19" name="驳回" sourceRef="_8" targetRef="shenpiA">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${bingxing.agree3==false}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="_20" name="同意" sourceRef="_8" targetRef="_9">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${bingxing.agree3==true}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="_21" sourceRef="_9" targetRef="_10"/>
<sequenceFlow id="_22" sourceRef="_10" targetRef="_11"/>
<sequenceFlow id="_3" sourceRef="shenpiA" targetRef="shenpiC">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${bingxing.agree1==true}]]></conditionExpression>
</sequenceFlow>
</process>
<bpmndi:BPMNDiagram documentation="background=#3C3F41;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
<bpmndi:BPMNPlane bpmnElement="bingxingleveal">
<bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
<dc:Bounds height="32.0" width="32.0" x="10.0" y="190.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="shenqing" id="Shape-shenqing">
<dc:Bounds height="55.0" width="85.0" x="125.0" y="180.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4">
<dc:Bounds height="32.0" width="32.0" x="275.0" y="190.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="shenpiA" id="Shape-shenpiA">
<dc:Bounds height="55.0" width="85.0" x="400.0" y="80.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="shenpiB" id="Shape-shenpiB">
<dc:Bounds height="55.0" width="85.0" x="385.0" y="310.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="shenpiC" id="Shape-shenpiC">
<dc:Bounds height="55.0" width="85.0" x="550.0" y="85.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_8" id="Shape-_8" isMarkerVisible="false">
<dc:Bounds height="32.0" width="32.0" x="735.0" y="110.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_9" id="Shape-_9">
<dc:Bounds height="32.0" width="32.0" x="745.0" y="205.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_10" id="Shape-_10">
<dc:Bounds height="55.0" width="85.0" x="900.0" y="210.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_11" id="Shape-_11">
<dc:Bounds height="32.0" width="32.0" x="1105.0" y="230.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="_13" id="BPMNEdge__13" sourceElement="shenqing" targetElement="_4">
<di:waypoint x="210.0" y="207.5"/>
<di:waypoint x="275.0" y="206.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_12" id="BPMNEdge__12" sourceElement="_2" targetElement="shenqing">
<di:waypoint x="42.0" y="206.0"/>
<di:waypoint x="125.0" y="207.5"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_15" id="BPMNEdge__15" sourceElement="_4" targetElement="_5">
<di:waypoint x="290.0" y="191.0"/>
<di:waypoint x="290.0" y="110.0"/>
<di:waypoint x="400.0" y="110.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_14" id="BPMNEdge__14" sourceElement="_4" targetElement="_6">
<di:waypoint x="290.0" y="221.0"/>
<di:waypoint x="290.0" y="305.0"/>
<di:waypoint x="385.0" y="337.5"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_16" id="BPMNEdge__16" sourceElement="_6" targetElement="_9">
<di:waypoint x="470.0" y="335.0"/>
<di:waypoint x="760.0" y="335.0"/>
<di:waypoint x="760.0" y="236.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_19" id="BPMNEdge__19" sourceElement="_8" targetElement="_5">
<di:waypoint x="751.0" y="110.0"/>
<di:waypoint x="630.0" y="40.0"/>
<di:waypoint x="442.5" y="80.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_18" id="BPMNEdge__18" sourceElement="_7" targetElement="_8">
<di:waypoint x="635.0" y="112.5"/>
<di:waypoint x="735.0" y="126.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_3" id="BPMNEdge__3" sourceElement="_5" targetElement="_7">
<di:waypoint x="500.0" y="107.5"/>
<di:waypoint x="550.0" y="112.5"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_20" id="BPMNEdge__20" sourceElement="_8" targetElement="_9">
<di:waypoint x="756.0" y="137.0"/>
<di:waypoint x="756.0" y="210.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_22" id="BPMNEdge__22" sourceElement="_10" targetElement="_11">
<di:waypoint x="985.0" y="237.5"/>
<di:waypoint x="1105.0" y="246.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_21" id="BPMNEdge__21" sourceElement="_9" targetElement="_10">
<di:waypoint x="777.0" y="221.0"/>
<di:waypoint x="900.0" y="237.5"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
该实例图中有排他网关和并行网关,避免理解错误。菱形中间带X的是排他网关,带+号的是并行网关。
所谓并行其实就是java的&&。图片中只有上下两条路全部通过并行网关才会放行到最终审批,否则任意一条不通过,都会处于等待状态。例如:审批B通过了,但是审批C驳回了,那么并行网关是不会通过的。
接下来上具体操作代码:
准备下工具类和连线的限制条件所需的实体bean,实体bean会存放到act数据的全局变量中(act_ru_variable),可以通过这个变量操作流程。
工具类:
package com.example.demo.utils;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* @ProjectName: demo
* @Package: com.example.demo.utils
* @ClassName: ActivitiUtil
* @Author: MC
* @Description: ${description}
* @Date: 2019/9/19 0019 18:17
* @Version: 1.0
*/
@Service
public class ActivitiUtil {
@Autowired
private ProcessEngine processEngine;
@Autowired
private RuntimeService runtimeService ;
@Autowired
private TaskService taskService ;
@Autowired
private RepositoryService repositoryService;
/**
* @Method 部署流程
* @Author MC
* @Return
* @Date 2019/9/19 0019 18:34
*/
public void deploy(String filePath){
if(!StringUtils.isEmpty(filePath)){
repositoryService.createDeployment()
.addClasspathResource(filePath)
.deploy();
}
}
/**
* @Method 启动流程
* @Author MC
* @Return
* @Date 2019/9/19 0019 18:35
*/
public Map<String,Object> start(Map<String,Object> map ,String processId){
ProcessInstance leave1 = runtimeService.startProcessInstanceByKey(processId, map);
String processDefinitionId = leave1.getProcessDefinitionId();
System.out.print("============processDefinitionId:" + processDefinitionId);//流程定义的ID
System.out.print("============processInstanceId:" + leave1.getId());//流程实例的ID
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("result",leave1);
resultMap.put("processDefinitionId",processDefinitionId);
resultMap.put("processInstanceId",leave1.getId());
return resultMap;
}
/**
* @Method 根据流程实例ID和用户ID查询任务ID
* @Author MC
用户ID必须设置为Assignee
* @Return
* @Date 2019/9/19 0019 19:01
*/
public String getTaskIdByAssignee( String processInstanceId, String userId){
TaskService taskService = processEngine.getTaskService();//获取任务的Service,设置和获取流程变量
//查询当前办理人的任务ID
Task task = taskService.createTaskQuery()
.processInstanceId(processInstanceId)//使用流程实例ID
.taskAssignee(userId)//任务办理人
.singleResult();
return task.getId();
}
/**
* @Method 根据流程实例ID和userTask标签体设置的ID获取当前任务对象
* @Author MC
* @Return
* @Date 2019/9/24 0024 9:54
*/
public String getTaskIdByDefinitionKey( String processInstanceId, String defKey){
TaskService taskService = processEngine.getTaskService();//获取任务的Service,设置和获取流程变量
//查询当前办理人的任务ID
Task task = taskService.createTaskQuery()
.processInstanceId(processInstanceId)//使用流程实例ID
.taskDefinitionKey(defKey)//userTask标签体的id
.singleResult();
return task.getId();
}
/**
* @Method 获取流程实例列表
* @Author MC
* @Return
* @Date 2019/9/19 0019 18:32
*/
public List<ProcessInstance> queryProcessInstanceAllList(String processDefinitionKey){
return runtimeService
.createProcessInstanceQuery().processDefinitionKey(processDefinitionKey)
.list();
}
/**
* @Method 根据assignee来查询用户
* @Author MC
* @Return
* @Date 2019/9/19 0019 18:29
*/
public Task queryTask(String assignee) {
//startProcessInstance();
// taskService.createTaskQuery().taskCandidateGroup("sales").singleResult();
Task task= taskService.createTaskQuery().taskAssignee(assignee).singleResult();
if(task == null){
return null;
}
System.out.println("审批人为【"+assignee+"】的任务有:任务编号为【" + task.getId() + "】"+ task.getTaskDefinitionKey());
return task;
}
public Task queryTask(String assignee, String processInstanceId) {
Task task= taskService.createTaskQuery()
.processInstanceId(processInstanceId)//使用流程实例ID
.taskAssignee(assignee)//任务办理人
.singleResult();
if(task == null){
return null;
}
System.out.println("审批人为【"+assignee+"】的任务有:任务编号为【" + task.getId() + "】"+ task.getTaskDefinitionKey());
return task;
}
/**
*
* @param queryType 查询类型1 根据 assignee 查询 2 根据candidateuser查询
* @param str
*/
public String getNextNodeId(int queryType,String str) {
Task task = null;
if(queryType==1) {
task = taskService.createTaskQuery().taskAssignee(str).singleResult();
}else if(queryType==2){
task = taskService.createTaskQuery().taskCandidateUser(str).singleResult();
}else if(queryType==3){
task = taskService.createTaskQuery().taskCandidateGroup(str).singleResult();
}
// List<FlowElement> list = getNextNode(task.getId());
if(task==null) {
return null;
}
// for(FlowElement e :list) {
// //((org.activiti.bpmn.model.UserTask) e)
// }
return task.getId();
}
/**
* 获取流程的下一个节点 且要经过规则引擎判断后的节点
* @param taskId
* @return
*/
private List<FlowElement> getNextNode(String taskId) {
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if(task==null) {
return null;
}
List<FlowElement> list = new ArrayList<FlowElement>();
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
//当前活动节点
String activitiId = processInstance.getActivityId();
System.out.println("当前节点是【"+activitiId+"】");
//pmmnModel 遍历节点需要它
BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
List<Process> processList = bpmnModel.getProcesses();
//循环多个物理流程
for(Process process:processList) {
//返回该流程的所有任务,事件
Collection<FlowElement> cColl = process.getFlowElements();
//遍历节点
for(FlowElement f :cColl) {
//如果改节点是当前节点 者 输出该节点的下一个节点
if(f.getId().equals(activitiId)) {
List<SequenceFlow> sequenceFlowList = new ArrayList<SequenceFlow>();
//通过反射来判断是哪种类型
if(f instanceof org.activiti.bpmn.model.StartEvent) {
//开始事件的输出路由
sequenceFlowList = ((org.activiti.bpmn.model.StartEvent) f).getOutgoingFlows();
}else if(f instanceof org.activiti.bpmn.model.UserTask) {
sequenceFlowList = ((org.activiti.bpmn.model.UserTask) f).getOutgoingFlows();
for(SequenceFlow sf :sequenceFlowList) {
String targetRef = sf.getTargetRef();
FlowElement ref = process.getFlowElement(targetRef);
// nextActivitiIdList.add(ref.getId());
list.add(ref);
}
}else if(f instanceof org.activiti.bpmn.model.SequenceFlow) {
}else if(f instanceof org.activiti.bpmn.model.EndEvent) {
sequenceFlowList = ((org.activiti.bpmn.model.EndEvent) f).getOutgoingFlows();
}
break;
}
}
}
return list;
}
/**
* @Method 流程流转到下一步
* @Author MC
根据 assignee 查询出任务,如果存在则设置当前任务的 assignee 为 nextUser
* @Return 不存在下一个节点返回false;
* @Date 2019/9/19 0019 18:23
*/
public boolean completeByAssignee(String assignee,String nextUser) throws Exception {
HashMap<String,Object> map = new HashMap<String,Object>();
map.put("nextUser", nextUser);
Task task = taskService.createTaskQuery().taskAssignee(assignee).singleResult();
if(task == null){
System.out.println("下一节点不存在");
return false;
}
taskService.complete(task.getId(),map);
System.out.println("完成任务 编号为【" + task.getId() + "】,名称为【"+task.getName()+"】的任务");
return true;
}
/**
* 设置某个节点的审批人员
* @param taskId
* @param user
*/
public void setApproveUser(String taskId,String user) {
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
task.setAssignee(user);
taskService.saveTask(task);
}
/**
* 取下一个节点的审批人
* @param taskId
* @return
*/
public List<String> getNextTaskUserByTaskId(String taskId) {
List<String> list = new ArrayList<String>();
List<FlowElement> fList = getNextNode(taskId);
for(FlowElement u:fList){
String str = ((org.activiti.bpmn.model.UserTask) u).getAssignee();
list.add(str);
}
return list ;
}
/**
* 找当前节点的候选审批人 供流程实例start后调用
* @param taskId
* @return
*/
public List<String> getThisTaskUser(String taskId) {
List<String> list = new ArrayList<String>();
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
String taskUser = task.getAssignee();
//*****************************根据taskUser的配置到自己的表里面去找数据
list.add(taskUser);
return list ;
}
/**
* @Method 任务是否完结
* @Author MC
* @Return
* @Date 2019/9/20 0020 11:20
*/
public boolean isOverTask(String processInstanceId){
ProcessInstance pi= runtimeService.createProcessInstanceQuery() // 创建流程实例查询
.processInstanceId(processInstanceId) // 用流程实例id查询
.singleResult();
if(pi!=null){
System.out.println("流程正在执行!");
return false;
}else{
System.out.println("流程已经执行结束!");
}
return true;
}
/**
* @Method 历史流程实例查询
* @Author MC
* @Return
* @Date 2019/9/20 0020 11:22
*/
public List<HistoricProcessInstance> queryHisProInstance(String processDefinitionKey){
List<HistoricProcessInstance> historicProcessInstanceList = processEngine.getHistoryService().createHistoricProcessInstanceQuery()
.processDefinitionKey(processDefinitionKey)
.orderByProcessInstanceEndTime()
.desc()
.list();
/*for(HistoricProcessInstance historicProcessInstance:historicProcessInstanceList){
System.out.println("历史流程实例id: "+historicProcessInstance.getId());
System.out.println("历史流程实例的完成时间: "+historicProcessInstance.getEndTime());
}*/
return historicProcessInstanceList;
}
/**
* 查询历史流程变量
*/
public List<HistoricVariableInstance> queryHisProVariable(String processInstanceId){
List<HistoricVariableInstance> historicVariableInstanceList = processEngine.getHistoryService()
.createHistoricVariableInstanceQuery()
.processInstanceId(processInstanceId).list();
/*for(HistoricVariableInstance historicVariableInstance: historicVariableInstanceList){
System.out.println("历史流程变量id: "+historicVariableInstance.getId());
System.out.println("历史流程变量名称: "+historicVariableInstance.getVariableName());
System.out.println("历史流程变量值: "+historicVariableInstance.getValue());
System.out.println("==================================================");
}*/
return historicVariableInstanceList;
}
/**
* 根据办理人查询历史任务实例
*/
public List<HistoricTaskInstance> queryHisTaskInstanceByAssignee(String processDefinitionKey,String taskAssignee){
List<HistoricTaskInstance> historicTaskInstanceList = processEngine.getHistoryService().createHistoricTaskInstanceQuery()
.processDefinitionKey(processDefinitionKey)
.taskAssignee(taskAssignee).list();
/*for(HistoricTaskInstance historicTaskInstance:historicTaskInstanceList){
System.out.println("历史任务id: "+historicTaskInstance.getId());
System.out.println("历史任务名称: "+historicTaskInstance.getName());
System.out.println("历史任务结束时间: "+historicTaskInstance.getEndTime());
System.out.println("办理人: "+historicTaskInstance.getAssignee());
System.out.println("==================================================");
}*/
return historicTaskInstanceList;
}
/**
* 历史任务查询
* type: 0:未完成 1:已完成 "":all
*/
public List<HistoricTaskInstance> historyTaskList(String processInstanceId,String type){
List<HistoricTaskInstance> list=null;
if(StringUtils.isEmpty(type)){
list = processEngine.getHistoryService() // 历史相关Service
.createHistoricTaskInstanceQuery() // 创建历史任务实例查询
.processInstanceId(processInstanceId) // 用流程实例id查询
.list();
}else if("0".equals(type)){
list = processEngine.getHistoryService() // 历史相关Service
.createHistoricTaskInstanceQuery() // 创建历史任务实例查询
.processInstanceId(processInstanceId) // 用流程实例id查询
.unfinished()
.list();
}else if("1".equals(type)){
processEngine.getHistoryService() // 历史相关Service
.createHistoricTaskInstanceQuery() // 创建历史任务实例查询
.processInstanceId(processInstanceId) // 用流程实例id查询
.finished() // 查询已经完成的任务
.list();
}
/* for(HistoricTaskInstance hti:list){
System.out.println("任务ID:"+hti.getId());
System.out.println("流程实例ID:"+hti.getProcessInstanceId());
System.out.println("任务名称:"+hti.getName());
System.out.println("办理人:"+hti.getAssignee());
System.out.println("开始时间:"+hti.getStartTime());
System.out.println("结束时间:"+hti.getEndTime());
System.out.println("=================================");
}*/
return list;
}
/**
* 已完成的历史活动查询
*/
public List<HistoricActivityInstance> historyActInstanceList(String processInstanceId){
List<HistoricActivityInstance> list=processEngine.getHistoryService() // 历史相关Service
.createHistoricActivityInstanceQuery() // 创建历史活动实例查询
.processInstanceId(processInstanceId) // 执行流程实例id
.finished()
.list();
/* for(HistoricActivityInstance hai:list){
System.out.println("活动ID:"+hai.getId());
System.out.println("流程实例ID:"+hai.getProcessInstanceId());
System.out.println("活动名称:"+hai.getActivityName());
System.out.println("办理人:"+hai.getAssignee());
System.out.println("开始时间:"+hai.getStartTime());
System.out.println("结束时间:"+hai.getEndTime());
System.out.println("=================================");
}*/
return list;
}
}
act全局变量所需的实体对象leave:
package com.example.demo.model;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* @ProjectName: demo
* @Package: com.example.demo.service.model
* @ClassName: Leave
* @Author: MC
* @Description: ${description}
* @Date: 2019/9/19 0019 13:14
* @Version: 1.0
*/
@Data
public class Leave implements Serializable {
private static final long serialVersionUID = 2248469053125414262L;
private String userId;
private Boolean submit;
private Date startDate;
private Date endDate;
private float totalDay;
private String desc;
private String taskId;
private String taskName;
private String approver1;
private Boolean agree1;
private String approveDesc1;
private String approver2;
private Boolean agree2;
private String approveDesc2;
private Boolean agree3;
private String approveDesc3;
}
具体操作的代码:
package com.example.demo.web;
import com.example.demo.model.Leave;
import com.example.demo.utils.ActivitiUtil;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* @ProjectName: demo
* @Package: com.example.demo.web
* @ClassName: BingxingController
* @Author: MC
* @Description: ${description}
* @Date: 2019/9/23 0023 14:41
* @Version: 1.0
*/
@RestController
@RequestMapping("/bingxing")
public class BingxingController {
@Autowired
private ActivitiUtil activitiUtil;
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService ;
//----------------------------
// 注意:bingxing.bpmn没有设置userTask标签的 activiti:assignee 属性,所以获取task需要根据ID获取
// 另外,连接线的限制条件获取的是全局变量的bingxing,我之前写错了,写成获取全局变量的leave了
// -----------------------------
@RequestMapping(value = "/start")
public String start (){
activitiUtil.deploy("processes/bingxing.bpmn");
Map<String,Object> map = new HashMap<>();//流程变量对象
Leave leave = new Leave();
leave.setUserId("shenqing");
map.put("bingxing",leave);//其所存act_ru_variable表name属性值对应其map的Key
Map<String, Object> startMap = activitiUtil.start(map, "bingxingleveal");
String processInstanceId = startMap.get("processInstanceId").toString();
return processInstanceId;
}
@RequestMapping(value = "/approve")
public void approve(@RequestParam String processInstanceId){
Task task = taskService.createTaskQuery()
.processInstanceId(processInstanceId)//使用流程实例ID
.taskDefinitionKey("shenqing")//注意:这里是因为xml文件中的userTask标签没有设置activiti:assignee属性时获取的方法
.singleResult();
String taskId = task.getId();
activitiUtil.setApproveUser(taskId, "shenqing");
// Task task = activitiUtil.queryTask("shenqing",processInstanceId);
Map<String,Object> map = new HashMap<>();
// 获取流程参数 对应启动流程时,入参的参数leave
Leave variable = (Leave)taskService.getVariable(taskId, "bingxing");
// 从入参的表单对象中取值,设置流程参数对象的值
variable.setSubmit(true);
map.put("bingxing",variable);
taskService.complete(taskId,map);
}
@RequestMapping(value = "/approve2")
public void approve2(@RequestParam String processInstanceId){
/* Task shenpiBtask = taskService.createTaskQuery()
.processInstanceId(processInstanceId)//使用流程实例ID
.taskDefinitionKey("shenpiB")//注意:这里是因为xml文件中的userTask标签没有设置activiti:assignee属性时获取的方法
.singleResult();
String shenpiBtaskId = shenpiBtask.getId();
taskService.complete(shenpiBtaskId);*/
Task shenpiAtask = taskService.createTaskQuery()
.processInstanceId(processInstanceId)//使用流程实例ID
.taskDefinitionKey("shenpiA")//注意:这里是因为xml文件中的userTask标签没有设置activiti:assignee属性时获取的方法
.singleResult();
String shenpiAtaskId = shenpiAtask.getId();
// Task task = activitiUtil.queryTask("shenqing",processInstanceId);
Map<String,Object> map = new HashMap<>();
// 获取流程参数 对应启动流程时,入参的参数leave
Leave variable = (Leave)taskService.getVariable(shenpiAtaskId, "bingxing");
// 从入参的表单对象中取值,设置流程参数对象的值
variable.setAgree1(true);
// map.put("bingxing",variable);
map.put("leave",variable);//原来画图画错了,连接线的条件设置成了leave了。。。。。。
taskService.complete(shenpiAtaskId,map);
}
@RequestMapping(value = "/approve3")
public void approve3(@RequestParam String processInstanceId){
Task shenpiAtask = taskService.createTaskQuery()
.processInstanceId(processInstanceId)//使用流程实例ID
.taskDefinitionKey("shenpiC")//注意:这里是因为xml文件中的userTask标签没有设置activiti:assignee属性时获取的方法
.singleResult();
String shenpiAtaskId = shenpiAtask.getId();
// Task task = activitiUtil.queryTask("shenqing",processInstanceId);
Map<String,Object> map = new HashMap<>();
// 获取流程参数 对应启动流程时,入参的参数leave
Leave variable = (Leave)taskService.getVariable(shenpiAtaskId, "leave");
// 从入参的表单对象中取值,设置流程参数对象的值
variable.setAgree3(true);
// map.put("bingxing",variable);
map.put("leave",variable);//原来画图画错了,连接线的条件设置成了leave了。。。。。。
taskService.complete(shenpiAtaskId,map);
}
@RequestMapping(value = "/approve4")
public void approve4(@RequestParam String processInstanceId){
Task shenpiAtask = taskService.createTaskQuery()
.processInstanceId(processInstanceId)//使用流程实例ID
.taskDefinitionKey("_10")//注意:这里是因为xml文件中的userTask标签没有设置activiti:assignee属性时获取的方法
.singleResult();
String shenpiAtaskId = shenpiAtask.getId();
taskService.complete(shenpiAtaskId);
}
}
如果你看过上一篇博客排他网关,你会发现,排他网关的xml中userTask标签体设置了activiti:assignee而并行的xml中没有设置,在启动流程后,可以观察act_ru_task表中的assignee字段值为空,但是def_key字段值对应xml中userTask标签体的ID属性。
仔细看下approve2方法,我注释了一块代码,这一块可以单独写一个方法进行观察ru_task表数据,shenpiB和shenpiA会在task表中出现两条任务数据。
原文链接:https://blog.csdn.net/qq_33333654/article/details/101271621