一文精通flowable并使用springboot整合flowable工作流(最完整版本)
2025-06-24 12:08:43
来源:新华网
好文推荐:
jdk8之stream流式编程
2.5万字讲解DDD领域驱动设计(史上最全DDD)
springboot 实现延时队列(超级实用)
2.5万字详解23种设计模式
目录
- 1. 前言
- 2. 背景
- 3. flowable相关概念
- 3.1 流程定义:
- 3.2 流程实例:
- 3.3 任务:
- 3.4 网关:
- 3.5 条件表达式
- 3.6 边界事件
- 4. 配置工作流模型
- 4.1 请假工作流示意图
- 4.2 使用idea插件Flowable BPMN visualizer
- 4.3 插件里面的工具介绍
- 5. springboot集成flowable
- 5.1 pom依赖文件
- 3.2 application.yml
- 5.3 flowable 配置文件
- 5.4 流程任务实体
- 5.5 bpmn20.xml文件
- 5.6 核心功能类
- 6. 多租户flowable数据隔离
- 7. 总结
1. 前言
目前工作流框架最火的就是Activiti和Flowable,该文章介绍如何使用flowable,如果不想看理论的概念,可以直接跳到第五部分springboot集成flowable,或者文末直接获取代码!!!
2. 背景
Flowable起源于Activiti工作流引擎,由Activiti的主要开发者在2016年创建。它继承了Activiti的众多优点,并在此基础上进行了优化和改进,以提供更加稳定、高效的工作流管理解决方案。Flowable与Activiti有着共同的祖先,即jbpm,并随着技术的发展和需求的变化,逐渐发展成为独立且功能强大的工作流引擎。
应用场景:Flowable广泛应用于各种需要流程管理的场景,如人力资源管理(如员工入职、离职、请假、绩效评估等)、自动化业务流程(如财务审批、采购流程、销售订单处理等)、任务管理和分配等。在由流程驱动的各种系统中,如OA、CRM、ERP、ECM、BI等,Flowable都能发挥重要作用。
优势:轻量级与高效:Flowable是一个轻量级的引擎,启动快,内存占用小,非常适合在微服务架构中使用。
全面支持BPMN 2.0标准:允许使用标准化的方式来定义和执行流程,提高了流程的兼容性和可移植性。
丰富的API和可视化设计工具:降低了与其他系统的集成难度,提高了业务流程的建模和编辑效率。
良好的社区支持和文档:作为一个活跃的开源项目,Flowable拥有良好的社区支持和不断更新的文档,用户可以在社区中获取帮助和分享经验。
3. flowable相关概念
Flowable是一个功能强大的业务流程管理引擎,支持BPMN 2.0标准。以下是对Flowable相关概念的具体介绍:
3.1 流程定义:
流程定义(Process Definition)是使用BPMN 2.0标准的XML格式描述的,它包含了流程中的节点、连接线和事件等元素。
对应的类:org.flowable.engine.repository.ProcessDefinition
3.2 流程实例:
流程实例(Process Instance)当一个流程定义被启动时,会创建一个流程实例,这个实例将按照定义的流程节点顺序执行。
对应的类:org.flowable.engine.runtime.ProcessInstance
3.3 任务:
任务(Task)是流程实例中的一个执行单元,代表需要由用户或系统自动完成的操作。在Flowable中,任务可以是用户任务、服务任务、脚本任务等多种类型。
对应的类:org.flowable.engine.task.Task
3.4 网关:
网关(Gateway)用于控制流程的执行方向,Flowable支持多种类型的网关,如排他网关和并行网关等。排他网关用于在多个分支中选择一个分支进行执行,而并行网关则用于将流程拆分为多个并行执行的分支。
对应的类:
org.flowable.bpmn.model.ParallelGateway(并行网关)
org.flowable.bpmn.model.ExclusiveGateway(排他网关)
3.5 条件表达式
条件表达式(Conditional Expression):Flowable支持使用条件表达式来控制流程的执行方向。条件表达式使用Java的语法,可以在排他网关等地方使用,根据条件表达式的值来决定流程应该走向哪个分支。
3.6 边界事件
边界事件(Boundary Event):边界事件可以捕获流程中的错误或异常事件,并在事件发生时执行相应的处理逻辑。例如,可以在用户任务中添加一个错误边界事件,当用户任务执行失败时,触发错误边界事件进行错误处理。
对应的类:
org.flowable.bpmn.model.StartEvent(开始事件)
org.flowable.bpmn.model.EndEvent(结束事件)
org.flowable.bpmn.model.BoundaryEvent(边界事件)
总的来说,Flowable作为一个轻量级的业务流程引擎,提供了丰富的流程控制元素和灵活的扩展机制,通过掌握其核心概念和常见问题的解决方案,开发者可以更加高效地构建工作流应用,提高业务流程的自动化水平和执行效率。
4. 配置工作流模型
4.1 请假工作流示意图
员工请假案例:
4.2 使用idea插件Flowable BPMN visualizer
Flowable BPMN visualizer是一款为IntelliJ IDEA系列IDE设计的插件,它提供了一个强大的BPMN(Business Process Model and Notation,即业务流程模型和表示法)模型编辑工具.
- 安装idea插件Flowable BPMN visualizer
- 在resources文件夹下创建文件夹processes
- 然后创建文件leave.bpmn20.xml
- 选中leave.bpmn20.xml文件右键选择View BPMN (Flowable) Diagram
- 然后就可以开始制作流程图了,右键会有各种工具
重要的工具已标出
4.3 插件里面的工具介绍
右键会出现各种工具
- Start Events(开始事件)
Start Event: 流程的起点,手动触发。(重要)
Start Conditional Event: 条件满足时自动触发。
Start Message Event: 接收到特定消息时自动触发。
Start Error Event: 发生指定错误时自动触发。
Start Escalation Event: 需要升级或转交给更高级别人员时自动触发。
Start Signal Event: 接收到特定信号时自动触发。
Start Timer Event: 经过特定时间后自动触发。 - Activities(活动)
Task: 用户执行的任务,如审批、填写表单等。
Service Task: 系统自动执行的任务,如调用外部服务。
User Task: 分配给用户执行的任务。(重要)
Script Task: 使用脚本语言(如Groovy、JavaScript)编写的自定义任务。
Business Rule Task: 基于业务规则引擎执行的任务。
Manual Task: 需要人工干预的任务。 - Structural(结构)
Subprocess: 子流程,表示一个嵌套的流程。
Transaction: 事务,确保一组操作要么全部成功,要么全部失败。
Ad-hoc Subprocess: 临时子流程,可以在运行时动态创建。
Event Subprocess: 事件子流程,与特定事件相关联。 - Gateways(网关)
Exclusive Gateway: 排他网关,根据条件选择一条路径执行。(重要)
Parallel Gateway: 并行网关,将流程分成多个并行分支。
Inclusive Gateway: 包容网关,允许多条路径同时执行。
Complex Gateway: 复杂网关,结合了排他网关和并行网关的特性。 - Boundary Events(边界事件)
Boundary Timer Event: 定时边界事件,当到达指定时间点时触发。
Boundary Error Event: 错误边界事件,当发生指定错误时触发。
Boundary Signal Event: 信号边界事件,当接收到指定信号时触发。
Boundary Message Event: 消息边界事件,当接收到指定消息时触发。
Boundary Cancel Event: 取消边界事件,当流程被取消时触发。
Boundary Compensation Event: 补偿边界事件,用于处理补偿逻辑。 - Intermediate Catching Events(中间捕获事件)
Intermediate Message Event: 中间消息事件,等待接收到特定消息时触发。
Intermediate Timer Event: 中间定时事件,等待到达指定时间点时触发。
Intermediate Signal Event: 中间信号事件,等待接收到特定信号时触发。
Intermediate Conditional Event: 中间条件事件,等待满足特定条件时触发。 - Intermediate Throwing Events(中间抛出事件)
Intermediate Message Throw Event: 中间消息抛出事件,发送消息给其他流程或系统。
Intermediate Signal Throw Event: 中间信号抛出事件,发送信号给其他流程或系统。
Intermediate Escalation Event: 中间升级事件,将问题升级或转交给更高级别的人员或系统。
Intermediate Link Event: 中间链接事件,用于跨流程的通信。 - End Events(结束事件)
End Event: 流程的正常结束点。(重要)
Error End Event: 流程的错误结束点。
Escalation End Event: 流程的升级结束点。
Message End Event: 流程的消息结束点,发送消息给其他流程或系统。
Signal End Event: 流程的信号结束点,发送信号给其他流程或系统。
Terminate End Event: 流程的终止结束点,强制终止流程。 - Save to PNG
Save to PNG: 将当前BPMN模型保存为PNG格式的图片文件,便于分享和展示。
5. springboot集成flowable
5.1 pom依赖文件
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.2</version><relativePath/></parent><dependencies><!-- 工作流flowable jar包 --><dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>6.7.2</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!--Mybatis-Plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId><version>3.5.2</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.8</version></dependency></dependencies>
3.2 application.yml
# 工作流 Flowable配置flowable:check-process-definitions:true# 设置为 false,禁用 /resources/processes 自动部署 BPMN XML 流程 history-level:full # full:保存历史数据的最高级别,可保存全部流程相关细节,包括流程流转各节点参数 #关闭定时任务JOB async-executor-activate:false
5.3 flowable 配置文件
importorg.flowable.spring.SpringProcessEngineConfiguration;importorg.flowable.spring.boot.EngineConfigurationConfigurer;importorg.springframework.context.annotation.Configuration;/** * flowable配置 */@ConfigurationpublicclassFlowableConfigimplementsEngineConfigurationConfigurer<SpringProcessEngineConfiguration>{ @Overridepublicvoidconfigure(SpringProcessEngineConfigurationengineConfiguration){ engineConfiguration.setActivityFontName("宋体");engineConfiguration.setLabelFontName("宋体");engineConfiguration.setAnnotationFontName("宋体");}}
5.4 流程任务实体
importlombok.Data;importjava.util.Map;/** * @author wdyin * @date 2024/11/15 **/@DatapublicclassTaskVo{ /** * 任务id */privateStringtaskId;/** * 任务名称 */privateStringtaskName;/** * 流程实例id */privateStringprocessInstanceId;/** * 流程变量 */Map<String,Object>processVariables;}
5.5 bpmn20.xml文件
leave.bpmn20.xml,工作流模型配置请看第四部分使用idea插件可视化制作工作流模型
<?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="leave"name="leave"isExecutable="true"><startEvent id="sid-7271f156-c78c-403a-9d19-73ccbfdd9881"name="开始请假流程"><documentation>员工开始请假流程</documentation></startEvent><userTask id="sid-bd605c32-03cb-4e04-86cb-fa93d7e5ef83"name="请假申请"flowable:assignee="${ assignee}"><documentation>员工请假申请</documentation></userTask><sequenceFlow id="sid-ae7fd113-b1b7-4dc8-a276-f7355ef22d5c"sourceRef="sid-7271f156-c78c-403a-9d19-73ccbfdd9881"targetRef="sid-bd605c32-03cb-4e04-86cb-fa93d7e5ef83"name="流程开始"><documentation>流程开始</documentation></sequenceFlow><userTask id="sid-617c05f7-8e8d-4734-b831-f601443701df"name="领导审批"flowable:assignee="${ assignee}"><documentation>领导审批</documentation></userTask><sequenceFlow id="sid-53772e79-4146-49d9-a04e-fefefccfe21d"sourceRef="sid-bd605c32-03cb-4e04-86cb-fa93d7e5ef83"targetRef="sid-617c05f7-8e8d-4734-b831-f601443701df"name="申请流程"/><sequenceFlow id="sid-5b9c0f8c-594b-4dac-a07d-0ef68f5b0b54"sourceRef="sid-617c05f7-8e8d-4734-b831-f601443701df"targetRef="sid-bd605c32-03cb-4e04-86cb-fa93d7e5ef83"name="领导审批驳回"><conditionExpression xsi:type="tFormalExpression">${ result==false}</conditionExpression></sequenceFlow><exclusiveGateway id="sid-cb1bce6f-ecef-48aa-b4cb-7dee1f76fdb6"/><sequenceFlow id="sid-f433236a-6e6f-46ba-9799-b240cf151d76"sourceRef="sid-617c05f7-8e8d-4734-b831-f601443701df"targetRef="sid-cb1bce6f-ecef-48aa-b4cb-7dee1f76fdb6"name="领导审批通过"><conditionExpression xsi:type="tFormalExpression">${ result==true}</conditionExpression></sequenceFlow><endEvent id="sid-68b72d73-e005-4403-b454-5c8f5d99745d"/><sequenceFlow id="sid-575778a8-b18b-4542-b11a-dd2965b09a30"sourceRef="sid-cb1bce6f-ecef-48aa-b4cb-7dee1f76fdb6"targetRef="sid-68b72d73-e005-4403-b454-5c8f5d99745d"name="请假小于两天"><conditionExpression xsi:type="tFormalExpression">${ day<2}</conditionExpression></sequenceFlow><userTask id="sid-afa9dbd8-3aaf-44a5-8ae0-c2035cb2a698"name="老板审批"flowable:assignee="${ assignee}"><documentation>老板审批</documentation></userTask><sequenceFlow id="sid-30725bf0-64b7-45b5-a14b-914c27462e2d"sourceRef="sid-cb1bce6f-ecef-48aa-b4cb-7dee1f76fdb6"targetRef="sid-afa9dbd8-3aaf-44a5-8ae0-c2035cb2a698"name="请假大于等于两天"><conditionExpression xsi:type="tFormalExpression">${ day>=2}</conditionExpression></sequenceFlow><sequenceFlow id="sid-9b841925-57c1-4e6b-8ec8-ac4a58d2b80c"sourceRef="sid-afa9dbd8-3aaf-44a5-8ae0-c2035cb2a698"targetRef="sid-68b72d73-e005-4403-b454-5c8f5d99745d"name="老板审批通过"><documentation>老板不同意</documentation><conditionExpression xsi:type="tFormalExpression">${ result==true}</conditionExpression></sequenceFlow><sequenceFlow id="sid-0d2f0355-dded-45a9-8474-84893afae40d"sourceRef="sid-afa9dbd8-3aaf-44a5-8ae0-c2035cb2a698"targetRef="sid-7271f156-c78c-403a-9d19-73ccbfdd9881"name="老板审批驳回"><conditionExpression xsi:type="tFormalExpression">${ result==false}</conditionExpression></sequenceFlow></process><bpmndi:BPMNDiagram id="BPMNDiagram_leave"><bpmndi:BPMNPlane bpmnElement="leave"id="BPMNPlane_leave"><bpmndi:BPMNShape id="shape-bc3b6696-4835-4f6e-9458-e77ba9666cac"bpmnElement="sid-7271f156-c78c-403a-9d19-73ccbfdd9881"><omgdc:Bounds x="-330.0"y="-170.0"width="30.0"height="30.0"/></bpmndi:BPMNShape><bpmndi:BPMNShape id="shape-2ccaef2e-ca0c-43d9-9965-d0eda82b2633"bpmnElement="sid-bd605c32-03cb-4e04-86cb-fa93d7e5ef83"><omgdc:Bounds x="-275.0"y="-180.0"width="55.0"height="50.0"/></bpmndi:BPMNShape><bpmndi:BPMNEdge id="edge-9f7f9b61-5efe-4203-9010-822a74a103ce"bpmnElement="sid-ae7fd113-b1b7-4dc8-a276-f7355ef22d5c"><omgdi:waypoint x="-300.0"y="-155.0"/><omgdi:waypoint x="-275.0"y="-155.0"/></bpmndi:BPMNEdge><bpmndi:BPMNShape id="sid-d4255997-664d-4c6d-903b-38c48a453d09"bpmnElement="sid-617c05f7-8e8d-4734-b831-f601443701df"><omgdc:Bounds x="-178.5"y="-180.0"width="55.0"height="50.0"/></bpmndi:BPMNShape><bpmndi:BPMNEdge id="edge-a0b9bc01-a881-4f1f-87e0-363c0d904811"bpmnElement="sid-53772e79-4146-49d9-a04e-fefefccfe21d"><omgdi:waypoint x="-220.0"y="-155.0"/><omgdi:waypoint x="-178.5"y="-155.0"/></bpmndi:BPMNEdge><bpmndi:BPMNEdge id="edge-1cd38e63-1d71-4aea-b340-5ca4886333b3"bpmnElement="sid-5b9c0f8c-594b-4dac-a07d-0ef68f5b0b54"><omgdi:waypoint x="-151.0"y="-180.0"/><omgdi:waypoint x="-151.0"y="-222.5"/><omgdi:waypoint x="-247.5"y="-222.5"/><omgdi:waypoint x="-247.5"y="-180.0"/></bpmndi:BPMNEdge><bpmndi:BPMNShape id="shape-8f3a8a11-80b2-43cc-b754-ee73faf7c91c"bpmnElement="sid-cb1bce6f-ecef-48aa-b4cb-7dee1f76fdb6"><omgdc:Bounds x="-75.0"y="-175.0"width="40.0"height="40.0"/></bpmndi:BPMNShape><bpmndi:BPMNEdge id="edge-2459964a-c3e5-49a9-b182-0a1a9f1576b2"bpmnElement="sid-f433236a-6e6f-46ba-9799-b240cf151d76"><omgdi:waypoint x="-123.5"y="-155.0"/><omgdi:waypoint x="-75.0"y="-155.0"/></bpmndi:BPMNEdge><bpmndi:BPMNShape id="shape-b4874158-c2df-4d2a-8467-21cc5488e5f6"bpmnElement="sid-68b72d73-e005-4403-b454-5c8f5d99745d"><omgdc:Bounds x="10.0"y="-170.0"width="30.0"height="30.0"/></bpmndi:BPMNShape><bpmndi:BPMNEdge id="edge-793e0ef5-d447-41b5-8aa7-ebbfd9ea0ce8"bpmnElement="sid-575778a8-b18b-4542-b11a-dd2965b09a30"><omgdi:waypoint x="-35.0"y="-155.0"/><omgdi:waypoint x="10.0"y="-155.0"/></bpmndi:BPMNEdge><bpmndi:BPMNShape id="sid-1a7cb41a-8eb2-4db9-9237-7ab7d1d802ce"bpmnElement="sid-afa9dbd8-3aaf-44a5-8ae0-c2035cb2a698"><omgdc:Bounds x="-82.5"y="-82.25"width="55.0"height="50.0"/></bpmndi:BPMNShape><bpmndi:BPMNEdge id="edge-781d3fc5-dea4-4ec3-8741-1adcc1a03995"bpmnElement="sid-30725bf0-64b7-45b5-a14b-914c27462e2d"><omgdi:waypoint x="-55.0"y="-135.0"/><omgdi:waypoint x="-55.0"y="-108.625"/><omgdi:waypoint x="-55.0"y="-82.25"/></bpmndi:BPMNEdge><bpmndi:BPMNEdge id="edge-2dbcc4cc-2d70-41f1-9afe-b0e45bf598f4"bpmnElement="sid-9b841925-57c1-4e6b-8ec8-ac4a58d2b80c"><omgdi:waypoint x="-27.5"y="-57.25"/><omgdi:waypoint x="25.0"y="-57.25"/><omgdi:waypoint x="25.0"y="-140.0"/></bpmndi:BPMNEdge><bpmndi:BPMNEdge id="edge-18d2af23-bed9-4368-8f47-021d2fa60d01"bpmnElement="sid-0d2f0355-dded-45a9-8474-84893afae40d"><omgdi:waypoint x="-82.5"y="-57.25"/><omgdi:waypoint x="-315.0"y="-57.25"/><omgdi:waypoint x="-315.0"y="-140.0"/></bpmndi:BPMNEdge></bpmndi:BPMNPlane></bpmndi:BPMNDiagram></definitions>
5.6 核心功能类
实现功能如下
- 查询流程定义列表
- 创建请假审批流程
- 审批流程列表
- 提交审批流程
- 历史流程列表
- 删除流程
- 领导待办任务
- 领导已办任务
- 领导批准
- 领导拒绝
- 老板待办任务
- 老板批准
- 老板拒绝
- 员工再次申请请假
- 生成流程图
代码如下
importcom.wander.flowable.vo.TaskVo;importlombok.extern.slf4j.Slf4j;importorg.flowable.bpmn.model.BpmnModel;importorg.flowable.engine.*;importorg.flowable.engine.history.HistoricProcessInstance;importorg.flowable.engine.history.HistoricProcessInstanceQuery;importorg.flowable.engine.repository.ProcessDefinition;importorg.flowable.engine.runtime.Execution;importorg.flowable.engine.runtime.ProcessInstance;importorg.flowable.image.ProcessDiagramGenerator;importorg.flowable.task.api.Task;importorg.flowable.task.api.history.HistoricTaskInstance;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.*;importjavax.imageio.ImageIO;importjavax.servlet.http.HttpServletResponse;importjava.awt.image.BufferedImage;importjava.io.IOException;importjava.io.InputStream;importjava.io.OutputStream;importjava.util.*;importjava.util.stream.Collectors;/** * @author wdyin * @date 2024/11/13 **/@RestController@RequestMapping("/flowable/test")@Slf4jpublicclassFlowableTestController{ @AutowiredprivateRuntimeServiceruntimeService;@AutowiredprivateTaskServicetaskService;@AutowiredprivateRepositoryServicerepositoryService;@AutowiredprivateProcessEngineprocessEngine;/** * 对应leave.bpmn20.xml文件中process标签的id属性 */privateStringprocessKey ="leave";/** * 1. 查询流程定义列表 */@GetMapping("/processDefinitionList")publicvoidprocessDefinitionList(){ List<ProcessDefinition>processDefinitions =repositoryService.createProcessDefinitionQuery().list();for(ProcessDefinitionprocessDefinition :processDefinitions){ log.info("部署id:{ },流程定义id:{ },流程定义名称:{ }",processDefinition.getDeploymentId(),processDefinition.getId(),processDefinition.getName());}}/** * 2. 创建请假审批流程 * * @param day 请假天数 * @param employeeId 员工id * @return */@PostMapping("/start/{ day}/{ employeeId}")publicvoidstart(@PathVariable("day")Integerday,@PathVariable("employeeId")StringemployeeId){ Map<String,Object>variables =newHashMap<>();variables.put("day",day);variables.put("employeeId",employeeId);//assignee表示流程的办理人variables.put("assignee",employeeId);ProcessInstanceprocessInstance =runtimeService.startProcessInstanceByKey(processKey,variables);runtimeService.updateBusinessStatus(processInstance.getId(),"未审批");log.info("流程实例ID:{ }",processInstance.getId());}/** * 3. 审批流程列表 * * @return */@DeleteMapping("/processList")publicvoidprocessList(){ List<ProcessInstance>processInstances =runtimeService.createProcessInstanceQuery().list();for(ProcessInstanceprocessInstance :processInstances){ log.info("流程实例ID:{ }, 流程状态:{ }",processInstance.getId(),processInstance.getBusinessStatus());}}/** * 4. 提交审批流程 * * @param processInstanceId 流程实例ID * @param employeeId 员工ID * @param leaderId 领导ID */@PostMapping("/submit/{ processInstanceId}/{ employeeId}/{ leaderId}")publicvoidsubmit(@PathVariable("processInstanceId")StringprocessInstanceId,@PathVariable("employeeId")StringemployeeId,@PathVariable("leaderId")StringleaderId){ log.info("流程实例ID:"+processInstanceId);//查询自己的审批流程Tasktask =taskService.createTaskQuery().processInstanceId(processInstanceId).taskAssignee(employeeId).singleResult();Map<String,Object>variables =newHashMap<>();//交给哪位领导审批variables.put("assignee",leaderId);//提交请假审批流程taskService.complete(task.getId(),variables);//修改请假流程的状态runtimeService.updateBusinessStatus(processInstanceId,"审批中");log.info("流程id:{ },任务id:{ },",processInstanceId,task.getId(),"审批中");}/** * 5. 历史流程列表 * * @return */@DeleteMapping("/historicProcessInstanceList")publicvoidhistoricProcessInstanceList(){ HistoricProcessInstanceQueryquery =processEngine.getHistoryService().createHistoricProcessInstanceQuery();List<HistoricProcessInstance>historicProcessInstances =query.list();historicProcessInstances.forEach(historicProcessInstance ->{ log.info("历史流程列表ID:{ },流程状态:{ }",historicProcessInstance.getId(),historicProcessInstance.getBusinessStatus());});}/** * 6. 删除流程 * * @param id 流程id * @return */@DeleteMapping("/process/delete/{ id}")publicvoidprocessDelete(@PathVariable("id")Stringid){ runtimeService.deleteProcessInstance(id,"删除流程");log.info("删除该流程{ }",id);}/** * 7. 领导待办任务 * * @return */@GetMapping("/leaderTodoList/{ leaderId}")publicvoidleaderTodoList(@PathVariable("leaderId")StringleaderId){ List<Task>tasks =taskService.createTaskQuery().taskAssignee(leaderId).list();List<TaskVo>taskVoList =tasks.stream().map(task ->{ TaskVotaskVo =newTaskVo();taskVo.setTaskId(task.getId());taskVo.setTaskName(task.getName());taskVo.setProcessInstanceId(task.getProcessInstanceId());Map<String,Object>processVariables =processEngine.getHistoryService().createHistoricVariableInstanceQuery().processInstanceId(task.getProcessInstanceId()).list().stream().collect(Collectors.toMap(var->var.getVariableName(),var->var.getValue()));taskVo.setProcessVariables(processVariables);returntaskVo;}).collect(Collectors.toList());log.info("领导任务列表:"+taskVoList);}/** * 8. 领导已办任务 */@GetMapping("/leaderDoneList/{ leaderId}")publicvoidleaderDoneList(@PathVariable("leaderId")StringleaderId){ List<HistoricTaskInstance>historicTaskInstanceList =processEngine.getHistoryService().createHistoricTaskInstanceQuery().taskAssignee(leaderId).list();List<TaskVo>taskVoList =historicTaskInstanceList.stream().map(task ->{ TaskVotaskVo =newTaskVo();taskVo.setTaskId(task.getId());taskVo.setTaskName(task.getName());Map<String,Object>processVariables =processEngine.getHistoryService().createHistoricVariableInstanceQuery().processInstanceId(task.getProcessInstanceId()).list().stream().collect(Collectors.toMap(var->var.getVariableName(),var->var.getValue()));taskVo.setProcessVariables(processVariables);returntaskVo;}).collect(Collectors.toList());log.info("已办任务:"+taskVoList);}/** * 9. 领导批准 * * @param taskId 任务ID,非流程id */@GetMapping("/leaderApply/{ taskId}/{ bossId}")publicvoidleaderApply(@PathVariable("taskId")StringtaskId,@PathVariable("bossId")StringbossId){ Tasktask =taskService.createTaskQuery().taskId(taskId).taskAssignee("2000").singleResult();Map<String,Object>variables =newHashMap<>();variables.put("assignee",bossId);variables.put("result",true);taskService.complete(task.getId(),variables);runtimeService.updateBusinessStatus(task.getProcessInstanceId(),"领导审批完成");log.info("领导审批成功任务{ }",taskId);}/** * 10. 领导拒绝 * * @param taskId 任务ID */@GetMapping("/leaderRefuse/{ taskId}")publicvoidleaderRefuse(@PathVariable("taskId")StringtaskId){ Tasktask =taskService.createTaskQuery().taskId(taskId).taskAssignee("2000").singleResult();//通过审核HashMap<String,Object>variables =newHashMap<>();variables.put("result",false);taskService.complete(task.getId(),variables);runtimeService.updateBusinessStatus(task.getProcessInstanceId(),"领导审批拒绝");log.info("领导审批拒绝任务{ }",taskId);}/** * 11. 老板待办任务 */@GetMapping("/bossTodoList")publicvoidbossTodoList(){ List<Task>tasks =taskService.createTaskQuery().taskAssignee("3000").list();List<TaskVo>taskVoList =tasks.stream().map(task ->{ Map<String,Object>variables =taskService.getVariables(task.getId());TaskVotaskVO =newTaskVo();taskVO.setTaskId(task.getId());taskVO.setTaskName(task.getName());taskVO.setProcessVariables(variables);returntaskVO;}).collect(Collectors.toList());log.info("老板任务列表:"+taskVoList);}/** * 12. 老板批准 * * @param taskId 任务ID,非流程id * @return */@GetMapping("/bossApply/{ taskId}")publicvoidapply(@PathVariable("taskId")StringtaskId){ Tasktask =taskService.createTaskQuery().taskId(taskId).taskAssignee("3000").singleResult();if(task ==null){ log.info("老板没有任务");}//通过审核HashMap<String,Object>map =newHashMap<>();map.put("result",true);StringprocessInstanceId =task.getProcessInstanceId();runtimeService.updateBusinessStatus(processInstanceId,"老板审批完成");taskService.complete(task.getId(),map);}/** * 13. 老板拒绝 * * @param taskId 任务ID * @return */@GetMapping("/bossRefuse/{ taskId}")publicvoidbossRefuse(@PathVariable("taskId")StringtaskId){ Tasktask =taskService.createTaskQuery().taskId(taskId).taskCandidateGroupIn(Arrays.asList("boss")).singleResult();if(task ==null){ log.info("老板没有任务");}//通过审核HashMap<String,Object>map =newHashMap<>();map.put("result","驳回");taskService.complete(task.getId(),map);runtimeService.updateBusinessStatus(task.getProcessInstanceId(),"老板审批拒绝");log.info("领导审批拒绝任务{ }",taskId);}/** * 14. 员工再次申请请假 * * @param processId 流程id * @param day * @return */@GetMapping("/applyAgain/{ processId}/{ day}/{ employeeId}/{ leaderId}")publicvoidapplyAgain(@PathVariable("processId")StringprocessId,@PathVariable("day")Integerday,@PathVariable("employeeId")StringemployeeId,@PathVariable("leaderId")StringleaderId){ Tasktask =taskService.createTaskQuery().processInstanceId(processId).singleResult();if(task ==null){ log.info("员工没有任务");}// 提交请假申请Map<String,Object>map =newHashMap<>();map.put("day",day);map.put("employeeId",employeeId);map.put("leaderId",leaderId);map.put("groups",Arrays.asList("leader"));taskService.complete(task.getId(),map);runtimeService.updateBusinessStatus(task.getProcessInstanceId(),"审批中");log.info("员工再次请假申请,任务{ }",task.getId());}/** * 15. 生成流程图 * * @param processId 流程ID */@GetMapping("/processDiagram/{ processId}")publicvoidgenProcessDiagram(HttpServletResponsehttpServletResponse,@PathVariable("processId")StringprocessId)throwsException{ ProcessInstancepi =runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();if(pi ==null){ return;}Tasktask =taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();StringInstanceId=task.getProcessInstanceId();List<Execution>executions =runtimeService.createExecutionQuery().processInstanceId(InstanceId).list();List<String>activityIds =newArrayList<>();List<String>flows =newArrayList<>();for(Executionexe :executions){ List<String>ids =runtimeService.getActiveActivityIds(exe.getId());activityIds.addAll(ids);}BpmnModelbpmnModel =repositoryService.getBpmnModel(pi.getProcessDefinitionId());ProcessEngineConfigurationengconf =processEngine.getProcessEngineConfiguration();ProcessDiagramGeneratordiagramGenerator =engconf.getProcessDiagramGenerator();InputStreaminputStream =diagramGenerator.generateDiagram(bpmnModel,"png",activityIds,flows,engconf.getActivityFontName(),engconf.getLabelFontName(),engconf.getAnnotationFontName(),engconf.getClassLoader(),1.0,true);OutputStreamos =null;try{ BufferedImageimage =ImageIO.read(inputStream);httpServletResponse.setContentType("image/png");os =httpServletResponse.getOutputStream();if(image !=null){ ImageIO.write(image,"png",os);}}catch(Exceptione){ e.printStackTrace();}finally{ try{ if(os !=null){ os.flush();os.close();}}catch(IOExceptione){ e.printStackTrace();}}}}
6. 多租户flowable数据隔离
多租户Flowable是指在一个单一的应用实例中支持多个租户(客户)的业务流程管理。每个租户拥有独立的数据和流程定义,但共享同一个应用实例。这种架构在SaaS(软件即服务)应用中非常常见,因为它能够有效地利用资源并降低运营成本。有关flowable多租户的完整代码在文末获取!
7. 总结
flowable工作流对于提高效率、优化流程、降低成本、提高质量等方面都有重要作用,是现代企业管理中不可或缺的工具,老铁们用起来吧!
如果看到这里,说明你喜欢这篇文章,请转发,点赞。
- 关注公众号老板来一杯java
- 加群即可获取flowable多租户代码,并赠送DDD领域驱动设计实战落地解惑PDF一份!
- 公众号回复java即可获取java基础经典面试一份!
好文推荐:
推荐一款基于AI编程的代码自动生成工具Cursor,替代VSCode
2.5万字讲解DDD领域驱动设计(史上最全DDD)
python vs java,从java转python一键简简单单入门,轻轻松松上手,抓紧收藏起来吧