Activiti 7系列文章目录
Activiti7 工作流设计器【一】
Activiti7 创建表【二】
Activiti7 表结构介绍 【三】
Activiti7 设计器创建流程 【四】
Activiti7 部署流程【五】
Activiti7 查询流程【六】
Activiti7 删除流程【七】
Activiti7 生成SVG图片【八】
Activiti7 发起任务【九】
Activiti7 查询任务执行流程图【十】
Activiti7 完成任务【十一】
Activiti7 历史数据【十二】
Activiti7 任务办理人、委派、转办、持有人、候选人、候选人组、审批意见【十三】
Activiti7 监听器【十四】
Activiti7 流程变量【十五】
Activiti7 网关Gateway【十六】
Activiti7 整合SpringBoot【十七】
Activiti7 多种任务类型【十八】
Activiti7 子流程【十九】
Activiti7 流程回退、流程拒绝【二十】
流程文件中
在ServiceTask上设置Expression=${myTaskService.hasRole(execution)},其中myTaskService是Bean中的Id值,【方法参数名必须是execution不能修改】。
在ServiceTask执行一些逻辑,计算出来一些值,然后将这些值设置为变量,然后供后面的流程来使用。
自定义Task类
@Service如果没有指定名字,默认是类名的首字母小写,即myTaskService。
package com.boot.service;
import org.activiti.engine.delegate.DelegateExecution;
import org.springframework.stereotype.Service;
@Service
public class MyServiceTask {
public void hasRole(DelegateExecution delegateExecution){
Integer day = Integer.parseInt(delegateExecution.getVariable("day").toString());
if(day > 3){
delegateExecution.setVariable("type",1);
}else{
delegateExecution.setVariable("type",0);
}
}
}
测试
//发起流程
@Test
public void test05(){
Map<String,Object> variables = new HashMap<>();
variables.put("day",10);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("MyServiceTask",variables);
System.out.println("processInstance.getId() = " + processInstance.getId());
System.out.println("processInstance.getName() = " + processInstance.getName());
System.out.println("processInstance.getDescription() = " + processInstance.getDescription());
}
结果
当我们发起流程,直接走到【CEO审批】这里不会走到【经理处理】实际开发中需要注意!
流程定义文件
- Script Format:脚本类型,groovy
- Script:脚本代码
<?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="MyScriptTask" name="MyScriptTask" isExecutable="true">
<documentation>MyScriptTask</documentation>
<startEvent id="startEvent1" name="StartEvent
"></startEvent>
<endEvent id="sid-B1B0E762-1A1E-4501-805C-98F1D7D7F550" name="EndEvent"></endEvent>
<scriptTask id="sid-B0210B6B-4040-41CB-A715-210EA0C18D9A" name="Script Task" scriptFormat="groovy" activiti:autoStoreVariables="false">
<script><![CDATA[sum = 0
for (i in inputArray) {
sum += i
}
execution.setVariable("result", sum);]]></script>
</scriptTask>
<sequenceFlow id="sid-A51FCF6D-D18C-4544-94EE-E10DF92BCD8E" sourceRef="startEvent1" targetRef="sid-B0210B6B-4040-41CB-A715-210EA0C18D9A"></sequenceFlow>
<sequenceFlow id="sid-72B7EA1A-E6B2-4AB3-BA96-D73BC4F7B4A1" sourceRef="sid-B0210B6B-4040-41CB-A715-210EA0C18D9A" targetRef="sid-B1B0E762-1A1E-4501-805C-98F1D7D7F550"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_MyScriptTask">
<bpmndi:BPMNPlane bpmnElement="MyScriptTask" id="BPMNPlane_MyScriptTask">
<bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
<omgdc:Bounds height="30.0" width="30.0" x="90.0" y="174.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-B1B0E762-1A1E-4501-805C-98F1D7D7F550" id="BPMNShape_sid-B1B0E762-1A1E-4501-805C-98F1D7D7F550">
<omgdc:Bounds height="28.0" width="28.0" x="435.0" y="175.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-B0210B6B-4040-41CB-A715-210EA0C18D9A" id="BPMNShape_sid-B0210B6B-4040-41CB-A715-210EA0C18D9A">
<omgdc:Bounds height="80.0" width="100.0" x="225.0" y="149.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sid-A51FCF6D-D18C-4544-94EE-E10DF92BCD8E" id="BPMNEdge_sid-A51FCF6D-D18C-4544-94EE-E10DF92BCD8E">
<omgdi:waypoint x="120.0" y="189.0"></omgdi:waypoint>
<omgdi:waypoint x="225.0" y="189.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-72B7EA1A-E6B2-4AB3-BA96-D73BC4F7B4A1" id="BPMNEdge_sid-72B7EA1A-E6B2-4AB3-BA96-D73BC4F7B4A1">
<omgdi:waypoint x="325.0" y="189.0"></omgdi:waypoint>
<omgdi:waypoint x="435.0" y="189.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>3.0.9</version>
<type>pom</type>
</dependency>
@Test
void testStartAndComplete() {
Map<String, Object> map = new HashMap<>();
map.put("inputArray", Arrays.asList(1, 2));
runtimeService.startProcessInstanceByKey("MyScriptTask", map);
}
脚本任务是自动执行的,不需要调用 taskService.complete();
ReceiveTask 称之为接收任务、等待任务等。当执行流进入ReceiveTask时会先执行执行监听器,然后整个执行流进入wait等待状态,而且在act_ru_task中不没有当前正在进行中的任务,当执行流执行trigger()方法时才会触发正在睡眠的ReceiveTask,进入下一个节点。
<process id="MyReceiveTask" name="MyReceiveTask" isExecutable="true">
<documentation>MyReceiveTask</documentation>
<startEvent id="startEvent1"></startEvent>
<userTask id="sid-CCC8DD61-9250-49F5-B660-1B5792A66DFA"></userTask>
<userTask id="sid-D8B690BF-209B-4984-AF12-1354C2741106"></userTask>
<endEvent id="sid-EB7C8C79-2CB0-43D2-84BE-58F4C60E55EE"></endEvent>
<receiveTask id="sid-9DBEE1C0-74E7-40B2-82CE-540AFF901F9B">
<extensionElements>
<activiti:executionListener event="start" class="com.boot.service.ReceiveTaskDelegate"></activiti:executionListener>
<activiti:executionListener event="start" class="com.boot.service.ReceiveTaskDelegate"></activiti:executionListener>
</extensionElements>
</receiveTask>
<sequenceFlow id="sid-C9B5E8CA-269B-4C12-900E-0A6A45300B97" sourceRef="startEvent1" targetRef="sid-CCC8DD61-9250-49F5-B660-1B5792A66DFA"></sequenceFlow>
<sequenceFlow id="sid-6C92D43F-0A33-4EF4-8AFB-A668B99918F8" sourceRef="sid-CCC8DD61-9250-49F5-B660-1B5792A66DFA" targetRef="sid-9DBEE1C0-74E7-40B2-82CE-540AFF901F9B"></sequenceFlow>
<sequenceFlow id="sid-B6C946C0-0373-4FDD-847C-E47DE0A63FC9" sourceRef="sid-9DBEE1C0-74E7-40B2-82CE-540AFF901F9B" targetRef="sid-D8B690BF-209B-4984-AF12-1354C2741106"></sequenceFlow>
<sequenceFlow id="sid-5856EDD0-4A4D-4CC4-8D9C-54C1940D75CC" sourceRef="sid-D8B690BF-209B-4984-AF12-1354C2741106" targetRef="sid-EB7C8C79-2CB0-43D2-84BE-58F4C60E55EE"></sequenceFlow>
</process>
package com.boot.service;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
import java.util.Map;
public class ReceiveTaskDelegate implements ExecutionListener {
@Override
public void notify(DelegateExecution execution) {
Map<String, Object> variables = execution.getVariables();
System.out.println(execution.getEventName() + "-" + execution.getCurrentFlowElement().getId());
}
}
启动任务
//发起流程
@Test
public void test05(){
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("MyReceiveTask");
System.out.println("processInstance.getId() = " + processInstance.getId());
System.out.println("processInstance.getName() = " + processInstance.getName());
System.out.println("processInstance.getDescription() = " + processInstance.getDescription());
}
启动流程实例,UserTask1进入当前任务。
完成UserTask
@Test
void testCompleteUserTask1() {
List<Task> list = taskService.createTaskQuery().list();
for (Task task : list) {
System.out.println("task.getId() = " + task.getId());
System.out.println("task.getName() = " + task.getName());
System.out.println("task.getAssignee() = " + task.getAssignee());
taskService.complete(task.getId());
}
}
当UserTask1完成后进入ReceiveTask,执行了ReceiveTask对应的代理ReceiveTaskDelegate,
act_ru_task中竟然没有数据,而act_ru_exectuion中当然活动竟然是receiveTask。
下面查询任务也是没有任何内容输出的
@Test
void testCompleteUserTask1() {
List<Task> list = taskService.createTaskQuery().list();
for (Task task : list) {
System.out.println("task.getId() = " + task.getId());
System.out.println("task.getName() = " + task.getName());
System.out.println("task.getAssignee() = " + task.getAssignee());
}
}
act_ru_execution表中有数据
查询act_ru_execution表
@Test
public void testExecution(){
List<Execution> executions = runtimeService.createExecutionQuery().list();
for (Execution execution : executions) {
System.out.println("execution.getId() = " + execution.getId());
System.out.println("execution.getName() = " + execution.getName());
System.out.println("execution.getProcessInstanceId() = " + execution.getProcessInstanceId());
}
}
trigger
@Test
void testTriggeReceiveTask() {
List<Execution> executions = runtimeService.createExecutionQuery().list();
for (Execution execution : executions) {
runtimeService.trigger(execution.getId());
}
}
ReceiveTask就像多线程中的wait(), 而trigger()就像多线程中的notify()了。
act_ru_task中有数据了
查看当前流程图已经到下个任务了。
流程定义文件
方法之间可以相互调用,同理,流程定义之间也可以相关调用,达到流程定义复用的目的。
流程定义Process1
流程定义Process2
Called Element: 调用其它流程,值为其它流程Id:Process1
部署流程
发起流程:Process2
这里是发起流程Process2
//发起流程
@Test
public void test05(){
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Process2");
System.out.println("processInstance.getId() = " + processInstance.getId());
System.out.println("processInstance.getName() = " + processInstance.getName());
System.out.println("processInstance.getDescription() = " + processInstance.getDescription());
}
发起流程任务Task还是在Process2流程上
处理任务
处理完【发起申请】会触发Process1的【经理审批】
@Test
public void testApplyTask() {
Task task = taskService
.createTaskQuery()
.singleResult();
taskService.setAssignee(task.getId(), "zhangsan");
taskService.complete(task.getId());
}
目前已经调用Process1的流程了:走到了【经理审批】
执行完任务
【经理审批】完继续走到Process2【财务审批】
流程定义文件
Process1.bpmn20.xmlProcess2.bpmn20.xml
授权码、POP3/SMTP服务
我这里用的是新浪邮箱,大家也可以切换其他邮箱,操作类似。。。
邮件TASK
这里使用表达式比较好,直接写死也可以的,但是不够灵活
配置文件
activiti:
database-schema-update: true
history-level: full
check-process-definitions: false #是否检测resources/processes 目录
db-history-used: true #是否创建history表
use-strong-uuids: false
mail-server-host: smtp.sina.cn
mail-server-port: 994
mail-server-default-from: beyond_world@sina.cn
mail-server-user-name: beyond_world
# 注意这里的密码不是邮箱的登录密码, 邮箱客户端授权码
mail-server-password: 1a01100034a4ff47
mail-server-use-ssl: true
BPM文件
<?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="EmailTask" name="EmailTask" isExecutable="true">
<documentation>EmailTask</documentation>
<startEvent id="startEvent1" name="StartEvent"></startEvent>
<serviceTask id="sid-A4B24F6A-78AD-4544-9B79-EF120CB24BC1" name="EmailTask" activiti:type="mail">
<extensionElements>
<activiti:field name="to">
<activiti:expression><![CDATA[${to}]]></activiti:expression>
</activiti:field>
<activiti:field name="from">
<activiti:expression><![CDATA[${from}]]></activiti:expression>
</activiti:field>
<activiti:field name="subject">
<activiti:expression><![CDATA[${subject}]]></activiti:expression>
</activiti:field>
<activiti:field name="text">
<activiti:expression><![CDATA[${text}]]></activiti:expression>
</activiti:field>
<activiti:field name="charset">
<activiti:string>UTF-8</activiti:string>
</activiti:field>
</extensionElements>
</serviceTask>
<endEvent id="sid-DD3E2955-B10C-41E5-A7EC-B15CDFF3BF21" name="EndEvent"></endEvent>
<sequenceFlow id="sid-8BEA43C4-ACF6-45E7-BFA7-D445B1409DE0" sourceRef="startEvent1" targetRef="sid-A4B24F6A-78AD-4544-9B79-EF120CB24BC1"></sequenceFlow>
<sequenceFlow id="sid-CAF89079-3801-472D-B52E-BB5C4FC52F56" sourceRef="sid-A4B24F6A-78AD-4544-9B79-EF120CB24BC1" targetRef="sid-DD3E2955-B10C-41E5-A7EC-B15CDFF3BF21"></sequenceFlow>
</process>
测试代码
//发起流程
@Test
public void test05(){
Map<String, Object> variables = new HashMap<>();
variables.put("from", "beyond_world@sina.cn");
variables.put("to", "4407509@qq.com");
variables.put("subject", "Hello World");
variables.put("text", "欢迎学习Activiti邮件发送功能!");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("EmailTask",variables);
System.out.println("processInstance.getId() = " + processInstance.getId());
System.out.println("processInstance.getName() = " + processInstance.getName());
System.out.println("processInstance.getDescription() = " + processInstance.getDescription());
}
结果
手动任务
手动任务是在没有任何业务流程执行引擎或任何应用程序帮助的情况下执行的任务。
下面的示例显示了购物车检查的过程。关于签核的任务都是手动任务,无需借助任何流程执行引擎或软件系统即可执行。
当我们完成【经理审批】会自动执行【手工任务】后到达【人事审批】:手工任务主要是能自动执行一些逻辑,比如我们可以在手工任务上加上一些监听等等。