SpringBoot3-Flowable7初體驗

目錄

  • 簡介
  • 準備
    • JDK
    • MySQL
    • flowable-ui
  • 創建流程圖
    • 要注意的地方
  • 編碼
    • 依賴和配置
    • 控制器
    • 實體
    • Flowable任務處理類
  • 驗證
    • 啟動程序
    • 調用接口
  • 本文源碼
  • 參考

簡介

  • Flowable是一個輕量的Java業務流程引擎,用于實現業務流程的管理和自動化。相較于老牌的Activiti做了一些改進和擴展,實現更高的性能和更小的內存占用,支持更多的數據庫類型。

準備

JDK

  • JDK 17

MySQL

  • flowable程序初始化會生產表,所以要數據庫。
  • MySQL 數據庫,我使用的是phpstudy(下載地址:https://www.xp.cn/phpstudy#phpstudy)集成環境的MySQL8.0.12

在這里插入圖片描述

flowable-ui

  • 需要事先建一個流程給flowable,所以要個可視化界面創建流程。
  • flowable-ui:使用docker安裝,使用命令:
 docker run -d --name fu -p 8080:8080 flowable/flowable-ui

在這里插入圖片描述

  • 運行起來的網頁效果,地址是 http://ip:8080/flowable-ui

默認帳號密碼: admin test

在這里插入圖片描述

  • 如果拉不下來鏡像,請嘗試以下方案:
    • 方案一、設置代理,參考拙作Docker設置代理
    • 方案二、更換鏡像源,如下配置(編輯/etc/docker/daemon.json):
{"registry-mirrors": ["https://docker.m.daocloud.io"]
}

創建流程圖

  • 實現一個創建采購訂單,order.totalPrice金額大于1000要經理確認的功能。
    在這里插入圖片描述
    在這里插入圖片描述
  • 完整流程圖
    在這里插入圖片描述

要注意的地方

  • 設置分支條件,order.totalPrice大于1000要經理確認。
    在這里插入圖片描述

  • 任務要綁定處理類
    在這里插入圖片描述
    在這里插入圖片描述

  • 經理確認節點要綁定參數 Assignee manager
    在這里插入圖片描述
    在這里插入圖片描述

編碼

依賴和配置

  • 引入的包
		<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.11</version></dependency><!-- 阿里數據庫連接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.23</version></dependency><!-- Mysql驅動包 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>7.1.0</version></dependency>
  • 程序配置文件
spring:application:name: flowable-sampleprofiles:active: dev
server:port: 8080# MyBatis配置
mybatis-plus:# 搜索指定包別名typeAliasesPackage: com.zzq.domain# 配置mapper的掃描,找到所有的mapper.xml映射文件mapperLocations: classpath*:mapper/**/*Mapper.xml# 加載全局的配置文件configLocation: classpath:mybatis/mybatis-config.xml# 日志配置
logging:level:com.zzq: debug
flowable:#  是否激活異步執行器async-executor-activate: false# 數據庫模式更新策略,true表示自動更新數據庫模式database-schema-update: true
  • application-dev.yml
# 數據源配置
spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/flowable_sample?nullCatalogMeansCurrent=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8username: rootpassword: root
  • 下載文件放到項目中resources/processes
    在這里插入圖片描述
    在這里插入圖片描述
  • FlowableConfig
package com.zzq.config;import org.flowable.spring.SpringProcessEngineConfiguration;
import org.flowable.spring.boot.EngineConfigurationConfigurer;
import org.springframework.context.annotation.Configuration;/*** FlowableConfig** @Description: 解決Diagram生成的流程圖文字顯示為”口口口“ 這是因為本地沒有默認的字體,安裝字體或者修改配置解決* @Author: zzq* @Date 2025/4/5 15:16* @since 1.0.0*/
@Configuration
public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {@Overridepublic void configure(SpringProcessEngineConfiguration springProcessEngineConfiguration) {springProcessEngineConfiguration.setActivityFontName("宋體");springProcessEngineConfiguration.setLabelFontName("宋體");springProcessEngineConfiguration.setAnnotationFontName("宋體");}
}

控制器

  • OrderFlowController
package com.zzq.controller;import com.zzq.domain.Order;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricActivityInstanceQuery;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.*;import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;/*** Zhou Zhongqing* 2025-04-01* 訂單流程控制器*/
@RestController
@RequestMapping("/orderFlow")
public class OrderFlowController {private static final Logger log = LoggerFactory.getLogger(OrderFlowController.class);@Resourceprivate HistoryService historyService;@Resourceprivate RepositoryService repositoryService;@Resourceprivate RuntimeService runtimeService;@Resourceprivate TaskService taskService;@Resourceprivate ProcessEngine processEngine;/*** 開始流程* @param content* @param totalPrice* @return*/@PostMapping("/create_order")public ResponseEntity<String> startFlow(String content, Integer totalPrice) {Map<String, Object> map = new HashMap<>();map.put("order", new Order(content, totalPrice));ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("flowable-sample", map);String processId = processInstance.getId();log.info("{} 流程實例ID:{} ", processInstance.getProcessDefinitionName(), processId);Task task = taskService.createTaskQuery().processInstanceId(processId).active().singleResult();taskService.complete(task.getId());return ResponseEntity.ok(processId);}/*** 訂單列表,待確認的,返回任務id* @return*/@RequestMapping("/order_list")public String getOrderList() {List<Task> list = taskService.createTaskQuery().taskAssignee("manager").list();StringBuffer stringBuffer = new StringBuffer();list.stream().forEach(task -> stringBuffer.append(task.getId()+ " : " + runtimeService.getVariable(task.getExecutionId(), "order") + "\n"));return stringBuffer.toString();}/*** 經理確認* @param taskId* @return*/@PostMapping("/confirm/{taskId}")public ResponseEntity<String> confirm(@PathVariable String taskId) {Task task = taskService.createTaskQuery().taskId(taskId).singleResult();HashMap<String, Object> map = new HashMap<>();map.put("verified", true);taskService.complete(taskId, map);return ResponseEntity.ok("success");}/*** 生成圖,某個流程處理進度顯示* @param response* @param processId* @throws Exception*/@GetMapping(value = "/processDiagram/{processId}")public void genProcessDiagram(HttpServletResponse response, @PathVariable("processId") String processId) throws Exception{ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();if (null == pi) {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<>();List<HistoricActivityInstance> historyList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list();for (HistoricActivityInstance historicActivityInstance : historyList) {String activityId = historicActivityInstance.getActivityId();if("sequenceFlow".equals(historicActivityInstance.getActivityType())){flows.add(activityId);}}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();String format = "png";InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engConf.getActivityFontName(), engConf.getLabelFontName(), engConf.getAnnotationFontName(), engConf.getClassLoader(), 1.0, false);
//        OutputStream out = null;
//        byte[] buf = new byte[1024];
//        int legth = 0;
//        try {
//            out = response.getOutputStream();
//            while ((legth = in.read(buf)) != -1) {
//                out.write(buf, 0, legth);
//            }
//        } finally {
//            if (in != null) {
//                in.close();
//            }
//            if (out != null) {
//                out.close();
//            }
//        }IOUtils.copy(in, response.getOutputStream());}}

實體

  • Order
package com.zzq.domain;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;import java.io.Serializable;
import java.io.Serial;
@TableName(value = "t_order")
public class Order implements Serializable {@Serialprivate static final long serialVersionUID = 8347055723013141158L;public Order() {}public Order(String content, Integer totalPrice) {this.content = content;this.totalPrice = totalPrice;}public Order(Integer id, String content, Integer totalPrice) {this.id = id;this.content = content;this.totalPrice = totalPrice;}@TableId(value = "id",type = IdType.AUTO)private Integer id;private String content;private Integer totalPrice;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public Integer getTotalPrice() {return totalPrice;}public void setTotalPrice(Integer totalPrice) {this.totalPrice = totalPrice;}
}

Flowable任務處理類

  • CreateOderProcess
package com.zzq.process;import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class CreateOderProcess implements JavaDelegate {private static final Logger log = LoggerFactory.getLogger(CreateOderProcess.class);@Overridepublic void execute(DelegateExecution delegateExecution) {log.info("訂單創建成功 {}",delegateExecution.getVariable("order"));}
}
  • SendMailProcess
package com.zzq.process;import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class SendMailProcess implements JavaDelegate {private static final Logger log = LoggerFactory.getLogger(SendMailProcess.class);@Overridepublic void execute(DelegateExecution delegateExecution) {log.info("發送審核郵件 {} ",delegateExecution.getVariable("order"));}
}

驗證

啟動程序

  • 配置了database-schema-update: true第一次啟動會自動創建表
    在這里插入圖片描述

在這里插入圖片描述

調用接口

  • 創建采購訂單, /orderFlow/create_order ,返回流程實例ID

    • 不需要經理確認
      在這里插入圖片描述
    • 需要經理確認
      在這里插入圖片描述
  • 查看待確認的訂單,返回任務id拼接Order
    在這里插入圖片描述

  • 查看某個流程處理進度顯示,傳入流程實例id
    在這里插入圖片描述

  • 經理調用確認采購訂單,傳入taskId
    在這里插入圖片描述

  • 確認后再調用待確認訂單接口也就沒有剛才的任務id了
    在這里插入圖片描述

  • 驗證完成

本文源碼

  • https://github.com/1030907690/flowable-sample

參考

  • https://www.bilibili.com/video/BV1gnkJYJEbg/
  • https://blog.csdn.net/qq_34162294/article/details/143806673
  • https://blog.51cto.com/u_16213663/10188533
  • https://blog.csdn.net/houyj1986/article/details/85546680

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/88770.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/88770.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/88770.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

phpMyAdmin:一款經典的MySQL在線管理工具又回來了

phpMyAdmin 是一個免費開源、基于 Web 的 MySQL/MariaDB 數據庫管理和開發工具。它提供了一個直觀的圖形用戶界面&#xff0c;使得我們無需精通復雜的 SQL 命令也能執行大多數數據庫管理任務。 phpMyAdmin 項目曾經暫停將近兩年&#xff0c;不過 2025 年又開始發布新版本了。 …

存儲服務一NFS文件存儲概述

前言&#xff1a; 網絡文件系統&#xff08;Network File System&#xff0c;NFS&#xff09;誕生于1984年&#xff0c;由Sun Microsystems首創&#xff0c;旨在解決異構系統間的文件共享需求。作為一種基于客戶端-服務器架構的分布式文件協議&#xff0c;NFS允許遠程主機通過T…

libimagequant 在 mac 平臺編譯雙架構

在 macOS 上編譯 libimagequant 的雙架構&#xff08;aarch64 x86_64&#xff09;通用二進制庫&#xff0c;以下是完整步驟&#xff1a;??1. 準備 Rust 工具鏈?? # 安裝兩個目標平臺 rustup target add aarch64-apple-darwin x86_64-apple-darwin# 確認安裝成功 rustup ta…

暑期自學嵌入式——Day01(C語言階段)

點關注不迷路喲。你的點贊、收藏&#xff0c;一鍵三連&#xff0c;是我持續更新的動力喲&#xff01;&#xff01;&#xff01; 主頁&#xff1a; 一位搞嵌入式的 genius-CSDN博客https://blog.csdn.net/m0_73589512?spm1011.2682.3001.5343感悟&#xff1a; 今天我認為最重…

Flutter基礎(前端教程⑧-數據模型)

這個示例展示了如何創建數據模型、解析 JSON 數據&#xff0c;以及在 UI 中使用這些數據&#xff1a;import package:flutter/material.dart; import dart:convert;void main() {// 示例&#xff1a;手動創建User對象final user User(id: 1,name: 張三,age: 25,email: zhangsa…

SSRF10 各種限制繞過之30x跳轉繞過協議限制

ssrf漏洞在廠商的處理下可能進行一些特殊處理導致我們無法直接利用漏洞 有以下四種&#xff1a; 1.ip地址限制繞過 2.域名限制繞過 3.30x跳轉繞過域名限制 4.DNS rebinding繞過內網ip限制 本章我們講30x跳轉繞過域名限制 30x跳轉繞過域名限制 之前我們使用ssrf漏洞時可以…

DNS解析過程和nmap端口掃描

目錄 DNS解析流程&#xff1a; nmap端口掃描 指定掃描方式 TCP全連接掃描 -sT SYN半連接掃描 -sS -sT和 -sS的區別 Linux提權 利用好谷歌語法查找敏感信息 如果自己搭建了網站文件要放在phpstudy_pro\WWW下。 如果想要使用域名訪問網站&#xff0c;需要在phpstudy_pro…

【基于開源大模型(如deepseek)開發應用及其發展趨勢的一點思考】

1. 開源大模型技術發展現狀1.1 DeepSeek等主流開源大模型的技術特性分析 DeepSeek作為當前最具代表性的開源大模型之一&#xff0c;其技術架構具有多項創新特性。該模型采用混合專家架構(MoE)&#xff0c;通過將視覺編碼分離為"理解"和"生成"兩條路徑&…

java8 ConcurrentHashMap 桶級別鎖實現機制

Java 8 ConcurrentHashMap 桶級別鎖實現機制 Java 8 中的 ConcurrentHashMap 拋棄了分段鎖設計&#xff0c;采用了更細粒度的桶級別鎖&#xff08;bucket-level locking&#xff09;實現&#xff0c;這是其并發性能提升的關鍵。下面詳細解析其實現原理&#xff1a; 1. 基本實現…

Python正則表達式實戰指南

一 正則表達式庫正則表達式是文本處理中不可或缺的強大工具&#xff0c;Python通過re模塊提供了完整的正則表達式支持。本文將詳細介紹re模塊中最常用的match()、search()和findall()函數&#xff0c;以及貪婪模式與非貪婪模式的區別&#xff0c;幫助讀者掌握Python中正則表達式…

使用球體模型模擬相機成像:地面與天空的可見性判斷與紋理映射

在傳統相機模擬中&#xff0c;地面通常被建模為一個平面&#xff08;Plane&#xff09;&#xff0c;這在低空場景下是合理的。但在更大視場范圍或遠距觀察時&#xff0c;地球的曲率不可忽視。因此&#xff0c;我們需要將地面模型從平面升級為球體&#xff0c;并基于球面與光線的…

Agent自動化與代碼智能

核心問題&#xff1a; 現在很多團隊做AI系統有個大毛病&#xff1a;只顧追求“高大上”的新技術&#xff08;尤其是AI Agent&#xff09;&#xff0c;不管實際業務需不需要。 結果系統搞得又貴、又復雜、還容易出錯。大家被“Agent”這個概念搞暈了&#xff1a;到底啥時候用簡單…

SQL141 試卷完成數同比2020年的增長率及排名變化

SQL141 試卷完成數同比2020年的增長率及排名變化 withtemp as (selectexam_id,tag,date(submit_time) as submit_timefromexamination_infoleft join exam_record using (exam_id)wheresubmit_time is not null),2021_temp as (selecttag,count(*) as exam_cnt_21,rank() over…

C語言<數據結構-單鏈表>

鏈表是一種常見且重要的數據結構&#xff0c;在 C 語言中&#xff0c;它通過指針將一系列的節點連接起來&#xff0c;每個節點可以存儲不同類型的數據。相比數組&#xff0c;鏈表在插入和刪除元素時不需要移動大量數據&#xff0c;具有更好的靈活性&#xff0c;尤其適合處理動態…

archive/tar: unknown file mode ?rwxr-xr-x

這個是我在docker build報錯的&#xff0c;這是一個node.js項目。我猜你也是一個node.js下的項目&#xff0c;或者前端項目。 解決方法&#xff1a; .dockerignore里面寫一下node_modules就行了。 未能解決&#xff1a;archive/tar&#xff1a;未知文件模式&#xff1f;rwxr-…

【前端】ikun-markdown: 純js實現markdown到富文本html的轉換庫

文章目錄背景界面當前支持的 Markdown 語法不支持的Markdown 語法代碼節選背景 出于興趣,我使用js實現了一個 markdown語法 -> ast語法樹 -> html富文本的庫, 其速度應當慢于正則實現的同類js庫, 但是語法擴展性更好, 嵌套列表處理起來更方便. 界面 基于此js實現vue組…

【echarts踩坑記錄】為什么第二個Y軸最大值不整潔

目錄問題復現示意圖&#xff1a;解決方法有以下幾種&#xff1a;1. 在y軸配置中手動設置max屬性&#xff1a;2. 使用ECharts提供的坐標軸標簽格式化功能&#xff1a;&#x1f680;寫在最后問題復現示意圖&#xff1a; 今天在用echarts圖表的時候&#xff0c;出現了一個小問題。…

Duplicate cleaner pro 的使用技巧

Duplicate cleaner pro 的使用技巧前言文件去重基本介紹經驗之談目錄結構修改盤符起因方法手動分配方法?數據修改方法安裝sqlite-web修改數據庫GPU加速安裝驅動獲取驅動和硬件信息安裝CUDA配置環境變量&#xff08;如果是自定義安裝&#xff09;創建程序<1>獲取參數和命…

數字孿生技術引領UI前端設計新趨勢:增強現實與虛擬現實的融合應用

hello寶子們...我們是艾斯視覺擅長ui設計和前端數字孿生、大數據、三維建模、三維動畫10年經驗!希望我的分享能幫助到您!如需幫助可以評論關注私信我們一起探討!致敬感謝感恩!一、引言&#xff1a;AR 與 VR 的 “割裂” 與數字孿生的 “融合” 契機增強現實&#xff08;AR&…

Qt使用dump文件記錄并查找軟件奔潰信息詳細教程

Qt使用dump文件記錄并查找軟件奔潰信息一、dump文件概述1、dump文件的基本概念2、dump文件的常見類型3、dump文件的分析工具4、dump文件的應用場景二、具體實現步驟1、下載dbghelp庫2、將庫添加到自己的工程中3、main.cpp添加代碼記錄奔潰日志4、編寫測試代碼5、測試6、結果查看…