Activiti环境
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-dependencies</artifactId>
<version>7.0.0.Beta1</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
1) Database:
activiti运行需要有数据库的支持,支持的数据库有:h2, mysql, oracle, postgres, mssql, db2。
流程设计器IDEA下安装
注意新版idea已经不支持,自己百度下载
搜索到actiBPM插件,它就是Activiti Designer的IDEA版本,我们点击Install安装
1.pom
首先需要在 java 工程中加入 ProcessEngine 所需要的 jar 包,包括:
1) activiti-engine-7.0.0.beta1.jar2) activiti 依赖的 jar 包: mybatis、 alf4j、 log4j 等
3) activiti 依赖的 spring 包
4) mysql数据库驱动
5) 第三方数据连接池 dbcp6) 单元测试 Junit-4.12.jar
<properties>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<activiti.version>7.0.0.Beta1</activiti.version>
</properties>
<dependencies>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- bpmn 模型处理 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-model</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- bpmn 转换 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-converter</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- bpmn json数据转换 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- bpmn 布局 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-layout</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- activiti 云支持 -->
<dependency>
<groupId>org.activiti.cloud</groupId>
<artifactId>activiti-cloud-services-api</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!-- 链接池 -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
3) 添加log4j日志配置
我们使用log4j日志包,可以对日志进行配置
在resources 下创建log4j.properties
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=f:\act\activiti.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n
4) 添加activiti配置文件
我们使用activiti提供的默认方式来创建mysql的表。
默认方式的要求是在 resources 下创建 activiti.cfg.xml 文件,
注意:默认方式目录和文件名不能修改,因为activiti的源码中已经设置,到固定的目录读取固定文件名的文件。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
</beans>
5) 在 activiti.cfg.xml 中进行配置
默认方式要在在activiti.cfg.xml中bean的名字叫processEngineConfiguration,名字不可修改
在这里有2中配置方式:一种是单独配置数据源,一种是不单独配置数据源
1、直接配置processEngineConfiguration
processEngineConfiguration 用来创建 ProcessEngine,在创建 ProcessEngine 时会执行数据库的操作
/// 表示本地localhost
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 默认id对应的值 为processEngineConfiguration -->
<!-- processEngine Activiti的流程引擎 -->
<bean id="processEngineConfiguration"
class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///activiti"/>
<property name="jdbcUsername" value="root"/>
<property name="jdbcPassword" value="123456"/>
<!-- activiti数据库表处理策略 -->
<property name="databaseSchemaUpdate" value="true"/>
</bean>
</beans>
2、配置数据源后,在processEngineConfiguration 引用
首先配置数据源
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 这里可以使用 链接池 dbcp-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql:///activiti" />
<property name="username" value="root" />
<property name="password" value="123456" />
<property name="maxActive" value="3" />
<property name="maxIdle" value="1" />
</bean>
<bean id="processEngineConfiguration"
class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<!-- 引用数据源 上面已经设置好了-->
<property name="dataSource" ref="dataSource" />
<!-- activiti数据库表处理策略 -->
<!--actviti数据库表在生成时的策略
true - 如果数据库中已经存在相应的表,那么直接使用,
如果不存在,那么会创建-->
<property name="databaseSchemaUpdate" value="true"/>
</bean>
</beans>
6) java类编写程序生成表
创建一个测试类,调用activiti的工具类,生成acitivti需要的数据库表。
直接使用activiti提供的工具类ProcessEngines,会默认读取classpath下的activiti.cfg.xml文件,读取其中的数据库配置,创建 ProcessEngine,在创建ProcessEngine 时会自动创建表。
代码如下:
package com.itheima.activiti01.test;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.junit.Test;
public class TestDemo {
/**
* 生成 activiti的数据库表
*/
@Test
public void testCreateDbTable() {
//使用classpath下的activiti.cfg.xml中的配置创建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
System.out.println(processEngine);
}
}
说明:1、运行以上程序段即可完成 activiti 表创建,通过改变 activiti.cfg.xml 中databaseSchemaUpdate 参数的值执行不同的数据表处理策略。2 、 上 边 的 方法 getDefaultProcessEngine方法在执行时,从activiti.cfg.xml 中找固定的名称 processEngineConfiguration 。
在测试程序执行过程中,idea的控制台会输出日志,说明程序正在创建数据表,类似如下,注意红线内容:
执行完成后我们查看数据库, 创建了 25 张表,结果如下:
到这,我们就完成activiti运行需要的数据库和表的创建。
3.4 表结构介绍
3.4.1 表的命名规则和作用
看到刚才创建的表,我们发现Activiti 的表都以 ACT_ 开头。
第二部分是表示表的用途的两个字母标识。 用途也和服务的 API 对应。
ACT_RE :'RE'表示 repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
ACT_RU:'RU'表示 runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti 只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快
ACT_HI:'HI'表示 history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
ACT_GE : GE 表示 general。 通用数据, 用于不同场景下
3.4.2 Activiti数据表介绍
表分类 | 表名 | 解释 |
---|---|---|
一般数据 | ||
[ACT_GE_BYTEARRAY] | 通用的流程定义和流程资源 | |
[ACT_GE_PROPERTY] | 系统相关属性 | |
流程历史记录 | ||
[ACT_HI_ACTINST] | 历史的流程实例 | |
[ACT_HI_ATTACHMENT] | 历史的流程附件 | |
[ACT_HI_COMMENT] | 历史的说明性信息 | |
[ACT_HI_DETAIL] | 历史的流程运行中的细节信息 | |
[ACT_HI_IDENTITYLINK] | 历史的流程运行过程中用户关系 | |
[ACT_HI_PROCINST] | 历史的流程实例 | |
[ACT_HI_TASKINST] | 历史的任务实例 | |
[ACT_HI_VARINST] | 历史的流程运行中的变量信息 | |
流程定义表 | ||
[ACT_RE_DEPLOYMENT] | 部署单元信息 | |
[ACT_RE_MODEL] | 模型信息 | |
[ACT_RE_PROCDEF] | 已部署的流程定义 | |
运行实例表 | ||
[ACT_RU_EVENT_SUBSCR] | 运行时事件 | |
[ACT_RU_EXECUTION] | 运行时流程执行实例 | |
[ACT_RU_IDENTITYLINK] | 运行时用户关系信息,存储任务节点与参与者的相关信息 | |
[ACT_RU_JOB] | 运行时作业 | |
[ACT_RU_TASK] | 运行时任务 | |
[ACT_RU_VARIABLE] |
流程定义部署
流程定义部署后操作activiti的3张表如下:
act_re_deployment 流程定义部署表,每部署一次增加一条记录
act_re_procdef 流程定义表,部署每个新的流程定义都会在这张表中增加一条记录
act_re_procdef 表中的 KEY 这个字段是用来唯一识别不同流程的关键字
act_ge_bytearray 流程资源表
注意:
act_re_deployment和act_re_procdef一对多关系,一次部署在流程部署表生成一条记录,但一次部署可以部署多个流程定义,每个流程定义在流程定义表生成一条记录。每一个流程定义在act_ge_bytearray会存在两个资源记录,bpmn和png。
启动流程实例
发起一个请假流程
/**
* 启动流程实例
*/
@Test
public void testStartProcess(){
// 1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
// 3、根据流程定义Id启动流程
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey("evection");
// 输出内容
System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
System.out.println("流程实例id:" + processInstance.getId());
System.out.println("当前活动Id:" + processInstance.getActivityId());
操作数据表
act_hi_actinst 流程实例执行历史(流程节点信息,可以看到流程走到哪里)
act_hi_identitylink 流程的参与用户历史信息
act_hi_procinst 流程实例历史信息
act_hi_taskinst 流程任务历史信息
act_ru_execution 流程执行信息
act_ru_identitylink 流程运行中的参与用户信息
字段:userid 是审批人
act_ru_task 流程运行中的任务信息
流程任务处理(审批)
任务负责人查询待办任务,选择任务进行处理审批,完成任务。
完成任务
// 完成任务
@Test
public void completTask(){
// 获取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskService
TaskService taskService = processEngine.getTaskService();
// 根据流程key 和 任务的负责人 查询任务
// 返回一个任务对象
Task task = taskService.createTaskQuery()
.processDefinitionKey("evection") //流程Key
.taskAssignee("审核人") //要查询的负责人
.singleResult();
// 完成任务,参数:任务id
taskService.complete(task.getId());
}
流程历史信息的查看
即使流程定义已经删除了,流程执行的历史信息通过前面的分析,依然保存在activiti的act_hi_*相关的表中。所以我们还是可以查询流程执行的历史信息,可以通过HistoryService来查看相关的历史记录。
/**
* 查看历史信息
*/
@Test
public void findHistoryInfo(){
// 获取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取HistoryService
HistoryService historyService = processEngine.getHistoryService();
// 获取 actinst表的查询对象
HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
// 查询 actinst表,条件:根据 InstanceId 查询
// instanceQuery.processInstanceId("2501");
// 查询 actinst表,条件:根据 DefinitionId 查询
instanceQuery.processDefinitionId("myEvection:1:4");
// 增加排序操作,orderByHistoricActivityInstanceStartTime 根据开始时间排序 asc 升序
instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
// 查询所有内容
List<HistoricActivityInstance> activityInstanceList = instanceQuery.list();
// 输出
for (HistoricActivityInstance hi : activityInstanceList) {
System.out.println(hi.getActivityId());
System.out.println(hi.getActivityName());
System.out.println(hi.getProcessDefinitionId());
System.out.println(hi.getProcessInstanceId());
System.out.println("<==========================>");
}
}
新springboot整合
配置Activiti
引入Activiti依赖
<!--引入activiti的springboot启动器 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.1.0.M6</version>
<exclusions>
<exclusion>
<artifactId>mybatis</artifactId>
<groupId>org.mybatis</groupId>
</exclusion>
</exclusions>
</dependency>
添加配置
在application-dev.yml
中添加如下配置
spring:
activiti:
# false:默认,数据库表不变,但是如果版本不对或者缺失表会抛出异常(生产使用)
# true:表不存在,自动创建(开发使用)
# create_drop: 启动时创建,关闭时删除表(测试使用)
# drop_create: 启动时删除表,在创建表 (不需要手动关闭引擎)
database-schema-update: true
#监测历史表是否存在,activities7默认不开启历史表
db-history-used: true
#none:不保存任何历史数据,流程中这是最高效的
#activity:只保存流程实例和流程行为
#audit:除了activity,还保存全部的流程任务以及其属性,audit为history默认值
#full:除了audit、还保存其他全部流程相关的细节数据,包括一些流程参数
history-level: full
#校验流程文件,默认校验resources下的process 文件夹的流程文件
check-process-definitions: true
重启项目
会自己创建数据表
activiti 常用service服务接口
使用activiti插件
解压部署
把解压出来的activiti-explorer.war
放在Tomcat的webapps
下
启动Tomcat服务器
http://localhost:8080/activiti-explorer
默认登录账号: kermit
kermit
10.2、流程控制
绘制流程
请假流程审批绘制
绘制
导出
下载文件
qingjia.bpmn20.xml
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
<process id="qingjia" isExecutable="true">
<startEvent id="sid-14A3E2A6-84E4-49E0-BF92-3DABD741430B"></startEvent>
<userTask id="sid-38632C81-C407-4F0D-944D-FC30F90637A3" name="张三审批" activiti:assignee="zhangsan"></userTask>
<sequenceFlow id="sid-081A176E-6756-4C4C-B36C-2649B12CFC5D" sourceRef="sid-14A3E2A6-84E4-49E0-BF92-3DABD741430B" targetRef="sid-38632C81-C407-4F0D-944D-FC30F90637A3"></sequenceFlow>
<userTask id="sid-655780D5-8492-494F-9E30-2CFD6691E98D" name="李四审批" activiti:assignee="lisi"></userTask>
<sequenceFlow id="sid-7DCE821D-4AE0-4F27-9811-80B575E7A758" sourceRef="sid-38632C81-C407-4F0D-944D-FC30F90637A3" targetRef="sid-655780D5-8492-494F-9E30-2CFD6691E98D"></sequenceFlow>
<endEvent id="sid-7EE28419-BC61-49AC-8990-C63C4D2F7C0D"></endEvent>
<sequenceFlow id="sid-2E583A5C-265A-4C05-B5E1-7F5DB98291F1" sourceRef="sid-655780D5-8492-494F-9E30-2CFD6691E98D" targetRef="sid-7EE28419-BC61-49AC-8990-C63C4D2F7C0D"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_qingjia">
<bpmndi:BPMNPlane bpmnElement="qingjia" id="BPMNPlane_qingjia">
<bpmndi:BPMNShape bpmnElement="sid-14A3E2A6-84E4-49E0-BF92-3DABD741430B" id="BPMNShape_sid-14A3E2A6-84E4-49E0-BF92-3DABD741430B">
<omgdc:Bounds height="30.0" width="30.0" x="93.5" y="75.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-38632C81-C407-4F0D-944D-FC30F90637A3" id="BPMNShape_sid-38632C81-C407-4F0D-944D-FC30F90637A3">
<omgdc:Bounds height="80.0" width="100.0" x="168.5" y="50.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-655780D5-8492-494F-9E30-2CFD6691E98D" id="BPMNShape_sid-655780D5-8492-494F-9E30-2CFD6691E98D">
<omgdc:Bounds height="80.0" width="100.0" x="313.5" y="50.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-7EE28419-BC61-49AC-8990-C63C4D2F7C0D" id="BPMNShape_sid-7EE28419-BC61-49AC-8990-C63C4D2F7C0D">
<omgdc:Bounds height="28.0" width="28.0" x="458.5" y="76.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sid-7DCE821D-4AE0-4F27-9811-80B575E7A758" id="BPMNEdge_sid-7DCE821D-4AE0-4F27-9811-80B575E7A758">
<omgdi:waypoint x="268.5" y="90.0"></omgdi:waypoint>
<omgdi:waypoint x="313.5" y="90.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-081A176E-6756-4C4C-B36C-2649B12CFC5D" id="BPMNEdge_sid-081A176E-6756-4C4C-B36C-2649B12CFC5D">
<omgdi:waypoint x="123.5" y="90.0"></omgdi:waypoint>
<omgdi:waypoint x="168.5" y="90.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-2E583A5C-265A-4C05-B5E1-7F5DB98291F1" id="BPMNEdge_sid-2E583A5C-265A-4C05-B5E1-7F5DB98291F1">
<omgdi:waypoint x="413.5" y="90.0"></omgdi:waypoint>
<omgdi:waypoint x="458.5" y="90.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
下载流程定义图片
单击右键上图图片,图片另存为:qingjia.png
将资源文件放入项目
在resources下新建process资源文件夹
将qingjia.bpmn20.xml与qingjia.png放入process目录
部署流程 相当于创建类
单个文件部署
package com.jerry.auth.activiti;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* ClassName: ProcessTest <br>
* Package: com.jerry.activiti <br>
* Description:
*
* @Author: jerry_jy
* @Create: 2023-03-05 10:51
* @Version: 1.0
*/
@SpringBootTest
public class ProcessTest {
@Autowired
private RepositoryService repositoryService;
// 单个文件的部署
@Test
public void deployProcess() {
Deployment deploy = repositoryService.createDeployment()
.addClasspathResource("process/qingjia.bpmn20.xml")
.addClasspathResource("process/qingjia.png")
.name("请假申请流程")
.deploy();
System.out.println("deploy.getId() = " + deploy.getId());
System.out.println("deploy.getName() = " + deploy.getName());
}
}
压缩包部署
流程实例 类(部署)的对象
package com.jerry.auth.activiti;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class ProcessTest1 {
@Autowired
private RepositoryService repositoryService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Autowired
private HistoryService historyService;
/**
* 启动流程实例,添加businessKey 业务标识
*/
@Test
public void startUpProcessAddBusinessKey(){
// 启动流程实例,指定业务标识businessKey,也就是请假申请单id
ProcessInstance processInstance = runtimeService.
startProcessInstanceByKey("qingjia","1001");
// 输出
System.out.println("业务id:"+processInstance.getBusinessKey()); //1001
System.out.println("processInstance.getId() = " + processInstance.getId()); // 71f6803b-bb19-11ed-a845-005056c00001
}
/**
* 查询流程定义
*/
@Test
public void findProcessDefinitionList(){
List<ProcessDefinition> definitionList = repositoryService.createProcessDefinitionQuery()
.orderByProcessDefinitionVersion()
.desc()
.list();
//输出流程定义信息
for (ProcessDefinition processDefinition : definitionList) {
System.out.println("流程定义 id="+processDefinition.getId());
System.out.println("流程定义 name="+processDefinition.getName());
System.out.println("流程定义 key="+processDefinition.getKey());
System.out.println("流程定义 Version="+processDefinition.getVersion());
System.out.println("流程部署ID ="+processDefinition.getDeploymentId());
}
}
/**
* 删除流程定义
*/
@Test
public void deleteDeployment() {
//部署id
String deploymentId = "qingjia:1:c493c327-bb02-11ed-8360-005056c00001";
// //删除流程定义,如果该流程定义已有流程实例启动则删除时出错
// repositoryService.deleteDeployment(deploymentId);
//设置true 级联删除流程定义,即使该流程有流程实例启动也可以删除,设置为false非级别删除方式
repositoryService.deleteDeployment(deploymentId, true);
}
// 查询已经处理的任务
@Test
public void findCompleteTaskList(){
List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
.taskAssignee("zhangsan")
.finished().list();
for (HistoricTaskInstance historicTaskInstance : list) {
System.out.println("流程实例id:" + historicTaskInstance.getProcessInstanceId());
System.out.println("任务id:" + historicTaskInstance.getId());
System.out.println("任务负责人:" + historicTaskInstance.getAssignee());
System.out.println("任务名称:" + historicTaskInstance.getName());
}
}
// 处理当前任务
@Test
public void completeTask(){
// 查询负责人需要处理的任务,返回一条
Task task = taskService.createTaskQuery().taskAssignee("zhangsan").singleResult();
// 完成任务
taskService.complete(task.getId());
}
// 查询个人的代办任务--zhangsan
@Test
public void findTaskList(){
String assign = "zhangsan";
List<Task> list = taskService.createTaskQuery()
.taskAssignee(assign).list();
for (Task task : list) {
System.out.println("task.getProcessInstanceId() = " + task.getProcessInstanceId());
System.out.println("任务id:" + task.getId());
System.out.println("任务负责人:" + task.getAssignee());
System.out.println("任务名称:" + task.getName());
}
}
// 启动流程实例
@Test
public void startProcess(){
ProcessInstance processInstance = runtimeService.startProcessInstanceById("qingjia");
System.out.println("processInstance.getProcessDefinitionId() = " + processInstance.getProcessDefinitionId());
System.out.println("processInstance.getId() = " + processInstance.getId());
System.out.println("processInstance.getActivityId() = " + processInstance.getActivityId());
}
//部署
// 单个文件的部署
@Test
public void deployProcess() {
Deployment deploy = repositoryService.createDeployment()
.addClasspathResource("process/qingjia.bpmn20.xml")
.addClasspathResource("process/qingjia.png")
.name("请假申请流程")
.deploy();
System.out.println("deploy.getId() = " + deploy.getId());
System.out.println("deploy.getName() = " + deploy.getName());
}
}
流程实例挂起
@SpringBootTest
public class ProcessTest1 {
@Autowired
private RepositoryService repositoryService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Autowired
private HistoryService historyService;
// 单个流程实例挂起
@Test
public void SingleSuspendProcessInstance() {
//流程实例id
String processInstanceId = "71f6803b-bb19-11ed-a845-005056c00001";
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
//获取到当前流程定义是否为暂停状态 suspended方法为true代表为暂停 false就是运行的
boolean suspended = processInstance.isSuspended();
if (suspended) {
runtimeService.activateProcessInstanceById(processInstanceId);
System.out.println("流程实例:" + processInstanceId + "激活");
} else {
runtimeService.suspendProcessInstanceById(processInstanceId);
System.out.println("流程实例:" + processInstanceId + "挂起");
}
}
// 全部流程实例挂起
@Test
public void suspendProcessInstance() {
// 1、获取流程定义对象
ProcessDefinition qingjia = repositoryService.createProcessDefinitionQuery().processDefinitionKey("qingjia").singleResult();
// 2、调用流程定义对象的方法判断当前状态:挂起 激活
boolean suspended = qingjia.isSuspended();
if (suspended) {
// 暂定,那就可以激活
// 参数1:流程定义的id 参数2:是否激活 参数3:时间点
repositoryService.activateProcessDefinitionById(qingjia.getId(), true, null);
System.out.println("流程定义:" + qingjia.getId() + "激活");
} else {
repositoryService.suspendProcessDefinitionById(qingjia.getId(), true, null);
System.out.println("流程定义:" + qingjia.getId() + "挂起");
}
}
}
任务分配
表达式分配
uel-value
package com.jerry.auth.activiti;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SpringBootTest
public class ProcessTest2 {
@Autowired
private RepositoryService repositoryService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Autowired
private HistoryService historyService;
// uel-value
// 部署流程定义
@Test
public void deployProcess() {
Deployment deploy = repositoryService.createDeployment().addClasspathResource("process/jiaban.bpmn20.xml").name("加班申请流程").deploy();
System.out.println("deploy.getId() = " + deploy.getId()); // 5c5519ad-bb1d-11ed-b5c8-005056c00001
System.out.println("deploy.getName() = " + deploy.getName()); // 加班申请流程
}
// 启动流程实例
@Test
public void startProcessInstance() {
Map<String, Object> map = new HashMap<>();
// 设置任务人
map.put("assignee1","tom");
map.put("assignee2","jerry");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("jiaban", map);
System.out.println("processInstance.getProcessDefinitionId() = " + processInstance.getProcessDefinitionId()); // jiaban:1:5c60d97f-bb1d-11ed-b5c8-005056c00001
System.out.println("processInstance.getId() = " + processInstance.getId()); // 7f720dd9-bb1d-11ed-b6e9-005056c00001
}
// 查询个人的代办任务--tom
@Test
public void findTaskList(){
String assign = "tom";
List<Task> list = taskService.createTaskQuery()
.taskAssignee(assign).list();
for (Task task : list) {
System.out.println("task.getProcessInstanceId() = " + task.getProcessInstanceId()); //7f720dd9-bb1d-11ed-b6e9-005056c00001
System.out.println("任务id:" + task.getId()); // 7f759051-bb1d-11ed-b6e9-005056c00001
System.out.println("任务负责人:" + task.getAssignee()); // tom
System.out.println("任务名称:" + task.getName()); // 经理审批
}
}
}
uel-method表达式
package com.jerry.auth.activiti;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SpringBootTest
public class ProcessTest2 {
@Autowired
private RepositoryService repositoryService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Autowired
private HistoryService historyService;
// uel-method
// 部署流程定义
@Test
public void deployProcess01() {
Deployment deploy = repositoryService.createDeployment().addClasspathResource("process/jiaban01.bpmn20.xml").name("加班申请流程01").deploy();
System.out.println("deploy.getId() = " + deploy.getId()); // 8c4ac05e-bb20-11ed-8d65-005056c00001
System.out.println("deploy.getName() = " + deploy.getName()); // 加班申请流程01
}
//创建流程实例,会自动调用userBean.getUserName()方法
@Test
public void startProcessInstance01(){
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("jiaban01");
System.out.println("processInstance.getProcessDefinitionId() = " + processInstance.getProcessDefinitionId()); // jiaban01:1:8c56a740-bb20-11ed-8d65-005056c00001
System.out.println("processInstance.getId() = " + processInstance.getId()); // abb9c7c4-bb20-11ed-b608-005056c00001
}
// 查询个人的代办任务--zhangsan
@Test
public void findTaskList01(){
String assign = "zhangsan";
List<Task> list = taskService.createTaskQuery()
.taskAssignee(assign).list();
for (Task task : list) {
System.out.println("task.getProcessInstanceId() = " + task.getProcessInstanceId()); // abb9c7c4-bb20-11ed-b608-005056c00001
System.out.println("任务id:" + task.getId()); // abbd4a38-bb20-11ed-b608-005056c00001
System.out.println("任务负责人:" + task.getAssignee()); // LiLei
System.out.println("任务名称:" + task.getName()); // 经理审批
}
}
}
监听器分配
配置监听器
package com.jerry.auth.activiti;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SpringBootTest
public class ProcessTest2 {
@Autowired
private RepositoryService repositoryService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Autowired
private HistoryService historyService;
///
// 监听器分配任务
// 部署流程定义
@Test
public void deployProcess02() {
Deployment deploy = repositoryService.createDeployment().addClasspathResource("process/jiaban02.bpmn20.xml").name("加班申请流程02").deploy();
System.out.println("deploy.getId() = " + deploy.getId()); // ed080f00-bb41-11ed-a6f2-005056c00001
System.out.println("deploy.getName() = " + deploy.getName()); // 加班申请流程02
}
@Test
public void startProcessInstance02(){
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("jiaban02");
System.out.println("processInstance.getProcessDefinitionId() = " + processInstance.getProcessDefinitionId()); // jiaban02:1:ed150752-bb41-11ed-a6f2-005056c00001
System.out.println("processInstance.getId() = " + processInstance.getId()); // 06eca124-bb42-11ed-9bbc-005056c00001
}
// 查询个人的代办任务--Tim
@Test
public void findTaskList02(){
String assign = "Tim";
List<Task> list = taskService.createTaskQuery()
.taskAssignee(assign).list();
for (Task task : list) {
System.out.println("task.getProcessInstanceId() = " + task.getProcessInstanceId()); // 06eca124-bb42-11ed-9bbc-005056c00001
System.out.println("任务id:" + task.getId()); // 06f071b8-bb42-11ed-9bbc-005056c00001
System.out.println("任务负责人:" + task.getAssignee()); // Tim
System.out.println("任务名称:" + task.getName()); // 经理审批
}
}
}
流程变量
任务组
package com.jerry.auth.activiti;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* ClassName: ProcessTest3 <br>
* Package: com.jerry.auth.activiti <br>
* Description:
*
* @Author: jerry_jy
* @Create: 2023-03-05 19:18
* @Version: 1.0
*/
@SpringBootTest
public class ProcessTest3 {
@Autowired
private RepositoryService repositoryService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
// 1、部署流程定义
@Test
public void deployProcess() {
Deployment deploy = repositoryService.createDeployment().addClasspathResource("process/jiaban04.bpmn20.xml").name("加班申请流程04").deploy();
System.out.println("deploy.getId() = " + deploy.getId()); // f204be8a-bb48-11ed-950e-005056c00001
System.out.println("deploy.getName() = " + deploy.getName()); // 加班申请流程04
}
// 1.5、启动流程实例
@Test
public void startProcessInstance() {
// Map<String, Object> map = new HashMap<>();
// 设置任务人
// map.put("assignee1","tom");
// map.put("assignee2","jerry");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("jiaban04");
System.out.println("processInstance.getProcessDefinitionId() = " + processInstance.getProcessDefinitionId()); // jiaban04:1:f210f38c-bb48-11ed-950e-005056c00001
System.out.println("processInstance.getId() = " + processInstance.getId()); // 428d0c0f-bb49-11ed-83a5-005056c00001
}
// 2、查询组任务
@Test
public void findGroupTaskList(){
List<Task> list = taskService.createTaskQuery()
.taskCandidateUser("tom01")
.list();
for (Task task : list) {
System.out.println("----------------------------");
System.out.println("流程实例id:" + task.getProcessInstanceId());
System.out.println("任务id:" + task.getId());
System.out.println("任务负责人:" + task.getAssignee());
System.out.println("任务名称:" + task.getName());
}
}
// 3、分配组任务,拾取任务,让某人去做这个事情
@Test
public void claimTask(){
Task task = taskService.createTaskQuery()
.taskCandidateUser("tom01")
.singleResult();
if (task!=null){
taskService.claim(task.getId(),"tom");
System.out.println("分配任务完成/任务拾取完成");
}
}
// 4、查询个人的代办任务--tom01
@Test
public void findTaskList(){
String assign = "tom01";
List<Task> list = taskService.createTaskQuery()
.taskAssignee(assign).list();
for (Task task : list) {
System.out.println("task.getProcessInstanceId() = " + task.getProcessInstanceId()); //7f720dd9-bb1d-11ed-b6e9-005056c00001
System.out.println("任务id:" + task.getId()); // 7f759051-bb1d-11ed-b6e9-005056c00001
System.out.println("任务负责人:" + task.getAssignee()); // tom
System.out.println("任务名称:" + task.getName()); // 经理审批
}
}
// 5、办理个人任务
@Test
public void completeGroupTask() {
Task task = taskService.createTaskQuery()
.taskAssignee("tom01") //要查询的负责人
.singleResult();//返回一条
taskService.complete(task.getId());
}
}
10.3、网关
网关用来控制流程的流向,通常会和流程变量一起使用。
- 排他网关:只有一条路径会被选择
当你的流程出现这样的场景:请假申请,两天以内,部门经理审批流程就结束了,两天以上需要总经理直接审批,这个时候就需要排他网关
并行网关
- 并(平)行网关:所有路径会被同时选择
当出现这样的场景:请假申请开始,需要部门经理和总经理都审批,两者没有前后需要两个人全部审批才能进入下个节点人事审批。这个时候就需要并行网关
与排他网关的主要区别是,并行网关不会解析条件。 即使顺序流中定义了条件,也会被忽略。
包含网关
包容网关:可以同时执行多条线路,也可以在网关上设置条件,可以看做是排他网关和并行网关的结合体。
当出现这样的场景:请假申请大于等于2天需要由部门总经理审批,小于2天由部门经理审批,请假申请必须经过人事经理审批。这个时候就需要包含网关
package com.jerry.auth.activiti;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SpringBootTest
public class ProcessTestGateway {
@Autowired
private RepositoryService repositoryService;
//注入RuntimeService
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Autowired
private HistoryService historyService;
//1 部署流程定义
@Test
public void deployProcess() {
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("process/qingjia003.bpmn20.xml")
.name("请假申请流程003")
.deploy();
System.out.println(deployment.getId()); // af9242f0-bb4c-11ed-85bf-005056c00001
System.out.println(deployment.getName()); // 请假申请流程002
}
//2 启动流程实例
@Test
public void startProcessInstance() {
Map<String, Object> map = new HashMap<>();
//设置请假天数
map.put("day", "3");
ProcessInstance processInstance =
// runtimeService.startProcessInstanceByKey("qingjia002", map);
runtimeService.startProcessInstanceByKey("qingjia003");
System.out.println(processInstance.getProcessDefinitionId()); // qingjia002:1:afac0c82-bb4c-11ed-85bf-005056c00001
System.out.println(processInstance.getId()); // 90d46e2c-bb4d-11ed-9b92-005056c00001
}
//3 查询个人的代办任务--zhao6
@Test
public void findTaskList() {
// String assign = "zhao6";
// String assign = "gousheng";
// String assign = "xiaocui";
// String assign = "wang5";
// String assign = "gouwa";
String assign = "xiaoli";
List<Task> list = taskService.createTaskQuery()
.taskAssignee(assign).list();
for (Task task : list) {
System.out.println("流程实例id:" + task.getProcessInstanceId());
System.out.println("任务id:" + task.getId());
System.out.println("任务负责人:" + task.getAssignee());
System.out.println("任务名称:" + task.getName());
}
}
//完成任务
@Test
public void completeTask() {
Task task = taskService.createTaskQuery()
// .taskAssignee("zhao6") //要查询的负责人
// .taskAssignee("xiaocui") //要查询的负责人
// .taskAssignee("gousheng")
// .taskAssignee("wang5")
.taskAssignee("gouwa")
.singleResult();//返回一条
//完成任务,参数:任务id
taskService.complete(task.getId());
}
}
11、审批管理
11.1、审批设置–CRUD
package com.jerry.process.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jerry.common.result.Result;
import com.jerry.model.process.ProcessType;
import com.jerry.process.service.OaProcessTypeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
/**
* <p>
* 审批类型 前端控制器
* </p>
*
* @author jerry
* @since 2023-03-05
*/
@Api(value = "审批类型", tags = "审批类型")
@RestController
@RequestMapping(value = "/admin/process/processType")
public class OaProcessTypeController {
@Autowired
private OaProcessTypeService processTypeService;
@ApiOperation(value = "获取分页列表")
@GetMapping("{page}/{pageSize}")
public Result index(@PathVariable Long page, @PathVariable Long pageSize) {
Page<ProcessType> pageInfo = new Page<>(page, pageSize);
Page<ProcessType> pageModel = processTypeService.page(pageInfo);
return Result.ok(pageModel);
}
@PreAuthorize("hasAuthority('bnt.processType.list')")
@ApiOperation(value = "获取")
@GetMapping("get/{id}")
public Result get(@PathVariable Long id) {
ProcessType processType = processTypeService.getById(id);
return Result.ok(processType);
}
@PreAuthorize("hasAuthority('bnt.processType.add')")
@ApiOperation(value = "新增")
@PostMapping("save")
public Result save(@RequestBody ProcessType processType) {
processTypeService.save(processType);
return Result.ok();
}
@PreAuthorize("hasAuthority('bnt.processType.update')")
@ApiOperation(value = "修改")
@PutMapping("update")
public Result updateById(@RequestBody ProcessType processType) {
processTypeService.updateById(processType);
return Result.ok();
}
@ApiOperation(value = "删除")
@DeleteMapping("remove/{id}")
public Result remove(@PathVariable Long id) {
processTypeService.removeById(id);
return Result.ok();
}
}
11.2、模板审批–CRUD
package com.jerry.process.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jerry.common.result.Result;
import com.jerry.model.process.ProcessTemplate;
import com.jerry.process.service.OaProcessTemplateService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* <p>
* 审批模板 前端控制器
* </p>
*
* @author jerry
* @since 2023-03-05
*/
@Api(value = "审批模板管理", tags = "审批模板管理")
@RestController
@RequestMapping(value = "/admin/process/processTemplate")
public class OaProcessTemplateController {
@Autowired
private OaProcessTemplateService processTemplateService;
// 分页查询审批模板
@ApiOperation("获取分页查询审批模板数据")
@GetMapping("{page}/{pageSize}")
public Result index(@PathVariable Long page, @PathVariable Long pageSize){
Page<ProcessTemplate> pageInfo = new Page<>(page, pageSize);
//分页查询审批模板,把审批类型对应名称查询
IPage<ProcessTemplate> pageModel =
processTemplateService.selectPageProcessTemplate(pageInfo);
return Result.ok(pageModel);
}
//@PreAuthorize("hasAuthority('bnt.processTemplate.list')")
@ApiOperation(value = "获取")
@GetMapping("get/{id}")
public Result get(@PathVariable Long id) {
ProcessTemplate processTemplate = processTemplateService.getById(id);
return Result.ok(processTemplate);
}
//@PreAuthorize("hasAuthority('bnt.processTemplate.templateSet')")
@ApiOperation(value = "新增")
@PostMapping("save")
public Result save(@RequestBody ProcessTemplate processTemplate) {
processTemplateService.save(processTemplate);
return Result.ok();
}
//@PreAuthorize("hasAuthority('bnt.processTemplate.templateSet')")
@ApiOperation(value = "修改")
@PutMapping("update")
public Result updateById(@RequestBody ProcessTemplate processTemplate) {
processTemplateService.updateById(processTemplate);
return Result.ok();
}
//@PreAuthorize("hasAuthority('bnt.processTemplate.remove')")
@ApiOperation(value = "删除")
@DeleteMapping("remove/{id}")
public Result remove(@PathVariable Long id) {
processTemplateService.removeById(id);
return Result.ok();
}
}
11.3、添加审批模板
OaProcessTypeController
@ApiOperation(value = "获取全部审批分类")
@GetMapping("findAll")
public Result findAll() {
return Result.ok(processTypeService.list());
}
OaProcessTemplateController
@ApiOperation(value = "上传流程定义")
@PostMapping("/uploadProcessDefinition")
public Result uploadProcessDefinition(MultipartFile file) throws FileNotFoundException {
// 获取classes目录位置
String path = new File(ResourceUtils.getURL("classpath:").getPath()).getAbsolutePath();
// 设置上传文件夹
File tempFile = new File(path + "/processes/");
if (!tempFile.exists()) {
tempFile.mkdirs();
}
// 创建空文件,实现文件写入
String filename = file.getOriginalFilename();
File zipFile = new File(path + "/processes/" + filename);
// 保存文件
try {
file.transferTo(zipFile);
} catch (IOException e) {
return Result.fail();
}
Map<String, Object> map = new HashMap<>();
//根据上传地址后续部署流程定义,文件名称为流程定义的默认key
map.put("processDefinitionPath", "processes/" + filename);
map.put("processDefinitionKey", filename.substring(0, filename.lastIndexOf(".")));
return Result.ok(map);
}
public static void main(String[] args) {
try {
String path = new File(ResourceUtils.getURL("classpath:").getPath()).getAbsolutePath();
System.out.println("path = " + path); //E:\CodeLife\IdeaProject\guigu-oa\guigu-oa-parent\service-oa\target\classes
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
11.4、查看审批模板
整合前端,无后台接口
11.5、审批列表
分页查询
OaProcessController
package com.jerry.process.controller;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jerry.common.result.Result;
import com.jerry.model.process.Process;
import com.jerry.process.service.OaProcessService;
import com.jerry.vo.process.ProcessQueryVo;
import com.jerry.vo.process.ProcessVo;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 审批类型 前端控制器
* </p>
*
* @author jerry
* @since 2023-03-06
*/
@RestController
@RequestMapping(value = "/admin/process")
public class OaProcessController {
@Autowired
private OaProcessService processService;
//审批管理列表
@ApiOperation(value = "获取分页列表")
@GetMapping("{page}/{limit}")
public Result index(@PathVariable Long page,
@PathVariable Long limit,
ProcessQueryVo processQueryVo) {
Page<ProcessVo> pageInfo = new Page<>(page, limit);
IPage<ProcessVo> pageModel = processService.selectPage(pageInfo,processQueryVo);
return Result.ok();
}
}
OaProcessService
public interface OaProcessService extends IService<Process> {
//审批管理列表
IPage<ProcessVo> selectPage(Page<ProcessVo> pageInfo, ProcessQueryVo processQueryVo);
}
OaProcessServiceImpl
//审批管理列表
@Override
public IPage<ProcessVo> selectPage(Page<ProcessVo> pageInfo, ProcessQueryVo processQueryVo) {
IPage<ProcessVo> pageModel = baseMapper.selectPage(pageInfo,processQueryVo);
return pageModel;
}
OaProcessMapper
//审批管理列表
IPage<ProcessVo> selectPage(Page<ProcessVo> pageInfo, @Param("vo") ProcessQueryVo processQueryVo);
涉及到4张表的多表查询,自己编写SQL语句
OaProcessMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jerry.process.mapper.OaProcessMapper">
<select id="selectPage" resultType="com.jerry.vo.process.ProcessVo">
SELECT
a.id,a.process_code,a.user_id,a.process_template_id,a.process_type_id,a.title,a.description,a.form_values,a.process_instance_id,a.current_auditor,a.status,a.create_time,a.update_time,
b.name AS processTemplateName,
c.name AS processTypeName,
d.name
FROM oa_process a
LEFT JOIN sys_user d ON a.user_id =d.id
LEFT JOIN oa_process_template b ON a.process_template_id = b.id
LEFT JOIN oa_process_type c ON a.process_type_id = c.id
<where>
<if test="vo.keyword != null and vo.keyword != ''">
and (a.process_code like CONCAT('%',#{vo.keyword},'%') or
a.title like CONCAT('%',#{vo.keyword},'%'))
</if>
<if test="vo.userId != null and vo.userId != ''">
and a.user_id = #{vo.userId}
</if>
<if test="vo.status != null and vo.status != ''">
and a.status = #{vo.status}
</if>
<if test="vo.createTimeBegin != null and vo.createTimeBegin != ''">
and a.create_time >= #{vo.createTimeBegin}
</if>
<if test="vo.createTimeEnd != null and vo.createTimeEnd != ''">
and a.create_time <= #{vo.createTimeEnd}
</if>
</where>
</select>
</mapper>
修改mapper的映射路径
页面展示
部署流程定义
OaProcessTemplateServiceImpl
// 修改模板的发布状态 status==1 代表已发布
// 流程定义部署
@Override
public void publish(Long id) {
// 修改模板的发布状态 status==1 代表已发布
ProcessTemplate processTemplate = baseMapper.selectById(id);
processTemplate.setStatus(1);
baseMapper.updateById(processTemplate);
// 流程定义部署
if (StringUtils.isEmpty(processTemplate.getProcessDefinitionPath())){
processService.deployByZip(processTemplate.getProcessDefinitionPath());
}
}
}
OaProcessService
// 流程定义部署
void deployByZip(String deployPath);
OaProcessServiceImpl
// 流程定义部署
@Override
public void deployByZip(String deployPath) {
InputStream inputStream= this.getClass().getClassLoader().getResourceAsStream(deployPath);
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
// 部署
Deployment deployment = repositoryService.createDeployment().addZipInputStream(zipInputStream).deploy();
System.out.println("deployment.getId() = " + deployment.getId());
System.out.println("deployment.getName() = " + deployment.getName());
}
12、前端审批
12.1、OA审批
activiti-explorer整合到项目中
Springboot2.0与activiti-explorer5.23.0整合,从0开始构建自己的工作流编辑平台(附件 ***) - 灰信网(软件开发博客聚合)
解压,如图:
B) 将DIAGRAM-VIEWER,EDITOR-APP,MODELER.HTML三个文件复制到SPRINGBOOT的项目
在Springboot的项目的resource目录的static文件夹下新建一个activiti-explorer文件夹。(此处根据自己要求是否新建文件夹)
复制配置文件STENCILSET.JSON到SPRINGBOO项目
stencilset.json在activiti-webapp-explorer2-5.23.0.war的文件夹下路径:
于是手动编写一个初始化模型数据类如下:
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
@Controller
@RequestMapping("/models")
public class TestActivitiController {
private static final Logger LOGGER = LoggerFactory.getLogger(TestActivitiController.class);
@Autowired
private RepositoryService repositoryService;
@Autowired
private ObjectMapper objectMapper;
@RequestMapping("/create")
public void newModel(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
try {
// 初始化一个空模型
Model model = repositoryService.newModel();
// 设置一些默认信息
String name = "new-process";
String description = "";
int revision = 1;
String key = "process";
ObjectNode modelNode = objectMapper.createObjectNode();
modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);
modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);
model.setName(name);
model.setKey(key);
model.setMetaInfo(modelNode.toString());
repositoryService.saveModel(model);
String id = model.getId();
// 完善ModelEditorSource
ObjectNode editorNode = objectMapper.createObjectNode();
editorNode.put("id", "canvas");
editorNode.put("resourceId", "canvas");
ObjectNode stencilSetNode = objectMapper.createObjectNode();
stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
editorNode.put("stencilset", stencilSetNode);
repositoryService.addModelEditorSource(id, editorNode.toString().getBytes("utf-8"));
response.sendRedirect(request.getContextPath() + "/static/modeler.html?modelId=" + id);
} catch (IOException e) {
e.printStackTrace();
LOGGER.info("模型创建失败!");
}
}
}
同时加上Bean的扫描路径注解:
@SpringBootApplication(scanBasePackages = { "org.activiti.rest", "hu.itget" }, exclude = {
org.activiti.spring.boot.SecurityAutoConfiguration.class,
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class })