springboot整合flowable工作流

1、工作流介绍

1.Flowable起源于Activiti工作流引擎,由Activiti的主要开发者在2016年创建。它继承了Activiti的众多优点,并在此基础上进行了优化和改进,以提供更加稳定、高效的工作流管理解决方案。Flowable与Activiti有着共同的祖先,即jbpm,并随着技术的发展和需求的变化,逐渐发展成为独立且功能强大的工作流引擎。

2.应用场景:Flowable广泛应用于各种需要流程管理的场景,如人力资源管理(如员工入职、离职、请假、绩效评估等)、自动化业务流程(如财务审批、采购流程、销售订单处理等)、任务管理和分配等。在由流程驱动的各种系统中,如OA、CRM、ERP、ECM、BI等,Flowable都能发挥重要作用。
优势:

3.轻量级与高效:Flowable是一个轻量级的引擎,启动快,内存占用小,非常适合在微服务架构中使用。

4.全面支持BPMN 2.0标准:允许使用标准化的方式来定义和执行流程,提高了流程的兼容性和可移植性。

5.丰富的API和可视化设计工具:降低了与其他系统的集成难度,提高了业务流程的建模和编辑效率。

6.良好的社区支持和文档:作为一个活跃的开源项目,Flowable拥有良好的社区支持和不断更新的文档,用户可以在社区中获取帮助和分享经验。

2、flowable相关概念

Flowable是一个功能强大的业务流程管理引擎,支持BPMN 2.0标准。以下是对Flowable相关概念的具体介绍:

2.1 流程定义
流程定义(Process Definition)是使用BPMN 2.0标准的XML格式描述的,它包含了流程中的节点、连接线和事件等元素。
对应的类:org.flowable.engine.repository.ProcessDefinition

2.2 流程实例
流程实例(Process Instance)当一个流程定义被启动时,会创建一个流程实例,这个实例将按照定义的流程节点顺序执行。
对应的类:org.flowable.engine.runtime.ProcessInstance

2.3 任务
任务(Task)是流程实例中的一个执行单元,代表需要由用户或系统自动完成的操作。在Flowable中,任务可以是用户任务、服务任务、脚本任务等多种类型。
对应的类:org.flowable.engine.task.Task

2.4 网关
网关(Gateway)用于控制流程的执行方向,Flowable支持多种类型的网关,如排他网关和并行网关等。排他网关用于在多个分支中选择一个分支进行执行,而并行网关则用于将流程拆分为多个并行执行的分支。
对应的类:
org.flowable.bpmn.model.ParallelGateway(并行网关)
org.flowable.bpmn.model.ExclusiveGateway(排他网关)

2.5 条件表达式
条件表达式(Conditional Expression):Flowable支持使用条件表达式来控制流程的执行方向。条件表达式使用Java的语法,可以在排他网关等地方使用,根据条件表达式的值来决定流程应该走向哪个分支。

2.6 边界事件
边界事件(Boundary Event):边界事件可以捕获流程中的错误或异常事件,并在事件发生时执行相应的处理逻辑。例如,可以在用户任务中添加一个错误边界事件,当用户任务执行失败时,触发错误边界事件进行错误处理。
对应的类:
org.flowable.bpmn.model.StartEvent(开始事件)
org.flowable.bpmn.model.EndEvent(结束事件)
org.flowable.bpmn.model.BoundaryEvent(边界事件)

总的来说,Flowable作为一个轻量级的业务流程引擎,提供了丰富的流程控制元素和灵活的扩展机制,通过掌握其核心概念和常见问题的解决方案,开发者可以更加高效地构建工作流应用,提高业务流程的自动化水平和执行效率。

3、配置工作流模型

3.1 请假工作流示意图

3.2 使用idea插件Flowable BPMN visualizer

Flowable BPMN visualizer是一款为IntelliJ IDEA系列IDE设计的插件,它提供了一个强大的BPMN(Business Process Model and Notation,即业务流程模型和表示法)模型编辑工具.

1、安装idea插件Flowable BPMN visualizer

2、在resources文件夹下创建文件夹processes

3、然后创建文件leave.bpmn20.xml

4、选中leave.bpmn20.xml文件右键选择View BPMN (Flowable) Diagram

 

5、然后就可以开始制作流程图了,右键会有各种工具 

3.3 插件里面的工具介绍

1、Start Events(开始事件)
Start Event: 流程的起点,手动触发。(重要)
Start Conditional Event: 条件满足时自动触发。
Start Message Event: 接收到特定消息时自动触发。
Start Error Event: 发生指定错误时自动触发。
Start Escalation Event: 需要升级或转交给更高级别人员时自动触发。
Start Signal Event: 接收到特定信号时自动触发。
Start Timer Event: 经过特定时间后自动触发。

2、Activities(活动)
Task: 用户执行的任务,如审批、填写表单等。
Service Task: 系统自动执行的任务,如调用外部服务。
User Task: 分配给用户执行的任务。(重要)
Script Task: 使用脚本语言(如Groovy、JavaScript)编写的自定义任务。
Business Rule Task: 基于业务规则引擎执行的任务。
Manual Task: 需要人工干预的任务。

3、Structural(结构)
Subprocess: 子流程,表示一个嵌套的流程。
Transaction: 事务,确保一组操作要么全部成功,要么全部失败。
Ad-hoc Subprocess: 临时子流程,可以在运行时动态创建。
Event Subprocess: 事件子流程,与特定事件相关联。

4、Gateways(网关)
Exclusive Gateway: 排他网关,根据条件选择一条路径执行。(重要)
Parallel Gateway: 并行网关,将流程分成多个并行分支。
Inclusive Gateway: 包容网关,允许多条路径同时执行。
Complex Gateway: 复杂网关,结合了排他网关和并行网关的特性。

5、Boundary Events(边界事件)
Boundary Timer Event: 定时边界事件,当到达指定时间点时触发。
Boundary Error Event: 错误边界事件,当发生指定错误时触发。
Boundary Signal Event: 信号边界事件,当接收到指定信号时触发。
Boundary Message Event: 消息边界事件,当接收到指定消息时触发。
Boundary Cancel Event: 取消边界事件,当流程被取消时触发。
Boundary Compensation Event: 补偿边界事件,用于处理补偿逻辑。

6、Intermediate Catching Events(中间捕获事件)
Intermediate Message Event: 中间消息事件,等待接收到特定消息时触发。
Intermediate Timer Event: 中间定时事件,等待到达指定时间点时触发。
Intermediate Signal Event: 中间信号事件,等待接收到特定信号时触发。
Intermediate Conditional Event: 中间条件事件,等待满足特定条件时触发。

7、Intermediate Throwing Events(中间抛出事件)
Intermediate Message Throw Event: 中间消息抛出事件,发送消息给其他流程或系统。
Intermediate Signal Throw Event: 中间信号抛出事件,发送信号给其他流程或系统。
Intermediate Escalation Event: 中间升级事件,将问题升级或转交给更高级别的人员或系统。
Intermediate Link Event: 中间链接事件,用于跨流程的通信。

8、End Events(结束事件)
End Event: 流程的正常结束点。(重要)
Error End Event: 流程的错误结束点。
Escalation End Event: 流程的升级结束点。
Message End Event: 流程的消息结束点,发送消息给其他流程或系统。
Signal End Event: 流程的信号结束点,发送信号给其他流程或系统。
Terminate End Event: 流程的终止结束点,强制终止流程。

9、Save to PNG
Save to PNG: 将当前BPMN模型保存为PNG格式的图片文件,便于分享和展示。

4、Flowable基础表结构

工作流程的相关操作都是操作存储在对应的表结构中,为了能更好的弄清楚Flowable的实现原理和细节,我们有必要先弄清楚Flowable的相关表结构及其作用。在Flowable中的表结构在初始化的时候会创建五类表结构,具体如下:

ACT_RE :'RE'表示 repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
ACT_RU:'RU'表示 runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Flowable只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。
ACT_HI:'HI'表示 history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
ACT_GE: GE 表示 general。 通用数据, 用于不同场景下
ACT_ID: ’ID’表示identity(组织机构)。这些表包含标识的信息,如用户,用户组,等等。

 

 

 

Flowable在项目启动的时候会自动创建表,以下是主要几张表介绍

ACT_RU_TASK:每次启动的流程都会在这张表中,表示代办项,流程结束会删除该流程数据
ACT_RU_EXECUTION:流程执行过程表,会存该流程正在执行的过程数据,流程结束会删除该流程数据
ACT_RU_VARIABLE:流程变量表,流程中传的参数都会在该表存储,流程结束会删除该流程数据
ACT_HI_PROCINST:历史运行流程,当流程处理完了, 在ACT_RU_* 表中就不会有数据, 可以在该表中查询历史
ACT_HI_TASKINST:历史运行的task信息,
ACT_RE_PROCDEF:流程模板记录,同一个key多次发布version_字段会递增
ACT_RE_DEPLOYMENT:部署的流程模板,可以启动流程使用的

5、springboot集成flowable

5.1、pom依赖文件

<!-- 工作流flowable jar包 -->
<dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>6.7.2</version>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version>
</dependency>

5.2、application.properties

 

server.port=8090spring.datasource.username=root
spring.datasource.password=root3306
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Drivermybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImplmybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0# 工作流 Flowable 配置
# 设置为 false,禁用 /resources/processes 自动部署 BPMN XML 流程
flowable.check-process-definitions=true 
# full 保存历史数据的最高级别,可保存全部流程相关细节,包括流程流转各节点参数
flowable.history-level=full 
#关闭定时任务JOB
flowable.async-executor-activate=false

5.3、flowable 配置文件 

import org.flowable.spring.SpringProcessEngineConfiguration;
import org.flowable.spring.boot.EngineConfigurationConfigurer;
import org.springframework.context.annotation.Configuration;/*** @Author: BestLiu* @CreateTime: 2024-12-02 09:08* @Descripton: flowable配置* @Version:*/
@Configuration
public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {@Overridepublic void configure(SpringProcessEngineConfiguration engineConfiguration) {engineConfiguration.setActivityFontName("宋体");engineConfiguration.setLabelFontName("宋体");engineConfiguration.setAnnotationFontName("宋体");}
}

5.4、流程任务实体

import lombok.Data;import java.util.Map;/*** @Author: BestLiu* @CreateTime: 2024-12-02 09:10* @Descripton: TODO* @Version:*/
@Data
public class TaskVo {/*** 任务id*/private String taskId;/*** 任务名称*/private String taskName;/*** 流程实例id*/private String processInstanceId;/*** 流程变量*/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&lt;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&gt;=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、核心功能类

实现功能如下

  1. 查询流程定义列表
  2. 创建请假审批流程
  3. 审批流程列表
  4. 提交审批流程
  5. 历史流程列表
  6. 删除流程
  7. 领导待办任务
  8. 领导已办任务
  9. 领导批准
  10. 领导拒绝
  11. 老板待办任务
  12. 老板批准
  13. 老板拒绝
  14. 员工再次申请请假
  15. 生成流程图
import com.zkaw.flowable.vo.TaskVo;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;/*** @Author: BestLiu* @CreateTime: 2024-12-02 09:33* @Descripton: TODO* @Version:*/
@RestController
@RequestMapping("/flowable/test")
@Slf4j
public class FlowableTestController {@Autowiredprivate RuntimeService runtimeService;@Autowiredprivate TaskService taskService;@Autowiredprivate RepositoryService repositoryService;@Autowiredprivate ProcessEngine processEngine;/*** 对应leave.bpmn20.xml文件中process标签的id属性*/private String processKey = "leave";/*** 1. 查询流程定义列表*/@GetMapping("/processDefinitionList")public void processDefinitionList() {List<ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery().list();for (ProcessDefinition processDefinition : processDefinitions) {log.info("部署id:{},流程定义id:{},流程定义名称:{}", processDefinition.getDeploymentId(), processDefinition.getId(), processDefinition.getName());}}/*** 2. 创建请假审批流程** @param day        请假天数* @param employeeId 员工id* @return*/@PostMapping("/start/{day}/{employeeId}")public void start(@PathVariable("day") Integer day, @PathVariable("employeeId") String employeeId) {Map<String, Object> variables = new HashMap<>();variables.put("day", day);variables.put("employeeId", employeeId);//assignee表示流程的办理人variables.put("assignee", employeeId);ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processKey, variables);runtimeService.updateBusinessStatus(processInstance.getId(), "未审批");log.info("流程实例ID:{}", processInstance.getId());}/*** 3. 审批流程列表** @return*/@DeleteMapping("/processList")public void processList() {List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery().list();for (ProcessInstance processInstance : processInstances) {log.info("流程实例ID:{}, 流程状态:{}", processInstance.getId(), processInstance.getBusinessStatus());}}/*** 4. 提交审批流程** @param processInstanceId 流程实例ID* @param employeeId        员工ID* @param leaderId          领导ID*/@PostMapping("/submit/{processInstanceId}/{employeeId}/{leaderId}")public void submit(@PathVariable("processInstanceId") String processInstanceId, @PathVariable("employeeId") String employeeId, @PathVariable("leaderId") String leaderId) {log.info("流程实例ID:" + processInstanceId);//查询自己的审批流程Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).taskAssignee(employeeId).singleResult();Map<String, Object> variables = new HashMap<>();//交给哪位领导审批variables.put("assignee", leaderId);//提交请假审批流程taskService.complete(task.getId(), variables);//修改请假流程的状态runtimeService.updateBusinessStatus(processInstanceId, "审批中");log.info("流程id:{},任务id:{},", processInstanceId, task.getId(), "审批中");}/*** 5. 历史流程列表** @return*/@DeleteMapping("/historicProcessInstanceList")public void historicProcessInstanceList() {HistoricProcessInstanceQuery query = 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}")public void processDelete(@PathVariable("id") String id) {runtimeService.deleteProcessInstance(id, "删除流程");log.info("删除该流程{}", id);}/*** 7. 领导待办任务** @return*/@GetMapping("/leaderTodoList/{leaderId}")public void leaderTodoList(@PathVariable("leaderId") String leaderId) {List<Task> tasks = taskService.createTaskQuery().taskAssignee(leaderId).list();List<TaskVo> taskVoList = tasks.stream().map(task -> {TaskVo taskVo = new TaskVo();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);return taskVo;}).collect(Collectors.toList());log.info("领导任务列表:" + taskVoList);}/*** 8. 领导已办任务*/@GetMapping("/leaderDoneList/{leaderId}")public void leaderDoneList(@PathVariable("leaderId") String leaderId) {List<HistoricTaskInstance> historicTaskInstanceList = processEngine.getHistoryService().createHistoricTaskInstanceQuery().taskAssignee(leaderId).list();List<TaskVo> taskVoList = historicTaskInstanceList.stream().map(task -> {TaskVo taskVo = new TaskVo();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);return taskVo;}).collect(Collectors.toList());log.info("已办任务:" + taskVoList);}/*** 9. 领导批准** @param taskId 任务ID,非流程id*/@GetMapping("/leaderApply/{taskId}/{bossId}")public void leaderApply(@PathVariable("taskId") String taskId, @PathVariable("bossId") String bossId) {Task task = taskService.createTaskQuery().taskId(taskId).taskAssignee("2000").singleResult();Map<String, Object> variables = new HashMap<>();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}")public void leaderRefuse(@PathVariable("taskId") String taskId) {Task task = taskService.createTaskQuery().taskId(taskId).taskAssignee("2000").singleResult();//通过审核HashMap<String, Object> variables = new HashMap<>();variables.put("result", false);taskService.complete(task.getId(), variables);runtimeService.updateBusinessStatus(task.getProcessInstanceId(), "领导审批拒绝");log.info("领导审批拒绝任务{}", taskId);}/*** 11. 老板待办任务*/@GetMapping("/bossTodoList")public void bossTodoList() {List<Task> tasks = taskService.createTaskQuery().taskAssignee("3000").list();List<TaskVo> taskVoList = tasks.stream().map(task -> {Map<String, Object> variables = taskService.getVariables(task.getId());TaskVo taskVO = new TaskVo();taskVO.setTaskId(task.getId());taskVO.setTaskName(task.getName());taskVO.setProcessVariables(variables);return taskVO;}).collect(Collectors.toList());log.info("老板任务列表:" + taskVoList);}/*** 12. 老板批准** @param taskId 任务ID,非流程id* @return*/@GetMapping("/bossApply/{taskId}")public void apply(@PathVariable("taskId") String taskId) {Task task = taskService.createTaskQuery().taskId(taskId).taskAssignee("3000").singleResult();if (task == null) {log.info("老板没有任务");}//通过审核HashMap<String, Object> map = new HashMap<>();map.put("result", true);String processInstanceId = task.getProcessInstanceId();runtimeService.updateBusinessStatus(processInstanceId, "老板审批完成");taskService.complete(task.getId(), map);}/*** 13. 老板拒绝** @param taskId 任务ID* @return*/@GetMapping("/bossRefuse/{taskId}")public void bossRefuse(@PathVariable("taskId") String taskId) {Task task = taskService.createTaskQuery().taskId(taskId).taskCandidateGroupIn(Arrays.asList("boss")).singleResult();if (task == null) {log.info("老板没有任务");}//通过审核HashMap<String, Object> map = new HashMap<>();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}")public void applyAgain(@PathVariable("processId") String processId, @PathVariable("day") Integer day, @PathVariable("employeeId") String employeeId, @PathVariable("leaderId") String leaderId) {Task task = taskService.createTaskQuery().processInstanceId(processId).singleResult();if (task == null) {log.info("员工没有任务");}// 提交请假申请Map<String, Object> map = new HashMap<>();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}")public void genProcessDiagram(HttpServletResponse httpServletResponse, @PathVariable("processId") String processId) throws Exception {ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();if (pi == null) {return;}Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();String InstanceId = task.getProcessInstanceId();List<Execution> executions = runtimeService.createExecutionQuery().processInstanceId(InstanceId).list();List<String> activityIds = new ArrayList<>();List<String> flows = new ArrayList<>();for (Execution exe : executions) {List<String> ids = runtimeService.getActiveActivityIds(exe.getId());activityIds.addAll(ids);}BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();InputStream inputStream = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engconf.getActivityFontName(),engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0, true);OutputStream os = null;try {BufferedImage image = ImageIO.read(inputStream);httpServletResponse.setContentType("image/png");os = httpServletResponse.getOutputStream();if (image != null) {ImageIO.write(image, "png", os);}} catch (Exception e) {e.printStackTrace();} finally {try {if (os != null) {os.flush();os.close();}} catch (IOException e) {e.printStackTrace();}}}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/484395.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux Shell 脚本题目集(2)

1、使用 case 语句根据用户输入的分数&#xff08;0-100&#xff09;输出相应的成绩等级&#xff08;A, B, C, D&#xff09;。 #! /bin/bashread -p "请输入您的分数&#xff08;0-100&#xff09;&#xff1a;" score# 验证输入是否为数字且在0到100之间 if ! [[ …

交换机四大镜像(端口镜像、流镜像、VLAN镜像、MAC镜像)应用场景、配置实例及区别对比

在网络管理中&#xff0c;端口镜像、流镜像、VLAN镜像和MAC镜像都是用于监控和分析网络流量的重要技术。 端口镜像&#xff08;Port Mirroring&#xff09; 定义&#xff1a;端口镜像是将一个或多个源端口的流量复制到一个目标端口&#xff0c;以便于网络管理员能够监控和分析…

Redis(1)

Redis是一个在内存中存储数据的中间件。 1.在内存中存储数据。 通过数据结构来存储&#xff0c;mysql通过表的方式存储数据&#xff0c;是关系型数据库&#xff0c;redis通过键值对存储&#xff0c;key的类型是string&#xff0c;value的类型是非关系型数据库。 2.可编程的 …

基于Pyside6开发一个通用的在线升级工具

UI main.ui <?xml version"1.0" encoding"UTF-8"?> <ui version"4.0"><class>MainWindow</class><widget class"QMainWindow" name"MainWindow"><property name"geometry"&…

Linux 系统/etc目录下配置文件分类

目录 一、网络相关配置文件 主机名与 IP 映射类 /etc/hosts /etc/hostname 网络接口配置类 /etc/sysconfig/network-scripts/ifcfg-ens33 DNS 相关类 /etc/resolv.conf /etc/host.conf 网络服务相关类 /etc/hosts.allow文件 /etc/hosts.deny文件 /etc/netconfig …

自由学习记录(28)

C# 中的流&#xff08;Stream&#xff09; 流&#xff08;Stream&#xff09;是用于读取和写入数据的抽象基类。 流表示从数据源读取或向数据源写入数据的矢量过程。 C# 中的流类是从 System.IO.Stream 基类派生的&#xff0c;提供了多种具体实现&#xff0c;每种实现都针对…

Redis3——线程模型与数据结构

Redis3——线程模型与数据结构 本文讲述了redis的单线程模型和IO多线程工作原理&#xff0c;以及几个主要数据结构的实现。 1. Redis的单线程模型 redis6.0之前&#xff0c;一个redis进程只有一个io线程&#xff0c;通过reactor模式可以连接大量客户端&#xff1b;redis6.0为了…

Elasticsearch Serverless 现已正式发布

作者&#xff1a;来自 Elastic Yaru Lin 基于全新无状态&#xff08;stateless&#xff09;架构的 Elasticsearch Serverless 现已正式发布。它采用完全托管方式&#xff0c;因此你可以快速启动项目而无需操作或升级&#xff0c;并且可以使用最新的向量搜索和生成式 AI 功能。 …

Android CoordinatorLayout:打造高效交互界面的利器

目录 一、CoordinatorLayout 介绍及特点 二、使用方法 2.1 创建 CoordinatorLayout 布局 2.2 添加需要协调的子视图 2.3 自定义 Behavior 三、结语 相关推荐 在Android开发中&#xff0c;面对复杂多变的用户界面需求&#xff0c;CoordinatorLayout以其强大的交互管理能力…

基于Java Springboot旅游攻略APP且微信小程序

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 微信…

多模态大语言模型的对比

简介 文章主要对比了包括 VideoLLaMA 2 、CogVLM2-video 、MiniCPM-V等模型 目前主流的多模态视觉问答大模型&#xff0c;大部分采用视觉编码器、大语言模型、图像到文本特征的投影模块 目录 简介1. VideoLLaMA 21.1 网络结构1.2 STC connector具体的架构 2. MiniCPM-V 2.62.…

Android渗透环境配置教程

工具 模拟器 ADB brew install android-platform-tools set import cert # cer 证书转为 pem 证书 openssl x509 -inform DER -in cacert.der -out cacert.pem# 获取证书的 hash 值 hash$(openssl x509 -inform PEM -subject_hash_old -in cacert.pem | head -n 1)# 将 pem…

Microi吾码|.NET、VUE快速搭建项目,低代码便捷开发教程

Microi吾码&#xff5c;VUE快速搭建项目&#xff0c;低代码便捷开发教程 一、摘要二、Microi吾码介绍2.1 功能介绍2.2 团队介绍2.3 上线项目案例 三、VUE中使用Microi吾码3.1 前期了解3.2 创建第一个低代码应用3.3 接口API使用说明3.4 引擎界面可视化配置&#xff0c;生成API3.…

常见Linux命令(详解)

文章目录 常见Linux命令文件目录类命令pwd 打印当前目录的绝对路径ls 列出目录内容cd 切换路径mkdir 建立目录rmdir 删除目录touch 创建空文件cp 复制文件或目录rm 移除文件或者目录mv 移动文件与目录或重命名cat 查看文件内容more 文件分屏查看器less 分屏显示文件内容head 显…

AI - 如何构建一个大模型中的Tool

AI - 如何构建一个大模型中的Tool 大家好&#xff01;今天我们聊聊一个有趣的技术问题&#xff1a;什么是工具&#xff08;Tool&#xff09;&#xff0c;如何使用聊天模型调用工具&#xff0c;以及如何将工具的输出传递给聊天模型。我们还是基于LangChain来进行讨论&#xff0…

【测试工具JMeter篇】JMeter性能测试入门级教程(四):JMeter中BeanShell内置方法使用

一、什么是BeanShell BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法;BeanShell是一种松散类型的脚本语言(这点和JS类似);BeanShell是用Java写成的,一个小型的、免费的、可以下载的、嵌入式的Java源代码解释器,具有对象脚本语言特性,非常精简…

MyBatis异常体系中ErrorContext和ExceptionFactory原理分析

&#x1f3ae; 作者主页&#xff1a;点击 &#x1f381; 完整专栏和代码&#xff1a;点击 &#x1f3e1; 博客主页&#xff1a;点击 文章目录 exceptions包分包设计ExceptionFactory类介绍为什么使用工厂不是直接new呢&#xff1f;【统一的异常处理机制】【异常的封装与转化】【…

白鹿 Hands-on:消除冷启动——基于 Amazon Lambda SnapStart 轻松打造 Serverless Web 应用(二)

文章目录 前言一、前文回顾二、在 Lambda 上运行2.1、查看 Amazon SAM template2.2、编译和部署到 Amazon Lambda2.3、功能测试与验证 三、对比 Snapstart 效果四、资源清理五、实验总结总结 前言 在这个环节中&#xff0c;我们将延续《白鹿 Hands-on&#xff1a;消除冷启动——…

Spring Shell如何与SpringBoot集成并快速创建命令行界面 (CLI) 应用程序

Spring Shell 介绍 Spring Shell 是一个强大的工具&#xff0c;可用于构建命令行应用程序&#xff0c;提供了简单的方式来创建和管理交互式 CLI。它适合那些希望通过命令行与 Java 应用程序进行交互的开发者&#xff0c;尤其是在需要自动化、交互式输入或与 Spring 生态系统集…

齐护机器人ModbusRTU RS485转TTL通信模块与ESP32 Arduino通信可Mixly的图形化编程Scratch图形化编程

齐护机器人ModbusRTU RS485-TTL通信模块 一、概念理解 Modbus协议是一种由Modicon公司&#xff08;现为施耐德电气Schneider Electric&#xff09;于1979年发表的网络通信协议&#xff0c;旨在实现可编辑逻辑控制器&#xff08;PLC&#xff09;之间的通信。 1.1 什么是Mod…