# 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 创建的表格 ![28张表](IMGS/OVERALL/02.png) ```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 安装插件 ![安装插件](IMGS/01-plugin.png) ## resources 新建文件夹 processes(名称不能更改),并新增Bpmn文件,画流程图 ![新建文件夹](IMGS/03-新建文件夹.png) ![新建流程图文件](IMGS/04-新建流程图文件.png) ![打开流程图文件右键查看](IMGS/05-打开流程图右键.png) ![查看](IMGS/06-流程图查看.png) ![右键添加节点](IMGS/07-右键添加流程节点.png) ![节点配置详情](IMGS/08-节点配置详情.png) ## 使用 camunda-modeler 设计流程图 resources/pkg/camunda-modeler-3.0.0-win-x64.zip ### 解压后配置 ![配置扩展](IMGS/OVERALL/03.png) ![查看](IMGS/OVERALL/04.png) ![](IMGS/OVERALL/05.png)




# 流程部署 ```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 流程部署表 ![流程部署表](IMGS/OVERALL/06.png) ### act_re_procdef 流程定义表 ![流程定义表](IMGS/OVERALL/07.png) ### act_ge_bytearray 流程资源表 ![流程资源表](IMGS/OVERALL/08.png)




# 启动流程实例 ```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 历史节点表 历史节点数据,图片上的节点信息 ![历史节点表](IMGS/OVERALL/09.png) ### act_hi_procinst 历史流程实例信息 历史流程实例数据表,正在执行的任务也在其中 ![历史流程实例信息](IMGS/OVERALL/10.png) ### act_hi_taskinst 历史任务流程实例信息 历史任务实例数据表 ![历史任务流程实例信息](IMGS/OVERALL/11.png) ### act_ru_execution 运行时流程执行实例 运行时流程执行实例数据表,一条是开始事件的执行实例,这个一直存在, 只到流程结束后才会自动删除,is_active字段表示是否正在执行实例 ![运行时流程执行实例](IMGS/OVERALL/12.png) ### act_ru_task 运行时任务数据表 只有一条 运行时任务信息数据信息表 ![运行时任务数据表 只有一条](IMGS/OVERALL/13.png) ### act_ru_identitylink 身份联系 存储当前节点参与者的信息,任务参与者数据表 ![运行时任务数据表 只有一条](IMGS/OVERALL/13.png)




# 查询个人代办任务 ```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 插入两条数据 开始节点 和 当前审批节点** ![](IMGS/OVERALL/14.png) **act_hi_procinst 表创建一条流程实例数据** ![](IMGS/OVERALL/15.png) **act_hi_taskinst 表插入一条当前审批任务** ![](IMGS/OVERALL/16.png) **act_ru_execution 表有两条数据 有 ACT_ID_ 的是当前流程任务** ![](IMGS/OVERALL/18.png) **act_ru_task 表只有一条数据 是当前流程任务** ![](IMGS/OVERALL/19.png) **act_ru_identitylink 表 是当前审批人的信息** ![](IMGS/OVERALL/20.png) ## 审批任务 **当审批任务时 下面是上面六张表的 变化** **act_hi_actinst 表会 修改已审批任务 的 结束时间 和 耗时 ms** ![](IMGS/OVERALL/21.png) **act_hi_procinst 表无变化** ![](IMGS/OVERALL/22.png) **act_hi_taskinst 表 会修改已审批任务的 结束时间和耗时 并插入下一条任务** ![](IMGS/OVERALL/23.png) **act_ru_execution 表会将 ACT_ID_ 修改为当前任务** ![](IMGS/OVERALL/24.png) **act_ru_task 表 只有一条数据 最新任务** ![](IMGS/OVERALL/25.png) **act_ru_identitylink 表 将当前审批人信息插入一条** ![](IMGS/OVERALL/26.png) ## 审批所有任务 **继续审批 直到任务结束** **act_hi_actinst** ![](IMGS/OVERALL/27.png) **act_hi_procinst 表修改结束时间 耗时 和 结束 ACT_ID_** ![](IMGS/OVERALL/28.png) **act_hi_taskinst 表保存历史任务实例** ![](IMGS/OVERALL/29.png) **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("<==========================>"); } } ``` ![审批历史](IMGS/OVERALL/30.png)




# 使用 UEL 表达式设置负责人 principal ## 修改流程图 ![${assignee}](IMGS/OVERALL/31.png) ## 部署 ```sql select * from act_ge_bytearray; select * from act_re_deployment; select * from act_re_procdef; ``` act_ge_bytearray ![](IMGS/OVERALL/32.png) act_re_deployment ![](IMGS/OVERALL/33.png) act_re_procdef ![](IMGS/OVERALL/34.png) ## 启动 ```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 ![](IMGS/OVERALL/35.png) #### act_hi_detail ![](IMGS/OVERALL/36.png) #### act_hi_identitylink ![](IMGS/OVERALL/37.png) #### act_hi_procinst ![](IMGS/OVERALL/38.png) #### act_hi_taskinst ![](IMGS/OVERALL/39.png) #### act_hi_varinst ![](IMGS/OVERALL/40.png) #### act_ru_execution ![](IMGS/OVERALL/41.png) #### act_ru_identitylink ![](IMGS/OVERALL/42.png) #### act_ru_task ![](IMGS/OVERALL/43.png) #### act_ru_variable ![](IMGS/OVERALL/44.png) ### 添加 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 表新增下一个任务 并修改上一个任务的 完成时间和耗时 ![](IMGS/OVERALL/45.png) #### act_hi_detail 表无变化 ![](IMGS/OVERALL/46.png) #### act_hi_identitylink 表插入下一审批人信息 ![](IMGS/OVERALL/47.png) #### act_hi_procinst 表无变化 ![](IMGS/OVERALL/48.png) #### act_hi_taskinst 表插入下一个审批并 修改上一个 任务的 结束时间和耗时 ![](IMGS/OVERALL/49.png) #### act_hi_varinst 无变化 ![](IMGS/OVERALL/50.png) #### act_ru_execution 表将 ACT_ID_ 改为最新的任务 ![](IMGS/OVERALL/51.png) #### act_ru_identitylink 插入当前任务审批人信息 ![](IMGS/OVERALL/52.png) #### act_ru_task 表 改为 当前审批任务 ![](IMGS/OVERALL/53.png) #### act_ru_variable 无变化 ![](IMGS/OVERALL/54.png) ### 完成所有任务后 表的变化 #### act_hi_actinst 表记录了所有审批节点 的审批开始结束时间和耗时 ![](IMGS/OVERALL/55.png) #### act_hi_detail 表记录的信息无变化 ![](IMGS/OVERALL/56.png) #### act_hi_identitylink 表记录每个审批过的 人员信息 ![](IMGS/OVERALL/57.png) #### act_hi_procinst 还是只有一条 并且审批结束 记录开始结束时间 耗时 及结束节点 END_ACT_ID_ ![](IMGS/OVERALL/58.png) #### act_hi_taskinst 记录审批过的任务信息 及时间 审批人员 ![](IMGS/OVERALL/59.png) #### act_hi_varinst 表记录流程变量信息 无变化 ![](IMGS/OVERALL/60.png) #### act_ru_execution; -- 运行时流程执行实例 无相关数据 #### act_ru_identitylink; -- 身份联系 无相关数据 #### act_ru_task; -- 运行时任务数据表 无相关数据 #### act_ru_variable; -- 运行时流程变量数据表 无相关数据






# 候选人流程 ## 绘制流程图 candidate ![候选人](IMGS/OVERALL/61.png) ## 部署流程 ```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 ![](IMGS/OVERALL/62.png) #### act_hi_identitylink ![](IMGS/OVERALL/63.png) #### act_hi_procinst ![](IMGS/OVERALL/64.png) #### act_hi_taskinst ![](IMGS/OVERALL/65.png) #### act_ru_execution ![](IMGS/OVERALL/66.png) #### act_ru_identitylink ![](IMGS/OVERALL/67.png) #### act_ru_task ![](IMGS/OVERALL/68.png) ## 查询候选人 ```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 最新任务分配了审批人 ![](IMGS/OVERALL/69.png) #### act_hi_identitylink 无变化 ![](IMGS/OVERALL/70.png) #### act_hi_procinst 只有当任务结束时会变化 ![](IMGS/OVERALL/71.png) #### act_hi_taskinst 添加审批人 并更新拾取时间 ![](IMGS/OVERALL/72.png) #### act_ru_execution 无变化 ![](IMGS/OVERALL/73.png) #### act_ru_identitylink 无变化 ![](IMGS/OVERALL/74.png) #### act_ru_task 添加当前任务审批人 ![](IMGS/OVERALL/75.png) ## 归还任务给其他候选人 ```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 将当前任务的审批人修改为 归还的人 ![](IMGS/OVERALL/76.png) #### 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 的数据 并插入下一任务的审批人信息** ![](IMGS/OVERALL/77.png) ### 完成所有任务后的表数据变化 ```sql select * from act_ru_execution; -- 无相关数据 select * from act_ru_identitylink; -- 无相关数据 select * from act_ru_task; -- 无相关数据 ``` #### act_hi_actinst 表包含开始结束 审批节点 ![](IMGS/OVERALL/78.png) #### act_hi_identitylink 表包含 候选人 和 各个节点审批人 ![](IMGS/OVERALL/79.png) #### act_hi_procinst 表 填充 结束时间 结束 taskId 及 耗时 DURATION_ ![](IMGS/OVERALL/80.png) #### act_hi_taskinst 表只记录 审批过的节点 无开始结束节点 ![](IMGS/OVERALL/81.png)






# 监听器流程 ## 绘制流程图 ![](IMGS/OVERALL/82.png) ## 查看 流程图 XML 文件并 添加 监听器 ```java /** 监听器包括下面三种 Execution Listeners(执行监听器) Task Listeners(任务监听器) JavaDelegate(Java代理) */ ``` ## Task Listeners(任务监听器) ### 在 xml 文件中配置 任务监听器 ![](IMGS/OVERALL/83.png) **创建上图中的三个监听器** ```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()); } } ``` ### 结果 ![](IMGS/OVERALL/84.png) ## Execution Listeners(执行监听器) Execution Listeners(执行监听器)在Activiti中用于监听流程实例或 活动节点的生命周期事件,例如开始、结束、创建 和 删除等 ### 修改 XML BPMN 文件 ![](IMGS/OVERALL/85.png) ```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()); } } ``` #### 结果日志 ![](IMGS/OVERALL/86.png)








# 设置变量 variables ## 绘制 及 配置 流程图 ![整体](IMGS/OVERALL/87.png) ![线条配置](IMGS/OVERALL/88.png) ![线条配置](IMGS/OVERALL/89.png) ![细节](IMGS/OVERALL/90.png) **因为使用的是 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 ![](IMGS/OVERALL/91.png) #### act_hi_detail ![](IMGS/OVERALL/92.png) #### act_hi_identitylink ![](IMGS/OVERALL/93.png) #### act_hi_procinst ![](IMGS/OVERALL/94.png) #### act_hi_taskinst ![](IMGS/OVERALL/95.png) #### act_hi_varinst ![](IMGS/OVERALL/96.png) #### act_ru_execution ![](IMGS/OVERALL/97.png) #### act_ru_identitylink ![](IMGS/OVERALL/98.png) #### act_ru_variable ![](IMGS/OVERALL/99.png) #### act_ge_bytearray ![](IMGS/OVERALL/100.png) ### 审批 表数据变化 #### act_hi_actinst 表将最新的任务插入 ![](IMGS/OVERALL/101.png) #### act_hi_detail 无变化 ![](IMGS/OVERALL/102.png) #### act_hi_identitylink 插入最新任务的审批人 ![](IMGS/OVERALL/103.png) #### act_hi_procinst 无变化 ![](IMGS/OVERALL/104.png) #### act_hi_taskinst 插入最新任务的信息 ![](IMGS/OVERALL/105.png) #### act_hi_varinst 无变化 ![](IMGS/OVERALL/106.png) #### act_ru_execution ACT_ID_ 更新到最新任务 ![](IMGS/OVERALL/107.png) #### act_ru_identitylink 将最新审批人插入 ![](IMGS/OVERALL/108.png) #### act_ru_variable 无变化 ![](IMGS/OVERALL/109.png) #### act_ge_bytearray 无变化 ![](IMGS/OVERALL/110.png) ### 流程启动时 传递了 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 表是当前审批节点信息 ![](IMGS/OVERALL/111.png)








# 排他网关 ```java /** 所有分支都会判断条件是否为true,如果为true就执行该分支 注意:只会选择一个true的分支执行,如果都满足条件,则走flowid最小的任务。 与上述条件变量的区别:都不满足条件,则抛出异常。 */ ``` ## 绘制流程图 ![](IMGS/OVERALL/112.png) ### 细节 ```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 ![](IMGS/OVERALL/113.png) #### act_re_deployment ![](IMGS/OVERALL/114.png) #### act_re_procdef ![](IMGS/OVERALL/115.png) ### 启动流程表数据变化 ```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 因此下一节点是 总经理审批 ![](IMGS/OVERALL/116.png) select * from act_ru_task; ![](IMGS/OVERALL/117.png)








# 并行网关 ## 绘制流程图 Parallel Gateway ```java /** 可以把多条分支汇聚一起,会走所有的分支、还要等多个分支完成才可继续完成。 注意:并行网关不会解析条件,即使定义了条件也会被忽略。 */ ``` ![](IMGS/OVERALL/118.png) ## 部署 启动 审批 ```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 表数据 就会一目了然 ![](IMGS/OVERALL/119.png)








# 包含网关 Contains Gateway **排他网关和并行网关的结合。都为ture的时候,都要执行任务,并且最后汇聚在一起才可以执行下去。** ## 绘制流程图 ![](IMGS/OVERALL/120.png) ### 再添加一个节点 让走完最后一个节点 ![](IMGS/OVERALL/121.png) ## 部署 启动 审批 ```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 表 一目了然 ![](IMGS/OVERALL/122.png)








# 核心7大接口 ```java /** RepositoryService:提供一系列管理流程部署和流程定义的API。 RuntimeService:在流程运行时对流程实例进行管理与控制。 TaskService:对流程任务进行管理,例如任务提醒、任务完成和创建任务等。 IdentityService:提供对流程角色数据进行管理的API,这些角色数据包括用户组、用户及它们之间的关系。 ManagementService:提供对流程引擎进行管理和维护的服务。 HistoryService:对流程的历史数据进行操作,包括查询、删除这些历史数据。 FormService:表单服务。 */ ``` ![流程七大接口](IMGS/OVERALL/123.png) ## RepositoryService:提供一系列管理流程部署和流程定义的API ### 流程部署 -- classpath 的部署方式 ```java ``` ### 流程部署 -- 输入流(InpurStream) 的部署方式 ```java ``` ### 流程部署 -- zip/bar 的部署方式 ```java ``` ### 流程部署 -- 字符串 的部署方式 ```java ``` ### 流程部署 -- BPMN模型 的部署方式 ```java ```