目录
1、定义流程(画图)
2、Springboot部署流程
3、Springboot删除所有流程
4、Springboot根据 流程部署ID 查询 流程定义ID
5、Springboot启动(发起)流程
6、Springboot查询任务
6.1全部任务
6.2我的任务(代办任务)
7、springboot审批任务
1、审批通过
2、驳回
8、Springboot流程状态管理
1、流程定义
1、挂起《流程定义》
2、激活《流程定义》
2、流程实例
1、挂起《流程实例》
2、激活《流程实例》
9、资源
1.单元测试代码
2.xml代码
看了很多文档,总结一个完整的工作流包含以下步骤:
- 定义流程: 创建一个BPMN 2.0格式的流程定义文件。
- 部署流程: 将流程定义文件部署到Flowable引擎中。
- 启动流程实例: 使用部署好的流程定义启动一个新的流程实例。
- 执行任务: 查询和完成流程实例中的任务
ps:我使用的工具是 IDEA2019, 环境JDK8,Springboot版本2.5.15,Flowable版本6.8.0
大家先搞懂一个概念:是先有 流程定义 才会有 流程实例
1、定义流程(画图)
现在有很多优秀的画BPMN2.0开源系统。
我这里使用的是IDEA的插件:Flowable BPMN visualizer
安装好插件之后,在资源目录创建一个processes(flowable默认读取resources/processes下的流程文件)
创建BPMN文件
创建BPMN视图
开始画图:(整个流程必须是有一个起点,一个任务,一个终点)
我这里画一个请假流程:(开始-人事审核-主管审核-结束)
用户任务(UserTask)属性解释:
-
id:
- 描述:
User Task
的唯一标识符。 - 示例:
id="sid-bb849ec0-1482-4057-a447-c8d68adc9ca2"
- 描述:
-
name:
- 描述:
User Task
的显示名称。 - 示例:
name="人事审核"
- 描述:
-
assignee:
- 描述: 指定执行此任务的单个用户。
- 示例:
flowable:assignee="cpw"
-
candidateUsers:
- 描述: 任务的候选用户列表。这些用户都有资格完成任务。
- 示例:
flowable:candidateUsers="cpw,zhangsan,lisi" (通过逗号隔开)
-
candidateGroups:
- 描述: 任务的候选用户组列表。这些用户组中的用户都有资格完成任务。
- 示例:
flowable:candidateGroups="managers"
-
formKey:
- 描述: 指定与任务关联的表单的键,用于在任务执行时显示相应的表单。
- 示例:
flowable:formKey="approveForm"
-
dueDate:
- 描述: 任务的到期日期,可以是一个具体日期或相对时间表达式。
- 示例:
flowable:dueDate="${now() + 5 days}"
-
priority:
- 描述: 任务的优先级,数值越高表示优先级越高。
- 示例:
flowable:priority="50"
-
documentation:
- 描述: 任务的文档说明,可以提供任务的详细描述。
- 示例:
<documentation>This task requires approval from the manager.</documentation>
-
extensions:
- 描述: 自定义属性,可以添加额外的配置。例如,自定义表单字段或执行特定操作
连接节点
点击一个图案 按住拖动右上角的箭头进行连线
好了,完整的一个图出来了、完整的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:flowable="http://flowable.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.flowable.org/processdef">
<process id="flowDemo" name="flowDemo" isExecutable="true">
<startEvent id="sid-bb849ec0-1482-4057-a447-c8d68adc9ca2" name="开始"/>
<userTask id="sid-c30c0960-a986-4cd6-80e2-bae02d6af707" name="人事审核" flowable:assignee="cpw"></userTask>
<userTask id="sid-fc70937d-9773-4db8-acb3-a3af3e6ccb39" name="主管审核" flowable:assignee="zhuguan"/>
<endEvent id="sid-712aab8a-a060-4363-b3eb-cd3fa9215808"/>
<sequenceFlow id="sid-2c879163-8816-4dd7-89bb-bf1a4485fef4" sourceRef="sid-bb849ec0-1482-4057-a447-c8d68adc9ca2" targetRef="sid-c30c0960-a986-4cd6-80e2-bae02d6af707"/>
<sequenceFlow id="sid-2fca88ff-d597-430c-a5e9-edfefbdd2569" sourceRef="sid-c30c0960-a986-4cd6-80e2-bae02d6af707" targetRef="sid-fc70937d-9773-4db8-acb3-a3af3e6ccb39"/>
<sequenceFlow id="sid-e8b6c848-1c54-4fdb-a8b0-e085d715c906" sourceRef="sid-fc70937d-9773-4db8-acb3-a3af3e6ccb39" targetRef="sid-712aab8a-a060-4363-b3eb-cd3fa9215808"/>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_flowDemo">
<bpmndi:BPMNPlane bpmnElement="flowDemo" id="BPMNPlane_flowDemo">
<bpmndi:BPMNShape id="shape-d460f24b-1aac-4028-b625-929601acd3c0" bpmnElement="sid-bb849ec0-1482-4057-a447-c8d68adc9ca2">
<omgdc:Bounds x="-375.0" y="-37.25" width="30.0" height="30.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="shape-ad3ec780-dd25-42f1-8e53-6ed0608d5b91" bpmnElement="sid-c30c0960-a986-4cd6-80e2-bae02d6af707">
<omgdc:Bounds x="-282.75" y="-62.25" width="100.0" height="80.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="shape-2a1947d2-0365-4dd8-8083-9bdaa7bea300" bpmnElement="sid-fc70937d-9773-4db8-acb3-a3af3e6ccb39">
<omgdc:Bounds x="-134.25" y="-62.25" width="100.0" height="80.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="shape-c748377a-bdcd-4892-b001-3621cf05589a" bpmnElement="sid-712aab8a-a060-4363-b3eb-cd3fa9215808">
<omgdc:Bounds x="15.625" y="-37.25" width="30.0" height="30.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="edge-a51efb51-2d88-4eae-9ffe-baa2e50cd0e5" bpmnElement="sid-2c879163-8816-4dd7-89bb-bf1a4485fef4">
<omgdi:waypoint x="-345.0" y="-22.25"/>
<omgdi:waypoint x="-282.75" y="-22.25"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="edge-69253e56-2532-4829-b515-d27caeeb275a" bpmnElement="sid-2fca88ff-d597-430c-a5e9-edfefbdd2569">
<omgdi:waypoint x="-182.75" y="-22.25"/>
<omgdi:waypoint x="-134.25" y="-22.25"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="edge-86a73120-1957-453e-b988-7f2ede9f75dc" bpmnElement="sid-e8b6c848-1c54-4fdb-a8b0-e085d715c906">
<omgdi:waypoint x="-34.25" y="-22.25"/>
<omgdi:waypoint x="-10.011603" y="-22.25"/>
<omgdi:waypoint x="15.625" y="-22.25"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
2、Springboot部署流程
有两种使用Flowable类的方法:
第一种是使用ProcessEngine,它里面包含了所有flowable的核心类,我们可以查看源码:
第二种是直接使用***Service
有哪些Service可以查看flowable的jar包下engine里的Serivce类
现在开始部署流程:(使用Springboot单元测试)
@SpringBootTest
@DisplayName("流程测试")
public class UnitTest {
//第一种方法使用ProcessEngine
@Resource
private ProcessEngine processEngine;
//第二种方法使用若干个 ***Service
//@Autowired
//private RuntimeService runtimeService;
//@Autowired
//private RepositoryService repositoryServiceService;
@DisplayName("部署流程")
@Test
void deployFlow(){
Deployment deploy = processEngine.getRepositoryService().createDeployment() //创建部署对象
.addClasspathResource("processes/flowDemo.bpmn20.xml") // 默认是在resources/processes下寻找,当然你可以自定义目录
.name("第一个Flowable案例") //设置流程的名字
.deploy(); //deploy部署流程
System.out.println("部署流程ID为:"+deploy.getId()); //获取到当前流程的ID
}
}
运行结果:获取到部署成功的流程的ID
部署成功之后会涉及到以下数据表:
ACT_GE_BYTEARRAY
- 描述: 存储二进制数据,如流程定义的BPMN XML文件,PNG图片和其他附加数据。
ACT_RE_DEPLOYMENT
- 描述: 存储流程部署的信息。每次部署一个新版本的流程定义时,会在此表中创建一条记录。
ACT_RE_PROCDEF
- 描述: 存储流程定义的元数据,包括流程的ID、版本、名称和相关的部署ID。
部署成功之后查看 ACT_RE_DEPLOYMENT 表,你会发现创建的两条数据
因为项目启动时会自动部署flowable默认位置下的流程文件,所以会出现两个流程,这时候我们可以关闭自动部署。
可以根据你的需求加上以下配置:
flowable:
# 关闭定时任务
async-executor-activate: true
# 将databaseSchemaUpdate设置为true。如果Flowable发现数据库的结构与应用所需的结构不一致的时候,会自动帮你更新或者新增表或者表结构。
database-schema-update: true
# 项目启动时会自动部署默认位置下的流程文件,false表示不检查,true表示检查,默认为true
check-process-definitions: false
也可以根据需求更改存放路径和后缀名:
flowable.process-definition-location-prefix:classpath*:/processes/
flowable.process-definition-location-suffixes: **.bpmn20.xml,**.bpmn,
3、Springboot删除所有流程
@DisplayName("删除全部流程")
@Test
void deleteAllFlowable(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
// 删除所有流程定义
repositoryService.createProcessDefinitionQuery().list().forEach(pd ->
repositoryService.deleteDeployment(pd.getDeploymentId(), true)
);
System.out.println("删除成功");
}
4、Springboot根据 流程部署ID 查询 流程定义ID
注意:一个 流程部署ID 可以对应多个 流程定义ID
@DisplayName("根据 流程部署ID 查询 流程定义ID ")
@Test
void selectProcessByDeployId(){
String deployId = "dd77ca7c-554e-11ef-93dc-581122450312";//从上一个流程获取到的部署ID
List<ProcessDefinition> list = processEngine.getRepositoryService().createProcessDefinitionQuery().deploymentId(deployId).list();
for (ProcessDefinition processDefinition : list) {
System.out.println("deployId对应的流程定义ID为:"+processDefinition.getId());
}
}
运行结果:
流程定义ID由流程定义的name和一串uuid组成。
5、Springboot启动(发起)流程
启动流程有很多种方法,主要使用的是两种:一种是根据 流程定义的ID,一种是根据流程定义的KEY(标识)
最好是使用 流程定义ID(随机生成),因为KEY就是流程定义的名字可能会重复(实际业务中注意新增流程的时候,如果选择KEY来查询流程,记得做唯一判断)
PS:前面关于部署和定义使用的是RepositoryService,接下来操作流程则使用RuntimeService
@DisplayName("启动流程")
@Test
void startProcess(){
// 前面关于部署和定义使用的是RepositoryService,接下来操作流程则使用RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
// act_re_procdef(流程定义)表中的id
String processId = "flowDemo:1:dd9eb36f-554e-11ef-93dc-581122450312";
runtimeService.startProcessInstanceById(processId);
//String processKey = "flowDemo";
//runtimeService.startProcessInstanceByKey(processKey);
System.out.println("启动流程成功");
}
运行结果
启动流程后下面的表发生变化:
-
流程实例表 (
ACT_RU_EXECUTION
)- 记录流程实例的当前状态和运行时信息。
- 启动流程后,新增一条记录,记录新流程实例的信息。
-
任务表 (
ACT_RU_TASK
)- 记录运行时任务的信息。
- 如果启动流程后有用户任务,会在这个表中新增一条或多条任务记录。
-
历史流程实例表 (
ACT_HI_PROCINST
)- 记录历史流程实例的信息。
- 启动流程后,新增一条记录,用于记录历史流程实例的信息。
-
历史任务表 (
ACT_HI_TASKINST
)- 记录历史任务的信息。
- 如果启动流程后有用户任务,会在这个表中新增历史任务记录。
-
历史活动实例表 (
ACT_HI_ACTINST
)- 记录历史活动实例的信息。
- 启动流程后,每个活动节点(如任务、网关等)都会在这个表中新增一条记录。
-
任务参与者表 (
ACT_RU_IDENTITYLINK
)- 记录任务的参与者信息。
- 如果启动的流程涉及到任务分配,会在这个表中新增记录
6、Springboot查询任务
PS:涉及到任务则使用TaskService方法
6.1全部任务
@DisplayName("全部任务查询")
@Test
void findAllTask(){
List<Task> list = processEngine.getTaskService().createTaskQuery().list();
for (Task task : list) {
System.out.println("任务ID:"+task.getId()+"---任务名称:"+task.getName()+"---任务当前办理人:"+task.getAssignee());
}
}
运行结果:
6.2我的任务(代办任务)
@DisplayName("我的(代办)任务查询")
@Test
void findMyTask(){
//任务查询 通过TaskService来实现
TaskService taskService = processEngine.getTaskService();
List<Task> list = taskService.createTaskQuery().taskAssignee("cpw").list(); //流程设置的 用户任务的办理人--人事
//List<Task> list = taskService.createTaskQuery().taskAssignee("zhuguan").list(); //流程设置的 用户任务的办理人--主管
for (Task task : list) {
System.out.println("任务ID:"+task.getId()+"---任务名称:"+task.getName()+"---任务当前办理人:"+task.getAssignee());
}
}
7、springboot审批任务
发起流程之后,会从开始节点流到人事审核节点
根据上面查询到的任务ID进行操作:
1、审批通过
@DisplayName("任务审批通过")
@Test
void completeTask(){
//任务相关操作通过TaskService来实现
TaskService taskService = processEngine.getTaskService();
String taskId = "df2f8b51-5559-11ef-8d43-581122450312";
taskService.complete(taskId);
System.out.println("审批通过");
}
运行结果:
此时流程就会跑到:人事审核节点跑到了主管审核节点
验证:这时候我们查询一下主管的代办任务,就会发现任务跑到主管这里来了
@DisplayName("我的(代办)任务查询")
@Test
void findMyTask(){
//任务查询 通过TaskService来实现
TaskService taskService = processEngine.getTaskService();
//List<Task> list = taskService.createTaskQuery().taskAssignee("cpw").list(); //流程设置的 用户任务的办理人--人事
List<Task> list = taskService.createTaskQuery().taskAssignee("zhuguan").list(); //流程设置的 用户任务的办理人--主管
for (Task task : list) {
System.out.println("任务ID:"+task.getId()+"---任务名称:"+task.getName()+"---任务当前办理人:"+task.getAssignee());
}
}
审批任务影响以下表:
ACT_RU_TASK
表
-
操作: 删除任务记录。
-
描述: 当任务完成后,任务记录会从该表中删除。这个表存储的是正在运行的任务。
ACT_RU_IDENTITYLINK
表
-
操作: 删除相关任务的身份链接记录。
-
描述: 当任务完成后,相关的用户和组的身份链接记录会从该表中删除。这个表存储的是任务与用户/组之间的关系,如任务的分配者、候选人和参与者。
ACT_HI_TASKINST
表
-
操作: 插入或更新任务历史记录。
-
描述: 当任务完成后,会在该表中插入一条新的历史任务实例记录,或者更新现有的任务实例记录,以反映任务的完成时间和状态。
ACT_HI_ACTINST
表
-
操作: 插入或更新活动历史记录。
-
描述: 当任务完成后,会在该表中插入一条新的历史活动实例记录,或者更新现有的活动实例记录,以反映任务的完成。
ACT_HI_IDENTITYLINK
表
-
操作: 插入或更新身份链接历史记录。
-
描述: 当任务完成后,与任务相关的身份链接信息会在该表中插入新的历史记录或者更新现有的记录。
-----------------------------------------------------------------------------------------------------------------------
主管再次审批,则就到了结束节点即任务完成,act_ru表(流程运行实例表)相关的记录就会被完善
PS:注意在人事审核节点的时候任务审批通过之后,将会生成新的任务ID流向主管审核
2、驳回
我们再部署第二个流程来进行驳回操作,接下来重复简单讲解(因为上面的已经说完了)
部署流程:
查询流程:
发起流程:
查询我的任务:
审核任务:
好了,终于又回到主管审核节点~ 重头戏来了~
驳回:
根据业务驳回可以是驳回到上一个节点,或者是驳回到起点重新开始。
这里讲一下驳回到起点重新开始。
1、在查询任务的时候,我们加上查询当前任务的流程实例ID
@DisplayName("我的(代办)任务查询")
@Test
void findMyTask(){
//任务查询 通过TaskService来实现
TaskService taskService = processEngine.getTaskService();
//List<Task> list = taskService.createTaskQuery().taskAssignee("cpw").list(); //流程设置的 用户任务的办理人--人事
List<Task> list = taskService.createTaskQuery().taskAssignee("zhuguan").list(); //流程设置的 用户任务的办理人--主管
for (Task task : list) {
System.out.println("任务ID:"+task.getId()+"---任务名称:"+task.getName()+"---任务当前办理人:"+task.getAssignee()+"---任务的流程实例ID:"+task.getProcessInstanceId());
}
}
2、根据实例ID获取到流程实例,然后根据流程实例获取到流程定义,然后取消当前流程实例,重新启动新的流程实例 (驳回流程)
以下是运行的过程的参数变化:
运行结果:
验证:看看流程是否从 主管审核 退回到起点 人事审核
ok兄弟们,驳回成功
@DisplayName("任务驳回")
@Test
void rejectTask(){
String processInstanceId = "9cd07051-555d-11ef-ba69-581122450312";
RuntimeService runtimeService = processEngine.getRuntimeService();
RepositoryService repositoryService = processEngine.getRepositoryService();
// 获取当前流程实例
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(processInstanceId).singleResult();
System.out.println("获取当前流程实例:"+processInstance);
// 获取流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionId(processInstance.getProcessDefinitionId()).singleResult();
System.out.println("获取当前流程定义:"+processDefinition);
// 取消当前流程实例
runtimeService.deleteProcessInstance(processInstanceId, "驳回流程");
System.out.println("取消流程实例ID:"+processInstanceId);
// 启动新的流程实例
runtimeService.startProcessInstanceById(processDefinition.getId());
System.out.println("流程ID:"+processDefinition.getId()+"启动成功!!!");
}
8、Springboot流程状态管理
重要的事情说三遍:是先有 流程定义 才会有 流程实例 才会有 流程任务
PS:操作流程使用RepositoryService方法
1、流程定义
查询所有的流程定义
@DisplayName("查询流程定义状态")
@Test
void selectProcessDefinition(){
List<ProcessDefinition> list = processEngine.getRepositoryService().createProcessDefinitionQuery().list();
for (ProcessDefinition processDefinition : list) {
//流程定义是否挂起 false为否(fasle表示该流程定义的状态为:激活) true为是(true表示该流程定义的状态为:挂起)
System.out.println("流程定义的ID:"+processDefinition.getId()+"---流程定义的Name:"+processDefinition.getName()+"---该流程定义是否挂起:"+processDefinition.isSuspended());
}
}
运行结果:
processDefinition.isSuspended()查询流程定义是否挂起
false为否(fasle表示该流程定义的状态为:激活)
true为是(true表示该流程定义的状态为:挂起)
由此可以判断这两个《流程定义》都是激活状态
1、挂起《流程定义》
当一个流程定义被挂起时,新的流程实例将不能基于该流程定义启动,但已经运行的流程实例不受影响。
挂起流程定义主要有两种方法,一种是通过id 另一种是通过key,这里使用id来演示
@DisplayName("挂起流程定义")
@Test
void stopProcessDefinition(){
String processDefinitionId = "flowDemo2:1:82ce3927-555c-11ef-859f-581122450312";
processEngine.getRepositoryService().suspendProcessDefinitionById(processDefinitionId);
System.out.println("流程定义ID为:"+processDefinitionId+"挂起成功!");
}
运行结果:
检验:
第一种检验方法:
第二种方法:
当流程定义被挂起时,我们来测试一下新的流程实例能不能启动?
2、激活《流程定义》
当一个挂起的流程定义被激活时,新的流程实例可以基于该流程定义启动。
跟挂起流程定义同理,激活流程定义也是主要通过两种方法来激活(ID,KEY)
我们继续使用ID来激活:
@DisplayName("激活流程定义")
@Test
void startProcessDefinition(){
String processDefinitionId = "flowDemo2:1:82ce3927-555c-11ef-859f-581122450312";
processEngine.getRepositoryService().activateProcessDefinitionById(processDefinitionId);
System.out.println("流程定义ID为:"+processDefinitionId+"激活成功!");
}
运行结果:
检验:
好了,我好兄弟又激活回来了,我们来看看能否发起新的流程实例?
成功!
2、流程实例
操作流程实例使用RuntimeService方法
查询所有在运行的流程实例:
@DisplayName("查询流程实例状态")
@Test
void selectProcessInstance(){
List<ProcessInstance> list = processEngine.getRuntimeService().createProcessInstanceQuery().list();
for (ProcessInstance processInstance : list) {
//processDefinition.isSuspended()查询流程定义是否挂起 false为否(fasle表示该流程定义的状态为:激活) true为是(true表示该流程定义的状态为:挂起)
System.out.println("流程实例的ID:"+processInstance.getId()+"---流程实例的Name:"+processInstance.getName()+"---该流程实例是否挂起:"+processInstance.isSuspended());
}
}
运行结果:
1、挂起《流程实例》
当一个流程实例被挂起时,该实例中的任务将不能被执行,不能继续进行下一步的操作。
@DisplayName("挂起流程实例")
@Test
void stopProcessInstance(){
String processInstanceId = "93012f42-5569-11ef-bb69-581122450312";
processEngine.getRuntimeService().suspendProcessInstanceById(processInstanceId);
System.out.println("流程实例ID为:"+processInstanceId+"挂起成功!");
}
检验:
找到该挂起的流程实例下的用户任务,看看能否作业?
2、激活《流程实例》
当一个挂起的流程实例被激活时,该实例可以继续执行,进行下一步的操作。
@DisplayName("激活流程实例")
@Test
void startProcessInstance(){
String processInstanceId = "93012f42-5569-11ef-bb69-581122450312";
processEngine.getRuntimeService().activateProcessInstanceById(processInstanceId);
System.out.println("流程实例ID为:"+processInstanceId+"激活成功!");
}
运行结果:
检验:
那兄弟们再执行一下该流程实例的任务看看
OKOK 审批通过!!
完结撒花~~~~
----------------------------------------------------------------------------------------------------------------------------
9、资源
1.单元测试代码
附上全部测试代码:
@SpringBootTest
@DisplayName("流程测试")
public class UnitTest {
//第一种方法使用ProcessEngine
@Resource
private ProcessEngine processEngine;
//第二种方法使用若干个 ***Service
//@Autowired
//private RuntimeService runtimeService;
//@Autowired
//private RepositoryService repositoryServiceService;
@DisplayName("部署流程")
@Test
void deployFlow(){
Deployment deploy = processEngine.getRepositoryService().createDeployment() //创建部署对象
.addClasspathResource("processes/flowDemo2.bpmn20.xml") // 默认是在resources/processes下寻找,当然你可以自定义目录
.name("第二个Flowable案例") //设置流程的名字
.deploy(); //deploy部署流程
System.out.println("流程部署ID为:"+deploy.getId()); //获取到当前流程的ID
}
@DisplayName("根据 流程部署ID 查询 流程定义ID ")
@Test
void selectProcessByDeployId(){
String deployId = "82aa5d74-555c-11ef-859f-581122450312";//从上一个流程获取到的部署ID
List<ProcessDefinition> list = processEngine.getRepositoryService().createProcessDefinitionQuery().deploymentId(deployId).list();
for (ProcessDefinition processDefinition : list) {
System.out.println("deployId对应的流程定义ID为:"+processDefinition.getId());
}
}
@DisplayName("启动流程")
@Test
void startProcess(){
// 前面关于部署和定义使用的是RepositoryService,接下来操作流程则使用RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
// act_re_procdef(流程定义)表中的id
String processId = "flowDemo2:1:82ce3927-555c-11ef-859f-581122450312";
runtimeService.startProcessInstanceById(processId);
//String processKey = "flowDemo";
//runtimeService.startProcessInstanceByKey(processKey);
System.out.println("启动流程成功");
}
@DisplayName("全部任务查询")
@Test
void findAllTask(){
List<Task> list = processEngine.getTaskService().createTaskQuery().list();
for (Task task : list) {
System.out.println("任务ID:"+task.getId()+"---任务名称:"+task.getName()+"---任务办理人:"+task.getAssignee());
}
}
@DisplayName("我的(代办)任务查询")
@Test
void findMyTask(){
//任务查询 通过TaskService来实现
TaskService taskService = processEngine.getTaskService();
List<Task> list = taskService.createTaskQuery().taskAssignee("cpw").list(); //流程设置的 用户任务的办理人--人事
//List<Task> list = taskService.createTaskQuery().taskAssignee("zhuguan").list(); //流程设置的 用户任务的办理人--主管
for (Task task : list) {
System.out.println("任务ID:"+task.getId()+"---任务名称:"+task.getName()+"---任务当前办理人:"+task.getAssignee()+"---任务的流程实例ID:"+task.getProcessInstanceId());
}
}
@DisplayName("任务审批通过")
@Test
void completeTask(){
//任务相关操作通过TaskService来实现
TaskService taskService = processEngine.getTaskService();
String taskId = "93043c87-5569-11ef-bb69-581122450312";
taskService.complete(taskId);
System.out.println("审批通过");
}
@DisplayName("任务驳回")
@Test
void rejectTask(){
String processInstanceId = "9cd07051-555d-11ef-ba69-581122450312";
RuntimeService runtimeService = processEngine.getRuntimeService();
RepositoryService repositoryService = processEngine.getRepositoryService();
// 获取当前流程实例
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(processInstanceId).singleResult();
System.out.println("获取当前流程实例:"+processInstance);
// 获取流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionId(processInstance.getProcessDefinitionId()).singleResult();
System.out.println("获取当前流程定义:"+processDefinition);
// 取消当前流程实例
runtimeService.deleteProcessInstance(processInstanceId, "驳回流程");
System.out.println("取消流程实例ID:"+processInstanceId);
// 启动新的流程实例
runtimeService.startProcessInstanceById(processDefinition.getId());
System.out.println("流程ID:"+processDefinition.getId()+"启动成功!!!");
}
@DisplayName("查询流程定义状态")
@Test
void selectProcessDefinition(){
List<ProcessDefinition> list = processEngine.getRepositoryService().createProcessDefinitionQuery().list();
for (ProcessDefinition processDefinition : list) {
//processDefinition.isSuspended()查询流程定义是否挂起 false为否(fasle表示该流程定义的状态为:激活) true为是(true表示该流程定义的状态为:挂起)
System.out.println("流程定义的ID:"+processDefinition.getId()+"---流程定义的Name:"+processDefinition.getName()+"---该流程定义是否挂起:"+processDefinition.isSuspended());
}
}
@DisplayName("挂起流程定义")
@Test
void stopProcessDefinition(){
String processDefinitionId = "flowDemo2:1:82ce3927-555c-11ef-859f-581122450312";
processEngine.getRepositoryService().suspendProcessDefinitionById(processDefinitionId);
System.out.println("流程定义ID为:"+processDefinitionId+"挂起成功!");
}
@DisplayName("激活流程定义")
@Test
void startProcessDefinition(){
String processDefinitionId = "flowDemo2:1:82ce3927-555c-11ef-859f-581122450312";
processEngine.getRepositoryService().activateProcessDefinitionById(processDefinitionId);
System.out.println("流程定义ID为:"+processDefinitionId+"激活成功!");
}
@DisplayName("查询流程实例状态")
@Test
void selectProcessInstance(){
List<ProcessInstance> list = processEngine.getRuntimeService().createProcessInstanceQuery().list();
for (ProcessInstance processInstance : list) {
//processDefinition.isSuspended()查询流程定义是否挂起 false为否(fasle表示该流程定义的状态为:激活) true为是(true表示该流程定义的状态为:挂起)
System.out.println("流程实例的ID:"+processInstance.getId()+"---流程实例的Name:"+processInstance.getName()+"---该流程实例是否挂起:"+processInstance.isSuspended());
}
}
@DisplayName("挂起流程实例")
@Test
void stopProcessInstance(){
String processInstanceId = "93012f42-5569-11ef-bb69-581122450312";
processEngine.getRuntimeService().suspendProcessInstanceById(processInstanceId);
System.out.println("流程实例ID为:"+processInstanceId+"挂起成功!");
}
@DisplayName("激活流程实例")
@Test
void startProcessInstance(){
String processInstanceId = "93012f42-5569-11ef-bb69-581122450312";
processEngine.getRuntimeService().activateProcessInstanceById(processInstanceId);
System.out.println("流程实例ID为:"+processInstanceId+"激活成功!");
}
@DisplayName("删除全部流程")
@Test
void deleteAllFlowable(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
// 删除所有流程定义
repositoryService.createProcessDefinitionQuery().list().forEach(pd ->
repositoryService.deleteDeployment(pd.getDeploymentId(), true)
);
System.out.println("删除成功");
}
}
2.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:flowable="http://flowable.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.flowable.org/processdef">
<process id="flowDemo" name="flowDemo" isExecutable="true">
<startEvent id="sid-bb849ec0-1482-4057-a447-c8d68adc9ca2" name="开始"/>
<userTask id="sid-c30c0960-a986-4cd6-80e2-bae02d6af707" name="人事审核" flowable:assignee="cpw"></userTask>
<userTask id="sid-fc70937d-9773-4db8-acb3-a3af3e6ccb39" name="主管审核" flowable:assignee="zhuguan"/>
<endEvent id="sid-712aab8a-a060-4363-b3eb-cd3fa9215808"/>
<sequenceFlow id="sid-2c879163-8816-4dd7-89bb-bf1a4485fef4" sourceRef="sid-bb849ec0-1482-4057-a447-c8d68adc9ca2" targetRef="sid-c30c0960-a986-4cd6-80e2-bae02d6af707"/>
<sequenceFlow id="sid-2fca88ff-d597-430c-a5e9-edfefbdd2569" sourceRef="sid-c30c0960-a986-4cd6-80e2-bae02d6af707" targetRef="sid-fc70937d-9773-4db8-acb3-a3af3e6ccb39"/>
<sequenceFlow id="sid-e8b6c848-1c54-4fdb-a8b0-e085d715c906" sourceRef="sid-fc70937d-9773-4db8-acb3-a3af3e6ccb39" targetRef="sid-712aab8a-a060-4363-b3eb-cd3fa9215808"/>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_flowDemo">
<bpmndi:BPMNPlane bpmnElement="flowDemo2" id="BPMNPlane_flowDemo">
<bpmndi:BPMNShape id="shape-d460f24b-1aac-4028-b625-929601acd3c0" bpmnElement="sid-bb849ec0-1482-4057-a447-c8d68adc9ca2">
<omgdc:Bounds x="-375.0" y="-37.25" width="30.0" height="30.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="shape-ad3ec780-dd25-42f1-8e53-6ed0608d5b91" bpmnElement="sid-c30c0960-a986-4cd6-80e2-bae02d6af707">
<omgdc:Bounds x="-282.75" y="-62.25" width="100.0" height="80.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="shape-2a1947d2-0365-4dd8-8083-9bdaa7bea300" bpmnElement="sid-fc70937d-9773-4db8-acb3-a3af3e6ccb39">
<omgdc:Bounds x="-133.5509" y="-62.9491" width="100.0" height="80.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="shape-c748377a-bdcd-4892-b001-3621cf05589a" bpmnElement="sid-712aab8a-a060-4363-b3eb-cd3fa9215808">
<omgdc:Bounds x="15.625" y="-37.25" width="30.0" height="30.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="edge-a51efb51-2d88-4eae-9ffe-baa2e50cd0e5" bpmnElement="sid-2c879163-8816-4dd7-89bb-bf1a4485fef4">
<omgdi:waypoint x="-345.0" y="-22.25"/>
<omgdi:waypoint x="-282.75" y="-22.25"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="edge-69253e56-2532-4829-b515-d27caeeb275a" bpmnElement="sid-2fca88ff-d597-430c-a5e9-edfefbdd2569">
<omgdi:waypoint x="-182.75" y="-22.25"/>
<omgdi:waypoint x="-133.5509" y="-22.9491"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="edge-86a73120-1957-453e-b988-7f2ede9f75dc" bpmnElement="sid-e8b6c848-1c54-4fdb-a8b0-e085d715c906">
<omgdi:waypoint x="-33.550903" y="-22.9491"/>
<omgdi:waypoint x="-10.011603" y="-22.25"/>
<omgdi:waypoint x="15.625" y="-22.25"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>