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

BPM引擎系列(二) Activiti入门-老牌引擎还能打吗

Activiti入门——老牌引擎还能打吗?

系列第二篇:Activiti 7 + Spring Boot 集成实战,从配置到跑通一个请假流程。


一、Activiti?Flowable?Camunda?我懵了

上篇咱们学完了BPMN,信心满满地准备上手干活。结果一搜"Java工作流引擎",跳出来三个名字:

  • Activiti
  • Flowable
  • Camunda

更离谱的是,搜Activiti的教程,评论区总有人喊"别用Activiti了,用Flowable";搜Flowable,又有人说"Camunda更专业"。

问题来了:这三个到底啥关系?Activiti这个"老将"还能不能打?

先上一张"族谱图":

jBPM 3/4 │ ↓ ┌─────────────────┐ │ Activiti 5 │ ← 2010年,Tom Baeyens 创建 │ (Alfresco) │ └────────┬────────┘ │ ┌──────────────┼──────────────┐ ↓ ↓ ↓ Activiti 6 Flowable 6 Camunda 7 (维护减少) (原班人马) (更专业) │ │ │ ↓ ↓ ↓ Activiti 7 Flowable 7 Camunda 8 (TOMATO) (活跃开发) (云原生)

一句话总结

  • Activiti 是"老祖宗",但 7 版本之后维护力度下降
  • Flowable 是 Activiti 核心团队"分家"出来做的,更活跃
  • Camunda 也是 Activiti 分支,定位更偏向企业级BPM平台

那Activiti还能不能用?能,但更适合以下场景

  • 项目已经用了Activiti,不想折腾迁移
  • 需求简单,就是个审批流,不需要复杂功能
  • 团队对Activiti比较熟悉

好,不纠结了,咱们先把它跑起来再说!


二、Spring Boot 集成 Activiti

2.1 创建项目

用 Spring Initializr 创建一个 Spring Boot 项目,或者直接在现有项目加依赖。

pom.xml 核心依赖:

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.18</version></parent><properties><activiti.version>7.1.0.M6</activiti.version></properties><dependencies><!-- Spring Boot Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Activiti Spring Boot Starter --><dependency><groupId>org.activiti</groupId><artifactId>activiti-spring-boot-starter</artifactId><version>${activiti.version}</version></dependency><!-- H2 内存数据库(演示用) --><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency></dependencies>

⚠️ 注意:Activiti 7 的依赖不在 Maven Central,需要从 Alfresco 仓库拉取。如果下载失败,在 pom.xml 里加一下仓库配置:

<repositories><repository><id>alfresco</id><url>https://artifacts.alfresco.com/nexus/content/repositories/activiti-releases/</url></repository></repositories>

2.2 配置文件

application.yml:

server:port:8081spring:datasource:url:jdbc:h2:mem:activiti-db;DB_CLOSE_DELAY=-1driver-class-name:org.h2.Driverusername:sapassword:# Activiti 核心配置activiti:# 自动更新数据库表结构database-schema-update:true# 自动检查并部署流程定义文件check-process-definitions:true# 流程定义文件存放位置process-definition-location-prefix:classpath:/processes/# 历史记录级别:none/activity/audit/fullhistory-level:full

关键配置说明:

配置项作用
database-schema-update自动建表,第一次运行必备
check-process-definitions启动时自动扫描并部署流程
history-level历史数据记录级别,full记录最全

2.3 流程定义文件

把上篇画的请假流程BPMN文件放到src/main/resources/processes/目录下:

src/main/resources/processes/leave-process.bpmn20.xml

文件内容(核心片段,完整版见配套源码):

<?xml version="1.0" encoding="UTF-8"?><definitionsxmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"xmlns:activiti="http://activiti.org/bpmn"targetNamespace="http://example.org/leave-process"><processid="leave-process"name="请假流程"isExecutable="true"><!-- 开始事件 --><startEventid="start"name="提交申请"/><!-- 经理审批:用户任务 --><userTaskid="manager-approval"name="经理审批"activiti:assignee="${managerId}"/><!-- 排他网关:经理是否通过 --><exclusiveGatewayid="manager-decision"name="经理审批结果"/><!-- 驳回 → 结束 --><endEventid="manager-reject-end"name="经理驳回"/><!-- 通过 → 检查天数 --><exclusiveGatewayid="days-check"name="天数>3?"/><!-- 总监审批:用户任务 --><userTaskid="director-approval"name="总监审批"activiti:assignee="${directorId}"/><!-- HR备案:服务任务(自动执行) --><serviceTaskid="hr-record"name="HR备案"activiti:expression="${hrService.record(execution)}"/><!-- 发送邮件:服务任务 --><serviceTaskid="send-email"name="发送通知邮件"activiti:expression="${emailService.send(execution)}"/><!-- 结束事件 --><endEventid="end"name="流程结束"/><!-- 连线 + 条件表达式... --></process></definitions>

注意命名空间:Activiti 使用activiti:前缀的属性,比如activiti:assigneeactiviti:expression


三、Java代码:启动流程、查待办、完成任务

Activiti 的核心 API 就几个 Service,记住它们:

Service作用
RuntimeService启动流程、查询运行中的流程实例
TaskService查询待办任务、完成任务
RepositoryService部署流程定义、查询流程模型
HistoryService查询历史数据(已完成的流程)

3.1 启动流程

@RestController@RequestMapping("/api/leave")publicclassLeaveController{@AutowiredprivateRuntimeServiceruntimeService;@PostMapping("/start")publicMap<String,Object>startProcess(@RequestParamStringapplicant,@RequestParamStringmanagerId,@RequestParamStringdirectorId,@RequestParamIntegerdays){// 准备流程变量Map<String,Object>variables=newHashMap<>();variables.put("applicant",applicant);// 申请人variables.put("managerId",managerId);// 经理IDvariables.put("directorId",directorId);// 总监IDvariables.put("days",days);// 请假天数// 启动流程!关键就这一行ProcessInstanceinstance=runtimeService.startProcessInstanceByKey("leave-process",variables);returnMap.of("processInstanceId",instance.getId(),"message","请假流程已启动");}}

关键点

  • startProcessInstanceByKey("leave-process", ...)里的"leave-process"必须和 BPMN 文件里<process id="leave-process">对应
  • 启动时传入的变量(applicantdays等)可以在整个流程中使用

3.2 查询待办任务

@AutowiredprivateTaskServicetaskService;@GetMapping("/tasks")publicList<Map<String,Object>>getTasks(@RequestParamStringassignee){// 查某个人的待办任务List<Task>tasks=taskService.createTaskQuery().taskAssignee(assignee)// 按处理人过滤.list();returntasks.stream().map(task->Map.of("taskId",task.getId(),"taskName",task.getName(),"processInstanceId",task.getProcessInstanceId())).collect(Collectors.toList());}

3.3 完成任务(审批)

@PostMapping("/complete")publicMap<String,Object>completeTask(@RequestParamStringtaskId,@RequestParamBooleanapproved){// 设置审批结果变量Map<String,Object>variables=newHashMap<>();variables.put("approved",approved);// true=通过, false=驳回variables.put("result",approved?"通过":"驳回");// 完成任务,引擎会自动根据条件判断下一步去哪taskService.complete(taskId,variables);returnMap.of("taskId",taskId,"message",approved?"审批通过":"已驳回");}

这里有个坑要注意

完成任务时传入的approved变量,会被网关的条件表达式${approved == true}${approved == false}使用。如果变量名写错了,网关就不知道怎么走了,流程会卡住。


四、服务任务:自动执行的逻辑

流程里有两个服务任务(HR备案、发送邮件),不需要人处理,系统自动执行。

Activiti 里实现服务任务有几种方式:

方式1:Spring Bean 表达式(推荐)

@Service("hrService")// Bean名称要和BPMN里的 ${hrService.record(execution)} 对应publicclassHrService{publicvoidrecord(DelegateExecutionexecution){// 从流程变量里取数据Stringapplicant=(String)execution.getVariable("applicant");Integerdays=(Integer)execution.getVariable("days");log.info("【HR备案】员工 {} 请假 {} 天,已记录",applicant,days);// 实际这里可以调用HR系统的API}}

BPMN里这样引用:

<serviceTaskid="hr-record"name="HR备案"activiti:expression="${hrService.record(execution)}"/>

方式2:JavaDelegate 接口

@ComponentpublicclassHrRecordDelegateimplementsJavaDelegate{@Overridepublicvoidexecute(DelegateExecutionexecution){// 同样的逻辑}}

BPMN里这样引用:

<serviceTaskid="hr-record"name="HR备案"activiti:class="com.example.HrRecordDelegate"/>

两种方式的区别

  • 表达式方式:可以调用Spring管理的Bean,支持传参,更灵活
  • JavaDelegate方式:每次执行都创建新实例(除非用Spring代理),适合无状态逻辑

推荐用表达式方式,和Spring结合更紧密。


五、跑起来!完整测试流程

5.1 启动应用

mvn spring-boot:run

启动日志里你会看到 Activiti 自动创建了几十张表:

Activiti Engine create activiti tables

5.2 测试API

Step 1:启动请假流程

curl-XPOST"http://localhost:8081/api/leave/start"\-d"applicant=小明"\-d"managerId=manager-zhang"\-d"directorId=director-li"\-d"days=5"

返回:

{"processInstanceId":"2501","message":"请假流程已启动"}

Step 2:经理查待办

curl"http://localhost:8081/api/leave/tasks?assignee=manager-zhang"

返回:

[{"taskId":"2505","taskName":"经理审批","processInstanceId":"2501"}]

Step 3:经理审批通过

curl-XPOST"http://localhost:8081/api/leave/complete"\-d"taskId=2505"\-d"approved=true"

Step 4:总监查待办(因为天数=5>3,需要总监审批)

curl"http://localhost:8081/api/leave/tasks?assignee=director-li"

返回:

[{"taskId":"2510","taskName":"总监审批","processInstanceId":"2501"}]

Step 5:总监审批通过

curl-XPOST"http://localhost:8081/api/leave/complete"\-d"taskId=2510"\-d"approved=true"

这时候日志会输出:

【HR备案】员工 小明 请假 5 天,已记录到HR系统 【发送邮件】通知 小明:你的请假申请已通过,请查收!

流程结束!


六、数据库表速览

Activiti 自动创建的表很多,但核心就几类:

表前缀说明常用表
ACT_RE_*流程定义(Repository)ACT_RE_PROCDEF流程定义
ACT_RU_*运行时数据(Runtime)ACT_RU_TASK待办任务,ACT_RU_EXECUTION执行实例
ACT_HI_*历史数据(History)ACT_HI_PROCINST历史流程实例,ACT_HI_TASKINST历史任务
ACT_ID_*身份数据(Identity)ACT_ID_USER用户,ACT_ID_GROUP用户组

一个查询小技巧:想看当前有哪些待办任务,直接查ACT_RU_TASK

SELECTID_,NAME_,ASSIGNEE_,PROC_INST_ID_FROMACT_RU_TASK;

七、Activiti 的优缺点

优点

  • ✅ 历史悠久,文档和教程多
  • ✅ API 设计简洁,上手快
  • ✅ 和 Spring 集成成熟
  • ✅ 社区版免费

缺点

  • ❌ Activiti 7 之后维护力度下降
  • ❌ 部分高级功能(如动态表单、CMMN案例管理)支持较弱
  • ❌ 没有内置的Web管理界面(Camunda有Cockpit)

八、小结

这篇咱们聊了:

  1. Activiti 的身世——老牌引擎,Flowable和Camunda的"老祖宗"
  2. Spring Boot 集成——加依赖、配YAML、放BPMN文件
  3. 核心API——RuntimeService启动流程,TaskService查待办/完成任务
  4. 服务任务——用Spring Bean表达式实现自动逻辑
  5. 完整测试——从启动到结束,一步步跑通

下一篇预告:Activiti 原班人马"分家"做出来的Flowable,到底升级了啥?迁移成本高吗?咱们代码里见分晓。


配套源码

本文完整源码位于:02-activiti-demo/

包含:

  • 完整的pom.xmlapplication.yml
  • 请假流程 BPMN 定义
  • REST API Controller
  • 服务任务实现
  • 单元测试(3个场景全覆盖)

你在用 Activiti 吗?遇到过什么坑?欢迎交流!

http://www.jsqmd.com/news/685393/

相关文章:

  • 如何快速解决TranslucentTB启动问题:3步修复透明任务栏工具
  • 加权决策树解决不平衡分类问题的原理与实践
  • CoolProp架构深度解析:开源热力学计算库的技术实现
  • MFlow02-项目学习指南
  • 2026高低温冲击试验箱优质厂家推荐:三综合试验箱/两箱式冷热冲击试验箱/可程式恒温恒湿试验箱/复合式环境试验箱/选择指南 - 优质品牌商家
  • 【UE C++】虚幻引擎WebSocket网络模块封装与蓝图化实战
  • vben开发入门13:自定义多语言
  • BPM引擎系列(三) Flowable实战-Activiti分家后的升级版
  • 手机存储速度翻倍的秘密:一文读懂UFS 2.2协议中的MIPI UniPro层
  • Flutter 鸿蒙应用权限管理功能实战:标准化权限申请与状态管控,提升用户信任度
  • OpenVINO AI音频插件:为Audacity注入本地化AI处理能力
  • Claude Design 会取代设计师吗
  • 如何快速构建中文医疗AI:79万条高质量对话数据终极指南
  • STM32G474与F334系列HRTIM实战:从CubeMX配置到移相全桥PWM生成
  • 神经隐式表示在3D乳房重建中的创新应用
  • BPM引擎系列(四) Camunda上手-专业选手的配置与应用
  • GaussDB慢SQL排查实战:从告警到定位,手把手教你用这些视图和命令
  • 【2026年华为暑期实习-非AI方向(通软嵌软测试算法数据科学)-4月22日-第一题- 简易的二进制包依赖关系检查和处】(题目+思路+JavaC++Python解析+在线测试)
  • VxWorks核心内核模块:任务管理模块完整解读实践篇(1)
  • Windows系统级输入模拟终极指南:Interceptor库的7个关键技术突破
  • 脉冲神经网络中延迟异质性的计算优势与应用
  • mysql如何设置定时自动备份脚本_编写shell脚本与cron任务
  • 【2026年华为暑期实习-非AI方向(通软嵌软测试算法数据科学)-4月22日-第二题- 硬件布线】(题目+思路+JavaC++Python解析+在线测试)
  • Halcon小技巧:快速找到Region的‘最高点’,搞定工件定位与方向判断
  • 耳挂式ExG设备设计:多模态生物电信号采集技术
  • ChatBI是什么?一文拆解ChatBI应用落地!
  • 全域数学:核素对称能与物质稳定性定量定理(投稿精简版)【乖乖数学】
  • FRED应用:准直透镜模拟与优化
  • BPM引擎系列(五) 三选一-Activiti-vs-Flowable-vs-Camunda选型指南
  • 【2026年华为暑期实习-非AI方向(通软嵌软测试算法数据科学)-4月22日-第三题- 星球大战】(题目+思路+JavaC++Python解析+在线测试)