# activiti6_study
**Repository Path**: gwcc/activiti6_study
## Basic Information
- **Project Name**: activiti6_study
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2024-10-15
- **Last Updated**: 2024-12-10
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 创建Spring Boot 工程
# 引入相关依赖
```xml
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-jdbc
org.springframework.boot
spring-boot-starter-test
mysql
mysql-connector-java
8.0.26
org.projectlombok
lombok
org.mybatis
mybatis
3.4.5
commons-dbcp
commons-dbcp
1.4
junit
junit
4.12
log4j
log4j
1.2.12
org.slf4j
slf4j-api
${slf4j.version}
org.slf4j
slf4j-log4j12
1.6.6
commons-io
commons-io
2.6
org.activiti
activiti-spring-boot-starter-rest-api
6.0.0
org.activiti
activiti-bpmn-layout
6.0.0.RC1
org.activiti
activiti-bpmn-converter
6.0.0
org.activiti
activiti-json-converter
6.0.0
```
# 编写配置类
```properties
spring.application.name=activiti6
#启动端口
server.port=8888
spring.datasource.url=jdbc:mysql://localhost:13306/activiti?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
spring.datasource.username=****
spring.datasource.password=****
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# 1.false,默认值,acticiti启动时对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常
# 2.true,acticiti会对数据中所有的表进行更新操作,如果表不存在,则自动创建
# 3.create_drop,在acticiti启动时创建表,关闭时删除表(必须手动关闭引擎才能删除表)
# 4.drop_create,在acticiti启动时删除原来的表,然后创建新表(不需要手动关闭引擎)
# 这里最好是注释 如果配置为 false 则手动无法创建 activiti 的表
#spring.activiti.database-schema-update=true
# 检测历史表是否存在,acticit7 默认没有开启历史记录信息
spring.activiti.db-history-used=true
#历史记录等级
# 1.none:不保存任何历史记录,因此在流程执行过程中,这是最高效的
# 2.acticiti:级别高于none,保存流程实例与流程行为,其他数据不保存
# 3.audit:除activiti级别会保存的数据外,还会保存全部的流程任务及其属性,audit为默认值
# 4.full:保存历史数据的最高级别,除了保存audit级别的数据外,还会保存其他流程相关的细节数据,包括一些流程参数等
spring.activiti.history-level=full
# 默认true,效验流程文件,默认效验resources下的processes文件夹里的流程
# 为true自动部署流程,为false则不部署
spring.activiti.check-process-definitions=false
####### 上面的配置中-项目启动 不创建表 不自动部署 resources/processes 下的流程到数据库中
####### 启动的时候会报错 可以手动 创建数据库表
####### 但是切记 手动创建表的时候 别写 spring.activiti.database-schema-update=false
####### 但是切记 手动创建表的时候 别写 spring.activiti.database-schema-update=false
####### 但是切记 手动创建表的时候 别写 spring.activiti.database-schema-update=false
```
# 编写启动类
```java
package com.dragons.activiti6;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 剔除 spring security
*
* org.activiti.spring.boot.SecurityAutoConfiguration: Activiti 提供的一个安全自动配置类,
* 用于配置与 Activiti 工作流引擎相关的安全设置。
*
* org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration:
* 是 Spring Boot 提供的默认安全自动配置类,用于配置基于 Spring Security 的安全设置。
*
* 为什么要剔除这些自动配置类?
* 避免冲突: 某些情况下,Activiti 和 Spring Security 的自动配置可能会产生冲突,导致应用无法正常启动或运行。
* 通过剔除这些自动配置类,可以避免这种冲突。
*
* 自定义配置: 可使用自定义的安全配置来替代默认的配置。剔除这些自动配置类,可以确保不会加载默认的安全配置,
* 从而允许在应用中手动配置安全设置。
*
* 简化配置: 如果项目中不需要复杂的安全配置,或者已经通过其他方式实现了安全控制。
*
* 性能优化: 自动配置类有时会引入一些不必要的依赖和配置,剔除它们可以减少应用的启动时间和内存占用,从而提高性能。
*/
@SpringBootApplication(exclude = {
org.activiti.spring.boot.SecurityAutoConfiguration.class,
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class})
public class Activiti6Application {
public static void main(String[] args) {
SpringApplication.run(Activiti6Application.class, args);
}
}
```
# 手动创建 activiti6 的数据库表
## 方式一 单元测试
```xml
com.mchange
c3p0
0.9.5.4
junit
junit
4.12
```
```java
@Test
public void createTable() {
// 创建一个数据源 c3p0
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:13306/activiti?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true");
dataSource.setUser("root");
dataSource.setPassword("123456");
// 创建流程引擎配置
ProcessEngineConfiguration configuration = ProcessEngineConfiguration
.createStandaloneInMemProcessEngineConfiguration();
// 设置数据源
// configuration.setDataSource(dataSource);
// 如果不使用数据源, 可以通过配置连接信息来连接数据库
configuration.setJdbcDriver("com.mysql.jdbc.Driver");
configuration.setJdbcUrl("jdbc:mysql://localhost:13306/activiti?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true");
configuration.setJdbcUsername("root");
configuration.setJdbcPassword("123456");
// 设置创建表的一个规则,有三种
// DB_SCHEMA_UPDATE_FALSE = "false" 如果数据库里没有acti相关的表, 也不会创建
// DB_SCHEMA_UPDATE_CREATE_DROP = "create-drop" 不管数据库里有没acti的相关表, 都会先删除旧表再创建新表, 不推荐在生产中使用
// DB_SCHEMA_UPDATE_TRUE = "true" 如果数据库里没有acti相关的表, 会自动创建
// 仔细看看, 是不是有些类似于hibernate里的ddl-auto :)
configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_CREATE_DROP);
// 构建流程引擎, 这一步就会创建好表, 但基本上表内都是空的, 因为还没有部署, 再没有流程实例
ProcessEngine processEngine = configuration.buildProcessEngine();
// 可以获取流程引擎的一些信息, 不过这个东西没啥用..
System.out.println(processEngine.getName());
}
```
## 方式二 实现 CommandLineRunner
```java
package com.dragons.activiti6;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class ActivitiTableCreator implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
// 创建ProcessEngineConfiguration对象
ProcessEngineConfiguration config = ProcessEngineConfiguration
.createStandaloneProcessEngineConfiguration();
// 设置数据库连接相关信息
config.setJdbcDriver("com.mysql.jdbc.Driver");
config.setJdbcUrl("jdbc:mysql://localhost:13306/activiti?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true");
config.setJdbcUsername("root");
config.setJdbcPassword("123456");
// 设置数据库模式更新策略为true,表示自动创建表
/**
* 这里就是设置 spring.activiti.database-schema-update=true
* 但是如果在配置文件中配置了 spring.activiti.database-schema-update=false
* 则创建数据库表的时候会失败
* 原因:
* --配置属性的作用原理:
* 代码中通过ProcessEngineConfiguration对象设置databaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE)时,
* 是代码层面告诉Activiti要在构建ProcessEngine时更新数据库模式,也就是创建表。
*
* 而 spring.activiti.database-schema-update=false 这个配置是在Spring Boot自动配置Activiti时使用的。Spring Boot的ActivitiAutoConfiguration
* 类 会读取这个配置属性来决定是否对Activiti的数据库模式进行更新。
*
* 当 spring.activiti.database-schema-update=false 时,Spring Boot 自动配置过程会覆盖你在代码中通过ProcessEngineConfiguration对象设置的更新策略,
* 以遵循配置文件中的设置,从而导致无法创建表。
*
* --深入分析Spring Boot和Activiti的自动配置交互
* 在Spring Boot中,ActivitiAutoConfiguration类负责Activiti相关组件的自动配置。它会在应用启动时读取配置文件中的spring.activiti相关属性来初始化
* Activiti的ProcessEngine。
*
* 当配置文件中设置了database-schema-update=false,ActivitiAutoConfiguration会按照这个设置来构建ProcessEngine,忽略代码中手动设置的
* DB_SCHEMA_UPDATE_TRUE。因为 Spring Boot的 自动配置机制【优先考虑配置文件中的属性来保证配置的一致性和可维护性】。
*
* --解决方案
* 如果你想在代码中手动控制表的创建,而不受配置文件中spring.activiti.database-schema-update属性的影响,可以考虑不使用Spring Boot的Activiti自动配置。
* 方法是在Spring Boot应用的启动类上添加@SpringBootApplication(exclude = {org.activiti.spring.boot.ActivitiAutoConfiguration.class})注解,
*
* 这样就排除了Activiti的自动配置。然后完全通过自己的代码来构建和管理Activiti的ProcessEngine,包括表的创建等操作。不过这样做需要你自己负责更多的Activiti
* 组件的初始化和配置工作。
*/
config.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
// 根据配置创建ProcessEngine对象,这一步会触发表的创建
ProcessEngine processEngine = config.buildProcessEngine();
processEngine.close();
}
}
```
## 方式三 配置文件-true
```xml
# 1.false,默认值,acticiti启动时对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常
# 2.true,acticiti会对数据中所有的表进行更新操作,如果表不存在,则自动创建
# 3.create_drop,在acticiti启动时创建表,关闭时删除表(必须手动关闭引擎才能删除表)
# 4.drop_create,在acticiti启动时删除原来的表,然后创建新表(不需要手动关闭引擎)
spring.activiti.database-schema-update=true
```
# activiti6 创建的表格

```sql
act_ge_ 通用数据表,ge是general的缩写
act_hi_ 历史数据表,hi是history的缩写,对应 HistoryService 接口
act_id_ 身份数据表,id是identity的缩写,对应 IdentityService 接口
act_re_ 流程存储表,re是repository的缩写,对应 RepositoryService 接口,存储流程部署和流程定义等静态数据
act_ru_ 运行时数据表,ru是runtime的缩写,对应 RuntimeService 接口和 TaskService 接口,存储流程实例和用户任务等动态数据
```
```sql
资源库流程规则表
1) act_re_deployment 部署信息表
2) act_re_model 流程设计模型部署表
3) act_re_procdef 流程定义数据表
运行时数据库表
1) act_ru_execution 运行时流程执行实例表
2) act_ru_identitylink 运行时流程人员表,主要存储任务节点与参与者的相关信息
3) act_ru_task 运行时任务节点表
4) act_ru_variable 运行时流程变量数据表
历史数据库表
1) act_hi_actinst 历史节点表
2) act_hi_attachment 历史附件表
3) act_ih_comment 历史意见表
4) act_hi_identitylink 历史流程人员表
5) act_hi_detail 历史详情表,提供历史变量的查询
6) act_hi_procinst 历史流程实例表
7) act_hi_taskinst 历史任务实例表
8) act_hi_varinst 历史变量表
组织机构表
1) act_id_group 用户组信息表
2) act_id_info 用户扩展信息表
3) act_id_membership 用户与用户组对应信息表
4) act_id_user 用户信息表
这四张表很常见,基本的组织机构管理,关于用户认证方面建议还是自己开发一套,
组件自带的功能太简单,使用中有很多需求难以满足
通用数据表
1) act_ge_bytearray 二进制数据表
2) act_ge_property 属性数据表存储整个流程引擎级别的数据,初始化表结构时,会默认插入三条记录
流程部署相关表
act_re_deployement 部署对象表
act_rep_procdef 流程定义表
act_ge_bytearray 资源文件表
act_ge_prperty 主键生成策略表(对于部署对象表的主键ID)
流程实例相关表
act_ru_execution 正在执行的执行对象表(包含执行对象ID和流程实例ID,如果有多个线程可能流程实例ID不一样)
act_hi_procinst 流程实例历史表
act_hi_actinst 存放历史所有完成的任务
Task 任务相关表
act_ru_task 代办任务表 (只对应节点是UserTask的)
act_hi_taskinst 代办任务历史表 (只对应节点是UserTask的)
act_hi_actinst 所有节点活动历史表 (对应流程的所有节点的活动历史,从开始节点一直到结束节点中间的所有节点的活动都会被记录)
流程变量表
act_ru_variable 正在执行的流程变量表
act_hi_variable 流程变量历史表
```
# 绘制流程图
## IDEA 安装插件

## resources 新建文件夹 processes(名称不能更改),并新增Bpmn文件,画流程图






## 使用 camunda-modeler 设计流程图 resources/pkg/camunda-modeler-3.0.0-win-x64.zip
### 解压后配置



# 流程部署
```xml
# 若手动部署流程 配置文件 设置为 false 这样项目启动 resources/processes 下的流程不会自动部署
# 默认true,效验流程文件,默认效验resources下的processes文件夹里的流程
# 为true自动部署流程,为false则不部署
spring.activiti.check-process-definitions=false
```
## classpath 部署方式
```java
@RequestMapping("/deployByClassPath")
public void deploymentByClassPath() {
// 1. 创建 ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2. 获取 RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3. 使用 service 进行流程部署,即把 bpmn 部署到数据库,并定义流程的名称
Deployment deploy = repositoryService.createDeployment()
// 定义流程资源名称
.name("出差申请流程")
// 加载待部署的资源,可以多次引用
.addClasspathResource("processes/alyson.bpmn20.xml")
// 完成部署
.deploy();
}
```
## 输入流(InputStream)方式部署资源
```java
@RequestMapping("/deployByInputStream")
public void deploymentByInputStream() {
// 1. 创建 ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2. 获取 RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3. 获取输入流
String filePath = "src/main/resources/processes/dragons.bpmn20.xml";
FileInputStream fileIns = null;
try {
fileIns = new FileInputStream(filePath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 4. 使用 service 进行流程部署
Deployment deploy = repositoryService.createDeployment()
.name("出差申请流程")
.addInputStream("processes/dragons.bpmn20.xml", fileIns)
.deploy();
}
```
## zip/bar 部署
```java
@RequestMapping("/deployByZip")
public void deployProcessByZip() {
// 1. 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2. 获取 RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3. 流程部署
InputStream inputStream = this.getClass()
.getClassLoader()
.getResourceAsStream("processes/zipdeploy.bpmn20.zip");
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
repositoryService.createDeployment()
.addZipInputStream(zipInputStream)
.deploy();
}
```
## 字符串方式部署
```java
@RequestMapping("/deployByString")
public void deployProcessByString() {
// 1. 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2. 获取 RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3. 构建字符串
String str = readFileToString("src/main/resources/processes/helloword.bpmn20.xml");
// 4. 流程部署
repositoryService.createDeployment()
.name("字符串形式的部署")
.addString("processes/helloword.bpmn20.xml", str)
.deploy();
}
```
## 动态 BPMN 模型部署
```java
@RequestMapping("/deploymentByBPMN")
public void deploymentByBPMN() {
// 1. 创建 BPMN 模型实例
BpmnModel bpmnModel = new BpmnModel();
// 2. 创建开始事件
StartEvent startEvent = new StartEvent();
startEvent.setId("startEvent");
startEvent.setName("动态创建开始节点");
// 3. 创建用户任务
UserTask userTask = new UserTask();
userTask.setId("userTask1");
userTask.setName("用户任务节点1");
// 4. 创建结束事件
EndEvent endEvent = new EndEvent();
endEvent.setId("endEvent");
endEvent.setName("动态创建结束节点");
// 5. 定义连接
ArrayList sequenceFlows = new ArrayList<>();
ArrayList toEnd = new ArrayList<>();
SequenceFlow s1 = new SequenceFlow();
s1.setId("sequenceFlow1");
s1.setName("开始节点指向用户任务节点");
s1.setSourceRef("startEvent");
s1.setTargetRef("userTask1");
sequenceFlows.add(s1);
SequenceFlow s2 = new SequenceFlow();
s2.setId("sequenceFlow2");
s2.setName("用户任务节点指向结束节点");
s2.setSourceRef("userTask1");
s2.setTargetRef("endEvent");
toEnd.add(s2);
startEvent.setOutgoingFlows(sequenceFlows);
userTask.setOutgoingFlows(toEnd);
userTask.setIncomingFlows(sequenceFlows);
endEvent.setIncomingFlows(toEnd);
Process process = new Process();
process.setId("process1");
process.setName("test");
process.addFlowElement(startEvent);
process.addFlowElement(s1);
process.addFlowElement(userTask);
process.addFlowElement(s2);
process.addFlowElement(endEvent);
bpmnModel.addProcess(process);
// 自动布局工具类导入 需要添加依赖
/*
org.activiti
activiti-bpmn-layout
6.0.0.RC1
*/
new BpmnAutoLayout(bpmnModel).execute();
// 6. 部署
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
.name("出差申请流程")
.addBpmnModel("evection.bpmn20.xml", bpmnModel)
.deploy();
}
```
## 流程部署后影响到的表
```sql
select * from act_re_deployment; -- 流程部署表
select * from act_re_procdef; -- 流程定义表
select * from act_ge_bytearray; -- 流程资源表
```
### act_re_deployment 流程部署表

### act_re_procdef 流程定义表

### act_ge_bytearray 流程资源表

# 启动流程实例
```java
/**
* 开启流程
* 启动流程时, 自身系统的业务就跟流程的业务有交集了, 自己项目里的业务怎么跟流程的东西关联起来的呢? 答案就在启动流程这块
*
* 可以看到 startProcessInstanceByKey() 这个方法传了两个参数
*
* Q: 为啥要用ProcessInstanceByKey而不用 ID呢?
*
* A: 流程的Key就是流程图的名字,这个可以提前知道, 而且一个流程图定义好之后这个key就不会变了
* 但id不一样, 流程部署一次就变一次, 如果用id的话, 还要事先查询好
*
* Q: 这里的businessKey是什么东西
*
* A: 这个就是把自己项目里的业务跟Activiti的业务关联起来的东西,
* 例子, 请假的表是自己项目里创建的一个表存储的, 当发起流程的时候, 把这个请假的表里的id传给activiti的流程,
* 这样在流程处理的过程中可以随时去获取这个 businessKey 然后查询出请假的信息
*/
@RequestMapping("/startProcessByProcDefKey")
public void startProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
// 在画流程图的时候,给流程图起的名字
String processDefinitionKey = "travel_application";
// 业务逻辑中的id
String businessKey = "123456";
ProcessInstance instance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey);
System.out.println("ID: " + instance.getId());
}
```
## 启动流程影响到的表
```sql
select * from act_hi_actinst; -- 历史节点表
select * from act_hi_procinst;-- 历史流程实例信息
select * from act_hi_taskinst;-- 历史任务流程实例信息
select * from act_ru_execution; -- 运行时流程执行实例
select * from act_ru_task;-- 运行时任务数据表 只有一条
select * from act_ru_identitylink;-- 身份联系
```
### act_hi_actinst 历史节点表
历史节点数据,图片上的节点信息

### act_hi_procinst 历史流程实例信息
历史流程实例数据表,正在执行的任务也在其中

### act_hi_taskinst 历史任务流程实例信息
历史任务实例数据表

### act_ru_execution 运行时流程执行实例
运行时流程执行实例数据表,一条是开始事件的执行实例,这个一直存在,
只到流程结束后才会自动删除,is_active字段表示是否正在执行实例

### act_ru_task 运行时任务数据表 只有一条
运行时任务信息数据信息表

### act_ru_identitylink 身份联系
存储当前节点参与者的信息,任务参与者数据表

# 查询个人代办任务
```java
/** 方式一 */
// 坑: 建议使用 Activiti BPMN visualizer 插件画图 camunda-modeler-3.0.0-win-x64 绘图读取不到 审批人信息
@RequestMapping("/getPersonTodo")
public void getPersonTodo() {
//1、获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、获取taskService
TaskService taskService = processEngine.getTaskService();
//3、根据流程key 和 任务的负责人 查询任务
List taskList = taskService.createTaskQuery()
//流程Key
.processDefinitionKey("travel_application")
//要查询的负责人
.taskAssignee("zhangsan")
.list();
for (Task task : taskList) {
System.out.println("流程实例id="+task.getProcessInstanceId());
System.out.println("任务Id="+task.getId());
System.out.println("任务负责人="+task.getAssignee());
System.out.println("任务名称="+task.getName());
}
```
## 查询 SQL
```sql
select
distinct RES.*
from ACT_RU_TASK RES
inner join ACT_RE_PROCDEF D on RES.PROC_DEF_ID_ = D.ID_
WHERE RES.ASSIGNEE_ = 'zhangsan' and D.KEY_ = 'travel_application'
order by RES.ID_ asc LIMIT 2147483647 OFFSET 0
```
# 完成个人任务
```java
/**方式一*/
@RequestMapping("/completePersonTask")
public void completeTask() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
//完成任务,参数:任务id,完成 zhangsan 的任务,9 是上述ACT_RU_TASK表的id
taskService.complete("9");
}
```
```java
/**方式二*/
@PostMapping("/completePersonTask1")
public void completeTask1(String assignee) {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
//获取 jerry - travel_application 对应的任务
Task task = taskService.createTaskQuery()
.processDefinitionKey("travel_application")
.taskAssignee(assignee)
.singleResult();
System.out.println("procId="+task.getProcessInstanceId());
System.out.println("taskId="+task.getId());
System.out.println("assign="+task.getAssignee());
System.out.println("name="+task.getName());
taskService.complete(task.getId());
}
```
## 任务启动
**当启动任务时 act_hi_actinst 插入两条数据 开始节点 和 当前审批节点**

**act_hi_procinst 表创建一条流程实例数据**

**act_hi_taskinst 表插入一条当前审批任务**

**act_ru_execution 表有两条数据 有 ACT_ID_ 的是当前流程任务**

**act_ru_task 表只有一条数据 是当前流程任务**

**act_ru_identitylink 表 是当前审批人的信息**

## 审批任务
**当审批任务时 下面是上面六张表的 变化**
**act_hi_actinst 表会 修改已审批任务 的 结束时间 和 耗时 ms**

**act_hi_procinst 表无变化**

**act_hi_taskinst 表 会修改已审批任务的 结束时间和耗时 并插入下一条任务**

**act_ru_execution 表会将 ACT_ID_ 修改为当前任务**

**act_ru_task 表 只有一条数据 最新任务**

**act_ru_identitylink 表 将当前审批人信息插入一条**

## 审批所有任务
**继续审批 直到任务结束**
**act_hi_actinst**

**act_hi_procinst 表修改结束时间 耗时 和 结束 ACT_ID_**

**act_hi_taskinst 表保存历史任务实例**

**act_ru_execution; -- 运行时流程执行实例 清空**
**act_ru_task;-- 运行时任务数据表 只有一条 清空**
**act_ru_identitylink;-- 身份联系 清空**
# 查看审批历史
```java
@PostMapping("/getHisTasks")
public void getHisTasks(String procId) {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取HistoryService
HistoryService historyService = processEngine.getHistoryService();
//获取 actinst表的查询对象
HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
//查询 actinst表,条件:根据 InstanceId 查询
instanceQuery.processInstanceId(procId);
//查询 actinst表,条件:根据 DefinitionId 查询
//instanceQuery.processDefinitionId("myEvection:1:7504");
//增加排序操作, 根据开始时间排序 asc 升序
instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
//查询所有内容
List activityInstanceList = instanceQuery.list();
for (HistoricActivityInstance hi : activityInstanceList) {
System.out.println(hi);
System.out.println("<==========================>");
}
}
```

# 使用 UEL 表达式设置负责人 principal
## 修改流程图

## 部署
```sql
select * from act_ge_bytearray;
select * from act_re_deployment;
select * from act_re_procdef;
```
act_ge_bytearray

act_re_deployment

act_re_procdef

## 启动
```java
@PostMapping("/startPrincipalProcess")
public void startPrincipalProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
//设定assignee的值,用来替换 uel 表达式
Map assigneeMap = new HashMap<>();
assigneeMap.put("assignee0","张三");
assigneeMap.put("assignee1","李经理");
assigneeMap.put("assignee2","王总经理");
assigneeMap.put("assignee3","赵财务");
//启动流程实例
runtimeService.startProcessInstanceByKey("travel_application_principal",assigneeMap);
}
```
### 启动流程变化的表
```sql
select * from act_hi_actinst; -- 历史节点表
select * from act_hi_detail; -- 历史详细信息
select * from act_hi_identitylink; -- 历史流程人员表
select * from act_hi_procinst; -- 历史流程实例信息
select * from act_hi_taskinst; -- 历史任务流程实例信息
select * from act_hi_varinst; -- 历史变量信息
select * from act_ru_execution; -- 运行时流程执行实例
select * from act_ru_identitylink; -- 身份联系
select * from act_ru_task; -- 运行时任务数据表
select * from act_ru_variable; -- 运行时流程变量数据表
```
#### act_hi_actinst

#### act_hi_detail

#### act_hi_identitylink

#### act_hi_procinst

#### act_hi_taskinst

#### act_hi_varinst

#### act_ru_execution

#### act_ru_identitylink

#### act_ru_task

#### act_ru_variable

### 添加 UEL 表达式后的流程图会额外的修改 ACT_HI_VARINST(历史流程运行中的变量信息数据表) ACT_RU_VARIABLE(运行时变量表)
## 完成任务
```java
@PostMapping("/completePrincipalTask")
public void completePrincipalTask(String assignee) {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
//获取 jerry - travel_application 对应的任务
Task task = taskService.createTaskQuery()
.processDefinitionKey("travel_application_principal")
.taskAssignee(assignee)
.singleResult();
System.out.println(task);
taskService.complete(task.getId());
}
```
### 完成任务后 这十张表的变化
#### act_hi_actinst 表新增下一个任务 并修改上一个任务的 完成时间和耗时

#### act_hi_detail 表无变化

#### act_hi_identitylink 表插入下一审批人信息

#### act_hi_procinst 表无变化

#### act_hi_taskinst 表插入下一个审批并 修改上一个 任务的 结束时间和耗时

#### act_hi_varinst 无变化

#### act_ru_execution 表将 ACT_ID_ 改为最新的任务

#### act_ru_identitylink 插入当前任务审批人信息

#### act_ru_task 表 改为 当前审批任务

#### act_ru_variable 无变化

### 完成所有任务后 表的变化
#### act_hi_actinst 表记录了所有审批节点 的审批开始结束时间和耗时

#### act_hi_detail 表记录的信息无变化

#### act_hi_identitylink 表记录每个审批过的 人员信息

#### act_hi_procinst 还是只有一条 并且审批结束 记录开始结束时间 耗时 及结束节点 END_ACT_ID_

#### act_hi_taskinst 记录审批过的任务信息 及时间 审批人员

#### act_hi_varinst 表记录流程变量信息 无变化

#### act_ru_execution; -- 运行时流程执行实例 无相关数据
#### act_ru_identitylink; -- 身份联系 无相关数据
#### act_ru_task; -- 运行时任务数据表 无相关数据
#### act_ru_variable; -- 运行时流程变量数据表 无相关数据
# 候选人流程
## 绘制流程图 candidate

## 部署流程
```java
/** classpath 部署方式 */
@RequestMapping("/deployCandidateProcessByClassPath")
public void deployCandidateProcessByClassPath() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
.name("出差申请流程-candidate")
.addClasspathResource("processes/travel_application_candidate.bpmn20.xml")
.deploy();
System.out.println("classpath 方式部署了流程");
}
```
```sql
select * from act_ge_bytearray;
select * from act_re_deployment;
select * from act_re_procdef;
```
## 启动流程
```java
/** 启动候选人流程 */
@PostMapping("/startCandidateProcess")
public void startCandidateProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
runtimeService.startProcessInstanceByKey("travel_application_candidate");
}
```
### 表数据变化
```sql
select * from act_hi_actinst;
select * from act_hi_identitylink;
select * from act_hi_procinst;
select * from act_hi_taskinst;
select * from act_ru_execution;
select * from act_ru_identitylink;
select * from act_ru_task;
```
#### act_hi_actinst

#### act_hi_identitylink

#### act_hi_procinst

#### act_hi_taskinst

#### act_ru_execution

#### act_ru_identitylink

#### act_ru_task

## 查询候选人
```java
/**
* 查询候选人任务
* @param candidate 候选人
*/
@PostMapping("/getCandidatePersonTodo")
public List getCandidatePersonTodo(String candidate) {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
List taskList = taskService.createTaskQuery()
.processDefinitionKey("travel_application_candidate")
//根据候选人查询任务
.taskCandidateUser(candidate)
.list();
for (Task task : taskList) {
System.out.println("========================");
System.out.println(task);
}
return taskList;
}
```
## 拾取候选人任务
```java
/**
* 拾取候选人任务
* @param taskId 任务ID
* @param candidateUser 候选人
*/
@PostMapping("/getCandidateClaimPersonTodo")
public void getCandidateClaimPersonTodo(String taskId, String candidateUser) {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskCandidateUser(candidateUser)
.singleResult();
if(task != null){
//拾取任务
taskService.claim(taskId,candidateUser);
System.out.println("taskid-"+taskId+"-用户-"+candidateUser+"-拾取任务完成");
}
}
```
### 拾取任务后 表数据变化
**拾取任务相当于是将当前任务分配给某个候选人**
#### act_hi_actinst 最新任务分配了审批人

#### act_hi_identitylink 无变化

#### act_hi_procinst 只有当任务结束时会变化

#### act_hi_taskinst 添加审批人 并更新拾取时间

#### act_ru_execution 无变化

#### act_ru_identitylink 无变化

#### act_ru_task 添加当前任务审批人

## 归还任务给其他候选人
```java
/**
* 归还任务给其他候选人
* @param taskId 任务ID
* @param assignee 当前候选人
* @param backToCandidate 归还给 候选人
*/
@PostMapping("/getCandidatePersonTodoBaskTask")
public void getCandidatePersonTodoBaskTask(String taskId, String assignee, String backToCandidate) {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
//根据key 和负责人来查询任务
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskAssignee(assignee)
.singleResult();
if(task != null){
//归还任务 ,就是把负责人 设置为空
taskService.setAssignee(taskId,null);
taskService.setAssignee(taskId,backToCandidate);
System.out.println("taskid-"+taskId+"-归还任务完成");
}
}
```
### 归还任务后表数据变化
#### act_hi_actinst 将当前任务的审批人修改为 归还的人

#### act_hi_identitylink 表无变化
#### act_hi_procinst 表无变化
#### act_hi_taskinst 表将 ASSIGNEE_ 修改为 归还人
#### act_ru_execution 表无变化
#### act_ru_identitylink 表无变化
#### act_ru_task 表将 ASSIGNEE_ 修改为 归还人
## 拾取后 完成候选人任务
```java
@PostMapping("/completeCandidateTask")
public void completeCandidateTask(String assignee) {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.processDefinitionKey("travel_application_candidate")
.taskAssignee(assignee)
.singleResult();
System.out.println("procId="+task.getProcessInstanceId() +
" taskId="+task.getId() + " assign="+task.getAssignee() +
" name="+task.getName());
taskService.complete(task.getId());
}
```
### 完成任务后表数据变化
```sql
select * from act_hi_actinst ORDER BY START_TIME_ asc; -- 添加下一审批节点并修改上一节点数据
select * from act_hi_identitylink; -- 无变化
select * from act_hi_procinst; -- 无变化
select * from act_hi_taskinst ORDER BY START_TIME_ asc; -- 添加下一审批节点数据并修改上一节点数据
select * from act_ru_execution; -- ACT_ID_ 更新到最新的审批节点
select * from act_ru_identitylink; -- 有变化
select * from act_ru_task; -- 更新到最新的节点数据
```
### act_ru_identitylink 表的变化
**删除了 TYPE_ = candidate 的数据 保留了 TYPE_ = participant 的数据 并插入下一任务的审批人信息**

### 完成所有任务后的表数据变化
```sql
select * from act_ru_execution; -- 无相关数据
select * from act_ru_identitylink; -- 无相关数据
select * from act_ru_task; -- 无相关数据
```
#### act_hi_actinst 表包含开始结束 审批节点

#### act_hi_identitylink 表包含 候选人 和 各个节点审批人

#### act_hi_procinst 表 填充 结束时间 结束 taskId 及 耗时 DURATION_

#### act_hi_taskinst 表只记录 审批过的节点 无开始结束节点

# 监听器流程
## 绘制流程图

## 查看 流程图 XML 文件并 添加 监听器
```java
/**
监听器包括下面三种
Execution Listeners(执行监听器)
Task Listeners(任务监听器)
JavaDelegate(Java代理)
*/
```
## Task Listeners(任务监听器)
### 在 xml 文件中配置 任务监听器

**创建上图中的三个监听器**
```java
package com.dragons.activiti6.listener.task_listener;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
/**任务创建时触发*/
public class TaskListenerCreate implements TaskListener {
//delegateTasK 是当前任务的对象
@Override
public void notify(DelegateTask delegateTask) {
//默认是create事件
if("创建申请".equals(delegateTask.getName()) && "create".equals(delegateTask.getEventName())){
// 此节点哦日第一个任务节点 当启动任务时 设置任务审批人 张三
delegateTask.setAssignee("张三");
System.out.println("create 设置 任务审批人 " + delegateTask.getAssignee());
}
}
}
```
```java
package com.dragons.activiti6.listener.task_listener;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
/**审批任务时触发*/
public class TaskListenerAssignment implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
if("创建申请".equals(delegateTask.getName()) &&
"assignment".equals(delegateTask.getEventName())){
//delegateTask.setAssignee("张三");
System.out.println("任务审批 "+delegateTask.getAssignee());
}
}
}
```
```java
package com.dragons.activiti6.listener.task_listener;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
/**任务完成时触发*/
public class TaskListenerComplete implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
if("创建申请".equals(delegateTask.getName()) &&
"complete".equals(delegateTask.getEventName())){
//delegateTask.setAssignee("张三");
System.out.println("任务完成 耗时 " + delegateTask.getDueDate());
}
}
}
```
### 部署 启动 审批
```java
package com.dragons.activiti6.controller;
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.task.Task;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ListenerProcessController {
/** classpath 部署方式 */
@RequestMapping("/deployTaskListenerProcessByClassPath")
public void deployTaskListenerProcessByClassPath() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
.name("监听器-listener")
.addClasspathResource("processes/test_listener.bpmn20.xml")
.deploy();
System.out.println("classpath 方式部署了流程");
}
/** 启动监听器流程 */
@PostMapping("/startTaskListenerProcess")
public void startTaskListenerProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
runtimeService.startProcessInstanceByKey("test_listener");
}
/**
* 完成任务
* @param assignee 审批人
*/
@PostMapping("/completeTaskListenerTask")
public void completeTaskListenerTask(String assignee) {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.processDefinitionKey("test_listener")
.taskAssignee(assignee)
.singleResult();
System.out.println("完成任务 procId="+task.getProcessInstanceId() + " taskId="+task.getId() +
" assign="+task.getAssignee() + " name="+task.getName());
taskService.complete(task.getId());
}
}
```
### 结果

## Execution Listeners(执行监听器)
Execution Listeners(执行监听器)在Activiti中用于监听流程实例或
活动节点的生命周期事件,例如开始、结束、创建 和 删除等
### 修改 XML BPMN 文件

```xml
```
### 编写监听器
```java
package com.dragons.activiti6.listener.execution_listener;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
/** 开始节点 执行监听器 */
public class ExecutionListenerStarter implements ExecutionListener {
@Override
public void notify(DelegateExecution execution) {
if ("start".equals(execution.getEventName())) {
System.out.println("开始节点 StartEvent 监听器 ExecutionListenerStarter 触发 " + execution.getCurrentActivityId());
}
}
}
```
```java
package com.dragons.activiti6.listener.execution_listener;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
/** 审批节点 执行监听器 */
public class ExecutionListenerUserTask implements ExecutionListener {
@Override
public void notify(DelegateExecution execution) {
if ("start".equals(execution.getEventName())) {
System.out.println("创建申请 节点 监听器 ExecutionListenerUserTask 触发 " + execution.getCurrentActivityId());
}
}
}
```
```java
package com.dragons.activiti6.listener.execution_listener;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
/** 结束节点 执行监听器 */
public class ExecutionListenerEnd implements ExecutionListener {
@Override
public void notify(DelegateExecution execution) {
if ("end".equals(execution.getEventName())) {
System.out.println("结束节点 EndEvent 监听器 ExecutionListenerEnd 触发 " + execution.getCurrentActivityId());
}
}
}
```
### 部署 启动 审批
```java
package com.dragons.activiti6.controller;
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.task.Task;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ListenerProcessController {
/** classpath 部署方式 */
@RequestMapping("/deployTaskListenerProcessByClassPath")
public void deployTaskListenerProcessByClassPath() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
.name("监听器-listener")
.addClasspathResource("processes/test_listener.bpmn20.xml")
.deploy();
System.out.println("classpath 方式部署了流程");
}
/**
* 启动监听器流程
*/
@PostMapping("/startTaskListenerProcess")
public void startTaskListenerProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
runtimeService.startProcessInstanceByKey("test_listener");
}
/**
* 完成任务
* @param assignee 审批人
*/
@PostMapping("/completeTaskListenerTask")
public void completeTaskListenerTask(String assignee) {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
//获取 jerry - travel_application 对应的任务
Task task = taskService.createTaskQuery()
.processDefinitionKey("test_listener")
.taskAssignee(assignee)
.singleResult();
// System.out.println("完成任务 procId="+task.getProcessInstanceId() + " taskId="+task.getId() +
// " assign="+task.getAssignee() + " name="+task.getName());
taskService.complete(task.getId());
}
}
```
#### 结果日志

# 设置变量 variables
## 绘制 及 配置 流程图




**因为使用的是 IDEA 插件 Activiti BPMN visualizer 绘制的流程图 而不是 Camunda 因此BPMN XML文件中的表表达式配置方式不同**
## 部署 启动 审批
```java
package com.dragons.activiti6.controller;
import com.dragons.activiti6.entities.EvectionVariable;
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.task.Task;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class VariablesProcessController {
/** classpath 部署方式 */
@RequestMapping("/deployVariablesProcessByClassPath")
public void deployVariablesProcessByClassPath() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
.name("监听器-listener")
.addClasspathResource("processes/variables_tes.bpmn20.xml")
.deploy();
System.out.println("classpath 方式部署了流程");
}
/** 启动 设置变量 流程 */
@PostMapping("/startVariablesProcess")
public void startVariablesProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
//流程变量的map
Map variables = new HashMap<>();
//设置流程变量
EvectionVariable evection = new EvectionVariable();
//设置出差日期
evection.setNum(2d);
//把流程变量的pojo放入map
variables.put("evection",evection);
//设定任务的负责人
variables.put("assignee0","李四");
variables.put("assignee1","王经理");
variables.put("assignee2","杨总经理");
variables.put("assignee3","张财务");
runtimeService.startProcessInstanceByKey("variables_tes",variables);
}
/** 启动 设置变量 流程 完成个人任务的时候设置流程变量 */
@PostMapping("/startVariablesProcess1")
public void startVariablesProcess1() {
EvectionVariable evection = new EvectionVariable();
//设置出差时间
evection.setNum(2d);
Map map = new HashMap<>();
map.put("evection",evection);
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
//查询任务
Task task = taskService.createTaskQuery()
.processDefinitionKey("variables_tes")
.taskAssignee("李四")
.singleResult();
if(task != null){
//根据任务id 完成任务,并传递流程变量
taskService.complete(task.getId(),map);
System.out.println(task.getId()+"----任务已完成");
};
}
/**
* 完成任务
* @param assignee 审批人
*/
@PostMapping("/completeVariablesTask")
public void completeVariablesTask(String assignee) {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
//获取 jerry - travel_application 对应的任务
Task task = taskService.createTaskQuery()
.processDefinitionKey("variables_tes")
.taskAssignee(assignee)
.singleResult();
System.out.println("完成任务");
taskService.complete(task.getId());
}
}
```
### 部署 表数据变化
```sql
select * from act_ge_bytearray;
select * from act_re_deployment;
select * from act_re_procdef;
```
### 启动 表数据变化
```sql
select * from act_hi_actinst;
select * from act_hi_detail;
select * from act_hi_identitylink;
select * from act_hi_procinst;
select * from act_hi_taskinst;
select * from act_hi_varinst;
select * from act_ru_execution;
select * from act_ru_identitylink;
select * from act_ru_variable;
select * from act_ge_bytearray;
```
#### act_hi_actinst

#### act_hi_detail

#### act_hi_identitylink

#### act_hi_procinst

#### act_hi_taskinst

#### act_hi_varinst

#### act_ru_execution

#### act_ru_identitylink

#### act_ru_variable

#### act_ge_bytearray

### 审批 表数据变化
#### act_hi_actinst 表将最新的任务插入

#### act_hi_detail 无变化

#### act_hi_identitylink 插入最新任务的审批人

#### act_hi_procinst 无变化

#### act_hi_taskinst 插入最新任务的信息

#### act_hi_varinst 无变化

#### act_ru_execution ACT_ID_ 更新到最新任务

#### act_ru_identitylink 将最新审批人插入

#### act_ru_variable 无变化

#### act_ge_bytearray 无变化

### 流程启动时 传递了 evection.num 当 部门经理审批节点时 下一节点为 财务审核
```java
/** 启动 设置变量 流程 */
@PostMapping("/startVariablesProcess")
public void startVariablesProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
//流程变量的map
Map variables = new HashMap<>();
//设置流程变量
EvectionVariable evection = new EvectionVariable();
//设置出差日期
evection.setNum(2d);
//把流程变量的pojo放入map
variables.put("evection",evection);
//设定任务的负责人
variables.put("assignee0","李四");
variables.put("assignee1","王经理");
variables.put("assignee2","杨总经理");
variables.put("assignee3","张财务");
runtimeService.startProcessInstanceByKey("variables_tes",variables);
}
```
#### act_ru_task 表是当前审批节点信息

# 排他网关
```java
/**
所有分支都会判断条件是否为true,如果为true就执行该分支
注意:只会选择一个true的分支执行,如果都满足条件,则走flowid最小的任务。
与上述条件变量的区别:都不满足条件,则抛出异常。
*/
```
## 绘制流程图

### 细节
```xml
= 3}]]>
```
## 部署 启动 审批
```java
package com.dragons.activiti6.controller;
import com.dragons.activiti6.entities.EvectionVariable;
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class ExclusiveGatewayController {
/** classpath 部署方式 */
@RequestMapping("/deployExclusiveGatewayProcessByClassPath")
public void deployExclusiveGatewayProcessByClassPath() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
.name("排他网关-ExclusiveGateway")
.addClasspathResource("processes/exclusive_gateway.bpmn20.xml")
.deploy();
System.out.println("classpath 方式部署了流程");
}
/** 启动 排他网关 流程 */
@PostMapping("/startExclusiveGatewayProcess")
public void startExclusiveGatewayProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Map map = new HashMap<>();
EvectionVariable evection = new EvectionVariable();
evection.setNum(3d);
map.put("evection",evection);
//启动流程实例,并设置流程变量的值(把map传入)
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey("exclusive_gateway", map);
}
/**
* 完成任务
* @param assignee 审批人
*/
@PostMapping("/completeExclusiveGatewayTask")
public void completeExclusiveGatewayTask(String assignee) {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.processDefinitionKey("exclusive_gateway")
.taskAssignee(assignee)
.singleResult();
System.out.println(assignee + " 完成任务");
taskService.complete(task.getId());
}
}
```
### 部署流程表数据变化
```sql
select * from act_ge_bytearray;
select * from act_re_deployment;
select * from act_re_procdef;
```
#### act_ge_bytearray

#### act_re_deployment

#### act_re_procdef

### 启动流程表数据变化
```sql
select * from act_hi_actinst;
select * from act_hi_detail;
select * from act_hi_identitylink;
select * from act_hi_procinst;
select * from act_hi_taskinst;
select * from act_hi_varinst;
select * from act_ru_execution;
select * from act_ru_identitylink;
select * from act_ru_task;
select * from act_ru_variable;
```
### 审批 部门经理审批 节点的下一节点是 总经理审批 因为在启动的时候 填写的 了参数
```java
/** 启动 排他网关 流程 */
@PostMapping("/startExclusiveGatewayProcess")
public void startExclusiveGatewayProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Map map = new HashMap<>();
EvectionVariable evection = new EvectionVariable();
evection.setNum(3d);/**这里设置的参数是 3 满足 ${evection.num}>=3*/
map.put("evection",evection);
//启动流程实例,并设置流程变量的值(把map传入)
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey("exclusive_gateway", map);
}
```
#### 部门经理审批后 判断网关条件 3 >= 3 ==> true 因此下一节点是 总经理审批

select * from act_ru_task;

# 并行网关
## 绘制流程图 Parallel Gateway
```java
/**
可以把多条分支汇聚一起,会走所有的分支、还要等多个分支完成才可继续完成。
注意:并行网关不会解析条件,即使定义了条件也会被忽略。
*/
```

## 部署 启动 审批
```java
package com.dragons.activiti6.controller;
import com.dragons.activiti6.entities.EvectionVariable;
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class ParallelGatewayController {
/** classpath 部署方式 */
@RequestMapping("/deployParallelGatewayProcessByClassPath")
public void deployParallelGatewayProcessByClassPath() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
.name("并行网关-ParallelGateway")
.addClasspathResource("processes/parallel_gateway.bpmn20.xml")
.deploy();
System.out.println("classpath 方式部署了流程");
}
/** 启动 并行网关 流程 */
@PostMapping("/startParallelGatewayProcess")
public void startParallelGatewayProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Map map = new HashMap<>();
EvectionVariable evection = new EvectionVariable();
evection.setNum(4);
map.put("evection",evection);
//启动流程实例,并设置流程变量的值(把map传入)
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey("parallel_gateway", map);
}
/**
* 完成任务
* @param assignee 审批人
*/
@PostMapping("/completeParallelGatewayTask")
public void completeParallelGatewayTask(String assignee) {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.processDefinitionKey("parallel_gateway")
.taskAssignee(assignee)
.singleResult();
System.out.println(assignee + " 完成任务");
taskService.complete(task.getId());
}
}
```
### 当 创建出差申请节点 审批结束后 技术经理审批 和 项目尽力审批 会同时进行
### 并且当 两者审批结束后 才会继续 走接下来的流程
### ParallelGateway03 下面的线条虽然 都配置了 表达式 但是每次都会 走 总经理审批 也即是 设置的表达式被忽略了
### 查看 act_hi_actinst 表数据 就会一目了然

# 包含网关 Contains Gateway
**排他网关和并行网关的结合。都为ture的时候,都要执行任务,并且最后汇聚在一起才可以执行下去。**
## 绘制流程图

### 再添加一个节点 让走完最后一个节点

## 部署 启动 审批
```java
package com.dragons.activiti6.controller;
import com.dragons.activiti6.entities.EvectionVariable;
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class ContainsGatewayController {
/** classpath 部署方式 */
@RequestMapping("/deployContainsGatewayProcessByClassPath")
public void deployContainsGatewayProcessByClassPath() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
.name("排他网关-ContainsGateway")
.addClasspathResource("processes/contains_gateway.bpmn20.xml")
.deploy();
System.out.println("classpath 方式部署了流程");
}
/** 启动 排他网关 流程 */
@PostMapping("/startContainsGatewayProcess")
public void startContainsGatewayProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Map map = new HashMap<>();
EvectionVariable evection = new EvectionVariable();
evection.setNum(4);
map.put("evection",evection);
//启动流程实例,并设置流程变量的值(把map传入)
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey("contains_gateway", map);
}
/**
* 完成任务
* @param assignee 审批人
*/
@PostMapping("/completeContainsGatewayTask")
public void completeContainsGatewayTask(String assignee) {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.processDefinitionKey("contains_gateway")
.taskAssignee(assignee)
.singleResult();
System.out.println(assignee + " 完成任务");
taskService.complete(task.getId());
}
}
```
#### 同样是 满足条件的 节点会有 活动审批任务 在 act_ru_task 表中
#### 当审批完成之后 才会继续走 ExclusiveGateway 网关
#### 满足条件的参数 evection.setNum(4); 会走 总经理节点
#### 可以审批结束之后 查看 act_hi_actinst 表 一目了然

# 核心7大接口
```java
/**
RepositoryService:提供一系列管理流程部署和流程定义的API。
RuntimeService:在流程运行时对流程实例进行管理与控制。
TaskService:对流程任务进行管理,例如任务提醒、任务完成和创建任务等。
IdentityService:提供对流程角色数据进行管理的API,这些角色数据包括用户组、用户及它们之间的关系。
ManagementService:提供对流程引擎进行管理和维护的服务。
HistoryService:对流程的历史数据进行操作,包括查询、删除这些历史数据。
FormService:表单服务。
*/
```

## RepositoryService:提供一系列管理流程部署和流程定义的API
### 流程部署 -- classpath 的部署方式
```java
```
### 流程部署 -- 输入流(InpurStream) 的部署方式
```java
```
### 流程部署 -- zip/bar 的部署方式
```java
```
### 流程部署 -- 字符串 的部署方式
```java
```
### 流程部署 -- BPMN模型 的部署方式
```java
```