1. Get to know Activiti
Official website address: https://www.activiti.org/
The Activiti project is a new open source BPM platform based on the Apache license. It is built from the ground up and aims to provide support for the new BPMN 2.0 standard, including support for the Object Management Group (OMG). ), providing technical implementation in the face of new technology opportunities, such as interoperability and cloud architecture.
1. Create a workflow engine
1. Introduce dependencies
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>6.0.0</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
<version>6.0.0</version>
</dependency>
<!--bpmn 模型处理-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-model</artifactId>
<version>6.0.0</version>
</dependency>
<!--bpmn 转换-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-converter</artifactId>
<version>6.0.0</version>
</dependency>
<!--bpmn json数据转换-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>6.0.0</version>
</dependency>
<!--bpmn 布局-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-layout</artifactId>
<version>6.0.0</version>
<scope>test</scope>
</dependency>
<!--activiti 云支持-->
<dependency>
<groupId>org.activiti.cloud</groupId>
<artifactId>activiti-cloud-services-api</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.41</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
<!--数据库连接池-->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
2. Write log configuration file
log4j.rootLogger=INFO,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.conversionPattern=%d %p [%c] - %m%n
3. Write activiti configuration file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--在默认方式下,bean的id固定为:processEngineConfiguration-->
<!--配置数据库连接池-->
<bean id="database" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///act?characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="12345678"/>
<property name="maxActive" value="3"/>
<property name="maxIdle" value="1"/>
</bean>
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<!--配置数据库信息-->
<!--<property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>-->
<!--<property name="jdbcUrl" value="jdbc:mysql:///act?characterEncoding=UTF-8"/>-->
<!--<property name="jdbcUsername" value="root"/>-->
<!--<property name="jdbcPassword" value="12345678"/>-->
<!--使用数据库连接池-->
<property name="dataSource" ref="database"/>
<!--activiti数据库表生成策略,true表示数据表如果存在直接使用,如果不存在则创建-->
<property name="databaseSchemaUpdate" value="true"/>
</bean>
</beans>
4. Create test classes and generate database tables
package com.yzs;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.junit.Test;
public class ActivitiTest {
//使用activiti提供的两种方式来创建数据表
@Test
public void testCreateDbTable(){
//默认创建方式
//ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//一般创建方式
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml", "processEngineConfiguration");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
System.out.println(processEngine);
}
}
2. Getting started with Activiti
Create an activiti workflow process:
- Define the process: According to the BPMN specification, use the process definition tool and use process symbols to describe the entire process.
- Deployment process: Load the drawn process definition file into the database and generate table data.
- Start the process: Use java code to operate the content in the database table.
service name | service function |
---|---|
RepositoryService | Resource management |
RuntimeService | Process operation management class |
TaskService | Task management |
HistoryService | Historical management |
ManagerService | Engine management class |
The test case code is as follows:
package com.yzs;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import java.io.*;
import java.util.List;
import java.util.zip.ZipInputStream;
public class ActivitiDemo {
/**
* 测试流程部署
*/
@Test
public void testDeployment(){
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3、使用service进行流程部署,定义流程名字,将bpmn部署到数据库中
Deployment deploy = repositoryService.createDeployment()
.name("出差申请流程")
.addClasspathResource("bpmn/evection.bpmn")
.deploy();
//4、输出部署信息
System.out.println("流程部署id="+deploy.getId());
System.out.println("流程部署名字="+deploy.getName());
}
/**
* 启动流程实例
*/
@Test
public void testStartProcess(){
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//3、根据流程定义的id启动流程
ProcessInstance instance = runtimeService.startProcessInstanceByKey("myEvection");
//4、输出流程信息
System.out.println("流程定义id="+instance.getProcessDefinitionId());
System.out.println("流程实例id="+instance.getId());
System.out.println("当前活动id="+instance.getActivityId());
}
/**
* 查询个人待执行任务
*/
@Test
public void testFindPersonalTaskList(){
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取TaskService
TaskService taskService = processEngine.getTaskService();
//3、使用流程key、任务的负责人来查询任务
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey("myEvection")
.taskAssignee("zhangsan")
.list();
//4、输出任务信息
for (Task task:taskList){
System.out.println("流程实例id="+task.getProcessInstanceId());
System.out.println("任务id="+task.getId());
System.out.println("任务名称="+task.getName());
System.out.println("任务负责人="+task.getAssignee());
}
}
/**
* 完成个人任务
*/
@Test
public void completTask(){
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取TaskService
TaskService taskService = processEngine.getTaskService();
//3、根据任务id完成任务
taskService.complete("2505");
}
/**
* 使用zip包进行批量部署
*/
@Test
public void deployProcessByZip(){
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3、流程部署 读取资源包文件,构造成inputStream
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("bpmn/evection.zip");
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
Deployment deploy = repositoryService.createDeployment()
.addZipInputStream(zipInputStream)
.deploy();
//4、输出部署信息
System.out.println("流程部署id="+deploy.getId());
System.out.println("流程部署名字="+deploy.getName());
}
/**
* 查询流程定义
*/
@Test
public void queryProcessDefinition(){
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3、获取ProcessDefinitionQuery对象
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
List<ProcessDefinition> processDefinitionList = processDefinitionQuery.processDefinitionKey("myEvection")
.orderByProcessDefinitionVersion()
.desc()
.list();
//4、输出信息
for (ProcessDefinition processDefinition:processDefinitionList){
System.out.println("流程定义id="+processDefinition.getId());
System.out.println("流程定义名称="+processDefinition.getName());
System.out.println("流程定义key="+processDefinition.getKey());
System.out.println("流程定义版本="+processDefinition.getVersion());
}
}
/**
* 删除流程部署信息
*/
@Test
public void deleteDeployment(){
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3、通过部署id来删除
String deploymentId = "1";
repositoryService.deleteDeployment(deploymentId);
//当前流程如果尚未完成,想要删除需要使用级联方式
//repositoryService.deleteDeployment(deploymentId,true);
}
/**
* 下载资源文件
*/
@Test
public void getDeployment() throws IOException {
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3、获取查询对象
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myEvection")
.singleResult();
//4、通过流程定义信息,获取部署id、png名字、bpmn名字
String deploymentId = processDefinition.getDeploymentId();
String pngName = processDefinition.getDiagramResourceName();
String bpmnName = processDefinition.getResourceName();
//5、传递部署id,读取资源信息(png、bpmn)
InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, pngName);
InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, bpmnName);
//6、构造OutputStream
File pngFile = new File("d:/evection.png");
File bpmnFile = new File("d:/evection.bpmn");
FileOutputStream pngOutput = new FileOutputStream(pngFile);
FileOutputStream bpmnOutput = new FileOutputStream(bpmnFile);
//7、输入流与输出流的转换
IOUtils.copy(pngInput,pngOutput);
IOUtils.copy(bpmnInput,bpmnOutput);
//8、关闭流
pngOutput.close();
bpmnOutput.close();
pngInput.close();
bpmnInput.close();
}
/**
* 查看历史信息
*/
@Test
public void findHistoryInfo(){
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取HistoryService
HistoryService historyService = processEngine.getHistoryService();
//3、获取actinst表查询对象
HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
//4、查询表内容
List<HistoricActivityInstance> list = historicActivityInstanceQuery.processInstanceId("2501").orderByHistoricActivityInstanceStartTime().asc().list();
//5、输出信息
for (HistoricActivityInstance historicActivityInstance : list){
System.out.println(historicActivityInstance.getActivityId());
System.out.println(historicActivityInstance.getActivityName());
System.out.println(historicActivityInstance.getProcessDefinitionId());
System.out.println(historicActivityInstance.getProcessInstanceId());
System.out.println("-----------------------");
}
}
/**
* 添加业务key到数据表中
*/
@Test
public void addBusinessKey(){
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//3、启动流程,添加businessKey
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myEvection", "1001");
//4、输出
System.out.println("businessKey="+processInstance.getBusinessKey());
}
/**
* 全部流程实例的挂起和激活
*/
@Test
public void suspendAllProcessInstance(){
//1、获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3、查询流程定义,获取流程定义查询对象
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myEvection")
.singleResult();
//4、获取当前流程定义的实例是否都是挂起状态
boolean suspended = processDefinition.isSuspended();
//5、获取流程定义的id
String processDefinitionId = processDefinition.getId();
//6、如果是挂起状态,改为激活状态
if (suspended){
repositoryService.activateProcessDefinitionById(processDefinitionId,true,null);
System.out.println("流程id="+processDefinitionId+",状态为激活");
}else {
//7、如果是激活状态,改为挂起状态
repositoryService.suspendProcessDefinitionById(processDefinitionId,true,null);
System.out.println("流程id="+processDefinitionId+",状态为挂起");
}
}
/**
* 单个流程实例的挂起与激活
*/
@Test
public void suspendSingleProcessInstance(){
//1、获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//3、获取流程实例对象
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId("7501")
.singleResult();
//4、获取当前流程实例的暂停状态
boolean suspended = processInstance.isSuspended();
//5、获取流程实例id
String processInstanceId = processInstance.getId();
//6、如果是挂起状态,改为激活状态
if (suspended){
runtimeService.activateProcessInstanceById(processInstanceId);
System.out.println("流程实例id="+processInstanceId+",状态为激活");
}else {
//7、如果是激活状态,改为挂起状态
runtimeService.suspendProcessInstanceById(processInstanceId);
System.out.println("流程实例id="+processInstanceId+",状态为挂起");
}
}
}
3. Activiti advanced
1. Person in charge of assigning personal tasks
Method 1: Fixed allocation
Method 2: Expression assignment
activiti uses UEL expressions. UEL is part of the JavaEE6 specification. UEL (Unified Expression Language) is the unified expression language and supports the following two expression languages:
- UEL-value: For example: ${assignee0}
- UEL-method: For example: ${UserBean.getUserId}
package com.yzs;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
public class AssigneeUelTest {
/**
* 流程部署
*/
@Test
public void testDeployment(){
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3、使用service进行流程部署,定义流程名字,将bpmn部署到数据库中
Deployment deploy = repositoryService.createDeployment()
.name("出差申请流程")
.addClasspathResource("bpmn/evection.bpmn")
.deploy();
//4、输出部署信息
System.out.println("部署id="+deploy.getId());
System.out.println("部署名字="+deploy.getName());
}
/**
* 启动流程实例
*/
@Test
public void startAssigneeUel(){
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//设定Assignee的值,用来替换uel表达式
Map<String, Object> map = new HashMap<>();
map.put("assignee0","张三");
map.put("assignee1","李四");
map.put("assignee2","王五");
map.put("assignee3","赵六");
//3、根据流程定义的id启动流程
ProcessInstance instance = runtimeService.startProcessInstanceByKey("myEvection",map);
//4、输出流程信息
System.out.println("流程定义id="+instance.getProcessDefinitionId());
System.out.println("流程实例id="+instance.getId());
System.out.println("当前活动id="+instance.getActivityId());
}
}
Method 3: Listener allocation
Options in the listener Event include:
- Create: triggered after the task is created
- Assignment: Triggered after task assignment
- Delete: triggered after the task is completed
- All: Triggered when all events occur.
Create a listening class:
package com.yzs;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
public class MyTaskListener implements TaskListener {
/**
* 指定负责人
* @param delegateTask
*/
@Override
public void notify(DelegateTask delegateTask) {
if ("创建出差申请".equals(delegateTask.getName()) && "create".equals(delegateTask.getEventName())){
delegateTask.setAssignee("xiaoyu");
}
}
}
2. Process variables
(1)Type
- String
- Integer
- short
- long
- double
- boolean
- date
- binary
- serializable
Note : If pojo is stored in a process variable, the serialization interface serializable must be implemented. In order to prevent the newly added fields from being unable to be deserialized, serializable needs to be generated.
(2) Scope
- globa variable: Repeated variable names are not allowed. If you set a variable with the same name, the value set later will overwrite the variable value set previously.
- Local variable: The variable names can be the same, and the scopes do not affect each other.
(3) How to use
- Using UEL expressions on properties
- Using UEL expressions on wires
(4) Code implementation:
Write the pojo entity class and implement the serialization interface serializable.
package com.yzs;
import java.io.Serializable;
import java.util.Date;
//出差实体类
public class Evection implements Serializable {
//出差id
private String id;
//出差人
private String name;
//出差时间
private Date time;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
}
Write test class
package com.yzs;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.junit.Test;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class VariablesTest {
/**
* 流程部署
*/
@Test
public void testDeployment(){
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3、使用service进行流程部署,定义流程名字,将bpmn部署到数据库中
Deployment deploy = repositoryService.createDeployment()
.name("出差申请流程")
.addClasspathResource("bpmn/evection.bpmn")
.deploy();
//4、输出部署信息
System.out.println("部署id="+deploy.getId());
System.out.println("部署名字="+deploy.getName());
}
/**
* 启动流程实例
*/
@Test
public void startAssigneeUel(){
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//设定Assignee的值,用来替换uel表达式
Evection evection = new Evection();
evection.setId("1");
evection.setName("张三");
evection.setTime(new Date());
Map<String, Object> map = new HashMap<>();
map.put("evection",evection);
map.put("assignee0","张三");
map.put("assignee1","李四");
map.put("assignee2","王五");
map.put("assignee3","赵六");
//3、根据流程定义的id启动流程
ProcessInstance instance = runtimeService.startProcessInstanceByKey("myEvection",map);
//4、输出流程信息
System.out.println("流程定义id="+instance.getProcessDefinitionId());
System.out.println("流程实例id="+instance.getId());
System.out.println("当前活动id="+instance.getActivityId());
}
}
3. How to set global process variables
(1) Set variables when starting the process.
/**
* 启动流程实例
*/
@Test
public void startAssigneeUel(){
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//设定Assignee的值,用来替换uel表达式
Evection evection = new Evection();
evection.setId("1");
evection.setName("张三");
evection.setTime(new Date());
Map<String, Object> map = new HashMap<>();
map.put("evection",evection);
map.put("assignee0","张三");
map.put("assignee1","李四");
map.put("assignee2","王五");
map.put("assignee3","赵六");
//3、根据流程定义的id启动流程
ProcessInstance instance = runtimeService.startProcessInstanceByKey("myEvection",map);
//4、输出流程信息
System.out.println("流程定义id="+instance.getProcessDefinitionId());
System.out.println("流程实例id="+instance.getId());
System.out.println("当前活动id="+instance.getActivityId());
}
(2) Set variables during task processing.
/**
* 完成任务,判断当前用户是否有权限
*/
@Test
public void completTask(){
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取TaskService
TaskService taskService = processEngine.getTaskService();
//3、创建变量集合
Map<String, Object> map = new HashMap<>();
Evection evection = new Evection();
evection.setId("1");
evection.setName("张三");
evection.setTime(new Date());
//4、定义流程变量
map.put("evection",evection);
//5、校验该负责人可以完成当前任务,查询到就去完成任务
Task task = taskService.createTaskQuery()
.processDefinitionKey("myEvection")
.taskAssignee("张三")
.singleResult();
if(task != null){
//6、根据任务id完成任务
taskService.complete(task.getId(),map);
}
}
(3) Set through the current process instance. (The process instance must not be completed yet)
@Test
public void setGlobalVariableByExecutionId(){
String executionId = "2601";
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//3、创建变量集合
Evection evection = new Evection();
evection.setId("1");
evection.setName("张三");
evection.setTime(new Date());
//4、通过流程实例id设置流程变量
runtimeService.setVariable(executionId,"evection",evection);
// 一次设置多个值
// runtimeService.setVariables(executionId,variables);
}
(4) Set by current task.
@Test
public void setGlobalVariableByTaskId(){
String taskId = "1404";
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取TaskService
TaskService taskService = processEngine.getTaskService();
//3、创建变量集合
Evection evection = new Evection();
evection.setId("1");
evection.setName("张三");
evection.setTime(new Date());
//4、通过任务设置流程变量
taskService.setVariable(taskId,"evection",evection);
// 一次设置多个值
// taskService.setVariables(taskId,variables);
Note : If no conditions are set for the connection, the line with the smaller flow number will be taken.
4. How to set local process variables
(1) Set variables during task processing.
@Test
public void completTask(){
String taskId = "1404";
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取TaskService
TaskService taskService = processEngine.getTaskService();
//3、创建变量集合
Map<String, Object> map = new HashMap<String,Object>();
Evection evection = new Evection();
evection.setId("1");
evection.setName("张三");
evection.setTime(new Date());
//4、定义流程变量
map.put("evection",evection);
//5、设置local变量,作用域为该任务
taskService.setVariablesLocal(taskId,map);
//6、完成任务
taskService.complete(taskId);
}
(2) Set by current task.
@Test
public void setGlobalVariableByTaskId(){
String taskId = "1404";
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取TaskService
TaskService taskService = processEngine.getTaskService();
//3、创建变量集合
Evection evection = new Evection();
evection.setId("1");
evection.setName("张三");
evection.setTime(new Date());
//4、通过任务设置流程变量
taskService.setVariableLocal(taskId,"evection",evection);
// 一次设置多个值
// taskService.setVariablesLocal(taskId,variables);
5. Group tasks
Group task processing process: Query group tasks –> Pick up (claim) tasks –> Query individual tasks –> Process individual tasks
/**
* 查询组任务
*/
@Test
public void findGroupTaskList(){
//流程定义key
String key = "myEvection";
//任务候选人
String candidateUser = "liming";
//1、获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取TaskService
TaskService taskService = processEngine.getTaskService();
//3、查询组任务
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskCandidateUser(candidateUser)
.list();
for (Task task:taskList){
System.out.println("流程实例id="+task.getProcessInstanceId());
System.out.println("任务id="+task.getId());
System.out.println("任务负责人="+task.getAssignee());
}
}
/**
* 拾取任务
*/
@Test
public void claimTask(){
//任务id
String taskId = "65001";
//任务候选人
String candidateUser = "liming";
//1、获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取TaskService
TaskService taskService = processEngine.getTaskService();
//3、查询组任务
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskCandidateUser(candidateUser)
.singleResult();
//拾取任务
if (task != null){
taskService.claim(taskId,candidateUser);
System.out.println("任务拾取成功");
}
}
/**
* 归还任务
*/
@Test
public void assigneeToGroup(){
//任务id
String taskId = "65001";
//任务负责人
String assignee = "liming";
//1、获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取TaskService
TaskService taskService = processEngine.getTaskService();
//3、查询组任务
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskAssignee(assignee)
.singleResult();
//归还任务,其实就是把任务的负责人设置为空
if (task != null){
taskService.claim(taskId,null);
System.out.println("任务归还成功");
}
}
/**
* 交接任务
*/
@Test
public void assigneeToCandidateUser(){
//任务id
String taskId = "65001";
//任务负责人
String assignee = "liming";
//任务候选人
String candidateUser = "lisi";
//1、获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取TaskService
TaskService taskService = processEngine.getTaskService();
//3、查询组任务
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskAssignee(assignee)
.singleResult();
//交接任务,其实就是把任务的负责人设置为新的候选人
if (task != null){
taskService.claim(taskId,candidateUser);
System.out.println("任务交接成功");
}
}
6. Gateway
(1) Exclusive gateway
Exclusive gateway, used to implement decisions in the process. When the process is executed to this gateway, all branches will determine whether the condition is true, and if it is true, the branch will be executed.
Note : The exclusive gateway will only select a true branch for execution. If there are two branch conditions that are true, the exclusive gateway will choose the branch with the smaller ID value to execute.
Why use an exclusive gateway?
Branching can be implemented without an exclusive gateway, such as setting branch conditions on the connection condition. The disadvantage of setting condition conditions on the connection: If the conditions are not met, the process will end (abnormal end). If an exclusive gateway is used to determine the direction of the branch, the system will throw an exception if all conditions for the line going out from the gateway are not met.
(2) Parallel gateway
The parallel gateway allows the process to be divided into multiple branches, and multiple branches can also be brought together. The function of the parallel gateway is based on the incoming and outgoing sequence flows.
- Fork branch: All outbound sequence flows after parallelization, and a concurrent branch is created for each sequence flow.
- Join convergence: All the branches that arrive at the parallel gateway and wait here enter the branch. After all the branches entering the sequential flow arrive, the process will pass through the convergence gateway.
Note : If the same parallel gateway has multiple incoming and multiple outgoing sequence flows, it has both branching and merging capabilities. At this time, the gateway will first aggregate all incoming sequence flows and then split them into multiple parallel branches. The main difference from other gateways is that parallel gateways do not parse conditions. Even if conditions are defined in the sequence flow, they will be ignored.
(3)Including gateway
Inclusive gateways can be viewed as a combination of exclusive gateways and parallel gateways. As with the exclusive gateway, you can define conditions on the outgoing sequence flow and the containing gateway will resolve them. But the main difference is that the included gateway can select more than one sequential stream, just like the parallel gateway. The functionality that encompasses the gateway is based on incoming and outgoing sequence flows.
- Branch: All conditions of the outbound sequence flow will be parsed, and the sequence flow with a result of true will continue to execute in parallel, and a branch will be created for each sequence flow.
- Convergence: When all parallel branches arrive at the gateway, they will enter the waiting state until each branch entering the sequential flow containing the process token arrives. This is the biggest difference from parallel gateways. In other words, the containing gateway will only wait for the incoming sequence flow to be selected for execution. After aggregation, the process continues through the containing gateway.
(4) Event gateway
Event-based gateways allow flow decisions to be made based on events. Each outgoing sequence flow of the gateway is connected to an intermediate capture event. When the process reaches an event-based gateway, the gateway will enter a waiting state: execution will be suspended. At the same time, corresponding event subscriptions are created for each outbound sequence flow.
Note : Outbound sequence flows based on event gateways are different from ordinary sequence flows. These sequence flows will not actually "execute". Instead, they let the process engine decide which events need to be subscribed to execute the event gateway-based process. The following conditions should be considered:
基于事件网关必须有两条或以上外出顺序流;
基于事件网关后,只能使用intermediateCatchEvent类型(activiti不支持基于事件网关后连接ReceiveTask。);
连接到事件网关的中间捕获事件必须只有一个入口顺序流。