工作流之Activiti7 和BPMN讲解
1 Activiti
1.1 简介
Activiti
是一个开源的工作流和业务流程管理 (BPM) 平台,旨在帮助开发者和企业自动化业务流程。它提供了一整套工具,用于定义、执行、监控和优化业务流程。Activiti
支持 BPMN 2.0 标准,具有强大的扩展能力和易用性,适用于各种规模的组织和复杂的业务需求。
官方网站:https://www.activiti.org
https://mp.weixin.qq.com/s/Xa3yIp1FRYpQF87lmf91OA
1.2 BPMN
1.2.1 简介
BPM(Business Process Management)
即业务流程管理,是一种规范化的构造端到端的业务流程,以持续提高组织业务效率
BPMN(Business Process Model AndNotation)
即业务流程模型和符号,是一套标准的业务流程建模符号,使用 BPMN
提供的符号可以创建业务流程。Activit
就是使用 BPMN
进行流程建模、流程执行管理的
BPMN2.0
是业务流程建模符号 2.0 的缩写,它由 Business Process Management Initiative
这个非营利协会创建并不断发展。BPMN2.0
是使用一些符号来明确业务流程设计流程图的一套符号规范,能增进业务建模时的沟通效率。
1.2.2 符号
BPMN2.0 的基本符号主要包含
-
事件
Event
开始:表示一个流程的开始
中间:发生的开始和结束事件之间,影响处理的流程
结束:表示该过程结束
-
活动
Activities
活动是工作或任务的一个通用术语。一个活动可以是一个任务,还可以是一个当前流程的子处理流程;其次,还可以为活动指定不同的类型。常见活动如下:
-
网关
GateWay
用于表示流程的分支与合并,有几种常用网关需要了解:
排他网关:只有一条路径会被选择,基于条件选择单一路径
并行网关:无条件并行执行所有路径
包容网关:可以同时执行多条线路,也可以在网关上设置条件,基于条件可以选择多个路径同时执行
事件网关:基于外部事件的发生来决定路径选择,即专门为中间捕获事件设置的,允许设置多个输出流指向多个不同的中间捕获事件。当流程执行到事件网关后,流程处于等待状态,需要等待抛出事件才能将等待状态转换为活动状态 -
流向
Flow
流是连接两个流程节点的连线,常见的流向包含以下几种:
顺序流:用一个带实心箭头的实心线表示,用于指定活动执行的顺序
信息流:用一条带箭头的虚线表示,用于描述两个独立的业务参与者(业务实体/业务角色)之间发送和接受的消息流动
关联:用一根带有线箭头的点线表示,用于将相关的数据、文本和其他人工信息与流对象联系起来。用于展示活动的输入和输出
-
边界事件(
Boundary Events
)
边界事件是一种特殊的事件,它附加在流程元素(如任务、子流程等)上,用于捕捉特定事件并对其进行处理。边界事件通常用于中断或处理任务的异常情况,或者处理流程中某些特定的事件场景。- 中断任务: 当绑定在某个任务上的边界事件被触发时,任务可以被中断,流程将根据边界事件的定义跳转到其他节点或执行特定的操作。这通常用于处理异常情况,如错误、超时等。
- 捕获事件: 边界事件可以用来捕捉在任务执行过程中发生的特定事件,例如错误事件(
Error Event
)、定时事件(Timer Event
)、消息事件(Message Event
)等。当这些事件发生时,流程会从当前任务转移到处理该事件的流程路径。 - 处理子流程: 在嵌套子流程中,边界事件可以用于在子流程内某个特定事件发生时触发相应的处理逻辑。
1.3 准备工作
1.3.1 安装插件
1.3.1.1 插件
IDEA版本小于等于2019,可使用Activiti插件actiBPM
,如果获取不到插件市场获取:https://plugins.jetbrains.com/plugin/7429-actibpm
否则使用Activiti BPMN visualizer
假如要画一个请假的 activiti
流程图,使用 Idea
安装 actiBPM
插件,创建该流程图,文件命名apply.mpmn,实现请假流程的二级审批能力,右键点击view bpmn diagram 才会有图示出来
1.3.1.2 本地网页
如果觉得插件画图麻烦,可以用 Activiti Modeler
,Activiti Modeler
是 Activiti 官方提供的一款在线流程设计的前端插件,开发人员可以方便在线进行流程设计,保存流程模型,部署至流程定义等等
下载activiti-explorer,官网下载:Get started | Activiti
解压activiti-5.22.0.zip,在activiti-5.22.0\wars目录下获取activiti-explorer.war
启动路径:双击startup.bat
访问activiti-explorer:http://localhost:8080/activiti-explorer
默认登录账号:kermit kermit
1.3.2 pom依赖
<!--引入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>
<!-- 不加如下依赖报错:'org.springframework.security.core.userdetails.UserDetailsService' that could not be found.
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- 不加可能报错:Consider defining a bean of type 'javax.sql.DataSource' in your configuration -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<!-- 或者使用druid-spring-boot-starter -->
</dependency>
</dependency>
说明:Activiti7
与SpringBoot
整合后,默认集成了SpringSecurity
安全框架,当前项目已经集成过了SpringSecurity
,后续案例设置审批人时都必须是系统用户,Activiti
框架会检查用户是否存在,否则会出现异常
1.3.3 添加配置
数据源项目已经添加,只需要如下配置即可
spring:
datasource:
url: jdbc:mysql://localhost:3316/activiti?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: xxxx
password: xxxx
driver-class-name: com.mysql.cj.jdbc.Driver
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: false
# 定义.bpmn文件的位置
process-definition-location-prefix: classpath:/process/
1.3.4 表介绍
启动项目,即可生成项目数据库表
Activiti
的运行支持必须要有这 25 张表的支持,主要是在业务流程运行过程中,记录参与流程的用户主体,用户组信息,以及流程的定义,流程执行时的信息,和流程的历史信息等等
表的命名规则和作用:
Activiti
的表都以act_
开头,紧接着是表示表的用途的两个字母标识,也和Activiti
所提供的服务的 API 对应:ACT_RE
:RE 表示 repository,这个前缀的表包含了流程定义和流程静态资源 (图片、规则、等等)ACT_RU
:RU 表示 runtime,这些表运行时,会包含流程实例、任务、变量、异步任务等流程业务进行中的数据。Activiti 只在流程实例执行过程中保存这些数据,在流程结束时就会删除这些记录。这样表就可以一直保持很小的体积,并且速度很快ACT_HI
:HI 表示 history,这些表包含一些历史数据,比如历史流程实例、变量、任务等等ACT_GE
:GE 表示 general,通用数据
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] | 运行时变量表 |
1.3.5 常用Service服务介绍
各个 Service 的实现类,这些服务是 Activiti
的底层核心 API,提供了对工作流引擎内部的细粒度控制。它们是 Activiti 5 和 6
中主要使用的服务,提供了更低级别的操作接口:
RepositoryService
Activiti
的资源管理类,该服务负责部署流程定义,管理流程资源。在使用Activiti
时,一开始需要先完成流程部署,即将使用建模工具设计的业务流程图通过RepositoryService
进行部署RuntimeService
Activiti
的流程运行管理类,用于开始一个新的流程实例,获取关于流程执行的相关信息。流程定义用于确定一个流程中的结构和各个节点间行为,而流程实例则是对应的流程定义的一个执行,可以理解为 Java 中类和对象的关系TaskService
Activiti
的任务管理类,用于处理业务运行中的各种任务,例如查询分给用户或组的任务、创建新的任务、分配任务、确定和完成一个任务HistoryService
Activiti
的历史管理类,可以查询历史信息。执行流程时,引擎会保存很多数据,比如流程实例启动时间、任务的参与者、完成任务的时间、每个流程实例的执行路径等等。这个服务主要通过查询功能来获得这些数据ManagementService
Activiti
的引擎管理类,提供了对Activiti
流程引擎的管理和维护功能,这些功能不在工作流驱动的应用程序中使用,主要用于Activiti
系统的日常维护
Activiti7后新增服务:
TaskRuntime
:这个服务主要用于管理用户任务。通过它,可以查询任务、完成任务、分配任务、认领任务等。这些操作是围绕任务管理的高层次抽象,开发人员可以更加方便地与任务进行交互,而无需直接处理底层的 API 调用。ProcessRuntime
:这个服务用于管理流程实例。可以通过它启动流程、查询流程实例、暂停和恢复流程等。ProcessRuntime 提供了一个更简单的方式来处理流程的生命周期管理。
1.4 无校验操作流程
将画好的流程图部署到activiti数据库中,就是流程定义部署。通过调用activiti
的api将流程定义的bpmn和png两个文件一个一个添加部署到activiti中,也可以将两个文件打成zip包进行部署。
1.4.1 部署&查看文件
流程定义部署后操作activiti的3张表如下:
act_re_deployment
:流程定义部署表,每部署一次增加一条记录act_re_procdef
:流程定义表,部署每个新的流程定义都会在这张表中增加一条记录act_ge_bytearray
:流程资源表
1.4.1.1 单个文件部署方式
@SpringBootTest
public class ProcessTest {
//注入RepositoryService
@Autowired
private RepositoryService repositoryService;
/**
* 单个文件部署方式
*/
@Test
public void deployProcess() {
//流程部署
Deployment deploy = repositoryService.createDeployment()
.addClasspathResource("process/qingjia.bpmn20.xml")
// 如果报错找不到图片在pom里面添加: <include>**/*.png</include>
.addClasspathResource("process/qingjia.png")
.name("请假申请流程")
.deploy();
System.out.println(deploy.getId());
System.out.println(deploy.getName());
}
}
1.4.1.2 静态类部署
@Test
public void testDeployment(){
// 1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到RepositoryService实例
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、使用RepositoryService进行部署
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("process/qingjia.bpmn") // 添加bpmn资源
.name("请假申请流程")
.deploy();
// 4、输出部署信息
System.out.println("流程部署id:" + deployment.getId());
System.out.println("流程部署名称:" + deployment.getName());
}
1.4.1.3 压缩包部署方式
@Autowired
private RepositoryService repositoryService;
@Test
public void deployProcessByZip() {
// 定义zip输入流
InputStream inputStream = this
.getClass()
.getClassLoader()
.getResourceAsStream(
"process/qingjia.zip");
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
// 流程部署
Deployment deployment = repositoryService.createDeployment()
.addZipInputStream(zipInputStream)
.name("请假申请流程")
.deploy();
System.out.println("流程部署id:" + deployment.getId());
System.out.println("流程部署名称:" + deployment.getName());
}
1.4.1.4 查看文件
@Test
public void queryBpmnFile() throws IOException {
//得到查询器:ProcessDefinitionQuery,设置查询条件,得到想要的流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("qingjia")
.singleResult();
//通过流程定义信息,得到部署ID
String deploymentId = processDefinition.getDeploymentId();
// 通过repositoryService的方法,实现读取图片信息和bpmn信息
// png图片的流
InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
// bpmn文件的流
InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getResourceName());
// 构造OutputStream流
File file_png = new File("d:/qingjia.png");
File file_bpmn = new File("d:/qingjia.bpmn");
FileOutputStream bpmnOut = new FileOutputStream(file_bpmn);
FileOutputStream pngOut = new FileOutputStream(file_png);
// 7、输入流,输出流的转换
IOUtils.copy(pngInput,pngOut);
IOUtils.copy(bpmnInput,bpmnOut);
// 8、关闭流
pngOut.close();
bpmnOut.close();
pngInput.close();
bpmnInput.close();
}
1.4.2 启动流程实例和查询
将bpmn文件放到activiti的三张表中,好比是java中的一个类 流程实例:好比是java中的一个实例对象(一个流程定义可以对应多个流程实例),张三可以启动一个请假流程实例,李四也可以启动一个请假流程实例,他们互不影响
@Autowired
private RuntimeService runtimeService;
@Test
public void startUpProcess() {
//创建流程实例,我们需要知道流程定义的key
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("qingjia");
//输出实例的相关信息
System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
System.out.println("流程实例id:" + processInstance.getId());
System.out.println("当前活动Id:" + processInstance.getActivityId());
}
注意
:使用startProcessInstanceByKey
的方式不用在部署了,springboot会自动部署bpmn文件
操作数据表:
- act_hi_actinst 流程实例执行历史
- act_hi_identitylink 流程的参与用户历史信息
- act_hi_procinst 流程实例历史信息
- act_hi_taskinst 流程任务历史信息
- act_ru_execution 流程执行信息
- act_ru_identitylink 流程的参与用户信息
- act_ru_task 任务信息
/**
* 查询流程实例
*/
@Test
public void queryProcessInstance() {
List<ProcessInstance> list = runtimeService
.createProcessInstanceQuery("qingjia")
.processDefinitionKey()//
.list();
for (ProcessInstance processInstance : list) {
System.out.println("----------------------------");
System.out.println("流程实例id:"
+ processInstance.getProcessInstanceId());
System.out.println("所属流程定义id:"
+ processInstance.getProcessDefinitionId());
System.out.println("是否执行完成:" + processInstance.isEnded());
System.out.println("是否暂停:" + processInstance.isSuspended());
System.out.println("当前活动标识:" + processInstance.getActivityId());
System.out.println("业务关键字:"+processInstance.getBusinessKey());
}
}
查看流程实例历史
/**
* 查看历史信息
*/
@Test
public void findHistoryInfo(){
// 获取 actinst表的查询对象
HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
// 查询 actinst表,条件:根据 InstanceId 查询,查询一个流程的所有历史信息
instanceQuery.processInstanceId("25001");
// 查询 actinst表,条件:根据 DefinitionId 查询,查询一种流程的所有历史信息
// instanceQuery.processDefinitionId("myLeave:1:22504");
// 增加排序操作,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("<==========================>");
}
}
1.4.3 查询任务和历史
每个节点都配置了Assignee
,流程启动后,任务的负责人就可以查询自己当前需要处理的任务,查询出来的任务都是该用户的待办任务。
@Autowired
private TaskService taskService;
/**
* 查询当前个人待执行的任务
*/
@Test
public void findPendingTaskList() {
//任务负责人
String assignee = "zhangsan";
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey("qingjia") //流程Key
.taskAssignee(assignee)//只查询该任务负责人的任务
.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());
}
}
@Autowired
private HistoryService historyService;
/**
* 查询已处理历史任务
*/
@Test
public void findProcessedTaskList() {
//张三已处理过的历史任务
List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
.processDefinitionKey("qingjia") //流程Key
.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());
}
}
说明:
- 流程实例id:一个流程只有一个,标识这个流程
- 任务id:流程每进行到某个节点,就会给这个节点分配一个任务id
1.4.4 处理当前任务
任务负责人查询待办任务,选择任务进行处理,完成任务。
@Test
public void completTask(){
Task task = taskService.createTaskQuery()
.processDefinitionKey("qingjia") //流程Key
.taskAssignee("zhangsan") //要查询的负责人
.singleResult();//返回一条
//完成任务,参数:任务id
taskService.complete(task.getId());
}
完成任务后,任务自动到下一个节点
1.4.5 流程定义
/**
* 查询流程定义
*/
@Test
public void findProcessDefinitionList(){
List<ProcessDefinition> definitionList = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("qingjia")
.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());
}
}
/**
* 删除流程定义
*/
public void deleteDeployment() {
//部署id
String deploymentId = "82e3bc6b-81da-11ed-8e03-7c57581a7819";
//删除流程定义,如果该流程定义已有流程实例启动则删除时出错
repositoryService.deleteDeployment(deploymentId);
//设置true 级联删除流程定义,即使该流程有流程实例启动也可以删除,设置为false非级别删除方式
//repositoryService.deleteDeployment(deploymentId, true);
}
1.5 新版校验操作
1.5.1 配置Security用户
@Configuration
@EnableWebSecurity
public class MyWebSecurityConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests(authorize -> authorize.anyRequest().authenticated())
.formLogin(Customizer.withDefaults());
return http.build();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring()
.requestMatchers()
// Spring Security should completely ignore URLs starting with /resources/
.antMatchers("/**");
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails admin = User.withUsername("tom")
.password("$2a$10$tk29HhXGXCZDOSvn.VZlFeBsLmtJrKE2Uv6zLrRpTyvZMu3ipQLgC")
.roles("ACTIVITI_USER", "ACTIVITI_ADMIN", "APPLICATION_MANAGER")
.build();
UserDetails user = User.withUsername("jerry")
.password("$2a$10$tk29HhXGXCZDOSvn.VZlFeBsLmtJrKE2Uv6zLrRpTyvZMu3ipQLgC")
.roles("ACTIVITI_USER", "GROUP_BUSINESS_MANAGER")
.build();
UserDetails zhangsan = User.withUsername("zhangsan")
.password("$2a$10$tk29HhXGXCZDOSvn.VZlFeBsLmtJrKE2Uv6zLrRpTyvZMu3ipQLgC")
.roles("ACTIVITI_USER")
.build();
UserDetails lisi = User.withUsername("lisi")
.password("$2a$10$tk29HhXGXCZDOSvn.VZlFeBsLmtJrKE2Uv6zLrRpTyvZMu3ipQLgC")
.roles("ACTIVITI_USER")
.build();
return new InMemoryUserDetailsManager(admin, user, zhangsan, lisi);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
public static void main(String[] args) {
System.out.println(new BCryptPasswordEncoder().encode("123456"));
}
}
Security工具类
@Component
public class SecurityUtil {
@Autowired
private UserDetailsService userDetailsService;
public void logInAs(String username) {
UserDetails user = userDetailsService.loadUserByUsername(username);
if (null == user) {
throw new IllegalStateException(String.format("用户【%s】不存在", username));
}
SecurityContextHolder.setContext(new SecurityContextImpl(new Authentication() {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return user.getAuthorities();
}
@Override
public Object getCredentials() {
return user.getPassword();
}
@Override
public Object getDetails() {
return user;
}
@Override
public Object getPrincipal() {
return user;
}
@Override
public boolean isAuthenticated() {
return true;
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
}
@Override
public String getName() {
return user.getUsername();
}
}));
org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);
}
}
1.5.2 操作
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestSecurityActiviti {
@Autowired
private ProcessRuntime processRuntime;
@Autowired
private TaskRuntime taskRuntime;
@Autowired
private SecurityUtil securityUtil;
@Test
public void findProcess(){
securityUtil.logInAs("jack");
final ProcessDefinition processDefinition = processRuntime.processDefinition("apply");
log.info("流程定义内容:{}",processDefinition);
final Page<ProcessDefinition> processDefinitionPage = processRuntime.processDefinitions(Pageable.of(0, 10));
for (ProcessDefinition definition : processDefinitionPage.getContent()) {
log.info("2- 流程定义内容: {}",definition);
}
}
/**
* 启动流程
*/
@Test
public void startProcess(){
// 设置登录用户
securityUtil.logInAs("system");
ProcessInstance processInstance = processRuntime.
start(ProcessPayloadBuilder.
start().
withProcessDefinitionKey("apply").
build());
log.info("流程实例的内容,{}",processInstance);
}
/**
* 执行任务
*/
@Test
public void doTask(){
// 设置登录用户
securityUtil.logInAs("jerry");
// 查询任务
Page<Task> taskPage = taskRuntime.tasks(Pageable.of(0, 10));
if(taskPage != null && taskPage.getTotalItems()>0){
for (Task task : taskPage.getContent()) {
// 拾取任务
taskRuntime.claim(TaskPayloadBuilder.
claim().
withTaskId(task.getId()).
build());
log.info("任务内容,{}",task);
// 完成任务
taskRuntime.complete(TaskPayloadBuilder.
complete().
withTaskId(task.getId()).
build());
}
}
}
}
1.5.3 报错 Process definition with the given id:xxx belongs to a different application version
报错参考:https://blog.csdn.net/u011410254/article/details/117368489
在resources目录下添加文件default-project.json
内容:
{
"createdBy": "superadminuser",
"creationDate": "2019-08-16T15:58:46.056+0000",
"lastModifiedBy": "qa-modeler-1",
"lastModifiedDate": "2019-08-16T16:03:41.941+0000",
"id": "c519a458-539f-4385-a937-2edfb4045eb9",
"name": "projectA",
"description": "",
"version": "1"
}
application配置文件:
# project manifest path
project.manifest.file.path=classpath:/default-project.json
1.6 Activiti 7.1.0.M6之后
activiti-spring-boot-starter
最大是支持到7.1.0.M6
,在大版本就需要 如下处理
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-dependencies</artifactId>
<version>7.6.1</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>activiti-releases</id>
<url>https://artifacts.alfresco.com/nexus/content/repositories/activiti-releases</url>
</repository>
</repositories>
修改 mirror 镜像
<mirrors>
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>*,!activiti-releases</mirrorOf>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>