当前位置: 首页 > article >正文

Flowable 实战:从零构建 Spring Boot 3 微服务审批系统

1. 为什么选择Flowable构建审批系统在开发企业级应用时审批流程是绕不开的核心功能。传统硬编码的审批逻辑往往面临流程变更困难、状态追踪复杂等问题。我经历过一个报销系统升级项目仅仅因为增加了副总经理审批环节就导致整个代码逻辑需要重构。这正是Flowable这类工作流引擎的价值所在——它通过可视化流程设计将业务逻辑与流程控制解耦。Flowable作为Activiti的分支项目经过多年发展已经形成三大核心优势标准化支持完整支持BPMN 2.0规范这意味着你设计的流程可以直接用业界标准工具打开和编辑Spring Boot友好提供starter依赖与Spring生态无缝集成我在实际项目中实测启动时间仅增加200-300ms历史追溯能力内置完善的流程实例追踪可以随时查询某个审批卡在哪个环节这个功能曾帮我快速定位过线上审批停滞问题特别在微服务架构下Flowable的轻量级特性核心jar包仅5MB左右使其非常适合作为独立流程服务部署。去年我们团队将审批服务从单体应用拆解为独立微服务流程引擎响应时间反而降低了40%。2. 环境搭建与基础配置2.1 项目初始化要点使用Spring Initializr创建项目时这几个选项需要特别注意Java版本必须选择17Spring Boot 3默认要求JDK 17打包方式建议用JAR而非WAR微服务场景下更轻量依赖选择除了基础的Web和JPA需要手动添加Flowable依赖这是我在多个项目中验证过的基础pom.xml配置dependencies !-- 基础Spring Boot依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-jpa/artifactId /dependency !-- Flowable核心 -- dependency groupIdorg.flowable/groupId artifactIdflowable-spring-boot-starter/artifactId version7.2.0/version /dependency !-- 数据库驱动以PostgreSQL为例 -- dependency groupIdorg.postgresql/groupId artifactIdpostgresql/artifactId scoperuntime/scope /dependency /dependencies2.2 数据库配置陷阱很多新手会在数据库配置上踩坑这里分享我的最佳实践# application.yml spring: datasource: url: jdbc:postgresql://localhost:5432/flowable_db username: flowable password: flowable driver-class-name: org.postgresql.Driver hikari: maximum-pool-size: 10 # Flowable需要较大连接池 flowable: database-schema-update: true # 开发环境开启自动更新表结构 async-executor-activate: false # 初期可关闭异步执行器 history-level: full # 记录完整历史便于调试特别注意生产环境一定要把database-schema-update改为false否则可能造成数据丢失。我有次在测试环境忘记关闭这个选项导致流程定义表被意外重建。3. 设计第一个审批流程3.1 BPMN设计实战在resources/processes目录下创建leave-request.bpmn20.xmlprocess idleaveRequest name请假审批流程 !-- 开始节点 -- startEvent idstartEvent / !-- 提交申请用户任务 -- userTask idsubmitRequest name提交请假申请 flowable:assignee${applicant} / !-- 部门审批候选组 -- userTask iddeptApprove name部门经理审批 flowable:candidateGroupsdept_managers / !-- 条件网关 -- exclusiveGateway iddecisionGateway / !-- 超过3天需要HR备案 -- sequenceFlow idtoHrRecord sourceRefdecisionGateway targetRefhrRecord conditionExpression xsi:typetFormalExpression ${days 3} /conditionExpression /sequenceFlow !-- 直接结束 -- sequenceFlow idtoEnd sourceRefdecisionGateway targetRefendEvent conditionExpression xsi:typetFormalExpression ${days 3} /conditionExpression /sequenceFlow userTask idhrRecord nameHR备案 flowable:assigneehr_staff / endEvent idendEvent / /process这个设计有几个关键点使用candidateGroups实现角色动态分配通过条件网关实现分支路由变量表达式${days}实现业务规则控制3.2 流程调试技巧开发阶段我常用这些方法验证流程单元测试法编写流程测试类SpringBootTest class LeaveProcessTest { Autowired private RuntimeService runtimeService; Test void testProcess() { MapString, Object vars new HashMap(); vars.put(applicant, zhangsan); vars.put(days, 5); ProcessInstance instance runtimeService .startProcessInstanceByKey(leaveRequest, vars); assertNotNull(instance.getId()); } }控制台查询通过API查看运行状态# 查询待办任务 curl http://localhost:8080/flowable-api/tasks?assigneezhangsan可视化监控安装Flowable Modeler组件实时查看流程走向4. 业务集成与API设计4.1 服务层封装模式推荐采用门面模式封装Flowable原生APIService RequiredArgsConstructor public class WorkflowFacade { private final RuntimeService runtimeService; private final TaskService taskService; public String startProcess(String processKey, String businessKey, MapString, Object variables) { // 建立业务ID与流程实例关联 variables.put(businessKey, businessKey); return runtimeService.startProcessInstanceByKey( processKey, businessKey, variables).getId(); } public ListTaskDTO getUserTasks(String userId, int page, int size) { return taskService.createTaskQuery() .taskAssignee(userId) .orderByTaskCreateTime().desc() .listPage(page, size) .stream() .map(this::convertToDTO) .collect(Collectors.toList()); } private TaskDTO convertToDTO(Task task) { // 转换逻辑... } }这种封装带来三个好处隔离底层API变更风险统一分页和DTO转换集中业务异常处理4.2 REST API设计规范审批系统的API需要特别注意幂等性设计RestController RequestMapping(/api/workflow) public class WorkflowController { PostMapping(/processes/{processKey}) public ResponseEntity? startProcess( PathVariable String processKey, RequestBody StartProcessRequest request) { // 幂等控制相同businessKey不重复创建流程 if(workflowService.existsProcess(request.getBusinessKey())){ return ResponseEntity.status(HttpStatus.CONFLICT).build(); } String instanceId workflowService.startProcess( processKey, request.getBusinessKey(), request.getVariables()); return ResponseEntity.ok( new ProcessInstanceResponse(instanceId)); } GetMapping(/tasks) public PageResponseTaskDTO queryTasks( RequestParam String assignee, RequestParam(defaultValue 0) int page, RequestParam(defaultValue 10) int size) { return workflowService.queryUserTasks(assignee, page, size); } }建议采用HATEOAS风格返回结果方便前端动态构建操作链接。5. 生产环境优化策略5.1 性能调优方案在高并发场景下这几个配置项需要调整flowable: async-executor: activate: true core-pool-size: 5 max-pool-size: 10 queue-size: 100 process: enable-xml-validation: false # 生产环境可关闭校验提升性能实测表明启用异步执行器后流程启动耗时从平均200ms降至50ms吞吐量提升3倍左右99%的流程实例能在1秒内完成初始化5.2 监控与告警推荐集成Prometheus监控这些关键指标Bean public MeterRegistryCustomizerMeterRegistry flowableMetrics() { return registry - { registry.gauge(flowable.active.tasks, taskService.createTaskQuery().active().count()); registry.gauge(flowable.completed.tasks, historyService.createHistoricTaskInstanceQuery() .finished().count()); }; }预警阈值建议待办任务积压超过1000条流程平均耗时超过业务SLA的1.5倍流程失败率超过1%6. 常见问题解决方案6.1 事务管理陷阱Flowable默认会开启事务与Spring事务混用时容易出现问题。我的经验是在Service方法上明确声明事务传播行为Transactional(propagation Propagation.REQUIRES_NEW) public void completeTask(String taskId) { // 业务逻辑 taskService.complete(taskId); }避免在事务中执行长时间操作对关键业务操作添加重试机制6.2 用户集成方案企业通常已有用户体系集成方案有两种选择同步模式通过EventListener同步用户数据Component RequiredArgsConstructor class UserSyncListener { private final IdentityService identityService; EventListener public void handleUserCreateEvent(UserCreatedEvent event) { User user identityService.newUser(event.getUserId()); user.setEmail(event.getEmail()); identityService.saveUser(user); } }动态解析模式实现Flowable的IdentitySession接口public class CustomIdentitySession implements IdentitySession { Override public User getUser(String userId) { return userClient.getUser(userId); // 调用外部系统 } }第一种方案实现简单但存在延迟第二种实时性更好但实现复杂度高。我们项目最终采用了混合模式高频属性动态获取基础信息定期同步。7. 进阶开发技巧7.1 动态流程控制通过API实现运行时流程调整public void addEmergencyStep(String processInstanceId) { runtimeService.createChangeActivityStateBuilder() .processInstanceId(processInstanceId) .moveActivityIdTo(currentTask, emergencyReview) .changeState(); }这种技术特别适合处理紧急加签场景流程异常时插入补救步骤A/B测试不同审批路径7.2 表单动态绑定结合前端实现灵活表单渲染userTask idhrApprove nameHR审批 flowable:formKeyhr_approval_form extensionElements flowable:formProperty idapprovalResult typeenum requiredtrue values同意,驳回,需补充材料/ /extensionElements /userTask后端通过FormService获取表单定义public FormModel getTaskForm(String taskId) { TaskFormData formData formService.getTaskFormData(taskId); return convertToFormModel(formData); }这套机制让我们在不重启服务的情况下就能调整审批表单字段。8. 微服务集成模式在分布式环境中推荐采用这些架构方案独立流程服务将Flowable部署为独立微服务优点资源隔离专业运维缺点需要处理分布式事务嵌入式模式每个业务服务包含流程引擎优点本地调用性能好缺点需要解决流程定义同步问题混合模式核心流程集中部署简单流程本地处理折中方案也是我们目前采用的架构跨服务调用建议使用消息队列TransactionalEventListener(phase AFTER_COMMIT) public void handleProcessEvent(ProcessCompletedEvent event) { kafkaTemplate.send(process-events, event.getBusinessKey(), event); }这种方案经历过双十一大流量考验峰值时每天处理超过200万条审批流程。

相关文章:

Flowable 实战:从零构建 Spring Boot 3 微服务审批系统

1. 为什么选择Flowable构建审批系统? 在开发企业级应用时,审批流程是绕不开的核心功能。传统硬编码的审批逻辑往往面临流程变更困难、状态追踪复杂等问题。我经历过一个报销系统升级项目,仅仅因为增加了副总经理审批环节,就导致整…...

email2phonenumber与Phonerator对比分析:选择最适合你的OSINT工具

email2phonenumber与Phonerator对比分析:选择最适合你的OSINT工具 【免费下载链接】email2phonenumber A OSINT tool to obtain a targets phone number just by having his email address 项目地址: https://gitcode.com/gh_mirrors/em/email2phonenumber e…...

Cinny架构设计揭秘:组件化开发与现代前端工程实践

Cinny架构设计揭秘:组件化开发与现代前端工程实践 【免费下载链接】cinny Yet another matrix client 项目地址: https://gitcode.com/GitHub_Trending/ci/cinny Cinny作为一款现代Matrix客户端,采用组件化架构与前沿前端技术栈,构建了…...

告别‘打架’的目标:用CMPSO算法轻松搞定多目标优化(Python代码实战)

告别‘打架’的目标:用CMPSO算法轻松搞定多目标优化(Python代码实战) 想象一下,你正在设计一款新型电动汽车,需要同时优化续航里程、制造成本和充电速度。这三个目标就像三个固执的谈判代表,各自坚持己见—…...

Emscripten构建优化指南:针对不同目标平台的终极优化策略

Emscripten构建优化指南:针对不同目标平台的终极优化策略 【免费下载链接】emscripten Emscripten: An LLVM-to-WebAssembly Compiler 项目地址: https://gitcode.com/gh_mirrors/em/emscripten Emscripten是一个强大的LLVM到WebAssembly编译器,它…...

【Android】ExoPlayer进阶:实现高效视频流播放与资源管理

1. ExoPlayer核心优势与适用场景 在Android视频播放开发领域,ExoPlayer早已成为开发者首选的解决方案。作为Google开源的媒体播放框架,它完美解决了系统自带MediaPlayer的诸多限制。我曾在多个百万级用户的应用中深度使用ExoPlayer,实测下来它…...

Go-multierror 实战案例:10个常见场景的错误处理优化

Go-multierror 实战案例:10个常见场景的错误处理优化 【免费下载链接】go-multierror A Go (golang) package for representing a list of errors as a single error. 项目地址: https://gitcode.com/gh_mirrors/go/go-multierror 在Go语言开发中&#xff0c…...

mysql主键设计原则_InnoDB聚簇索引对性能的影响

主键不必是自增整数但强烈推荐;非自增主键(如UUID、字符串)易引发页分裂、随机IO和索引碎片,增大二级索引体积并降低缓存效率;更新主键等于全行重建,必须禁止;无显式主键时InnoDB会生成隐藏ROW_…...

Polaris流量控制实战:5种负载均衡策略与智能路由配置

Polaris流量控制实战:5种负载均衡策略与智能路由配置 【免费下载链接】polaris Service Discovery and Governance Platform for Microservice and Distributed Architecture 项目地址: https://gitcode.com/gh_mirrors/pol/polaris Polaris作为微服务和分布…...

GD32F45ZG引脚模式实战指南:从基础配置到高级应用

1. GD32F45ZG引脚模式基础入门 第一次接触GD32F45ZG的引脚配置时,我也被各种模式搞得晕头转向。这就像刚拿到新手机时,得先搞清楚各个按键的功能才能玩转它。GD32F45ZG的引脚就是它的"按键",配置对了才能让芯片按我们的想法工作。 …...

ROLL Agentic RL实战:多轮交互智能体的训练与部署

ROLL Agentic RL实战:多轮交互智能体的训练与部署 【免费下载链接】ROLL An Efficient and User-Friendly Scaling Library for Reinforcement Learning with Large Language Models 项目地址: https://gitcode.com/gh_mirrors/roll13/ROLL ROLL(…...

嵌入式实时异步编程库:FreeRTOS轻量级Job调度框架

1. 项目概述Job是一个面向嵌入式实时系统的轻量级异步编程库,专为 FreeRTOS 环境深度定制。它并非通用 C 异步框架的简单移植,而是基于裸机资源约束与实时性要求重构的模块化任务调度抽象层。其核心设计哲学是:以最小运行时开销实现确定性异步…...

绕过喜马拉雅反爬?聊聊xm-sign签名机制的设计与合规数据获取方案

从商业视角解析xm-sign签名机制的设计逻辑与合规数据获取路径 在数字内容产业快速发展的今天,音频平台面临着数据保护与开放共享的双重挑战。喜马拉雅引入的xm-sign签名机制,正是这一背景下平台安全策略的典型代表。作为产品经理或开发者,理解…...

没有后台服务的鸿蒙应用,算不算“半成品”?——本地 Service Extension 开发真香指南

大家好,我是[晚风依旧似温柔],新人一枚,欢迎大家关注~ 本文目录:前言一、ExtensionAbility 类型:先搞清“职业分工”,再谈用谁干活1️⃣ ExtensionAbility 大家族速览二、后台服务场景:哪些事儿…...

Gophish实战指南:从零构建邮件钓鱼实验环境

1. Gophish简介与核心功能 Gophish是一款专为企业和安全团队设计的开源钓鱼模拟工具,它让安全测试人员能够快速搭建逼真的钓鱼攻击环境。我第一次接触这个工具是在2018年的一次内部安全演练中,当时我们需要测试公司员工的网络安全意识,但市面…...

没有后台服务的鸿蒙应用,算不算“半成品”?——本地 Service Extension 开发真香指南!

大家好,我是[晚风依旧似温柔],新人一枚,欢迎大家关注~ 本文目录:前言一、ExtensionAbility 类型:先搞清“职业分工”,再谈用谁干活1️⃣ ExtensionAbility 大家族速览二、后台服务场景:哪些事儿…...

探索正点原子7寸RGB液晶屏:AD20工程实战

适用于正点原子7寸RGB液晶屏资料,包含AD20完整工程最近,我入手了一块正点原子的7寸RGB液晶屏,搭配AD20开发板,想着能折腾出点有意思的东西。折腾的过程虽然有点坎坷,但收获还是挺多的,现在就来分享一下我的…...

2025身份证前六位地区代码解析:如何快速查询与使用指南

1. 身份证前六位地区代码的奥秘 每次看到身份证号码前六位数字,你有没有好奇过它们代表什么?这串看似简单的数字其实是行政区划代码,相当于每个地区的"身份证号"。我刚开始研究这个时也一头雾水,直到发现它背后藏着完整…...

TensorFlow Lite Micro:如何在微控制器上部署机器学习的终极指南

TensorFlow Lite Micro:如何在微控制器上部署机器学习的终极指南 【免费下载链接】tflite-micro Infrastructure to enable deployment of ML models to low-power resource-constrained embedded targets (including microcontrollers and digital signal processo…...

ADS实战:利用RFPro近场仿真精准定位微带电路耦合热点

1. 为什么需要近场仿真定位耦合热点? 微带电路设计中最头疼的问题,就是明明原理图仿真完美,实际布局后性能却突然恶化。上周我就遇到一个案例:某5G基站用的带通滤波器,在3.5GHz频段突然出现异常谐振,插损直…...

强力解锁Unity开发:Zenject依赖注入框架的5大实战优势

强力解锁Unity开发:Zenject依赖注入框架的5大实战优势 【免费下载链接】Zenject Dependency Injection Framework for Unity3D 项目地址: https://gitcode.com/gh_mirrors/ze/Zenject Zenject是Unity3D生态中最强大的依赖注入框架,它通过解耦组件…...

从Bash迁移到Zsh:Oh My Zsh实战避坑指南(含性能对比)

从Bash迁移到Zsh:Oh My Zsh实战避坑指南(含性能对比) 如果你长期使用Bash,可能会对Zsh的流畅补全和主题系统产生好奇。但迁移不只是换个Shell那么简单——环境变量继承、脚本兼容性和性能差异都可能成为隐形陷阱。本文将用实测数据…...

RAdam实战教程:如何在PyTorch中轻松集成和使用Rectified Adam优化器

RAdam实战教程:如何在PyTorch中轻松集成和使用Rectified Adam优化器 【免费下载链接】RAdam On the Variance of the Adaptive Learning Rate and Beyond 项目地址: https://gitcode.com/gh_mirrors/ra/RAdam Rectified Adam(RAdam)是…...

从零开始掌握YOLO——实时目标检测的技术详解

你正在打开手机相册,系统自动把所有照片按“人物”“风景”“宠物”整理好;你开车经过十字路口,路边的摄像头精准识别出车牌和车型;工厂流水线上,机械臂的“眼睛”实时锁定每一个瑕疵品——这些场景背后,几乎都站着一个名字:YOLO。 YOLO(You Only Look Once)自2015年…...

rasterizeHTML.js 终极指南:跨浏览器HTML到Canvas渲染完整教程

rasterizeHTML.js 终极指南:跨浏览器HTML到Canvas渲染完整教程 【免费下载链接】rasterizeHTML.js Renders HTML into the browsers canvas 项目地址: https://gitcode.com/gh_mirrors/ra/rasterizeHTML.js rasterizeHTML.js 是一款强大的 JavaScript 库&…...

如何快速上手IAMDinosaur:打造专属AI游戏助手的终极指南

如何快速上手IAMDinosaur:打造专属AI游戏助手的终极指南 【免费下载链接】IAMDinosaur 🦄 An Artificial Inteligence to teach Googles Dinosaur to jump cactus 项目地址: https://gitcode.com/gh_mirrors/ia/IAMDinosaur IAMDinosaur是一款令人…...

Prompt 焚诀——一个模板,终结你和 AI 的所有沟通问题确

AI训练存储选型的演进路线 第一阶段:单机直连时代 早期的深度学习数据集较小,模型训练通常在单台服务器或单张GPU卡上完成。此时直接将数据存储在训练机器的本地NVMe SSD/HDD上。 其优势在于IO延迟最低,吞吐量极高,也就是“数据离…...

【JavaScript高级编程】拆解函数流水线 上郴

一、什么是setuptools? setuptools 是一个用于创建、分发和安装 Python 包的核心库。 它可以帮助你: 定义 Python 包的元数据(如名称、版本、作者等)。 声明包的依赖项,确保你的包能够正确运行。 构建源代码分发包&…...

Cloudscape Design System扩展开发:自定义组件与插件系统完整指南

Cloudscape Design System扩展开发:自定义组件与插件系统完整指南 【免费下载链接】components React components for Cloudscape Design System 项目地址: https://gitcode.com/gh_mirrors/comp/components Cloudscape Design System是一套基于React的企业级…...

Moe-Counter:让网站计数变得萌萌哒的终极解决方案

Moe-Counter:让网站计数变得萌萌哒的终极解决方案 【免费下载链接】Moe-Counter Moe counter badge with multiple themes! - 多种风格可选的萌萌计数器 项目地址: https://gitcode.com/gh_mirrors/mo/Moe-Counter Moe-Counter 是一款功能强大且风格多样的萌…...