springboot特殊问题处理2——springboot集成flowable实现工作流程的完整教程(一)

在实际项目开发过程中,流程相关的业务实现采用工作流会异常清晰明了,但是Activity学习成本和开发难度对追求效率的开发工作者来说异常繁琐,但是作为Activity的亲儿子之一的flowable,其轻量化的使用和对应的api会让开发者感受简单,学习成本很低,值得推荐。

本文案基于springboot2.3.12为例讲解,jdk版本要求至少1.8+,mysql为8.0以上。

一.flowable相关官方网址

官方网站(英文):https://www.flowable.com/

第三方中文用户手册(V6.3.0):https://tkjohn.github.io/flowable-userguide/

二.如何集成springboot

1.引入官方jar或者对应springboot的starter
<dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>${flowable.version}</version>
</dependency>

我这边根据项目需要只引入相关的flowable-engine

        <dependency><groupId>org.flowable</groupId><artifactId>flowable-engine</artifactId><version>6.3.0</version><exclusions><exclusion><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></exclusion><exclusion><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></exclusion></exclusions></dependency>
2. 配置项目需要的数据
  • flowable.properties
flowable.url=jdbc:mysql://10.1.0.223:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=CTT&nullCatalogMeansCurrent=true
flowable.username=root
flowable.password=123456
flowable.driverClassName=com.mysql.cj.jdbc.Driver
###生成数据表
flowable.initialize=true
flowable.name=flowable
###动态生成流程执行图(定义中文字体为宋体,防止生成的图片资源存在乱码)
flowable.activityFontName=\u5B8B\u4F53
flowable.labelFontName=\u5B8B\u4F53
flowable.annotationFontName=\u5B8B\u4F53
flowable.xml.encoding=UTF-8
  • 项目结构如下 

  • 测试需要的流程图 

 

三.flowable项目正确开发使用流程

1.首先正确配置flowable.properties该文件,默认在启动项目时会生成34张工作流数据表(均已ACT_开头)

2.利用tomcat启动flowable-admin.war,然后用flowable-ui创建对应的bpm文件(或者其他的bpm工具)

3.调用/deployment这个接口,部署已经写好的流程实例,参数参照后台方法说明传递即可

4.分别查看act_re_deployment,act_re_procdef和act_ge_bytearray数据表,如果生成了相关数据即代表部署成功

5.最后就可以在相关模块创建任务开始动态执行流程

四.flowable流程业务实现以及部分关键代码展示

以下关键代码,需要特意说明的是:

  • ProcessEngine是flowable提供对公开BPM和工作流操作的所有服务的访问关键对象。
  • FlowProcessDiagramGenerator是flowable生成流程实例图片的关键,继承自
    org.flowable.image.impl.DefaultProcessDiagramGenerator类
1.流程部署
    /*** 1.部署流程** @return*/@GetMapping("/deployment")public String deploymentFlowable() {RepositoryService repositoryService = processEngine.getRepositoryService();Deployment deployment = repositoryService.createDeployment().addClasspathResource("flowable_xml/test_flowable.bpmn20.xml")//类别.category("审批类").name("领导审批").deploy();return ResponseResult.ok(deployment);}
2. 查询流程定义
    /*** 2.查询流程定义** @return*/@GetMapping("/queryDeployment")public String queryFlowableDeploy() {RepositoryService repositoryService = processEngine.getRepositoryService();//查询所有定义的流程List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();//查询单个定义的流程/*ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId("5").singleResult();*/
//        System.out.println("Found process definition : " + processDefinition.getName());return ResponseResult.ok(list);}
3.启动流程实例
    /*** 3.启动流程实例** @return*/@RequestMapping("/start/instance")public String startProcessInstance() {RuntimeService runtimeService = processEngine.getRuntimeService();//要启动流程实例,需要提供一些初始化流程变量,自定义Map<String, Object> variables = new HashMap<String, Object>(0);variables.put("employee", "工作组");variables.put("nrOfHolidays", 8);variables.put("description", "请假");ProcessInstance processInstance =runtimeService.startProcessInstanceByKey("leader_approval_key", variables);return ResponseResult.ok(processInstance.getName());}
4.通过流程执行人员查询任务和流程变量
    /*** 通过流程人员定义查询任务和流程变量** @return*/@RequestMapping("/query/task")public String queryProcessInstance() {TaskService taskService = processEngine.getTaskService();//通过组查询任务表
//        List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("managers").list();//通过人查询单个任务Task task = taskService.createTaskQuery().taskAssignee("小王").singleResult();//通过任务id查询流程变量Map<String, Object> processVariables = taskService.getVariables(task.getId());return ResponseResult.ok(processVariables);}
5.通过任务id完成任务
    /*** 通过任务id完成任务** @return*/@RequestMapping("/complete/task")public String completeTask(String taskId) {TaskService taskService = processEngine.getTaskService();//领导审批提交的表达信息Map<String, Object> variables = new HashMap<String, Object>(0);taskService.complete(taskId, variables);return ResponseResult.ok();}
 6.通过流程执行人或者审批人查询审批历史记录
    /*** 通过审批人获取历史任务数据** @param name* @return*/@RequestMapping("/history/task")public String getHistoryTask(@RequestParam("name") String name) {HistoryService historyService = processEngine.getHistoryService();//历史任务流程——流程idList<HistoricActivityInstance> activities =historyService.createHistoricActivityInstanceQuery().processInstanceId("2501").finished().orderByHistoricActivityInstanceEndTime().asc().list();//历史任务List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().taskAssignee(name).list();return ResponseResult.ok(list.toString());}
 7.通过流程id查询流程执行图(多种获取方式)
/*** 通过流程id获取流程资源** @return*/@RequestMapping("/process/resource")public void getProcessResource(HttpServletResponse response) throws IOException {RepositoryService repositoryService = processEngine.getRepositoryService();/*ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId("5085").processDefinitionId("defect_report_flowable:1:5088")
//                .processDefinitionKey("leader_approval_key")
//                .deploymentId("5").singleResult();*/BpmnModel bpmnModel = repositoryService.getBpmnModel("defect_report_flowable:1:4");InputStream imageStream = processDiagramGenerator.generateDiagram(bpmnModel);/*String diagramResourceName = processDefinition.getDiagramResourceName();InputStream imageStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), diagramResourceName);*/FileOutputStream fos = new FileOutputStream("D:\\data\\22222.png");byte[] b = new byte[1024];int leng = -1;while ((leng = imageStream.read(b)) != -1) {fos.write(b, 0, leng);}fos.flush();imageStream.close();fos.close();/*//文件流直接写出ByteArrayOutputStream baos = new ByteArrayOutputStream();OutputStream os = response.getOutputStream();int ch = 0;while (-1 != (ch = imageStream.read())) {baos.write(ch);}os.write(baos.toByteArray());imageStream.close();baos.close();os.close();*/}

五.其他相关的功能和问题持续更新,有问题私信 

1.生成流程实例图片的关键代码
@Service
public class FlowProcessDiagramGenerator extends DefaultProcessDiagramGenerator {private static final String IMAGE_TYPE = "png";@Value("${flowable.activityFontName}")private String activityFontName;@Value("${flowable.labelFontName}")private String labelFontName;@Value("${flowable.annotationFontName}")private String annotationFontName;@Value("${flowable.xml.encoding}")private String encoding;@Autowiredprivate ProcessEngine processEngine;/*** 生成执行动态图片流** @param processDefinitionId 流程定义的id——xml文件规固定的key* @param businessKey* @return*/public InputStream generateActiveDiagram(String processDefinitionId, String businessKey) {RuntimeService runtimeService = processEngine.getRuntimeService();HistoryService historyService = processEngine.getHistoryService();RepositoryService repositoryService = processEngine.getRepositoryService();//1.获取当前的流程定义ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processDefinitionId(processDefinitionId)
//                .processInstanceId(processInstanceId).processInstanceBusinessKey(businessKey).singleResult();//流程实例执行的实例idString processId = null;List<String> activeActivityIds = new ArrayList<>();List<String> highLightedFlows = new ArrayList<>();//3. 获取流程定义id和高亮的节点idif (processInstance != null) {//3.1. 正在运行的流程实例processId = processInstance.getProcessInstanceId();//2.获取所有的历史轨迹线对象List<HistoricActivityInstance> historicSquenceFlows = historyService.createHistoricActivityInstanceQuery()
//                .processDefinitionId(processInstanceId).processInstanceId(processId).activityType(BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW).list();historicSquenceFlows.forEach(historicActivityInstance -> highLightedFlows.add(historicActivityInstance.getActivityId()));activeActivityIds = runtimeService.getActiveActivityIds(processId);} else {//3.2. 已经结束的流程实例HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processDefinitionId(processDefinitionId)
//                    .processInstanceId(processId).processInstanceBusinessKey(businessKey).singleResult();if(historicProcessInstance == null){throw new MessageCodeException(MessageCode.FLOWABLE_PROCESS_IS_RELEASE_SUCCESS);}processId = historicProcessInstance.getId();//3.3. 获取结束节点列表List<HistoricActivityInstance> historicEnds = historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).activityType(BpmnXMLConstants.ELEMENT_EVENT_END).list();List<String> finalActiveActivityIds = activeActivityIds;historicEnds.forEach(historicActivityInstance -> finalActiveActivityIds.add(historicActivityInstance.getActivityId()));}//4. 获取bpmnModel对象BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);//模型 活动节点 高亮线return generateDiagram(bpmnModel, IMAGE_TYPE, activeActivityIds,highLightedFlows, activityFontName, labelFontName, annotationFontName,null, 1.0);}/*** 生成工作流程图** @param bpmnModel 模型* @return*/public InputStream generateDiagram(BpmnModel bpmnModel) {return generateDiagram(bpmnModel, IMAGE_TYPE, activityFontName,labelFontName, annotationFontName,null, 1.0);}

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

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

相关文章

超越GPT-4o!新王Claude 3.5 Sonnet来啦!免费使用

目录 01 比GPT-4o更智能&#xff0c;比Claude 3 Opus快两倍 02 最强视觉Model 03 使用Claude的新方式&#xff1a;Artifacts 04 安全性和透明度 Anthropic刚刚发布了全新大模型Claude 3.5 Sonnet&#xff0c;号称是迄今为止最智能的模型。一文几步教你注册使用Claude 3.5 S…

【面试题】风险评估和应急响应的工作流程

风险评估和应急响应是网络安全管理中两个重要的环节。下面分别介绍它们的工作流程&#xff1a; 一、风险评估工作流程&#xff1a; 1.确定评估范围&#xff1a;明确需要评估的信息系统或资产的范围。 2.资产识别&#xff1a;识别并列出所有需要评估的资产&#xff0c;包括硬件…

prometheus+grafana搭建监控系统

1.prometheus服务端安装 1.1下载包 使用wget下载 &#xff08;也可以直接去官网下载包Download | Prometheus&#xff09; wget https://github.com/prometheus/prometheus/releases/download/v2.44.0/prometheus-2.44.0.linux-amd64.tar.gz1.2解压 tar xf prometheus-2.44…

Modbus协议转Profibus协议网关模块连PLC与激光发射器通讯

一、概述 在PLC控制系统中&#xff0c;从站设备通常以Modbus协议&#xff0c;ModbusTCP协议&#xff0c;Profinet协议&#xff0c;Profibus协议&#xff0c;Profibus DP协议&#xff0c;EtherCAT协议&#xff0c;EtherNET协议等。本文将重点探讨PLC连接Modbus协议转Profibus协…

RGB彩色模型理解与编程实例

一、引言 RGB彩色模型中的R、G和B为三原色&#xff0c;通常R、G和B分别用8位表示&#xff0c;因此24位的RGB 真彩色图像能表示16777216种颜色。在如右图所示RGB彩色立方体可知&#xff0c;任意两种原色混合可以合成一种新的颜色。红&#xff08;1&#xff0c;0&#xff0c;0&a…

微型操作系统内核源码详解系列五(3):cm3下调度的开启

系列一&#xff1a;微型操作系统内核源码详解系列一&#xff1a;rtos内核源码概论篇&#xff08;以freertos为例&#xff09;-CSDN博客 系列二&#xff1a;微型操作系统内核源码详解系列二&#xff1a;数据结构和对象篇&#xff08;以freertos为例&#xff09;-CSDN博客 系列…

如何使用nginx部署https网站(亲测可行)

公司本来有网站sqlynx.com是http运行的&#xff0c;但因为产品出海&#xff0c;基本上都要求使用https&#xff0c;但又需要兼容已有的http服务&#xff0c;所以我自己尝试做了一次https的部署&#xff0c;目前是正常可用的。 目录 步骤 1&#xff1a;安装 Nginx 步骤 2&…

数据仓库的实际应用示例-广告投放平台为例

数据仓库的数据分层通常包括以下几层&#xff1a; ODS层&#xff1a;存放原始数据&#xff0c;如日志数据和结构化数据。DWD层&#xff1a;进行数据清洗、脱敏、维度退化和格式转换。DWS层&#xff1a;用于宽表聚合值和主题加工。ADS层&#xff1a;面向业务定制的应用数据层。…

node版本过高出现ERR_OSSL_EVP_UNSUPPORTED错误

错误原因&#xff1a; 新版本的nodejs使用的openssl和旧版本不同&#xff0c;导致出错 解决方法&#xff1a; 1.将node版本重新换回16.x 2 windows 下 在package.json文件下添加set NODE_OPTIONS--openssl-legacy-provider && "scripts": {"dev"…

Linux开发讲课8--- linux的5种IO模型

一、这里IO是什么 操作系统为了保护自己&#xff0c;设计了用户态、内核态两个状态。应用程序一般工作在用户态&#xff0c;当调用一些底层操作的时候&#xff08;比如 IO 操作&#xff09;&#xff0c;就需要切换到内核态才可以进行 服务器从网络接收的大致流程如下&#xff1…

非常难找的AI衣服图片处理工具推荐,一键轻松AI编辑

在当今数字化时代&#xff0c;AI技术已经渗透到我们生活的方方面面。特别是在图片处理领域&#xff0c;AI的强大功能让很多原本繁琐复杂的操作变得简单易行。今天&#xff0c;我要为大家推荐一款好用的AI衣服图片处理工具——让你一键轻松完成AI编辑&#xff0c;快速实现专业效…

wordpress站群搭建3api代码生成和swagger使用

海鸥技术下午茶-wordpress站群搭建3api代码生成和swagger使用 目标:实现api编写和swagger使用 0.本次需要使用到的脚手架命令 生成 http server 代码 goctl api go -api all.api -dir ..生成swagger文档 goctl api plugin -plugin goctl-swagger"swagger -filename st…

变电站智能巡检机器人解决方案

我国拥有庞大的电网体系&#xff0c;变电站数量众多&#xff0c;且近年来快速增长。然而目前我国变电站巡检方式仍以人工为主&#xff0c;存在效率低下、监控不全面等问题。变电站通常是一个封闭的系统空间&#xff0c;设备种类繁多、占地面积广阔&#xff0c;这对巡检人员实时…

缓存雪崩(主从复制、哨兵模式(脑裂)、分片集群)

缓存雪崩&#xff1a; 在同一时段大量的缓存key同时失效或者Redis服务宕机&#xff0c;导致大量请求到达数据库&#xff0c;带来巨大压力。 方法一&#xff1a; 给不同key的TTL添加随机值&#xff0c;以此避免同一时间大量key失效。&#xff08;用于解决同一时间大量key过期&…

qt 如何获取磁盘信息、QStorageInfo

以往获取qt磁盘信息&#xff0c;笔者是通过一下API转换的 BOOL GetDiskFreeSpaceExW([in, optional] LPCWSTR lpDirectoryName,[out, optional] PULARGE_INTEGER lpFreeBytesAvailableToCaller,[out, optional] PULARGE_INTEGER lpTotalNumberOfBytes,[out, optional…

excel基本操作

excel 若要取消在数据表中进行的所有筛选 步骤操作&#xff1a; 单击“数据”选项卡。在“排序和筛选”组中&#xff0c;找到“清除”按钮。点击“清除”按钮。 图例&#xff1a; 将文本文件的数据导入到Excel工作表中进行数据处理 步骤&#xff1a; 在Excel中&#xff0c…

java之文件上传代码审计

1 文件上传漏洞审计 1.1 漏洞原理介绍 大部分文件上传漏洞的产生是因为Web应用程序未对文件的格式和进行严格过滤&#xff0c;导致用户可上传jsp、php等webshell代码文件&#xff0c;从而被利用。例如在 BBS发布图片 , 在个人网站发布ZIP压缩包, 在办公平台发布DOC文件等 , 只…

高阶图神经网络 (HOGNN) 的概念、分类和比较

图神经网络&#xff08;GNNs&#xff09;是一类强大的深度学习&#xff08;DL&#xff09;模型&#xff0c;用于对相互连接的图数据集进行分类和回归。它们已被用于研究人类互动、分析蛋白质结构、设计化合物、发现药物、识别入侵机器、模拟单词之间的关系、寻找有效的交通路线…

Vue70-路由的几个注意点

一、路由组件和一般组件 1-1、一般组件 1-2、路由组件 不用写组件标签。靠路由规则匹配出来&#xff0c;由路由器渲染出来的组件。 1-3、注意点1 一般组件和路由组件&#xff0c;一般放在不同的文件夹&#xff0c;便于管理。 一般组件放在components文件夹下。 1-4、注意点…

河南大学24计算机考研数据,有三个学院招收计算机相关专业,都是考的408!

河南大学&#xff08;Henan University&#xff09;&#xff0c;简称“河大”&#xff0c;是河南省人民政府与中华人民共和国教育部共建高校&#xff0c;国家“双一流”建设高校&#xff0c;入选国家“111计划”、中西部高校基础能力建设工程、卓越医生教育培养计划、卓越法律人…