RuoYi-Vue-fast集成Flowable:工作流引擎应用教程

RuoYi-Vue-fast集成Flowable:工作流引擎应用教程

【免费下载链接】RuoYi-Vue-fast :tada: (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue & Element 的前后端分离权限管理系统 【免费下载链接】RuoYi-Vue-fast 项目地址: https://gitcode.com/GitHub_Trending/ru/RuoYi-Vue-fast

在企业级应用开发中,工作流(Workflow)是实现业务流程自动化的核心组件。本文将详细介绍如何在RuoYi-Vue-fast框架中集成Flowable工作流引擎,帮助开发者快速构建审批、任务流转等业务场景。通过本文,你将掌握环境配置、流程定义、任务管理等关键技能,并能基于实际业务需求扩展工作流功能。

技术栈与环境准备

核心技术栈说明

RuoYi-Vue-fast基于SpringBoot 2.5.15构建,采用前后端分离架构。集成Flowable需引入以下组件:

  • Flowable:6.7.2版本(兼容SpringBoot 2.x),提供BPMN 2.0流程引擎
  • 数据库:MySQL 8.0+(支持Flowable的历史数据存储)
  • 依赖管理:Maven 3.6+(通过pom.xml统一管理版本)

环境依赖配置

首先需要在项目pom.xml中添加Flowable核心依赖。打开pom.xml文件,在<dependencies>节点下添加:

<!-- Flowable工作流核心依赖 -->
<dependency>
    <groupId>org.flowable</groupId>
    <artifactId>flowable-spring-boot-starter</artifactId>
    <version>6.7.2</version>
</dependency>
<!-- Flowable REST API支持 -->
<dependency>
    <groupId>org.flowable</groupId>
    <artifactId>flowable-rest</artifactId>
    <version>6.7.2</version>
</dependency>

版本兼容性说明:Flowable 6.7.x系列与SpringBoot 2.5.x保持兼容,更高版本可能需要调整Spring生态组件版本。具体版本对应关系可参考Flowable官方文档

数据库配置与初始化

数据源配置

Flowable需要独立的数据库表结构存储流程定义、任务实例等数据。修改application.yml(通常位于src/main/resources目录),添加Flowable专用数据源配置:

spring:
  datasource:
    flowable:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/ruoyi_flowable?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
      username: root
      password: password

初始化脚本执行

Flowable提供自动建表功能,启动项目时会自动创建所需表结构。若需手动执行SQL脚本,可从Flowable官网下载对应版本的flowable-all.sql,或通过Maven依赖中的flowable-db.zip获取。

数据库表说明:Flowable会创建23张表,主要分为以下几类:

  • ACT_RE_*:流程定义相关(如ACT_RE_PROCDEF流程定义表)
  • ACT_RU_*:运行时数据(如ACT_RU_TASK任务实例表)
  • ACT_HI_*:历史数据(如ACT_HI_ACTINST活动历史表)
  • ACT_GE_*:通用数据(如ACT_GE_BYTEARRAY二进制存储表)

流程引擎配置

核心配置类实现

创建Flowable配置类,位于src/main/java/com/ruoyi/framework/config/FlowableConfig.java,代码如下:

@Configuration
public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {

    @Autowired
    private DataSource flowableDataSource;
    
    @Autowired
    private PlatformTransactionManager transactionManager;

    @Override
    public void configure(SpringProcessEngineConfiguration config) {
        config.setDataSource(flowableDataSource);
        config.setTransactionManager(transactionManager);
        // 禁用Flowable自动部署(建议通过管理界面手动部署)
        config.setDeploymentMode("never-fail");
        // 配置历史级别为FULL(保存所有流程数据)
        config.setHistoryLevel(HistoryLevel.FULL);
        // 配置字体支持中文显示
        config.setActivityFontName("SimHei");
        config.setLabelFontName("SimHei");
        config.setAnnotationFontName("SimHei");
    }
}

关键配置参数说明

参数说明推荐值
HistoryLevel历史数据保存级别FULL(完整记录流程流转)
DeploymentMode部署模式never-fail(部署失败时不中断应用启动)
Font配置流程图中文显示支持SimHei(宋体)
AsyncExecutorActivate异步执行器开关true(启用异步任务处理)

流程定义与部署

BPMN文件设计

Flowable使用BPMN 2.0规范定义流程,创建请假审批流程示例:src/main/resources/processes/leave.bpmn20.xml

<?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://flowable.org/processdef">
  <process id="leaveProcess" name="请假审批流程" isExecutable="true">
    <startEvent id="startEvent1" />
    <sequenceFlow id="flow1" sourceRef="startEvent1" targetRef="approveTask" />
    
    <userTask id="approveTask" name="经理审批" flowable:assignee="${managerId}">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler">false</modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <sequenceFlow id="flow2" sourceRef="approveTask" targetRef="decision" />
    
    <exclusiveGateway id="decision" name="审批结果" />
    <sequenceFlow id="flow3" sourceRef="decision" targetRef="endEvent1">
      <conditionExpression xsi:type="tFormalExpression">${approved == true}</conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow4" sourceRef="decision" targetRef="modifyTask">
      <conditionExpression xsi:type="tFormalExpression">${approved == false}</conditionExpression>
    </sequenceFlow>
    
    <userTask id="modifyTask" name="修改申请" flowable:assignee="${applicantId}" />
    <sequenceFlow id="flow5" sourceRef="modifyTask" targetRef="approveTask" />
    
    <endEvent id="endEvent1" />
  </process>
</definitions>

流程部署代码实现

创建流程部署服务类src/main/java/com/ruoyi/project/flow/service/ProcessDeployService.java:

@Service
public class ProcessDeployService {

    @Autowired
    private RepositoryService repositoryService;

    /**
     * 部署BPMN流程文件
     */
    public AjaxResult deployProcess(MultipartFile file) {
        try {
            Deployment deployment = repositoryService.createDeployment()
                    .name(file.getOriginalFilename())
                    .addInputStream(file.getOriginalFilename(), file.getInputStream())
                    .deploy();
            return AjaxResult.success("部署成功", deployment.getId());
        } catch (Exception e) {
            log.error("流程部署失败", e);
            return AjaxResult.error("部署失败:" + e.getMessage());
        }
    }
    
    /**
     * 查询已部署流程列表
     */
    public List<ProcessDefinition> getDeployedProcesses() {
        return repositoryService.createProcessDefinitionQuery()
                .latestVersion()
                .orderByProcessDefinitionName().asc()
                .list();
    }
}

任务管理与流程交互

流程实例启动

在业务代码中启动流程实例,以请假申请为例:

@Service
public class LeaveService {

    @Autowired
    private RuntimeService runtimeService;

    /**
     * 提交请假申请,启动流程实例
     */
    public String startLeaveProcess(LeaveApply apply) {
        // 设置流程变量
        Map<String, Object> variables = new HashMap<>();
        variables.put("applicantId", SecurityUtils.getUserId()); // 当前申请人ID
        variables.put("managerId", apply.getManagerId()); // 经理ID
        
        // 启动流程实例
        ProcessInstance instance = runtimeService.startProcessInstanceByKey(
            "leaveProcess", // BPMN文件中定义的process id
            apply.getApplyNo(), // 业务编号
            variables
        );
        return instance.getId();
    }
}

任务处理功能

创建任务审批接口,处理用户任务:

@RestController
@RequestMapping("/flow/task")
public class TaskController extends BaseController {

    @Autowired
    private TaskService taskService;

    /**
     * 完成审批任务
     */
    @PostMapping("/complete")
    public AjaxResult completeTask(@RequestBody TaskCompleteDTO dto) {
        // 获取任务对象
        Task task = taskService.createTaskQuery()
                .taskId(dto.getTaskId())
                .taskAssignee(SecurityUtils.getUsername())
                .singleResult();
                
        if (task == null) {
            return AjaxResult.error("任务不存在或无权限处理");
        }
        
        // 设置审批结果变量
        Map<String, Object> variables = new HashMap<>();
        variables.put("approved", dto.isApproved());
        taskService.complete(dto.getTaskId(), variables);
        
        return AjaxResult.success();
    }
    
    /**
     * 查询当前用户待办任务
     */
    @GetMapping("/myTasks")
    public TableDataInfo getMyTasks() {
        List<Task> tasks = taskService.createTaskQuery()
                .taskAssignee(SecurityUtils.getUsername())
                .orderByTaskCreateTime().desc()
                .listPage(getPageNum(), getPageSize());
                
        return getDataTable(tasks.stream().map(this::convertToVO).collect(Collectors.toList()));
    }
}

前端界面集成

流程设计器集成

前端集成Flowable Modeler设计器,在Vue路由配置文件src/router/index.js中添加:

{
  path: '/flow/modeler',
  component: Layout,
  hidden: true,
  children: [{
    path: 'index/:modelId',
    component: () => import('@/views/flow/modeler/index'),
    name: 'FlowModeler',
    meta: { title: '流程设计', icon: 'form' }
  }]
}

任务列表组件实现

创建待办任务列表组件src/views/flow/task/myTasks.vue:

<template>
  <div class="app-container">
    <el-table v-loading="loading" :data="taskList" border fit highlight-current-row>
      <el-table-column type="index" label="序号" width="50" />
      <el-table-column prop="name" label="任务名称" />
      <el-table-column prop="processDefinitionName" label="流程名称" />
      <el-table-column prop="createTime" label="创建时间" width="180" />
      <el-table-column label="操作" width="200" align="center">
        <template slot-scope="scope">
          <el-button type="primary" size="mini" @click="handleApprove(scope.row)">
            处理
          </el-button>
          <el-button size="mini" @click="showProcessImage(scope.row)">
            流程图
          </el-button>
        </template>
      </el-table-column>
    </el-table>
    <pagination v-show="total>0" :total="total" :page.sync="pageNum" :limit.sync="pageSize" />
    
    <!-- 审批弹窗 -->
    <el-dialog :visible.sync="approveVisible" title="任务审批">
      <el-form :model="approveForm" label-width="80px">
        <el-form-item label="审批意见">
          <el-radio-group v-model="approveForm.approved">
            <el-radio :label="true">同意</el-radio>
            <el-radio :label="false">驳回</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="意见备注">
          <el-input type="textarea" v-model="approveForm.comment" rows="4" />
        </el-form-item>
      </el-form>
      <div slot="footer">
        <el-button @click="approveVisible = false">取消</el-button>
        <el-button type="primary" @click="submitApprove">提交</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { getMyTasks, completeTask } from '@/api/flow/task'

export default {
  data() {
    return {
      loading: false,
      taskList: [],
      total: 0,
      pageNum: 1,
      pageSize: 10,
      approveVisible: false,
      approveForm: {
        taskId: '',
        approved: true,
        comment: ''
      }
    }
  },
  methods: {
    loadTasks() {
      this.loading = true
      getMyTasks({
        pageNum: this.pageNum,
        pageSize: this.pageSize
      }).then(response => {
        this.taskList = response.rows
        this.total = response.total
        this.loading = false
      })
    },
    handleApprove(row) {
      this.approveForm.taskId = row.id
      this.approveVisible = true
    },
    submitApprove() {
      completeTask(this.approveForm).then(() => {
        this.$message.success('审批成功')
        this.approveVisible = false
        this.loadTasks()
      })
    }
  },
  created() {
    this.loadTasks()
  }
}
</script>

功能测试与问题排查

测试流程说明

  1. 部署流程:通过前端上传BPMN文件,调用deployProcess接口完成部署
  2. 发起申请:提交请假单,调用startLeaveProcess启动流程
  3. 经理审批:使用经理账号登录,在待办任务列表中处理审批
  4. 结果验证:检查流程状态和历史记录,确认流程按预期流转

常见问题解决方案

  1. 中文乱码问题:在FlowableConfig中配置中文字体,确保BPMN文件编码为UTF-8
  2. 流程部署失败:检查BPMN文件语法,可使用Flowable Online Designer验证
  3. 任务分配错误:确认流程变量传递正确,用户ID与系统用户表匹配
  4. 历史数据查询慢:优化ACT_HI_*表索引,调整HistoryLevel级别

扩展功能与最佳实践

流程权限控制

集成RuoYi-Vue-fast的权限系统,在任务分配时通过角色过滤候选人:

// 在用户任务分配时使用角色查询
userTask.setAssigneeExpression("${taskService.findUserByRole('DEPARTMENT_MANAGER', processInstanceId)}");

流程监控与统计

利用Flowable的HistoryService实现流程效率分析:

@Service
public class ProcessAnalysisService {

    @Autowired
    private HistoryService historyService;

    /**
     * 统计流程平均耗时
     */
    public Map<String, Object> analyzeProcessEfficiency(String processKey) {
        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery()
                .processDefinitionKey(processKey)
                .finished();
                
        long count = query.count();
        if (count == 0) {
            return Collections.emptyMap();
        }
        
        Duration averageDuration = query.list().stream()
                .map(pi -> Duration.between(pi.getStartTime(), pi.getEndTime()))
                .reduce(Duration.ZERO, Duration::plus)
                .dividedBy(count);
                
        Map<String, Object> result = new HashMap<>();
        result.put("processKey", processKey);
        result.put("averageDuration", averageDuration);
        result.put("completedCount", count);
        return result;
    }
}

性能优化建议

  1. 异步任务处理:将流程中的耗时操作设计为异步服务任务
  2. 缓存流程定义:减少RepositoryService的查询次数
  3. 定期清理历史数据:使用Flowable的历史数据清理API:
managementService.deleteHistoricProcessInstancesAsync(
    historyService.createHistoricProcessInstanceQuery()
        .finished()
        .processInstanceCompletedBefore(LocalDateTime.now().minusYears(1))
        .listIds(),
    "清理一年前的历史数据"
);

总结与后续学习

通过本文的步骤,你已成功在RuoYi-Vue-fast中集成Flowable工作流引擎,并实现了基础的流程定义、任务管理功能。后续可深入学习以下内容:

  • 高级流程模式:如并行网关、包含网关的复杂流程设计
  • 事件机制:利用Flowable的事件监听实现业务扩展
  • 表单集成:结合RuoYi的表单生成器实现动态表单与流程结合

完整的集成代码已提交至项目仓库,可参考flow模块源码进一步学习。建议结合官方文档和实际业务场景,持续优化工作流功能。

【免费下载链接】RuoYi-Vue-fast :tada: (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue & Element 的前后端分离权限管理系统 【免费下载链接】RuoYi-Vue-fast 项目地址: https://gitcode.com/GitHub_Trending/ru/RuoYi-Vue-fast

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

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

抵扣说明:

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

余额充值