若依整合Activiti工作流引擎:企业OA审批系统架构与实现 📅 发布时间:2026/9/8 9:01:52 👁 浏览次数: 简介RuoYi-activiti工作流平台源码是一套面向Java开发者的企业级工作流管理系统基于若依权限管理框架整合Activiti引擎覆盖流程设计、部署、执行、任务办理与监控等环节适合需要快速搭建审批流、会签、请假等业务场景的团队。压缩包共982个文件体积约6.76MB含288个Java后端逻辑文件、191个JavaScript与116个Vue前端页面文件、36个XML流程定义文件、SQL初始化脚本以及Shell/Bat启动打包脚本源码结构清晰便于二次开发与本地调试。已有405人学习下载对刚接触Activiti工作流或若依框架的开发者有实际参考价值。资源附带可直接编译运行的ruoyi-admin工程入口并整理出一套从数据库初始化、打包运行到在线设计流程并发布的使用说明同时提出统一的任务办理接口和formkey表单关联机制展示了外置表单与流程变量分离的落地思路能帮助读者较快走通工作流模块的搭建与扩展流程。 做企业级开发这几年凡是涉及OA审批、项目立项、合同会签这类需求的最后基本都绕不开工作流引擎。RuoYi-activiti这个开源组合简单理解就是把若依RuoYi后台管理框架和Activiti工作流引擎整合在一起形成一套带完整权限体系、用户组织管理、可视化流程设计、审批追溯的二次开发平台。这篇文章围绕这套源码聊聊它的架构思路、部署初始化的细节、业务表单怎么和流程做挂接以及我实际使用中踩过的几个典型坑。适合正在做技术选型或者已经拿到源码却不知道怎么落地的Java后端开发同学。这个项目解决的核心问题很明确大多数企业内部系统并不需要从零写一套状态机来管审批直接用Activiti这类BPMN2.0标准引擎再加上若依这种现成的后台管理脚手架可以快速搭建出具备“用户-角色-部门-流程-权限”闭环的OA底座。RuoYi-activiti的价值在于它把两者缝好了你在它基础上做业务开发省掉的不是一点点时间。1. 项目核心思路与选型分析1.1 为什么是RuoYi加Activiti先说若依。它是一款非常主流的Java后台脚手架基于Spring Boot、Spring Security、MyBatis和Vue自带用户管理、角色权限、菜单管理、操作日志、代码生成器。国内公司做管理系统拿若依做底座的情况非常多因为省去了最基础的框架搭建和权限设计。再说Activiti。它是基于BPMN2.0规范的开源工作流引擎由Alfresco公司开发后来演进出了Flowable和Camunda等分支。Activiti在流程建模、流程执行、任务管理、历史追溯这些能力上非常成熟尤其对国内开发者来说相关资料多、社区讨论多遇到问题容易找到解决方案。把两者放一起的优势很清楚若依负责“系统骨架”Activiti负责“流程心脏”。业务需求中真正复杂的是流程的流转逻辑——比如会签、或签、驳回、撤回、转办、代理审批这些如果手写代码每个节点都是一堆状态判断和数据库操作测试成本极高而Activiti把BPMN2.0的语义已经做了底层实现你只需要在XML或者可视化设计器里画图再调用几个API引擎会自动处理任务的流转和历史的记录。我在选型时其实也对比过Flowable。它从Activiti 5时代的分支发展而来功能上更强支持更复杂的BPMN元素社区活跃度也不错。但最终选了RuoYi-activiti这套一个重要原因是若依官方生态和Activiti的整合在业务层做得比较浅很多开发者在此基础上改造成本低另外一个原因是Activiti 5/6版本的资料非常丰富遇到疑难问题能搜到的经验帖多这对团队后续维护非常重要。1.2 平台整体架构与代码模块划分整个项目虽然是“若依Activiti”的组合但从工程结构来看它并没有把Activit的所有能力一股脑塞进来而是做了分层处理。从模块划分上通常是标准若依的多模块结构ruoyi-admin负责Web层和权限控制ruoyi-framework负责框架核心ruoyi-system负责系统管理ruoyi-quartz负责定时任务另外会加一个ruoyi-workflow或者activiti相关的模块来承载流程相关的代码。流程模块内部再细分模型管理流程设计器、流程定义管理版本、挂起/激活、流程实例管理发起、运行状态、任务管理待办、已办、审批记录。这里要理解一个关键点若依本身是权限框架Activiti也有自己的一套用户和权限体系ACT_ID_*表。两者结合时通常不会让Activiti单独管用户而是做一个桥接——流程中指定的审批人直接换成若依的sys_user表中对应用户的userId流程引擎只负责把任务分配给这个ID具体该用户是谁、属于哪个部门还是从若依体系里去查。这样做的好处是用户不用两处维护业务系统内权限模型也统一。1.3 这个方案到底解决了什么RuoYi-activiti这套平台源码我把它定位成“中间态方案”它不是让你直接拿去就跑业务的成品因为它不包含具体的业务表单和流程逻辑比如请假单、报销单需要你自己定义它也不是一堆底层API的玩具Demo而是给了你从模型设计、流程部署、表单关联、任务处理到流程监控的完整闭环代码。你在这个闭环上填充业务比在纯Activiti上从零搭一套要快很多。比如最常见的“请假审批流程”需求你在设计器里画一个流程开始节点后接一个部门审批用户任务节点再接到总经理审批节点最后结束。部署后系统自动生成一个流程定义版本。发起人在前端填写请假表单提交后启动一个流程实例。部门经理登录后在待办列表里看到这条任务点击审批——同意则流程自动流转到总经理节点驳回则流程回到发起人或直接结束。这套逻辑在平台里已经封装好了你只需要搞清楚每个API是对应什么动作以及如何在流程变量里传递表单数据。2. 环境准备与源码导入初始化2.1 部署前需要准备的核心依赖虽然源码是现成的但环境不一致导致的各种问题在我实际部署过程中占了一半以上的排查时间。先列一下标准环境这也是我推荐大家用起来最省事的版本组合依赖项推荐版本说明JDK1.8Spring Boot 2.x对应JDK8换新JDK容易在cglib代理等环节出兼容问题Maven3.6.3编译和依赖管理MySQL5.7 / 8.0若依默认支持但8.0需要注意时区和驱动调整Redis5.x / 6.x若依的登录验证码、会话缓存、部分业务缓存依赖它Node.js部分前端12-16如果你用的是前后端分离版本的RuoYi-activiti前端环境也要配套一个容易忽略的细节是MySQL版本。如果你用的是8.0启动项目时经常会报时区相关错误。解决办法是在JDBC连接串里显式指定serverTimezoneAsia/Shanghai驱动的com.mysql.jdbc.Driver也要换成com.mysql.cj.jdbc.Driver。这类问题说大不大但对第一次上手的人很劝退。2.2 源码导入与数据库初始化实操拿到源码后第一步不是急着启动而是先初始化数据库。RuoYi-activiti一般会有两种SQL脚本一种是若依自带的通常是ry_2023.sql或者类似命名包含sys_user、sys_role、sys_menu等系统表数据另一种是Activiti建表脚本——如果你不知道具体放在哪里最简单的方法是启动项目时让Activiti自动建表。Activiti的ProcessEngineConfiguration有一个参数叫databaseSchemaUpdate它的取值决定了引擎启动时的建表策略。默认的false不会建表配置成true则会在第一次启动时根据对应数据库类型自动执行建表SQL。很多RuoYi-activiti版本里这个配置是打开的也就是说你只要先导入若依的SQL然后正常启动ACT_*这二十多张表就会自动生成。这样就不用自己去翻activiti-db-scripts里的MySQL脚本逐个执行。这里有一个实操中发现的问题自动建表虽然方便但表结构创建完成后有一些表是空的特别是ACT_ID_*Activiti的身份管理表。如果你的流程设计中有按用户组/角色去分配审批人可能需要在业务代码里把若依的用户数据同步过来或者直接用若依用户ID当审批人。如果你发现流程跑起来后待办任务查不到多半是任务分配时用户ID没有对上。2.3 项目启动的关键细节启动时还有一个非常容易出问题的环节Redis连接。若依默认配置要求Redis本机6379端口可用。如果你没有安装Redis启动会直接报“Unable to connect to Redis”之类的连接异常。我是建议直接装一个Windows下可以下载Redis的Windows版本或者用Docker起一个docker run -d -p 6379:6379 redis。开发阶段把Redis配成不带密码的默认模式省去一堆麻烦。导入项目到IDEA后建议先执行一次完整的Maven编译mvn clean package -DskipTests。这样做有两个好处一是提前下载所有依赖避免后续启动时网络问题导致的依赖缺失二是能暴露编译期错误比如有些版本源码使用了lombok如果本地没装lombok插件IDE会频繁报找不到getter/setter方法。3. 核心流程设计与功能落地实现3.1 流程模型设计与部署RuoYi-activiti一般会集成流程设计器你可以在浏览器里在线画流程图也可以使用Activiti Modeler插件在IDEA里设计。两种方式本质都是生成BPMN2.0的XML文件然后通过API部署到引擎。以在线设计器为例创建一个请假流程流程名称填“请假申请”流程Key填“leave”。拖一个开始事件一个用户任务节点“部门经理审批”一个用户任务节点“总经理审批”一个结束事件。在两个用户任务的配置里设置办理人。一种方式是直接写死某个用户ID这种方式适合测试另一种是用流程变量表达式比如${userId}代表该节点办理人由流程启动时传入的userId变量决定。保存并部署流程。部署完成后在流程定义管理列表里能看到这个流程并带有一个版本号如v1。这里特别需要注意Activiti的流程Key是逻辑标识同一个Key的多次部署会产生不同版本。发起流程时如果不指定版本默认使用最新版本。如果修改了流程图并重新部署旧的流程实例还能继续跑但新发起会走新版本。这个机制在实际项目里很实用符合“旧单走旧流程新单走新流程”的业务诉求。部署的API代码通常长这样Autowired private RepositoryService repositoryService; public void deploy(String bpmnPath) { Deployment deployment repositoryService.createDeployment() .addClasspathResource(bpmnPath) .name(请假流程) .deploy(); // deployment.getId() 就是部署ID // repositoryService.createProcessDefinitionQuery() // .deploymentId(deployment.getId()).singleResult() 拿到流程定义 }这个过程中的一个高频问题是流程图片中文乱码。部署后生成流程跟踪图时如果节点名称是中文图片上显示的汉字可能变成方块。解决办法一般是给流程引擎配置中文字体比如把字体设置为宋体或者微软雅黑。在ProcessEngineConfiguration的配置类中扩展一个方法protected void initDiagramGenerator() { // 设置默认字体 processEngineConfiguration.setActivityFontName(宋体); processEngineConfiguration.setLabelFontName(宋体); processEngineConfiguration.setAnnotationFontName(宋体); }3.2 业务表单与流程的挂接方式这是新手最容易困惑的地方。很多人以为RuoYi-activiti会自动生成业务表单实际上它不会。你需要把自己的业务表单页面和数据表和流程实例关联起来。通常做法是定义一个业务表比如leave_order字段包含id、user_id、start_date、end_date、reason、process_instance_id等。发起人填写表单后先把业务数据保存到自己的业务表拿到自增ID然后再启动流程实例并把业务表主键作为一个流程变量传入。启动流程时可以用businessKey来关联业务数据。启动流程的代码大致如下MapString, Object variables new HashMap(); variables.put(deptLeaderId, deptLeaderId); variables.put(gmId, gmId); variables.put(days, 3); ProcessInstance pi runtimeService.startProcessInstanceByKey( leave, businessKey, variables); // businessKey就是业务表主键后续查询待办时你可以通过taskService拿任务ID再通过task.getProcessInstanceId()去查询。反查业务数据时用runtimeService.createProcessInstanceQuery()去拿businessKey或者直接用自己的流程变量存业务主键。这个设计模式非常经典既保证了流程引擎与业务数据的解耦也能在流程跟踪、历史查询时快速找到原始单据。3.3 审批环节的关键实现审批功能是工作流里面业务最重的部分。待办列表的实现很简单taskService.createTaskQuery().taskAssignee(当前用户ID).list()但审批动作本身有很多变体。第一是同意。直接执行taskService.complete(taskId, variables)流程就按照BPMN线路往下走。注意complete时传入的variables会更新流程变量供下一步网关判断使用。第二是驳回。Activiti原生并没有“驳回”这个概念它只有“任务完成”。驳回的实现思路通常是两种一种是在流程图上显式画一条驳回线从当前审批节点指回上一个节点通过在网关处判断审批结果变量来走不同分支另一种是在程序里做跳转使用runtimeService.createChangeActivityStateBuilder()把当前任务从驳回节点移动到目标节点。第二种方式对流程图的依赖更小可以让用户选择“驳回到发起人”“驳回到上一个节点”。但需要自己记录历史节点的上下文比较考验逻辑。很多RuoYi-activiti项目干脆采用第一种方案在画流程图时默认加上驳回分支用approveStatus变量来控制。第三是会签和或签。会签所有审批人都同意才通过在BPMN2.0中对应多实例任务。你可以在用户任务节点上配置Multi Instance Loop Characteristics其中sequential false 表示并行会签loop cardinality 可以指定审批人数量collection 配合activiti:collection指定审批人列表activiti:elementVariable用于循环中的单个变量或签是任一审批人同意即通过逻辑上是同一套多实例机制只是在完成条件的表达式上做文章。例如设置completionCondition为${nrOfCompletedInstances nrOfInstances}表达全部通过或${nrOfCompletedInstances 1}表达任一通过即走人。这块代码逻辑上没有太大难度难的是理解BPMN2.0多实例的语义建议先在本地画一个演示流程跑通再上业务。3.4 流程状态的跟踪与历史查询平台的价值不仅在于能流转更在于能追溯。流程实例当前跑到哪个节点每个节点的处理人是谁审批耗时多久这些都需要使用HistoryService。我一般用两类查询运行态runtimeService.createProcessInstanceQuery()。只要流程没走完这里都能查到。历史态historyService.createHistoricProcessInstanceQuery() 和 createHistoricActivityInstanceQuery()。流程结束后运行态数据会被清理到历史表历史查询不受影响。流程跟踪图也是基于历史数据实现的。Activiti提供了diagram可视化能力大致思路是获取当前流程实例中已完成和待办的活动节点ID然后在流程图片上着色标注。RuoYi-activiti项目一般会把这张图片与审批意见列表展示在同一个详情页面方便领导快速掌握整个环节的“动线”。4. 常见问题与排查技巧实录4.1 流程启动后看不到待办任务这个问题出现的频率非常高。表象是发起流程成功了process_instance表里也有记录但审批人的待办列表是空的。排查思路通常是四步走。第一步检查流程定义中该用户任务节点的assignee到底设置成了什么。直接在流程XML里看比看设计器界面更直观。第二步确认发起流程时传入的变量名是否与assignee表达式一致。比如XML里写的是${deptLeader}但你在启动流程时传的变量叫${deptLeaderId}那任务就不会分配给任何人。第三步查ACT_RU_TASK表如果任务存在但assignee字段为空说明没有分配成功如果assignee有值再看查询条件是否拼错了用户ID。第四步如果是在线设计器配置了候选人组但候选人组的标识没有和任何用户关联也会导致待办列表为空。这类问题定位链路清晰顺着逻辑排查比瞎猜快得多。4.2 数据库表自动生成失败你配置了databaseSchemaUpdate为true但启动时发现ACT_*表根本没建。原因大多出在数据库账号权限不足或者是连接到了错误的数据库中。很多人在一个MySQL实例里建了多个库若依的系统表在一个库但JDBC连接指向了另一个库导致Activiti把表建到了别的地方。排查方式很简单启动日志里搜索“CREATE TABLE ACT_RE_”看看它执行时连接的是哪个库。另外MySQL8.0以下版本对索引长度有限制ACT_ID_表中有字符串索引如果用的数据库版本过老或者字符集改成utf8mb4但没注意字节数也可能建表失败。建议直接锁版本号能用官方推荐组合就不要强上最新版数据库。4.3 流程图片中文乱码这个前面提过再补充一点排查经验。乱码的根因是Java图形库在生成图片时找不到能支持中文的字体。除了在引擎配置里指定字体名称还需要确保你运行项目的操作系统里确实安装了对应字体。在CentOS的Docker容器里你可能需要额外安装fontconfig和fontpackages等组件。如果项目里配置了宋体但系统没有宋体配置也是白搭。另一个取巧的做法是把生成图片的字体直接指定为“sans-serif”这种Java虚拟机能映射的通用字体实测很多环境下比指定具体字体更省事。4.4 多人审批的权限边界问题在使用过程中我还遇到过一类业务上的问题两个不同流程都用了同一个审批人变量名导致A流程的审批人被错误传到了B流程。根本原因是我在启动流程时复用了同一个Map变量对象没有做清理。流程变量虽然灵活但也容易出这种“串数据”的事。建议每个流程启动时都新建一个Map或者做模块化的变量构造方法不要把当前登录用户的上下文直接塞进所有流程。毕竟流程变量一旦写入在实例生命周期内都能被任意节点读取变动要谨慎。4.5 版本升级的迁移坑Activiti版本差距大了API和表结构变化很显著。比如Activiti 5到Activiti 6很多服务类方法被标记过时或调整了签名表结构上ACT_ID_*身份表在后续版本中逐渐不是必选项。RuoYi-activiti的平台源码很多时候是基于Activiti 6或者7做的封装如果你拿到了一个基于Activiti 5的老项目做二次开发最好不要直接替换依赖版本不然会冒出一堆编译错误和运行时异常。经验是能用新平台就直接用官方推荐的Activiti版本代码里尽量通过Service接口调用引擎能力不要直接操作底层表这样将来升级时改动面最小。5. 实际使用中的几点建议5.1 不要一上来就追求高级功能如果你第一次接触这套平台建议先用在线设计器画一个最简单的“发起人-审批人-结束”流程把部署、发起、待办、审批这一整条链路手工跑通。确认没有技术障碍后再去尝试会签、驳回这些高级节点。直接上手复杂的流程图出了问题你分不清是流程定义错误还是代码逻辑错误调试会很痛苦。5.2 表单页面与流程引擎保持松耦合我见过很多项目把审批表单和流程任务强绑定每个流程节点都写死了一套页面。这么做短期没感觉后期流程调整时维护成本翻倍。更合理的做法是业务表单独立于流程用流程变量保存关键业务上下文页面只负责展示与交互流程引擎只负责流转。这样哪怕流程结构大改表单代码也基本不用动。5.3 善用流程监听器和事件如果你有一些与流程无关的副作用操作比如发送站内信、推送企业微信通知建议不要直接写在审批按钮的事件里而是使用Activiti的ExecutionListener和TaskListener。这样流程流转与业务系统解耦也方便做统一的重试和异常处理。我实践中就遇到过审批人点击同意后通知发送失败但因为通知代码与complete操作混在同一个事务里整个任务提交都回滚了。改成监听器加独立事务后这个问题彻底消失。最后再分享一个个人体会工作流平台这类东西源码本身只是起点真正的价值在于你如何理解BPMN2.0的语义以及如何把业务模型映射到流程模型上。拿到RuoYi-activiti源码后建议先花时间读懂它的流程模块代码结构和表设计再动手改业务远比直接复制粘贴一段启动流程的代码要靠谱得多。这套平台我实际用了大半年整体稳定性是过硬的只要你把环境配置和用户映射这两件事做好后面跑业务会越用越顺手。本文还有配套的精品资源点击获取