前言
Flowable是一个使用Java编写的轻量级业务流程引擎,可以实现需要工作流的业务流程。
一、环境
1、引入依赖
引入 flowable 相关依赖
<!-- https://mvnrepository.com/artifact/org.flowable/flowable-spring-boot-starter -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.7.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/xerces/xercesImpl -->
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.12.2</version>
</dependency>
2、创建表
(1)自动创建表
打开配置
flowable.database-schema-update=true
自动创建表的语句都在各个模块的包下面
(2)手动创建表
下载官网的sql文件
https://documentation.flowable.com/latest/develop/dbs/overview
下载下来是db-scripts-3.11.0.zip,解压后如下图,从里面找出对应数据库的sql文件,导入到数据库中
数据库表如图所示:
3、配置文件
# standalone 模式
flowable.standalone.server.enabled=false
# 允许 bean overriding
spring.main.allow-bean-definition-overriding=true
# 关闭定时任务
flowable.async-executor-activate=false
# 检测身份信息
flowable.idm.enabled=false
# 生成数据库表
flowable.database-schema-update=false
二、bpmn文件
1、holiday-request.bpmn20.xml
将文件放在classpath下
<?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: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"
xmlns:flowable="http://flowable.org/bpmn"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.flowable.org/processdef">
<process id="holidayRequest" name="请假流程" isExecutable="true">
<!--开始事件-->
<startEvent id="startEvent"/>
<!--顺序流,从 startEvent 到 approveTask-->
<sequenceFlow sourceRef="startEvent" targetRef="approveTask"/>
<!--用户任务,需要 assignee 来审批-->
<userTask id="approveTask" name="同意或驳回请求" flowable:candidateGroups="managers" flowable:assignee="admin"/>
<!--顺序流,从 approveTask 到 decision -->
<sequenceFlow sourceRef="approveTask" targetRef="decision"/>
<!--排他网关-->
<exclusiveGateway id="decision"/>
<!--顺序流,从 decision 到 successCall-->
<sequenceFlow sourceRef="decision" targetRef="successCall">
<conditionExpression xsi:type="tFormalExpression">
<!--approved 为 true 时,该顺序流生效-->
<![CDATA[
${approved}
]]>
</conditionExpression>
</sequenceFlow>
<!--顺序流,从 decision 到 failedCall-->
<sequenceFlow sourceRef="decision" targetRef="failedCall">
<conditionExpression xsi:type="tFormalExpression">
<!--approved 为 false 时,该顺序流生效-->
<![CDATA[
${!approved}
]]>
</conditionExpression>
</sequenceFlow>
<!--服务任务,审批通过 -->
<serviceTask id="successCall" name="审批通过调用服务"
flowable:class="com.iscas.biz.flowable.ApprovalSuccessDelegate"/>
<sequenceFlow sourceRef="successCall" targetRef="holidayApprovedTask"/>
<userTask id="holidayApprovedTask" name="审批通过"/>
<sequenceFlow sourceRef="holidayApprovedTask" targetRef="approveEnd"/>
<!--服务任务,审批驳回 -->
<serviceTask id="failedCall" name="审批驳回调用服务"
flowable:class="com.iscas.biz.flowable.ApprovalFailDelegate"/>
<sequenceFlow sourceRef="failedCall" targetRef="rejectEnd"/>
<!--结束事件-->
<endEvent id="approveEnd"/>
<endEvent id="rejectEnd"/>
</process>
</definitions>
2、ApprovalSuccessDelegate
审批通过回调任务
public class ApprovalSuccessDelegate implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) {
System.out.println("审批通过了");
}
}
3、ApprovalFailedDelegate
审批驳回回调任务
public class ApprovalFailedDelegate implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) {
System.out.println("审批驳回了");
}
}
三、测试
1、测试类
@RunWith(SpringRunner.class)
@SpringBootTest(classes = BizApp.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class FlowableTest {
@Autowired
private RepositoryService repositoryService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Autowired
private HistoryService historyService;
}
2、部署流程
@Test
public void createDeployment() {
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("holiday-request.bpmn20.xml")
.deploy();
System.out.println(deployment.getId());
}
打印出流程id
ce2bb094-caaf-11ec-90e1-00ff2b067e93
3、获取流程定义
@Test
public void getProcessDefinition() {
ProcessDefinition result = repositoryService.createProcessDefinitionQuery()
.deploymentId("ce2bb094-caaf-11ec-90e1-00ff2b067e93")
.singleResult();
System.out.println("definitionId: " + result.getId());
System.out.println("definition: " + JsonUtils.toJson(result));
}
结果:
definitionId: holidayRequest:1:ce44dde6-caaf-11ec-90e1-00ff2b067e93
definition: {
"id":"holidayRequest:1:ce44dde6-caaf-11ec-90e1-00ff2b067e93",
"revision":1,
"isInserted":false,
"isUpdated":false,
"isDeleted":false,
"originalPersistentState":{
"suspensionState":1,
"category":"http://www.flowable.org/processdef"
},
"name":"请假流程",
"key":"holidayRequest",
"version":1,
"category":"http://www.flowable.org/processdef",
"deploymentId":"ce2bb094-caaf-11ec-90e1-00ff2b067e93",
"resourceName":"holiday-request.bpmn20.xml",
"tenantId":"",
"isGraphicalNotationDefined":false,
"hasStartFormKey":false,
"suspensionState":1,
"isIdentityLinksInitialized":false,
"definitionIdentityLinkEntities":[
],
"derivedVersion":0,
"suspended":false,
"graphicalNotationDefined":false,
"inserted":false,
"updated":false,
"deleted":false
}
4、启动流程
模拟用户发起一个请假流程
@Test
public void startProcessDefinition() {
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("employee", "张三");
variables.put("nrOfHolidays", 3);
variables.put("description", "有事请假");
ProcessInstance processInstance =
runtimeService.startProcessInstanceByKey("holidayRequest", variables);
}
5、获取任务
用户发起流程后,相关的人员能够查询该任务
@Test
public void getTask() {
List<Task> tasks = taskService.createTaskQuery()
.active()
.includeProcessVariables()
.taskCandidateOrAssigned("admin")
.list();
System.out.println("You have " + tasks.size() + " tasks:");
for (int i = 0; i < tasks.size(); i++) {
Task task = tasks.get(i);
System.out.println((i + 1) + ") " + "taskId: " + task.getId() + ", taskName: " + task.getName());
}
}
结果:
You have 1 tasks:
1) taskId: 696f2831-cab0-11ec-aa1d-00ff2b067e93, taskName: 同意或驳回请求
6、审批任务
查询到任务后,对任务进行审批
@Test
public void completeTask() {
Map variables = new HashMap<String, Object>();
variables.put("approved", true);
taskService.complete("696f2831-cab0-11ec-aa1d-00ff2b067e93", variables);
}
结果回调了 ApprovalSuccessDelegate ,打印出"审批通过了"
7、查询历史任务
任务完成审批以后,会作为历史任务存储起来
@Test
public void historyTask() {
List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
.taskAssignee("admin")
.finished()
.list();
list.stream().map(JsonUtils::toJson).forEach(System.out::println);
}
结果:
{
"id":"696c1af0-cab0-11ec-aa1d-00ff2b067e93",
"revision":2,
"isInserted":false,
"isUpdated":false,
"isDeleted":false,
"originalPersistentState":{
"executionId":"696b308d-cab0-11ec-aa1d-00ff2b067e93",
"activityId":"approveTask",
"transactionOrder":3,
"durationInMillis":134771,
"activityName":"同意或驳回请求",
"endTime":"2022-05-03 15:14:51",
"assignee":"admin",
"taskId":"696f2831-cab0-11ec-aa1d-00ff2b067e93"
},
"processInstanceId":"696a9449-cab0-11ec-aa1d-00ff2b067e93",
"processDefinitionId":"holidayRequest:1:ce44dde6-caaf-11ec-90e1-00ff2b067e93",
"startTime":"2022-05-03 15:12:37",
"endTime":"2022-05-03 15:14:51",
"durationInMillis":134771,
"transactionOrder":3,
"activityId":"approveTask",
"activityName":"同意或驳回请求",
"activityType":"userTask",
"executionId":"696b308d-cab0-11ec-aa1d-00ff2b067e93",
"assignee":"admin",
"taskId":"696f2831-cab0-11ec-aa1d-00ff2b067e93",
"tenantId":"",
"inserted":false,
"updated":false,
"deleted":false
}