SpringBoot整合Flowable最新教程(二)启动流程

介绍

  文章主要从SpringBoot整合Flowable讲起,关于Flowable是什么?数据库表解读以及操作的Service请查看SpringBoot整合Flowable最新教程(一);
  其他说明:Springboot版本是2.6.13,java版本是1.8。如果你使用的是一些开源项目如:ruoyi里面已经集成了这些无须自己手动引入。
文章代码地址(包含bpmn文件):文章源码地址
   pom文件引入

<!-- 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><!--druid-->
<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.12</version>
</dependency><!--mysql驱动-->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope>
</dependency>

  因为加入flowable后项目启动时要往数据库加入流程表,所以这里就直接把druid也加上,数据库也配置上。

server:port: 8099spring:datasource:druid:url: jdbc:mysql://localhost:3306/spring_flowable?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTCusername: rootpassword: 1101165230driver-class-name: com.mysql.cj.jdbc.Driver# 初始化物理链接的个数initial-size: 5# 最大连接池数量max-active: 30# 最小 连接池数量min-idle: 5# 获取连接时最大等待时间,单位毫秒 timeout链接超时max-wait: 60000# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒  检测非核心链接的时间#既作为检测的间隔时间又作为testWhileIdel执行的依据time-between-eviction-runs-millis: 60000# 连接保持空闲而不被驱逐的最小时间min-evictable-idle-time-millis: 30000# 用来检测连接是否有效的sql,要求是一个查询语句  8小时问题 8个小时没跟mysql通信mysql会主动关闭该链接validation-query: SELECT 1 FROM DUAL# 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,# 如果空闲时间大于min-evictable-idle-time-millis,执行validationQuery检测连接是否有效。test-while-idle: true# 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。test-on-borrow: false# 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。test-on-return: false# 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,# 比如说oracle。在mysql下建议关闭。不是mysql端,链接端,select * from student 查询缓存pool-prepared-statements: true# 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。max-pool-prepared-statement-per-connection-size: 50#调优相关:基本上任何一个项目的性能瓶颈 1.io 2.cpu计算量# 配置监控统计拦截的filters,去掉后监控界面sql无法统计filters: stat,wall# 通过connectProperties属性来打开mergeSql功能;慢SQL记录  慢查询:增删改查connection-properties: druid.stat.mergeSql=true;filter:stat:slow-sql-millis: 1# 合并多个DruidDataSource的监控数据use-global-data-source-stat: true# druid连接池监控stat-view-servlet:login-username: adminlogin-password: 1101165230# 排除一些静态资源,以提高效率web-stat-filter:exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
# flowable配置
flowable:
# 请在第一次启动时使用true,之后使用falsedatabase-schema-update: true#pg用户使用指定,mysql不用
#  database-schema: spring_flowableactivity-font-name: "宋体"label-font-name: "宋体"annotation-font-name: "宋体"async-executor-activate: false

2、配置Mysql连接以及druid后,启动项目

  如果启动报错请看.act_ge_property‘ doesn‘t exist

3、接着开始部署我们的bpmn文件

  在线bpmn绘制地址:bpmn在线绘制
  文章配套xml文件在最上方,请在最上方点击staff-leave.bpmn20.xml下载资源
  1.下载好文件后,在我们的resources文件夹下创建一个processes文件夹(项目启动时候会自动加载该文件夹下的xml),并将xml文件放进去。
这里我创建的流程是一个员工休假申请,如图:
员工休假申请流程
流程非常简单主要是为了让大家熟悉如何启动流程。(因为是1.0版本所以我并没有控制网关节点流向控制值,所以加入项目启动后会有一个提示说这个网关没有配置值)

4、业务与代码讲解

  整个业务流程也非常简单就是员工填写休假申请,我们就开启流程。由于我们只讲解启动的流程,所以大家不用纠结每个业务所在节点的状态。
  题外话:就拿一级审批节点来说,我启动流程后进入一级审批,这个时候的状态应该是什么?应该是一个待审核状态,只有等审核人员审核后才会变成已审核,已审核后经过网关是进入二级审批还是修改信息节点就看审核人的具体操作。其实也有特别简单的理解,就是将整个业务和流程进行一个拆分,将流程中的状态变更提取成一张表,我觉得大家就更好理解。后续我可能会出一个视频去讲解。

4.1创建factory文件夹,创建一个WorkflowService将flowable的服务类全部放进去进行统一管理

import org.flowable.engine.*;
import org.springframework.beans.factory.annotation.Autowired;/*** @author by Guoshun* @version 1.0.0* @description flowable 工作流服务类* @date 2024/2/4 10:13*/
public class WorkflowService {/*** 流程引擎*/@Autowiredpublic ProcessEngine processEngine;/*** 流程仓库服务类*/@Autowiredpublic RepositoryService repositoryService;/*** 查询运行信息*/@Autowiredpublic RuntimeService runtimeService;/*** 查询任务信息*/@Autowiredpublic TaskService taskService;/*** 查询历史信息*/@Autowiredpublic HistoryService historyService;}
4.2接着我们还是按照标准开发流程创建Service、实体类这些步骤

请假表单实体类:

import lombok.*;import java.io.Serializable;
import java.util.Date;/*** @author by Guoshun* @version 1.0.0* @description 申请信息入参* @date 2024/2/4 10:21*/
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class ApproveInfoBO implements Serializable {private String name;private Date startTime;private Date endTime;private String remarks;}

创建service

import com.sg.flowable.entity.ApproveInfoBO;import javax.servlet.http.HttpServletResponse;/*** @author by Guoshun* @version 1.0.0* @description IStaffLeaveApproveService* @date 2024/2/4 10:10*/
public interface IStaffLeaveApproveService{/*** 休假申请*/String approve(ApproveInfoBO approveInfoBO);/*** 获取流程图* @param httpServletResponse* @param processId*/void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception;}

创建实现类


import com.sg.flowable.entity.ApproveInfoBO;
import com.sg.flowable.factory.WorkflowService;
import com.sg.flowable.service.IStaffLeaveApproveService;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.ProcessEngineConfiguration;
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.springframework.stereotype.Service;import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.List;/*** @author by Guoshun* @version 1.0.0* @description StaffLeaveApproveServiceImpl* @date 2024/2/4 10:10*/
@Service
public class StaffLeaveApproveServiceImpl extends WorkflowService implements IStaffLeaveApproveService {@Overridepublic String approve(ApproveInfoBO approveInfoBO){//数据的id(假设这是申请数据的id)String id = UUID.randomUUID().toString().replaceAll("-", "");//放入流程中的数据Map<String, Object> variables = new HashMap<>();variables.put("status", 1);variables.put("data", approveInfoBO);//启动流程ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("staff_leave", id, variables);String processInstanceId = processInstance.getId();System.out.println("流程启动id是:"+processInstanceId);return id;}/*** 返回流程图* @param httpServletResponse* @param processId*/@Overridepublic void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception {ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();//流程走完的不显示图if (pi == null) {return;}Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();//使用流程实例ID,查询正在执行的执行对象表,返回流程实例对象String InstanceId = task.getProcessInstanceId();List<Execution> executions = runtimeService.createExecutionQuery().processInstanceId(InstanceId).list();//得到正在执行的Activity的IdList<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 in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0,true);OutputStream out = null;byte[] buf = new byte[1024];int legth = 0;try {out = httpServletResponse.getOutputStream();while ((legth = in.read(buf)) != -1) {out.write(buf, 0, legth);}} finally {if (in != null) {in.close();}if (out != null) {out.close();}}}}

创建Controller

import com.sg.flowable.entity.ApproveInfoBO;
import com.sg.flowable.service.IStaffLeaveApproveService;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;/*** @author by Guoshun* @version 1.0.0* @description StaffLeaveApproveController* @date 2024/2/4 10:06*/
@RestController
@RequestMapping("/staff_leave")
public class StaffLeaveApproveController {@Resourceprivate IStaffLeaveApproveService iStaffLeaveApproveService;/*** 休假申请*/@PostMapping("/approve")public String approve(@RequestBody ApproveInfoBO approveInfoBO){return iStaffLeaveApproveService.approve(approveInfoBO);}/*** 返回流程图* @param httpServletResponse* @param processId* @throws Exception*/@GetMapping("/genProcessDiagram/{processId}")public void genProcessDiagram(HttpServletResponse httpServletResponse,@PathVariable("processId") String processId) throws Exception {iStaffLeaveApproveService.genProcessDiagram(httpServletResponse, processId);}
}

测试调用
接口调用
输出实例id
使用控制台实例id调用返回流程图接口,查看申请所在位置:
红色表示当前位置

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

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

相关文章

【QT+QGIS跨平台编译】之二十:【xerces+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、xerces介绍二、文件下载三、文件分析四、pro文件五、编译实践一、xerces介绍 Xerces是一个开源的XML解析器,由Apache软件基金会维护。它是用Java语言编写的,提供了对XML文档进行解析、验证和操作的功能。Xerces具有高性能和广泛的兼容性,可用于各种Java应用程…

Sentinel应用笔记

概念 当A、B、G、H掉线&#xff0c;其他服务就没法通信了 随着微服务的流行&#xff0c;服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点&#xff0c;从流量控制、流量路由、熔断降级、系统自适应过载保护、热点流量防护等多个维度保护服务的稳定性。 特性…

Java 错误 java.net.MalformedURLException: No Protocol

我们将研究 Java 中的错误 java.net.MalformedURLException: no protocol。 为什么会发生这种错误&#xff0c;以及我们如何解决该错误。 Java 中的 java.net.MalformedURLException: no protocol 错误 当我们的 URL 出现问题时&#xff0c;会出现 java.net.MalformedURLExcep…

Vue3.0(二):Vue组件化基础 - 脚手架

Vue组件化基础 - 脚手架 Vue的组件化 我们在处理一些任务量比较庞大的工作时候&#xff0c;会将工作内容进行拆分&#xff0c;分步骤完成 而组件化的思想正式如此&#xff0c;对于一个庞大的项目&#xff0c;我们可以将其拆分成一个个的小功能&#xff0c;分步骤进行实现 组…

一知半解,临时解决ajax跨域请求

在学习java编写接口。写好之后用vue写了个前端进行测试&#xff0c;结果总是有Access-Control-Allow-Origin错误。 上网找&#xff0c;说在vue.config.js做配置,加上以下内容&#xff1a; module.exports {devServer: {port : 8089,proxy: {/mytest: {target: http://192.16…

MySQL数据库基础第二篇(函数)

文章目录 一、函数介绍二、字符串函数1.练习代码2.读出结果 三、数值函数1.练习代码2.读出结果 四、日期函数1.练习代码2.读出结果 五、流程控制函数1.练习代码2.读出结果 在当代技术世界中&#xff0c;掌握数据库设计和操作的知识和技能&#xff0c;尤其是对SQL的理解&#xf…

react 之 useInperativeHandle

useInperativeHandle是通过ref暴露子组件中的方法 1.场景说明-直接调用子组件内部的方法 import { forwardRef, useImperativeHandle, useRef } from "react"// 子组件const Son forwardRef((props, ref) > {// 实现聚焦逻辑const inputRef useRef(null)const …

【C++】C++入门 — 类和对象初步介绍

类和对象 1 类的作用域2 类的实例化3 类对象模型4 this指针介绍&#xff1a;特性&#xff1a; Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读&#xff01;下一篇文章见&#xff01;&#xff01;&#xff01; 1 类的作用域 类定义了一个新的作用域&#xff0c;类的…

openGauss学习笔记-213 openGauss 性能调优-总体调优思路

文章目录 openGauss学习笔记-213 openGauss 性能调优-总体调优思路213.1 调优思路概述213.2 调优流程 openGauss学习笔记-213 openGauss 性能调优-总体调优思路 213.1 调优思路概述 openGauss的总体性能调优思路为性能瓶颈点分析、关键参数调整以及SQL调优。在调优过程中&…

【递归】 92. 反转链表 II

92. 反转链表 II 解题思路 定义了单链表节点的数据结构&#xff0c;包含整数值 val 和指向下一个节点的引用 next。 在 Solution 类中&#xff0c;定义了一个类变量 successor&#xff0c;用于保存当前节点的后继节点。 实现了 reverseBetween 方法&#xff0c;该方法通过递…

uniapp 高德地图显示

1. uniapp 高德地图显示 使用前需到**高德开放平台&#xff08;https://lbs.amap.com/&#xff09;**创建应用并申请Key   登录 高德开放平台&#xff0c;进入“控制台”&#xff0c;如果没有注册账号请先根据页面提示注册账号   打开 “应用管理” -> “我的应用”页面…

vue 渲染多列表格,拖动加载

vue在使用el-table渲染多列&#xff08;几千列&#xff09;表格时&#xff0c;页面会十分卡顿&#xff0c;使用html原生表格拖动滚动条加载列&#xff0c;可以解决这个问题 后端接口返回的数据格式如下&#xff1a; line_data中的数据title对应index_title里的内容 <temp…

diffusers代码梳理总结

常用类 这里总结一些频繁用到的支持类。 from dataclasses import dataclass from ..utils import BaseOutput from collections import OrderedDictclass BaseOutput(OrderedDict):...dataclass class Unet2DOutput(BaseOutput):"""The output of [Unet2DMod…

Linux---yum命令详解

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 1.概念2.yum的配置信…

【开源】WordPress一键崩溃宕机插件(整活娱乐)

插件介绍 可一键实现Wordpress崩溃宕机的整活向插件&#xff08;请勿用于非法途径&#xff0c;仅供整活娱乐&#xff09;。鼓励关注网站性能的提升&#xff0c;以提供更好的用户体验&#xff0c;提倡为用户提供良好体验和高效速度的原则。 介绍 长期以来&#xff0c;人们都在…

【webrtc】跟webrtc学list遍历

m98 代码:RTT G:\CDN\rtcCli\m98\src\video\call_stats.cc遍历list 进行删除 :remove_if void RemoveOldReports(int64_t now, std::list<CallStats::RttTime>* reports) {static constexpr const <

算法训练|乘积最大数组、最长有效括号

152. 乘积最大子数组 - 力扣&#xff08;LeetCode&#xff09; 总结&#xff1a;解题思路是需要维护一个最大值以及一个最小值&#xff0c;因为最小值如果是负数的话乘上接下来的一个负数会有可能成为最大的数 代码&#xff1a; class Solution { public:int maxProduct(vec…

【Vue】3-1、Vue 3 简介

一、Vue 3 的优势 Vue 2 Options API 的缺陷&#xff1a; 一个功能往往需要在不同的 vue 配置项中定义属性和方法&#xff0c;比较分散&#xff0c;需求简单还好&#xff0c;清晰明了&#xff1b;但是需求复杂之后&#xff0c;就会多出 watch&#xff0c;computed&#xff0c;i…

两次NAT

两次NAT即Twice NAT&#xff0c;指源IP和目的IP同时转换&#xff0c;该技术应用于内部网络主机地址与外部网络上主机地址重叠的情况。 如图所示&#xff0c;两次NAT转换的过程如下: 内网Host A要访问地址重叠的外部网络Host B&#xff0c;Host A向位于外部网络的DNS服务器发送…