RuoYi集成Activiti:工作流引擎与流程设计器全指南

RuoYi集成Activiti:工作流引擎与流程设计器全指南

【免费下载链接】RuoYi :tada: (RuoYi)官方仓库 基于SpringBoot的权限管理系统 易读易懂、界面简洁美观。 核心技术采用Spring、MyBatis、Shiro没有任何其它重度依赖。直接运行即可用 【免费下载链接】RuoYi 项目地址: https://gitcode.com/gh_mirrors/ruoyi/RuoYi

引言:告别繁琐审批,拥抱可视化工作流

你是否还在为RuoYi项目中手动处理审批流程而烦恼?是否希望通过可视化界面设计复杂的业务流程?本文将带你从零开始,在RuoYi框架中集成Activiti工作流引擎与流程设计器,彻底解决传统审批流程开发效率低、维护成本高的痛点。读完本文,你将获得:

  • 完整的Activiti与RuoYi集成方案
  • 可视化流程设计器的部署与使用
  • 实战级请假流程开发案例
  • 常见集成问题的解决方案

环境准备与版本兼容性分析

基础环境要求

环境/工具版本要求备注
JDK1.8+与RuoYi保持一致
Maven3.6+确保依赖下载正常
MySQL5.7+Activiti需InnoDB引擎
RuoYi4.8.1本文基于此版本开发
Activiti7.1.0.M6兼容Spring Boot 2.5.x

版本兼容性矩阵

mermaid

兼容性说明:Activiti 7.1.0.M6与Spring Boot 2.5.x存在最佳兼容性,需排除Spring Security依赖避免与RuoYi的Shiro框架冲突。

Activiti依赖集成与配置

添加Maven依赖

修改项目根目录下的pom.xml,在dependencyManagement节点添加Activiti版本控制:

<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-dependencies</artifactId>
    <version>7.1.0.M6</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

ruoyi-admin模块的pom.xml中添加具体依赖:

<dependencies>
    <!-- Activiti核心依赖 -->
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-spring-boot-starter</artifactId>
        <exclusions>
            <!-- 排除Spring Security依赖 -->
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    
    <!-- Activiti Modeler依赖 -->
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-modeler</artifactId>
        <version>6.0.0</version>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-config</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-web</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

配置Activiti引擎

ruoyi-admin/src/main/resources/application.yml中添加Activiti配置:

spring:
  activiti:
    # 自动更新数据库结构
    database-schema-update: true
    # 历史记录级别
    history-level: full
    # 校验流程定义文件
    check-process-definitions: true
    # 流程定义文件位置
    process-definition-location-prefix: classpath:/processes/
    # 使用历史表
    db-history-used: true
    # 关闭异步执行器
    async-executor-activate: false

数据库表自动生成

启动项目后,Activiti会自动在数据库中创建28张工作流相关表,主要包括:

表名前缀用途
ACT_RE_*流程存储库
ACT_RU_*运行时数据
ACT_HI_*历史数据
ACT_GE_*通用数据

注意:确保数据库用户有足够权限创建表,首次启动会较慢,因为需要执行DDL语句。

Activiti Modeler集成与配置

部署Modeler静态资源

  1. 创建ruoyi-admin/src/main/resources/static/modeler目录
  2. 从Activiti源码或Maven依赖中提取Modeler静态资源(editor-appmodeler.html等)
  3. 修改modeler.html中的CDN链接为国内镜像:
<!-- 替换为国内CDN -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/angular.js/1.8.2/angular.min.js"></script>

配置Modeler Servlet

创建Activiti配置类:

@Configuration
public class ActivitiConfig {

    @Bean
    public ServletRegistrationBean<DispatcherServlet> activitiModelerServlet() {
        DispatcherServlet servlet = new DispatcherServlet();
        WebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
        servlet.setApplicationContext(applicationContext);
        
        ServletRegistrationBean<DispatcherServlet> registrationBean = new ServletRegistrationBean<>(servlet, "/modeler/*");
        registrationBean.setName("activitiModeler");
        registrationBean.setLoadOnStartup(1);
        return registrationBean;
    }
}

集成RuoYi权限控制

修改modeler.html添加RuoYi的登录验证:

// 在页面加载前验证登录状态
$.ajax({
    url: '/system/user/getInfo',
    type: 'get',
    async: false,
    success: function(data) {
        if (data.code !== 200) {
            window.location.href = '/login';
        }
    }
});

RuoYi菜单集成与前端配置

添加菜单记录

执行SQL插入菜单数据:

INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
(1000, '工作流管理', 0, 10, 'workflow', NULL, 1, 0, 'M', '0', '0', NULL, 'flow', 'admin', '2025-09-08', 'admin', '2025-09-08', '工作流管理模块'),
(1001, '流程设计', 1000, 1, 'modeler', 'modeler/modeler.html', 0, 0, 'C', '0', '0', 'workflow:model:view', 'form', 'admin', '2025-09-08', 'admin', '2025-09-08', '流程设计器');

配置菜单权限

添加角色权限:

INSERT INTO `sys_role_menu` (`role_id`, `menu_id`) VALUES (1, 1000), (1, 1001);

流程设计与部署实战

创建第一个流程定义

  1. 访问RuoYi系统,进入「工作流管理」→「流程设计」
  2. 点击「新建流程」,输入流程名称"请假流程"
  3. 使用拖拽方式设计流程:
    • 开始事件 → 用户任务(申请人) → 用户任务(部门经理) → 用户任务(总经理) → 结束事件
  4. 设置每个用户任务的办理人:
    • 申请人:${applyUserId}
    • 部门经理:${deptManagerId}
    • 总经理:${gmId}

流程定义文件示例

保存后的流程定义文件leave.bpmn20.xml位于src/main/resources/processes/

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL http://www.omg.org/spec/BPMN/2.0/20100501/BPMN20.xsd"
             id="Definitions_1" targetNamespace="http://activiti.org/test">
  
  <process id="leaveProcess" name="请假流程" isExecutable="true">
    <startEvent id="startEvent1"/>
    
    <userTask id="applyTask" name="申请人提交" activiti:assignee="${applyUserId}"/>
    <userTask id="deptApproveTask" name="部门经理审批" activiti:assignee="${deptManagerId}"/>
    <userTask id="gmApproveTask" name="总经理审批" activiti:assignee="${gmId}"/>
    
    <endEvent id="endEvent1"/>
    
    <sequenceFlow id="flow1" sourceRef="startEvent1" targetRef="applyTask"/>
    <sequenceFlow id="flow2" sourceRef="applyTask" targetRef="deptApproveTask"/>
    <sequenceFlow id="flow3" sourceRef="deptApproveTask" targetRef="gmApproveTask"/>
    <sequenceFlow id="flow4" sourceRef="gmApproveTask" targetRef="endEvent1"/>
  </process>
</definitions>

工作流业务代码实现

流程服务接口

public interface IProcessService {
    /**
     * 部署流程
     */
    AjaxResult deployProcess(MultipartFile file);
    
    /**
     * 启动流程实例
     */
    String startProcessInstance(String processKey, Map<String, Object> variables);
    
    /**
     * 查询个人任务
     */
    List<TaskVO> queryPersonalTasks(Long userId);
    
    /**
     * 完成任务
     */
    AjaxResult completeTask(String taskId, Map<String, Object> variables);
}

服务实现类

@Service
public class ProcessServiceImpl implements IProcessService {

    @Autowired
    private RepositoryService repositoryService;
    
    @Autowired
    private RuntimeService runtimeService;
    
    @Autowired
    private TaskService taskService;
    
    @Override
    public AjaxResult deployProcess(MultipartFile file) {
        try {
            String fileName = file.getOriginalFilename();
            Deployment deployment = repositoryService.createDeployment()
                    .addInputStream(fileName, file.getInputStream())
                    .name(fileName)
                    .deploy();
            return AjaxResult.success("部署成功", deployment.getId());
        } catch (Exception e) {
            return AjaxResult.error("部署失败:" + e.getMessage());
        }
    }
    
    @Override
    public String startProcessInstance(String processKey, Map<String, Object> variables) {
        ProcessInstance instance = runtimeService.startProcessInstanceByKey(processKey, variables);
        return instance.getId();
    }
    
    @Override
    public List<TaskVO> queryPersonalTasks(Long userId) {
        List<Task> tasks = taskService.createTaskQuery()
                .taskAssignee(userId.toString())
                .orderByTaskCreateTime().desc()
                .list();
                
        return tasks.stream().map(task -> {
            TaskVO vo = new TaskVO();
            vo.setTaskId(task.getId());
            vo.setTaskName(task.getName());
            vo.setProcessInstanceId(task.getProcessInstanceId());
            vo.setCreateTime(task.getCreateTime());
            return vo;
        }).collect(Collectors.toList());
    }
    
    @Override
    public AjaxResult completeTask(String taskId, Map<String, Object> variables) {
        try {
            taskService.complete(taskId, variables);
            return AjaxResult.success("任务已完成");
        } catch (Exception e) {
            return AjaxResult.error("任务完成失败:" + e.getMessage());
        }
    }
}

控制器实现

@RestController
@RequestMapping("/workflow/process")
public class ProcessController extends BaseController {

    @Autowired
    private IProcessService processService;
    
    @PostMapping("/deploy")
    public AjaxResult deployProcess(@RequestParam("file") MultipartFile file) {
        return processService.deployProcess(file);
    }
    
    @PostMapping("/start")
    public AjaxResult startProcess(@RequestParam String processKey, 
                                   @RequestBody Map<String, Object> variables) {
        String instanceId = processService.startProcessInstance(processKey, variables);
        return AjaxResult.success("流程已启动", instanceId);
    }
    
    @GetMapping("/tasks")
    public AjaxResult queryTasks() {
        Long userId = ShiroUtils.getUserId();
        List<TaskVO> tasks = processService.queryPersonalTasks(userId);
        return AjaxResult.success(tasks);
    }
    
    @PostMapping("/complete/{taskId}")
    public AjaxResult completeTask(@PathVariable String taskId, 
                                  @RequestBody Map<String, Object> variables) {
        return processService.completeTask(taskId, variables);
    }
}

实战案例:请假流程实现

业务流程设计

mermaid

前端页面实现

<div class="row">
    <div class="col-sm-12">
        <div class="card">
            <div class="card-body">
                <form id="leaveForm">
                    <div class="form-group">
                        <label>请假类型</label>
                        <select class="form-control" name="leaveType">
                            <option value="annual">年假</option>
                            <option value="sick">病假</option>
                            <option value="personal">事假</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label>请假天数</label>
                        <input type="number" class="form-control" name="days" required>
                    </div>
                    <div class="form-group">
                        <label>请假理由</label>
                        <textarea class="form-control" name="reason" rows="3"></textarea>
                    </div>
                    <button type="button" class="btn btn-primary" onclick="submitLeave()">提交申请</button>
                </form>
            </div>
        </div>
    </div>
</div>

<script>
function submitLeave() {
    var formData = $('#leaveForm').serializeObject();
    
    // 获取流程变量
    var variables = {
        applyUserId: [[${shiro:getUserId()}]],
        deptManagerId: [[${deptManagerId}]],
        gmId: [[${gmId}]],
        leaveType: formData.leaveType,
        days: formData.days,
        reason: formData.reason
    };
    
    $.ajax({
        url: '/workflow/process/start?processKey=leaveProcess',
        type: 'post',
        contentType: 'application/json',
        data: JSON.stringify(variables),
        success: function(data) {
            if (data.code === 200) {
                layer.msg('请假申请已提交', {icon: 1});
                setTimeout(function() {
                    parent.location.reload();
                }, 1000);
            } else {
                layer.msg(data.msg, {icon: 2});
            }
        }
    });
}
</script>

流程测试与验证

  1. 以普通用户登录,提交请假申请
  2. 切换到部门经理账号,查看待办任务并审批
  3. 切换到总经理账号,查看待办任务并审批
  4. 查看流程历史记录,验证流程是否按预期执行

常见问题与解决方案

问题解决方案
Spring Security冲突排除Activiti依赖中的Spring Security模块
Modeler无法加载检查静态资源路径和AngularJS版本兼容性
中文乱码在pom.xml中配置资源过滤,设置UTF-8编码
流程定义部署失败检查BPMN文件格式,确保使用正确的命名空间
任务分配不生效确保Assignee表达式正确,用户ID转换为字符串

总结与展望

通过本文的步骤,我们成功在RuoYi框架中集成了Activiti工作流引擎和流程设计器,实现了可视化流程设计、流程部署、任务管理等核心功能。工作流技术的引入,能够显著提升企业级应用中业务流程的灵活性和可维护性。

未来可以进一步扩展:

  • 集成表单设计器,实现动态表单与流程的绑定
  • 添加流程监控与统计功能
  • 实现流程版本管理与流程实例迁移
  • 开发移动端工作流审批应用

希望本文能帮助你顺利在RuoYi项目中应用工作流技术,提升系统的业务处理能力。如有任何问题,欢迎在评论区留言讨论。

收藏本文,关注作者获取更多RuoYi高级开发技巧,下期将带来《RuoYi微服务改造实战》。

【免费下载链接】RuoYi :tada: (RuoYi)官方仓库 基于SpringBoot的权限管理系统 易读易懂、界面简洁美观。 核心技术采用Spring、MyBatis、Shiro没有任何其它重度依赖。直接运行即可用 【免费下载链接】RuoYi 项目地址: https://gitcode.com/gh_mirrors/ruoyi/RuoYi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值