ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

SpringBoot集成Flowable Modeler深度实践指南

SpringBoot集成Flowable Modeler深度实践指南 简介本资源是一套基于Spring Boot集成Flowable流程引擎与Modeler可视化流程设计器的完整可运行项目面向Java后端开发者及工作流系统学习者解决企业级流程自动化开发中引擎嵌入、流程建模与前后端联调等核心问题。压缩包共1500个文件含416个JavaScript前端逻辑文件、342个PNG图标资源、296个HTML页面模板、202个GZ压缩静态资源及7个核心Java配置类如ProcessEngineConfig、App等整体12.47MB结构清晰涵盖流程定义、部署、任务管理及UI定制全链路。已有3382人学习下载资源附带详细使用说明文档开箱即用导入IDE后仅需配置数据库连接启动即可通过http://127.0.0.1:8081/flow访问可视化设计器支持流程图绘制、XML导出与实时部署是理解Flowable架构与二次开发的优质实践样本。1. 为什么在 SpringBoot 中集成 Flowable Modeler 不是“加个依赖就完事”很多开发者第一次尝试把 Flowable 流程引擎嵌入 SpringBoot 项目时会直接mvn dependency:tree查到flowable-spring-boot-starter就以为万事大吉——结果启动报No bean named processEngine访问/modeler返回 404数据库里只建了 3 张表实际需 27甚至发现流程图保存后重启就丢失。这不是配置漏了而是没理清 Flowable 的三层架构本质流程引擎Process Engine负责执行、流程模型Model负责定义、Modeler 是独立 Web 应用不是 SpringBoot 内置组件。本项目完整源码的价值正在于它绕开了官方 starter 的“黑盒封装”显式暴露了FlowableModelerApplication启动逻辑、ModelEditorJsonRestResource的 CORS 配置细节、以及spring.flowable.database-schema-updatetrue在多数据源场景下的失效边界。适合需要定制审批节点权限、导出 BPMN XML 做二次解析、或对接国产信创中间件的中高级 Java 工程师——新手照着文档跑通基础流程后立刻会卡在“如何让 Modeler 和业务系统共享同一套用户体系”这个真实生产问题上。2. Flowable 引擎与 SpringBoot 的深度整合从自动装配到手动接管Flowable 官方提供的flowable-spring-boot-starter确实能快速拉起一个带 H2 内存库的 demo但生产环境必须面对三个硬性约束多数据源隔离、表结构预置、以及流程定义与业务代码的事务一致性。这就决定了不能全盘依赖 starter 的自动装配而要分层接管关键 Bean。2.1 为什么必须禁用 starter 的自动配置并手动构建 ProcessEngineSpringBoot Starter 默认启用FlowableAutoConfiguration它会扫描 classpath 下的flowable.cfg.xml或flowable-default.properties并创建ProcessEngineBean。但在微服务架构中你很可能已有主数据源dataSource而 Flowable 需要独立的流程库如flowable_db。若不干预starter 会强行复用主数据源导致业务 SQL 和流程 SQL 混杂在同一个连接池事务传播异常。正确做法是在application.yml中显式关闭spring: autoconfigure: exclude: org.flowable.spring.boot.FlowableAutoConfiguration提示排除后ProcessEngine不再自动注入所有流程 API如runtimeService.startProcessInstanceByKey()必须通过手动声明的 Bean 调用这反而强化了对流程生命周期的掌控力。2.2 手动构建 ProcessEngine 的 4 个核心步骤以下代码片段来自本项目FlowableConfig.java它展示了生产级配置的关键参数Configuration public class FlowableConfig { Bean Primary public ProcessEngine processEngine(DataSource flowableDataSource) { // 1. 创建 ProcessEngineConfiguration SpringProcessEngineConfiguration config new SpringProcessEngineConfiguration(); config.setDataSource(flowableDataSource); config.setDatabaseSchemaUpdate(true); // 生产环境应改为 false由 Flyway 管理 config.setDatabaseType(mysql); // 显式指定类型避免驱动自动探测失败 config.setTransactionsExternallyManaged(false); // 启用 Spring 事务管理 // 2. 注入 Spring 事务管理器关键否则 runtimeService.startXXX 不受 Transactional 控制 config.setTransactionManager(transactionManager()); // 3. 设置历史级别影响 ACT_HI_* 表写入量 config.setHistoryLevel(HistoryLevel.FULL); // 4. 加载自定义流程监听器如审批完成发消息 config.setCustomPostBPMNParseListeners(Collections.singletonList(new CustomBpmnParseListener())); return config.buildProcessEngine(); } Bean public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(flowableDataSource); } }参数说明与生产调优建议参数默认值生产建议作用databaseSchemaUpdatetruefalse关闭自动建表改用 Flyway 迁移脚本确保表结构版本可控historyLevelHistoryLevel.NONEHistoryLevel.AUDIT或FULLAUDIT记录节点进出FULL还记录变量快照高并发场景慎用FULLtransactionsExternallyManagedtruefalse设为false才能让Transactional注解生效保证业务操作与流程启动原子性customPostBPMNParseListenersnull自定义实现解析 BPMN 文件后注入业务逻辑如校验节点 ID 是否符合公司命名规范2.3 Flowable 表结构生成的 3 种方式及选型依据Flowable 启动时需创建约 27 张表含ACT_RE_*流程定义、ACT_RU_*运行时、ACT_HI_*历史表。本项目源码提供三种方案自动建表仅限开发databaseSchemaUpdatetrue启动时执行 DDL适合本地调试SQL 脚本初始化推荐测试/预发从 Flowable 发行包sql/flowable.mysql.create.sql复制脚本手动执行Flyway 版本化迁移强制生产将建表脚本拆分为V1__create_flowable_tables.sql配合flyway.locationsclasspath:db/migration/flowable使用。注意若使用 MyBatis-Plus 等 ORM 框架务必确认其table-prefix不会误匹配ACT_*表名否则TableName注解可能引发元数据冲突。3. Modeler 可视化设计器的嵌入式集成不止是静态资源拷贝Modeler 并非 Flowable 的子模块而是一个独立的 Spring MVC 应用基于 AngularJS 构建。官方提供两种集成方式独立部署推荐生产和嵌入式集成适合内网系统。本项目采用后者但做了关键改造——解决跨域、路径映射、以及用户体系打通三大痛点。3.1 Modeler 的嵌入式启动原理WebMvcConfigurer 的边界控制官方 Modeler 的web.xml或SpringBootServletInitializer会注册/modeler/**路径。若直接将modeler.war解压到src/main/resources/static/modelerSpringBoot 的静态资源处理器会将其当作普通 HTML 返回但 AngularJS 的路由如/modeler/editor) 无法被识别。正确做法是继承WebMvcConfigurer重写资源处理链Configuration public class ModelerWebConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // 1. 将 modeler 静态资源映射到 /modeler/** registry.addResourceHandler(/modeler/**) .addResourceLocations(classpath:/static/modeler/); // 2. 关键对 /modeler/editor 等前端路由统一返回 index.html支持 HTML5 History 模式 registry.addResourceHandler(/modeler/editor/**, /modeler/modeler/**) .addResourceLocations(classpath:/static/modeler/) .setCachePeriod(0); } Override public void addViewControllers(ViewControllerRegistry registry) { // 3. 配置默认视图访问 /modeler 直接跳转到编辑器 registry.addViewController(/modeler).setViewName(forward:/modeler/editor); } }3.2 Modeler 与 SpringBoot 用户体系的双向打通Modeler 默认使用内存用户admin/test但企业系统要求登录态同步。本项目通过AuthenticationFilter实现Component public class ModelerAuthFilter extends OncePerRequestFilter { Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String path request.getRequestURI(); // 仅拦截 modeler 的 API 请求静态资源放行 if (path.startsWith(/modeler/app/rest) || path.startsWith(/modeler/service)) { // 从 SpringSecurity Context 获取当前用户 Authentication auth SecurityContextHolder.getContext().getAuthentication(); if (auth ! null auth.isAuthenticated()) { // 将用户名注入 Modeler 的 REST 接口需修改 Modeler 源码中的 UserResource.java request.setAttribute(currentUser, auth.getName()); } else { response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return; } } filterChain.doFilter(request, response); } }Modeler 源码级改造点本项目已预编译修改UserResource.java的getUserInfo()方法读取request.getAttribute(currentUser)替代硬编码在app.js中全局配置$httpProvider.defaults.headers.common[X-Auth-Token]携带 SpringBoot 的 JWT Token覆盖app/views/login.html移除原生登录框改为跳转至业务系统的/login页面。3.3 Modeler 中文语言包的加载机制与热替换网络热词中提到的 “itwin capture modeler在哪里改语言”本质是 Modeler 的 i18n 配置问题。其语言包位于modeler/app/i18n/目录下本项目已内置zh-CN.json。关键在于app.js中的初始化// app.js 第 23 行 var locale navigator.language || navigator.userLanguage; if (locale.indexOf(zh) ! -1) { $translateProvider.useStaticFilesLoader({ prefix: i18n/, suffix: .json }); $translateProvider.preferredLanguage(zh-CN); } else { $translateProvider.useStaticFilesLoader({ prefix: i18n/, suffix: .json }); $translateProvider.preferredLanguage(en-US); }提示若需动态切换语言需在app/controllers/header-controller.js中添加$scope.changeLanguage function(lang) { $translate.use(lang); }并在 HTML 中绑定a ng-clickchangeLanguage(zh-CN)中文/a。4. 流程定义部署与运行时调试从 BPMN 文件到实例跟踪的全链路验证集成成功后真正的挑战才开始如何确保设计师画的 BPMN 能被引擎正确解析如何定位“流程卡在某个节点不动”的根因本项目源码配套的UsageGuide.md文档其实质是一套可执行的验证清单。4.1 BPMN 文件部署的 3 种方式及适用场景方式命令/代码适用场景注意事项Classpath 部署repositoryService.createDeployment().addClasspathResource(bpmn/leave-process.bpmn20.xml).deploy()单体应用流程定义随代码发布修改 BPMN 需重启应用文件系统部署repositoryService.createDeployment().addInputStream(leave.bpmn, new FileInputStream(/opt/flowable/bpmn/leave.bpmn)).deploy()支持热更新运维可替换文件路径需对 JVM 进程可读REST API 部署POST /repository/deployments multipart/form-data前端 Modeler 直接发布需开启flowable.rest.enabledtrue本项目使用第一种因其与 SpringBoot 的PostConstruct生命周期天然契合Component public class ProcessDeployer { Autowired private RepositoryService repositoryService; PostConstruct public void deployProcesses() { // 扫描 classpath:/processes/ 下所有 BPMN 文件 Resource[] resources new ClassPathResource(processes/).listResources(); for (Resource resource : resources) { if (resource.getFilename().endsWith(.bpmn20.xml)) { Deployment deployment repositoryService.createDeployment() .addInputStream(resource.getFilename(), resource.getInputStream()) .name(resource.getFilename().replace(.bpmn20.xml, )) .deploy(); System.out.println(Deployed: deployment.getId()); } } } }4.2 运行时流程实例的 4 层诊断法当流程启动后无响应按以下顺序排查检查流程定义状态SELECT ID_, NAME_, KEY_, VERSION_, DEPLOYMENT_ID_ FROM ACT_RE_PROCDEF WHERE KEY_ leave-process;若VERSION_为 1 但无记录说明部署失败常见于 BPMN 校验错误。确认流程实例是否创建SELECT ID_, PROC_DEF_ID_, START_TIME_, END_TIME_ FROM ACT_RU_EXECUTION WHERE PROC_DEF_ID_ LIKE leave-process:%;若END_TIME_非空说明流程已结束若为空但无ACT_RU_TASK记录说明卡在异步节点。查看待办任务SELECT ID_, NAME_, ASSIGNEE_, CREATE_TIME_ FROM ACT_RU_TASK WHERE PROC_DEF_ID_ LIKE leave-process:%;若ASSIGNEE_为空需检查userTask的assignee表达式如${approver}是否能解析。追踪活动节点// 通过 runtimeService 查询执行流 ListExecution executions runtimeService.createExecutionQuery() .processInstanceId(2501) .list(); for (Execution exec : executions) { System.out.println(ActivityId: exec.getActivityId() , IsActive: exec.isSuspended()); }4.3 本项目源码中预置的 3 个典型流程案例解析流程名称BPMN 特点验证要点源码路径leave-process.bpmn20.xml含userTaskexclusiveGateway检查网关条件表达式${days 3}是否触发分支/src/main/resources/processes/purchase-process.bpmn20.xml含serviceTask调用 Java 类验证classcom.example.service.PurchaseService是否在 classpath/src/main/java/com/example/service/multi-instance.bpmn20.xml含multiInstanceLoopCharacteristics检查collection${assignees}是否传入 List/src/main/resources/processes/提示所有 BPMN 文件均通过flowable-designer导出而非手写 XML确保语法合规。若用 IntelliJ 的 Flowable 插件编辑需在Settings Languages Frameworks Flowable中指定 BPMN Schema URL。5. 生产环境避坑指南数据库、线程池与监控指标的硬核配置Flowable 在高并发审批场景下常因底层配置不当引发连接池耗尽、历史表膨胀、或流程实例堆积。本项目源码的application-prod.yml文件已针对这些风险点做了加固。5.1 数据库连接池的 3 项关键调优Flowable 的ProcessEngine会创建独立的DataSource必须与业务数据源隔离。本项目使用 HikariCP配置如下spring: datasource: flowable: jdbc-url: jdbc:mysql://127.0.0.1:3306/flowable_db?useSSLfalseserverTimezoneAsia/Shanghai username: flowable password: flowable123 hikari: connection-timeout: 30000 maximum-pool-size: 20 # Flowable 默认 10高并发需提升 minimum-idle: 5 idle-timeout: 600000 max-lifetime: 1800000 leak-detection-threshold: 60000 # 检测连接泄漏毫秒为什么maximum-pool-size必须 ≥20每个流程实例启动时会占用 1~3 个连接部署、启动、查询HistoricActivityInstance写入频率极高单次审批可能产生 10 条历史记录若设为默认 10在 50 TPS 场景下极易触发HikariPool-1 - Connection is not available。5.2 Flowable 内置线程池的显式配置Flowable 的异步任务如定时器、邮件发送默认使用Executors.newCachedThreadPool()该线程池无界易导致 OOM。本项目强制指定Bean public ExecutorService asyncExecutor() { ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(100); executor.setThreadNamePrefix(flowable-async-); executor.initialize(); return executor.getThreadPoolExecutor(); } // 在 ProcessEngineConfiguration 中注入 config.setAsyncExecutorActivate(true); config.setAsyncExecutor(asyncExecutor());5.3 Prometheus 监控指标接入点本项目已集成 Micrometer暴露以下 Flowable 专属指标指标名类型说明查询示例flowable.process.instance.started.totalCounter启动的流程实例总数sum(rate(flowable_process_instance_started_total[1h]))flowable.task.active.countGauge当前活跃任务数flowable_task_active_count{applicationmyapp}flowable.job.executed.totalCounter已执行的定时任务数flowable_job_executed_total{statussuccess}需在pom.xml中添加dependency groupIdio.micrometer/groupId artifactIdmicrometer-registry-prometheus/artifactId /dependency然后访问http://localhost:8080/actuator/prometheus即可获取原始指标。5.4 本项目源码中已修复的 3 个高频 BugMySQL 8.0 时间戳精度问题ACT_RU_TIMER_JOB表的DUEDATE_字段类型从datetime改为datetime(3)适配 MySQL 8.0 的微秒精度Modeler 保存流程图后中文乱码在ModelSaveRestResource.java中将response.setContentType(application/json;charsetUTF-8)改为response.setCharacterEncoding(UTF-8)多租户场景下流程定义重复部署在ProcessDeployer中增加repositoryService.createProcessDefinitionQuery().processDefinitionKey(leave-process).count() 0判断避免重复部署。最后提醒所有配置变更后务必执行mvn clean compile清理旧 class并验证ACT_GE_PROPERTY表中的schema.version是否更新为6.8.0对应 Flowable 6.8.0 版本。本文还有配套的精品资源点击获取
返回列表