背景:
项目中用到工作流,其中有一个需求是,市民通过公众号上报事件,然后流程往下走,最后会回到上报人手中,但是由于是公众号,上报人可能上报之后就不关心之后怎么样了;如果市民最后没有确认流程,那么流程就不会结束;到最后会影响报表的数据;
现在这个需求需要改成:当案件回到上报人之后,如果上报人在三天之内没有处理这个案件,系统就把这个案件自动结束;
a) 张三提交请假单
b) 经理审批请假单。流程回到张三手中
c) 张三审批流程;如果超时则自动审批
如果是SSM项目,配置文件中添加
<property name="jobExecutorActivate" value="true" />
<!-- Activiti begin -->
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
<property name="dataSource" ref="dataSource" />
<property name="transactionManager" ref="transactionManager" />
<property name="deploymentResources" value="classpath*:/act/deployments/**/*.bar"/>
<property name="databaseSchemaUpdate" value="false" />
<!-- 在这在这在这在这在这在这在这在这在这在这-->
<property name="jobExecutorActivate" value="true" />
<property name="history" value="full" />
<property name="processDefinitionCacheLimit" value="10"/>
</bean>
如果是SpringBoot项目 ,在配置文件中添加此配置
spring:
activiti:
job-executor-activate: true
S表示秒,M表示分,D表示天;P表示时间段,T表示精确到时间的时间段;
timeDuration。指定定时器之前要等待多长时间。 使用ISO 8601规定的格式 (由BPMN 2.0规定)。
P1D:代表1天后执行此时间定时器。
P1H:代表1小时后执行此时间定时器。
P1M:代表1分钟后执行此时间定时器。
PT1M:代表1分钟后执行此时间定时器。
/**
* 超时自动结束测试
*/
@Test
public void timeOutAutoEndTest() throws InterruptedException {
String procDefKey = "user_leave_now"; // 流程定义ID
// 设置参数
Map<String, Object> vars = new HashMap<>();
vars.put("applyUserId","zhangsan");
vars.put("manager","manager");
vars.put("title", "超时未审批请假流程测试");
//用来设置启动流程的人员ID,引擎会自动把用户ID保存到activiti:initiator中
identityService.setAuthenticatedUserId(String.valueOf(6));
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(procDefKey, "business_leavebu_leave:8", vars);
String id1 = processInstance.getId(); // 流程启动实例ID
System.out.println("流程启动后的实例ID 是 " + id1);
// 查询待签收任务
// 指定任务办理者
String assignee = "manager";
List<Task> list1 = taskService.createTaskQuery().taskCandidateUser(assignee).includeProcessVariables().active().orderByTaskCreateTime().desc().list();
System.out.println("*******************待签收任务************************");
for (Task task : list1) {
System.out.println("任务ID 是 " + task.getId());
System.out.println("任务name 是 " + task.getName());
System.out.println("任务Assignee 是 " + task.getAssignee());
System.out.println("任务ProcessInstanceId 是 " + task.getProcessInstanceId());
}
System.out.println("*******************待签收任务************************");
// 签收任务
Task task = list1.get(0);
String taskId = task.getId();
taskService.claim(taskId, assignee);
System.out.println("*******************待签收任务已经签收************************");
String procInsId =task.getProcessInstanceId() ;
String comment = "生六胎";
// 设置审批消息
taskService.addComment(taskId,procInsId,comment);
Map<String,Object> vars1 = new HashMap<>();
vars1.put("title","经理已经审批");
// 提交任务
taskService.complete(taskId, vars);
System.out.println("*******************待签收任务经理已经审批************************");
System.out.println("当前处理任务名称:" + task.getName());
System.out.println("睡眠70秒===================");
Thread.sleep(70*1000);
// 查询待签收任务
// 指定任务办理者
String zhangsan = "zhangsan";
List<Task> listZhangsan = taskService.createTaskQuery().taskCandidateUser(zhangsan).includeProcessVariables().active().orderByTaskCreateTime().desc().list();
System.out.println("*******************张三的待签收任务************************");
System.out.println("*******************待签收任务************************");
for (Task taskZ : listZhangsan) {
System.out.println("任务ID 是 " + taskZ.getId());
System.out.println("任务name 是 " + taskZ.getName());
System.out.println("任务Assignee 是 " + taskZ.getAssignee());
System.out.println("任务ProcessInstanceId 是 " + taskZ.getProcessInstanceId());
}
System.out.println("*******************待签收任务************************");
ProcessInstance processInstanceStatus = processEngine.getRuntimeService().createProcessInstanceQuery().processInstanceId(procInsId).singleResult();
if(processInstanceStatus != null){
System.out.println("流程未结束************************");
System.out.println("流程进行Name:"+ processInstanceStatus.getName());
System.out.println("流程进行getActivityId:"+ processInstanceStatus.getActivityId());
}else{
System.out.println("流程已经结束************************");
}
}
在测试用例睡眠70秒的运行中,在数据库会产生数据分别如下;但是超时之后,数据会被删除;
测试用例执行之后,再去查表数据,会发现流程已经结束;
<?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:xsd="http://www.w3.org/2001/XMLSchema" 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/processdef">
<process id="user_leave_now" name="请假流程" isExecutable="true">
<startEvent id="userApply" name="提交请假单" activiti:initiator="${applyUserId}">
<documentation>用户提交请假单--</documentation>
</startEvent>
<userTask id="manager_made" name="经理审批" activiti:candidateUsers="${manager}"></userTask>
<endEvent id="sid_pass" name="通过"></endEvent>
<sequenceFlow id="sid_apply" name="提交" sourceRef="userApply" targetRef="manager_made"></sequenceFlow>
<userTask id="backApplyUser" name="回到申请人" activiti:candidateUsers="${applyUserId}"></userTask>
<sequenceFlow id="sid-83B6E838-BC2E-4C43-9D00-C940E58F385B" sourceRef="manager_made" targetRef="backApplyUser"></sequenceFlow>
<sequenceFlow id="sid-92A895CA-AB71-4589-B66A-63C4B7FEED6A" sourceRef="backApplyUser" targetRef="sid_pass"></sequenceFlow>
<boundaryEvent id="timeOutAutoAudit" name="超时自动审批" attachedToRef="backApplyUser" cancelActivity="true">
<timerEventDefinition>
<timeDuration>PT1M</timeDuration>
</timerEventDefinition>
</boundaryEvent>
<sequenceFlow id="sid-A7CA3B3D-2D6A-4AF7-8592-82F4E08E2B93" sourceRef="timeOutAutoAudit" targetRef="sid_pass"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_user_leave_now">
<bpmndi:BPMNPlane bpmnElement="user_leave_now" id="BPMNPlane_user_leave_now">
<bpmndi:BPMNShape bpmnElement="userApply" id="BPMNShape_userApply">
<omgdc:Bounds height="30.0" width="30.0" x="105.0" y="115.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="manager_made" id="BPMNShape_manager_made">
<omgdc:Bounds height="80.0" width="100.0" x="330.0" y="90.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid_pass" id="BPMNShape_sid_pass">
<omgdc:Bounds height="28.0" width="28.0" x="842.0" y="116.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="backApplyUser" id="BPMNShape_backApplyUser">
<omgdc:Bounds height="80.0" width="100.0" x="613.0" y="92.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="timeOutAutoAudit" id="BPMNShape_timeOutAutoAudit">
<omgdc:Bounds height="31.0" width="31.0" x="692.3704448753612" y="76.00715950272286"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sid-92A895CA-AB71-4589-B66A-63C4B7FEED6A" id="BPMNEdge_sid-92A895CA-AB71-4589-B66A-63C4B7FEED6A">
<omgdi:waypoint x="713.0" y="131.4818652849741"></omgdi:waypoint>
<omgdi:waypoint x="842.0007516374965" y="130.14506993121765"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-A7CA3B3D-2D6A-4AF7-8592-82F4E08E2B93" id="BPMNEdge_sid-A7CA3B3D-2D6A-4AF7-8592-82F4E08E2B93">
<omgdi:waypoint x="723.8655478549781" y="95.99486356033142"></omgdi:waypoint>
<omgdi:waypoint x="842.4417848928352" y="126.51075894959251"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid_apply" id="BPMNEdge_sid_apply">
<omgdi:waypoint x="135.0" y="130.0"></omgdi:waypoint>
<omgdi:waypoint x="330.0" y="130.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-83B6E838-BC2E-4C43-9D00-C940E58F385B" id="BPMNEdge_sid-83B6E838-BC2E-4C43-9D00-C940E58F385B">
<omgdi:waypoint x="430.0" y="130.35335689045937"></omgdi:waypoint>
<omgdi:waypoint x="613.0" y="131.64664310954063"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>