activity入门教程
1. 什么是工作流
工作流:就是通过计算机对业务流程自动化执行进行管理。
它主要解决的是:使在多个参与者之间按照某种预定义的规则☆☆☆☆☆自动进行传递☆☆☆☆☆文档、信息或任务的过程。
例如:员工的请假,出差,外出采购,合同审核等等,这些过程,都是一个工作流。
2. 为什么要使用工作流
不使用工作流:
对于工作流的处理,如果采用原始的方式,我们需要拿着各种文件到各个负责人那里去签字,需要在多个部门之间不断审批,这种方式费时费力。
例如:填写请假单->部门经理审批->总经理审批->人事备案。
要实现上述的流程,我们自己可以通过字段标识来实现这个审批效果,在业务表中加个字段,比如填写请假单用1标识,部门经理用2标识,总经理用3标识,人事备案用4标识,好像看起来没啥问题,也实现了审批效果。
可是一旦我们的流程出现了变化,这个时候我们就需要改动我们的代码了,这显然是不可取的,特别麻烦。
使用工作流:
工作流引擎实现了一个规范,这个规范要求我们的流程管理与状态字段无关,始终都是读取业务流程图的下一个节点。
当业务更新的时候我们只需要更新业务流程图就行了。这就实现了业务流程改变,不用修改代码。
3. 常见的工作流
主流的框架有:Activiti、jBPM、Camunda 、Flowable
4. Activiti介绍
activiti是一个工作流引擎,可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言BPMN进行定义,业务流程按照预先定义的流程进行执行。
5. BPMN介绍
BPMN:即业务流程模型和符号,是一套标准的业务流程建模符号,使用 BPMN 提供的符号可以创建业务流程。Activit 就是使用 BPMN 进行流程建模、流程执行管理的。
BPMN 使用一些符号来明确业务流程设计流程图的一套符号规范,能增进业务建模时的沟通效率。
6. Activty使用流程
- 引入依赖
- 绘制流程模型
- 流程部署(使用 activiti 提供的 api 向 activiti 中部署.bpmn 文件)
- 启动一个流程实例(启动一个流程实例就好比new一个java对象)
- 用户查询待办任务
- 用户办理任务
- 流程结束
7. Activty入门实战体验
7.3 启动项目
启动项目,即可生成项目数据库表
7.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常用Service服务接口介绍:
在activiti中,除了25张表外,还提供了 Service 服务层供我们使用,在项目中直接使用服务层接口,就能实现工作流相关的业务功能。
-
RepositoryService【仓储服务】
Activiti 的资源管理类,该服务负责部署流程定义,管理流程资源。
在使用 Activiti 时,一开始需要先完成流程部署,即将使用建模工具设计的业务流程图通过 RepositoryService 进行部署。
-
RuntimeService【运行时服务】
Activiti 的流程运行管理类,该服务用于开始一个新的流程实例,获取关于流程执行的相关信息。
流程定义用于确定一个流程中的结构和各个节点间行为,而流程实例则是对应的流程定义的一个执行,可以理解为 Java 中类和对象的关系。
-
TaskService【任务服务】
Activiti 的任务管理类,用于处理业务运行中的各种任务。
例如查询分给用户或组的任务、创建新的任务、分配任务、确定和完成一个任务。
-
HistoryService
Activiti 的历史管理类,该服务可以查询历史信息。在执行流程工程中,引擎会保存很多数据。
比如流程实例启动时间、任务的参与者、完成任务的时间、每个流程实例的执行路径等等。这个服务主要通过查询功能来获得这些数据。
-
ManagementService
Activiti 的引擎管理类,该服务提供了对 Activiti 流程引擎的管理和维护功能,这些功能不在工作流驱动的应用程序中使用。
主要用于 Activiti 系统的日常维护。
7.4 流程定义部署
// 部署流程图
@Test
public void test2() {
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
DeploymentBuilder builder = repositoryService.createDeployment();
Deployment deploy = builder
.addClasspathResource("bpmn/leave.bpmn")
.addClasspathResource("bpmn/leave.png")
.disableSchemaValidation()
.name("请求")
.deploy();
System.out.println("流程部署的id:" + deploy.getId()); // 流程ID:10001
System.out.println("流程name:" + deploy.getName()); // 流程name:请假
}
流程定义部署后,会操作activiti的3张表如下:
act_re_deployment 流程定义部署表,每部署一次增加一条记录
act_re_procdef 流程定义表,部署每个新的流程定义都会在这张表中增加一条记录
act_ge_bytearray 流程资源表
7.5 创建流程实例
// 创建(启动)流程实例
@Test
public void test3() {
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// 获取流程部署信息
ProcessDefinition result = defaultProcessEngine.getRepositoryService().createProcessDefinitionQuery().deploymentId("10001").singleResult();
String id = result.getId();
String key = result.getKey();
System.out.println("流程定义ID:" + id); // 流程定义ID:myProcess_1:1:10004
System.out.println("流程定义KEY:" + key); // 流程定义KEY:myProcess_1
RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceById(result.getId());// 根据流程定义的ID创建流程实例
//runtimeService.startProcessInstanceByKey() // 根据流程定义的KEY创建流程实例
System.out.println(processInstance);
}
7.4的 流程定义:将bpmn文件放到activiti的三张表中,好比是java中的一个类。
7.5的 流程实例:好比是java中的一个对象
(一个流程定义可以对应多个流程实例)
启动流程实例后,会操作activiti的4张表如下:
act_hi_actinst 流程实例执行历史
act_hi_identitylink 流程的参与用户历史信息
act_hi_procinst 流程实例历史信息
act_hi_taskinst 流程任务历史信息
act_ru_execution 流程执行信息
act_ru_identitylink 流程的参与用户信息
act_ru_task 任务信息
7.6 查询任务
// 查询任务
@Test
public void test4() {
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// 查询任务
TaskService taskService = defaultProcessEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().processDefinitionId("myProcess_1:1:10004").taskAssignee("zhangsan").list();
for (Task task : tasks) {
String processDefinitionId = task.getProcessDefinitionId(); // 流程定义ID
String processInstanceId = task.getProcessInstanceId(); // 流程实例ID
String taskDefinitionKey = task.getTaskDefinitionKey(); // 任务定义Key
String name = task.getName(); // 任务名称
String id = task.getId(); // 任务ID
System.out.println("流程定义ID:"+processDefinitionId); // 流程定义ID:myProcess_1:1:10004
System.out.println("流程实例ID:"+processInstanceId); // 流程实例ID:12501
System.out.println("任务定义Key:"+taskDefinitionKey); // 任务定义Key:_3
System.out.println("任务名称:"+name); // 任务名称:张三审批
System.out.println("任务ID:"+id); // 任务ID:12505
}
}
每个节点都配置了Assignee,流程启动后,任务的负责人就可以查询自己当前需要处理的任务,查询出来的任务都是该用户的待办任务。
个人任务查询–所涉及到的表如下:
ACT_RU_TASK表,ACT_RE_PROCDEF表
select
distinct RES.*
FROM
ACT_RU_TASK RES INNER JOIN ACT_RE_PROCDEF D
ON
RES.PROC_DEF_ID_ = D.ID_
WHERE
RES.ASSIGNEE_ = 'zs' and D.KEY_ = 'myJtxx' order by RES.ID_ asc
LIMIT 2147483647 OFFSET 0;
7.7 处理任务
// 处理任务
@Test
public void test5() {
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = defaultProcessEngine.getTaskService();
Task task = taskService.createTaskQuery().processDefinitionId("myProcess_1:1:10004").taskAssignee("zhangsan").singleResult();
// 完成任务
taskService.complete(task.getId()); // void complate(String id) 根据任务ID完成任务
}
完成任务后,任务自动到下一个节点
完成个人任务时会涉及的表如下:
ACT_RU_TASK 运行时任务表,就是对于一个流程,已经走到哪个节点了,这个里面保存的就是当前正在走的节点的信息;也就是保存的是当前正在执行的任务;
ACT_HI_TASKINST 流程任务历史信息 已经执行完成的任务,都会保存在这个里面
ACT_HI_ACTINST 历史的流程实例
ACT_HI_IDENTITYLINK 历史的流程运行过程中用户关系
ACT_RU_EXECUTION 运行时流程执行实例
ACT_RU_IDENTITYLINK 运行时用户关系信息,存储任务节点与参与者的相关信息 这个是更新操作
ACT_RU_TASK 任务信息
7.8 查询已处理任务
// 查询历史处理任务
@Test
public void test6() {
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
HistoryService historyService = defaultProcessEngine.getHistoryService();
// 根据节点的开始时间逆序的排序
List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery().processDefinitionId("myProcess_1:1:10004").orderByHistoricActivityInstanceStartTime().desc().list();
for (HistoricActivityInstance instance : list) {
System.out.println(instance.getActivityId());
System.out.println(instance.getActivityName());
System.out.println(instance.getActivityType());
System.out.println(instance.getAssignee());
System.out.println("------------");
}
}
_7
EndEvent
endEvent
null
------------
_5
李四
userTask
lisi
------------
_3
张三
userTask
zhangsan
------------
_2
StartEvent
startEvent
null
------------
7.9 流程实例绑定业务id
Activiti提供的数据是针对于该框架所需要的流程控制维护的数据,也就是数据库25张表存放的数据。
但是在业务系统中,业务数据(我们自己的表)如何与Activiti框架进⾏关联?
通过流程实例数据的BusinessKey字段来实现关联。在创建流程实例时,指明BusinessKey即可。
// 创建流程实例,关联业务id
@Test
public void test7(){
//1.获得engine对象
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
//2.获得RuntimeService对象
RuntimeService runtimeService = engine.getRuntimeService();
//3.创建流程实例,并指明业务id (我们自己的业务表)
ProcessInstance processInstance = runtimeService.startProcessInstanceById("myProcess_1:1:2504","1001");
System.out.println("流程实例已经创建");
System.out.println("业务ID:"+processInstance.getBusinessKey());
}
7.10 删除流程定义
删除流程定义,可以删除有未结束的流程实例的流程定义或者已结束的流程定义。
@Test
public void test2(){
//1.获得engine
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
//2.获得RepositoryService
RepositoryService repositoryService = engine.getRepositoryService();
//3.删除部署的流程,cascade:true,删除正在进⾏的流程实例,否则⽆法删除
repositoryService.deleteDeployment("2501",true);
}
8. 流程实例解释
什么是流程实例:
流程定义ProcessDefinition,
流程实例ProcessInstance
他们是Activiti重要的概念,类似于Java类和Java实例的关系。
启动一个流程实例表示开始一次业务流程的运行。
比如员工请假流程部署完成,如果张三要请假就可以启动一个流程实例。
如果李四也要请假,则也启动一个流程实例。
两个流程的执行互相不影响,就好比定义一个 java 类,实例化两个对象一样
如何获取流程定义:
获取流程定义的方法,在Activity中,提供了多种查询方法。
如,你可以使用如下方式来获取:
// 创建流程定义查询的对象
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
// 通过查询对象构建指定要查找的流程定义的名称
ProcessDefinition latestProcessDefinition = processDefinitionQuery.processDefinitionName("你的流程标识").latestVersion().singleResult();
在流程定义(ProcessDefinition)中,常用的属性包括以下内容:
ID(id): 流程定义的唯一标识符,通常是一个字符串或UUID。
Key(key): 流程定义的唯一标识键,通常是一个字符串。在启动流程实例时,可以使用流程定义的key来指定要启动的流程。
名称(name): 流程定义的名称,通常是一个描述性的字符串,用于标识流程的用途或目的。
版本号(version): 流程定义的版本号,用于区分不同版本的同一流程定义。当对流程定义进行更新时,版本号会递增。
部署ID(deploymentId): 流程定义所属的部署的唯一标识符。每次部署新的流程定义时,会生成一个新的部署ID。
资源名称(resourceName): 流程定义的XML资源文件的名称,通常以.bpmn或.bpmn20.xml为扩展名。这个文件包含了流程定义的描述信息。
部署时间(deploymentTime): 流程定义被部署的时间戳,记录了流程定义的创建时间。
描述(description): 流程定义的描述信息,通常提供了更详细的说明关于流程定义的用途和功能。
如何启动流程实例:
启动流程实例,在Activity中,提供了多种重载方法。
以下是 runtimeService 的部分方法:
startProcessInstanceByKey(): 通过流程定义的键(Key)来标识要启动的流程。
startProcessInstanceById(): 通过流程定义的ID来标识要启动的流程。
startProcessInstanceByMessage(): 根据流程定义中的消息启动新流程实例。
9. 流程挂起与激活
当因为业务需要,将执⾏的流程挂起,或者将已被挂起的流程激活,可以通过Activiti框架,对流程进⾏挂起和激活。
// 流程挂起
@Test
public void test8(){
//1.获得engine对象
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
//2.获得RuntimeService
RuntimeService runtimeService = engine.getRuntimeService();
//3.获得流程实例对象
ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId("22501").singleResult();
//4.先判断该流程是否属于正常状态(⾮挂起状态)
boolean suspended = instance.isSuspended();
if(!suspended){
//执⾏流程实例的挂起操作
runtimeService.suspendProcessInstanceById(instance.getId());
System.out.println(instance.getId()+"流程被挂起");
}
}
// 激活⼀个被挂起的流程
@Test
public void test9(){
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = engine.getRuntimeService();
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId("22501").singleResult();
boolean suspended = processInstance.isSuspended();
if(suspended){
//当前流程实例已被挂起,激活的操作
runtimeService.activateProcessInstanceById(processInstance.getId());
System.out.println(processInstance.getId()+"流程被激活");
}
}
9. 任务分配
任务分配:就是将任务分配给指定的负责人。
三种方式:
-
固定分配
-
UEL表达式分配
-
监听器分配
9.1 固定分配
业务流程建模时指定固定的任务负责人,如:Assignee:zhangsan
9.2 表达式分配
activiti支持两个UEL表达式:UEL-value和UEL-method。
UEL-value方式:
/**
* 启动流程实例
*/
@Test
public void startUpProcess01() {
Map<String, Object> variables = new HashMap<>();
variables.put("assignee1","zhangsan");
//创建流程实例,我们需要知道流程定义的key
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("qingjia01", variables);// 启动实例的方法跟之前的方法基本一致,唯一的不同是在启动时,添加了一个参数
//输出实例的相关信息
System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
System.out.println("流程实例id:" + processInstance.getId());
}
UEL-method 方式:
// userBean 是 spring 容器中的一个 bean,表示调用该 bean 的 getUsername(int id)方法。
// 经理审批:${userBean.getUsername(1)}
// 人事审批:${userBean.getUsername(2)}
@Component
public class UserBean {
public String getUsername(int id) {
if(id == 1) {
return "zhangsan";
}
if(id == 2) {
return "lisi";
}
return "admin";
}
}
/**
* 启动流程实例
*/
@Test
public void startUpProcess02() {
//创建流程实例,我们需要知道流程定义的key
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("qingjia02");
//输出实例的相关信息
System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
System.out.println("流程实例id:" + processInstance.getId());
}
//启动流程实例,就会调用bean方法,参数为:1,经理审批后,接着调用bean方法,参数为:2
10. 流程变量
10.1 流程变量概念
流程运转有时需要靠流程变量,业务系统和 activiti结合时少不了流程变量,流程变量就是 activiti 在管理工作流时根据管理需要而设置的变量。
比如:在请假申请流程流转时如果请假天数大于2 天则由总经理审核,否则由部门经理直接审核, 请假天数就可以设置为流程变量,在流程流转时使用。
10.2 流程变量的作用域
流程变量的作用可以是一个流程实例,但也可以是一个任务(task)或是一个执行实例。
globa全局变量:
globa变量:当一个流程变量的作用域为流程实例时,可以称为 global 变量。
流程变量的默认作用域是流程实例。
global 变量中变量名不允许重复,设置相同名称的变量,后设置的值会覆盖先设置的变量值。
local局部变量:
local 变量:任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大, 称为 local 变量。
Local 变量由于在不同的任务或不同的执行实例中,所以,作用域互不影响,变量名可以相同没有影响。
10.3 流程变量的使用方法
流程变量可以用来实现任务分配,也可以在任务与任务之间的连线上使用 UEL表达式 来实现流程的走向。
比如${day > 2 }和${day <= 2},day就是一个流程变量名称,UEL表达式的执行结果是布尔类型。
10.4 设置globa变量
在启动流程时设置流程变量,变量的作用域是整个流程实例。
@Test
public void startUpProcess() {
// ============ 通过 Map<key,value> 设置流程变量,map 中可以设置多个变量,这个 key 就是流程变量的名字 ================
Map<String, Object> variables = new HashMap<>();
variables.put("assignee1", "zhangsan");
variables.put("assignee2", "lisi");
variables.put("day", "3");
//创建流程实例,我们需要知道流程定义的key
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("qingjia", variables);
//输出实例的相关信息
System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
System.out.println("流程实例id:" + processInstance.getId());
}
10.5 设置local变量
local 流程变量的作用域只在当前任务节点下可用。当进⼊到下⼀个任务时,该局部变量失效。
任务办理时设置local流程变量,当前运行的流程实例只能在该任务结束前使用,任务结束该变量无法在当前流程实例使用
@Test
public void completLocalTask() {
Task task = taskService.createTaskQuery().taskAssignee("zhangsan").singleResult();//返回一条
// 设置local变量,作用域为该任务
taskService.setVariableLocal(task.getId(), "day", "3");
// 查看local变量
System.out.println(taskService.getVariableLocal(task.getId(), "day"));
//完成任务,参数:任务id
taskService.complete(task.getId());
}
11. 任务候选人设置
问题:如果任务负责⼈是单⼀存在的,且任务负责⼈因为默写原因没有办法完成任务,那么流程就没办法执⾏下去了。
解决:可以为任务设置候选⼈,通过候选⼈签收、归还(将签收的任务取消)、执⾏等操作解决单一负责人故障的问题。
11.1 如何设置候选人
// 部署流程图
@Test
public void test10() {
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
DeploymentBuilder builder = repositoryService.createDeployment();
Deployment deploy = builder
.addClasspathResource("bpmn/qingjia.bpmn")
.addClasspathResource("bpmn/qingjia.png")
.disableSchemaValidation()
.name("请假")
.deploy();
System.out.println("流程部署的id:" + deploy.getId()); // 流程部署的id:20001
System.out.println("流程name:" + deploy.getName()); // 流程name:请假
}
// 创建(启动)流程实例
@Test
public void test11() {
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// 获取流程部署信息
ProcessDefinition result = defaultProcessEngine.getRepositoryService().createProcessDefinitionQuery().deploymentId("20001").singleResult();
String id = result.getId();
String key = result.getKey();
System.out.println("流程定义ID:" + id); // 流程定义ID:myProcess_1:2:20004
System.out.println("流程定义KEY:" + key); // 流程定义KEY:myProcess_1
RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceById(result.getId());// 根据流程定义的ID创建流程实例
System.out.println(processInstance);
}
// 查询任务
@Test
public void test12() {
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// 查询任务
TaskService taskService = defaultProcessEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().processDefinitionId("myProcess_1:2:20004").list();
for (Task task : tasks) {
String processDefinitionId = task.getProcessDefinitionId(); // 流程定义ID
String processInstanceId = task.getProcessInstanceId(); // 流程实例ID
String taskDefinitionKey = task.getTaskDefinitionKey(); // 任务定义Key
String name = task.getName(); // 任务名称
String id = task.getId(); // 任务ID
System.out.println("流程定义ID:"+processDefinitionId); // 流程定义ID:myProcess_1:1:10004
System.out.println("流程实例ID:"+processInstanceId); // 流程实例ID:12501
System.out.println("任务定义Key:"+taskDefinitionKey); // 任务定义Key:_3
System.out.println("任务名称:"+name); // 任务名称:张三审批
System.out.println("任务ID:"+id); // 任务ID:12505
System.out.println("任务负责人:"+task.getAssignee()); // null
List<IdentityLink> list = taskService.getIdentityLinksForTask(task.getId());
for (IdentityLink identityLink : list) {
String userId = identityLink.getUserId();
System.out.println("该任务的任务候选人:" + userId); // zhangsan lisi
}
}
}
// 候选人lisi 签收任务
@Test
public void test13() {
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// 查询任务
TaskService taskService = defaultProcessEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().processDefinitionId("myProcess_1:2:20004").list();
for (Task task : tasks) {
String processDefinitionId = task.getProcessDefinitionId(); // 流程定义ID
String processInstanceId = task.getProcessInstanceId(); // 流程实例ID
String taskDefinitionKey = task.getTaskDefinitionKey(); // 任务定义Key
String name = task.getName(); // 任务名称
String id = task.getId(); // 任务ID
System.out.println("流程定义ID:"+processDefinitionId); // 流程定义ID:myProcess_1:2:20004
System.out.println("流程实例ID:"+processInstanceId); // 流程实例ID:22501
System.out.println("任务定义Key:"+taskDefinitionKey); // 任务定义Key:_3
System.out.println("任务名称:"+name); // 任务名称:发起请假审批
System.out.println("任务ID:"+id); // 任务ID:22505
System.out.println("任务负责人:"+task.getAssignee()); // null
// lisi签收任务
String user = "lisi";
taskService.claim(id, user); // 参数1:任务id 参数2:签收人
// 签收后查询任务负责人
System.out.println("任务签收后,负责人为:"+task.getAssignee()); // 任务签收后,负责人为:lisi
}
}
// 签收后,任务就归给签收人了。
// 结果候选人lisi 因一些原因现在不能完成该任务,要取消之前的签收操作。【实际上就是将该任务的负责人设置成null】
@Test
public void test14() {
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// 查询任务
TaskService taskService = defaultProcessEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().processDefinitionId("myProcess_1:2:20004").list();
for (Task task : tasks) {
String processDefinitionId = task.getProcessDefinitionId(); // 流程定义ID
String processInstanceId = task.getProcessInstanceId(); // 流程实例ID
String taskDefinitionKey = task.getTaskDefinitionKey(); // 任务定义Key
String name = task.getName(); // 任务名称
String id = task.getId(); // 任务ID
System.out.println("流程定义ID:"+processDefinitionId); // 流程定义ID:myProcess_1:2:20004
System.out.println("流程实例ID:"+processInstanceId); // 流程实例ID:22501
System.out.println("任务定义Key:"+taskDefinitionKey); // 任务定义Key:_3
System.out.println("任务名称:"+name); // 任务名称:发起请假审批
System.out.println("任务ID:"+id); // 任务ID:22505
System.out.println("当前任务负责人:"+task.getAssignee()); // 当前任务负责人:lisi
// lisi要退还任务。【本质就是将责任人设置称null】
// ★★★★★★★★★ 这里你也可以不设置成null,可以将任务转给其他人,如:taskService.setAssignee(task.getId(), zhangsan); 这样就表示将该任务的责任人变成zhangsan ★★★★★★★★★
taskService.setAssignee(task.getId(), null); // 参数1:任务ID 参数2:责任人
System.out.println("lisi退还任务后,任务负责人为:" + task.getAssignee()); // lisi退还任务后,任务负责人为:null
}
}
11. 网关
网关:用来控制流程的流向。
前面讲过可以通过流程变量来决定走向,这里又说可以通过网关来决定走向。他们之间的区别是什么?
流程变量决定走向:当出现都不满足的时候,流程就不会继续执行,也不报错。
网关决定走向:当都不满足的时候,流程就会报错。
网关分类:
- 排他网关X
- 并行网关+
- 包容网关⭕
- 事件网关
11.1 排他网关
排他网关:只有一条路径会被选择。如果有多个路径同时满足,只会执行第一个满足的。若都不满足,则会报错!
11.2 并行网关
并行网关:所有路径会被同时选择执行。只有当所有路径都执行完毕后,才会执行下一个节点任务。
与排他网关的主要区别是,并行网关不会解析条件。即使顺序流中定义了条件,也会被忽略。
场景:
请假申请开始,需要部门经理和总经理都审批,两者没有前后需要两个人全部审批才能进入下个节点人事审批。这个时候就需要并行网关
11.3 包容网关
包容网关:融合了排他网关与并行网关的特点。可以同时执行多条线路,且可以在网关上设置条件。 如果有多个线路同时执行时,只有当所有路径都执行完毕后,才会执行下一个节点任务。
场景:
请假申请大于等于2天需要由部门总经理审批,小于2天由部门经理审批,请假申请必须经过人事经理审批。这个时候就需要包容网关
12. springboot整合Activiti
12.1 引入依赖
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.1.0.M6</version>
</dependency>
12.2 配置文件
# 应⽤名称
spring.application.name=spring-boot-activiti-demo
# 应⽤服务 WEB 访问端⼝
server.port=8080
# 配置数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/activiti?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=qf123456
# 配置activiti
# true:activiti会对数据库中所有表进⾏更新操作。如果表不存在,则⾃动创建。
# flase: 默认值,activiti在启动时,会对⽐数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常。
spring.activiti.database-schema-update=true
# activiti7需要⼿动开启历史记录
spring.activiti.db-history-used=true
# 配置历史记录级别
# none:不保存任何的历史数据,因此,在流程执⾏过程中,这是最⾼效的。
# activity:级别⾼于none,保存流程实例与流程⾏为,其他数据不保存。
# audit:除activity级别会保存的数据外,还会保存全部的流程任务及其属性。audit为history的默认值。
# full:保存历史数据的最⾼级别,除了会保存audit级别的数据外,还会保存其他全部流程相关的细节数据,包括⼀些流程参数等。
spring.activiti.history-level=full
12.3 部署bpmn
在resources目录下创建目录:processes。并将流程图bpmn和png复制到该目录下。那么,activiti7框架将会自动进行部署!
12.4 创建流程实例
启动流程实例
@Test
public void test2(){
securityUtil.logInAs("王⼯");
ProcessInstance processInstance = processRuntime.start(ProcessPayloadBuilder.start().withProcessDefinitionKey("myProcess_1").build());
System.out.println("流程实例的id:"+processInstance.getId());
}
12.5 执行任务
// 完成任务
@Test
public void test3(){
securityUtil.logInAs("王⼯");
// 获得当前登陆⽤户的待处理的前10个任务
Page<Task> tasks = taskRuntime.tasks(Pageable.of(0,10));
if(tasks!=null && tasks.getTotalItems()>0){
for (Task task : tasks.getContent()) {
//执⾏任务
taskRuntime.complete(TaskPayloadBuilder.complete()
.withTaskId(task.getId()).build());
System.out.println("任务执⾏完成");
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗