若依(RuoYi-Vue)+Flowable工作流前后端整合教程
'# 若依(RuoYi-Vue)+Flowable工作流前后端整合教程
一、背景与问题
在企业级应用开发中,工作流系统是核心组件之一。传统开发中,流程审批、业务规则等逻辑常通过自定义代码实现,导致代码冗余、维护困难。而Flowable作为轻量级工作流引擎,结合若依(RuoYi-Vue)框架,可以实现流程定义、流程实例管理、任务审批等完整功能。
在实际开发中,我们常遇到以下问题:
- 流程审批需要与现有业务系统深度集成
- 复杂审批流程需要动态条件判断
- 多角色参与的审批流程需要权限控制
- 需要与现有权限系统(如RBAC)对接
传统的解决方案需要开发人员手动编写大量业务逻辑代码,而通过Flowable与若依框架的整合,可以实现流程引擎与业务系统的无缝对接。
二、基本原理
Flowable工作流引擎包含以下核心组件:
- 流程定义(Process Definition):通过BPMN2.0定义的业务流程图
- 流程实例(Process Instance):运行中的具体流程实例
- 任务(Task):流程中的具体操作步骤
- 事件(Event):流程中的关键节点事件
- 任务参与者(Actor):流程中需要处理任务的用户角色
若依框架作为Spring Boot + Vue的前后端分离架构,通过REST API与Flowable进行交互。其整合方式主要包括:
- 后端:Spring Boot集成Flowable,处理流程定义、启动流程、任务处理等
- 前端:Vue组件与后端API对接,展示流程图、任务列表、审批表单等
三、环境准备
1. 技术栈要求
| 组件 | 版本要求 |
|---|---|
| Java | 17+ |
| Spring Boot | 3.1.x |
| Flowable | 6.5.x |
| Vue | 3.x |
| Node.js | 16.x |
2. 依赖配置
Spring Boot项目pom.xml中添加Flowable依赖:
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.5.1</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-engine</artifactId>
<version>6.5.1</version>
</dependency>Vue项目package.json中添加依赖:
{
"dependencies": {
"vue": "^3.2.15",
"axios": "^1.5.1",
"flowable-ui": "^1.0.0"
}
}四、核心实现
1. 流程定义接口
创建流程定义的REST接口,用于上传BPMN文件:
@RestController
@RequestMapping("/api/process")
public class ProcessController {
@Autowired
private RepositoryService repositoryService;
@PostMapping("/define")
public ResponseEntity<String> defineProcess(@RequestParam("file") MultipartFile file) {
try {
InputStream inputStream = file.getInputStream();
String processName = file.getOriginalFilename();
String processKey = processName.substring(0, processName.lastIndexOf("."));
// 上传流程定义文件
repositoryService.createDeployment()
.name(processName)
.addClasspathResource("bpmn/" + file.getOriginalFilename())
.deploy();
return ResponseEntity.ok("流程定义成功");
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("流程定义失败");
}
}
}关键点说明:
- 使用
RepositoryService处理流程定义文件 - 支持从classpath加载BPMN文件
- 通过
createDeployment()创建部署 - 需要处理文件上传的异常情况
2. 流程启动接口
创建流程启动的REST接口,用于启动流程实例:
@RestController
@RequestMapping("/api/process")
public class ProcessController {
@Autowired
privateRuntimeService runtimeService;
@PostMapping("/start")
public ResponseEntity<String> startProcess(
@RequestParam("processKey") String processKey,
@RequestParam("businessKey") String businessKey,
@RequestBody Map<String, Object> variables) {
try {
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(
processKey, businessKey, variables);
return ResponseEntity.ok("流程启动成功,实例ID: " + processInstance.getId());
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("流程启动失败");
}
}
}关键点说明:
- 使用
RuntimeService启动流程实例 - 支持传入业务参数(variables)
- 需要处理流程Key不存在的异常
3. 任务处理接口
创建任务处理的REST接口,用于审批任务:
@RestController
@RequestMapping("/api/task")
public class TaskController {
@Autowired
private TaskService taskService;
@PostMapping("/complete")
public ResponseEntity<String> completeTask(
@RequestParam("taskId") String taskId,
@RequestParam("assignee") String assignee,
@RequestBody Map<String, Object> variables) {
try {
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("任务不存在");
}
taskService.complete(taskId, variables);
return ResponseEntity.ok("任务处理成功");
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("任务处理失败");
}
}
}关键点说明:
- 使用
TaskService处理任务 - 需要验证任务是否存在
- 支持传入处理变量(variables)
- 需要处理任务处理失败的情况
五、完整案例
1. 请假流程案例
1.1 BPMN流程定义
创建一个简单的请假流程BPMN文件(leave.bpmn):
<definitions xmlns="http://www.omg.org/spec/DMN/20191215/MODEL"
xmlns:flowable="http://www.flowable.org/schema/bpmn20"
targetNamespace="http://www.flowable.org/schema/bpmn20">
<process id="leaveProcess" name="请假流程" isExecutable="true">
<startEvent id="startEvent" name="提交申请" />
<sequenceFlow id="flow1" sourceRef="startEvent" targetRef="task1" />
<userTask id="task1" name="审批" activiti:assignee="${assignee}" />
<sequenceFlow id="flow2" sourceRef="task1" targetRef="endEvent" />
<endEvent id="endEvent" name="流程结束" />
</process>
</definitions>1.2 后端实现
创建流程启动的REST接口:
@RestController
@RequestMapping("/api/process")
public class ProcessController {
@Autowired
privateRuntimeService runtimeService;
@PostMapping("/start")
public ResponseEntity<String> startProcess(
@RequestParam("processKey") String processKey,
@RequestParam("businessKey") String businessKey,
@RequestParam("assignee") String assignee,
@RequestBody Map<String, Object> variables) {
try {
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(
processKey, businessKey, variables);
return ResponseEntity.ok("流程启动成功,实例ID: " + processInstance.getId());
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("流程启动失败");
}
}
}1.3 前端实现
创建任务列表组件(TaskList.vue):
<template>
<div>
<h2>待处理任务</h2>
<ul>
<li v-for="task in tasks" :key="task.id">
<strong>{{ task.name }}</strong> - {{ task.assignee }}
<button @click="completeTask(task.id, task.assignee)">处理</button>
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
tasks: []
};
},
mounted() {
this.fetchTasks();
},
methods: {
async fetchTasks() {
const response = await this.$axios.get('/api/task/list');
this.tasks = response.data;
},
async completeTask(taskId, assignee) {
const variables = {
approvalResult: '通过'
};
const response = await this.$axios.post('/api/task/complete', {
taskId,
assignee,
variables
});
alert(response.data);
this.fetchTasks();
}
}
};
</script>六、源码解析
1. 流程引擎初始化
在Spring Boot启动时,Flowable会自动加载配置:
@Configuration
@EnableFlowable
public class FlowableConfig {
@Autowired
private Environment env;
@PostConstruct
public void init() {
// 配置数据库连接
ProcessEngineConfiguration configuration = new StandaloneProcessEngineConfiguration()
.setJdbcUrl(env.getProperty("spring.datasource.url"))
.setJdbcUsername(env.getProperty("spring.datasource.username"))
.setJdbcPassword(env.getProperty("spring.datasource.password"));
// 初始化流程引擎
ProcessEngine processEngine = configuration.buildProcessEngine();
}
}关键点说明:
- 使用
StandaloneProcessEngineConfiguration配置 - 需要配置数据库连接参数
@EnableFlowable注解启用流程引擎
2. 流程实例处理
流程启动时的处理逻辑:
public ProcessInstance startProcessInstanceByKey(String processKey, String businessKey, Map<String, Object> variables) {
// 验证流程定义是否存在
if (!repositoryService.createProcessDefinitionQuery().processKey(processKey).count() > 0) {
throw new IllegalArgumentException("流程定义不存在: " + processKey);
}
// 启动流程实例
return runtimeService.startProcessInstanceByKey(processKey, businessKey, variables);
}关键点说明:
- 需要验证流程定义是否存在
businessKey用于关联业务数据variables参数用于传递业务参数
七、进阶使用
1. 动态审批条件
使用Flowable的条件表达式实现动态审批:
<userTask id="task1" name="审批" flowable:conditionExpression="${approvalLevel == '部门'}" />// 设置审批级别参数
Map<String, Object> variables = new HashMap<>();
variables.put("approvalLevel", "部门");2. 事件监听器
添加事件监听器处理流程事件:
public class TaskCreateListener implements TaskCreateListener {
@Override
public void notify(DelegateTask delegateTask) {
// 处理任务创建事件
System.out.println("创建任务: " + delegateTask.getName());
}
}@Configuration
public class FlowableConfig {
@Bean
public TaskCreateListener taskCreateListener() {
return new TaskCreateListener();
}
}3. 并行流程
使用并行网关实现并行审批:
<parallelGateway id="parallelGateway" />
<sequenceFlow id="flow1" sourceRef="parallelGateway" targetRef="task1" />
<sequenceFlow id="flow2" sourceRef="parallelGateway" targetRef="task2" />八、性能与工程实践
1. 性能优化
数据库索引优化
CREATE INDEX idx_process_definition_key ON act_re_procdef (process_definition_key_);缓存流程定义
@Cacheable("processDefinition") public ProcessDefinition getProcessDefinition(String processKey) { return repositoryService.createProcessDefinitionQuery().processKey(processKey).singleResult(); }流程实例清理
@Scheduled(cron = "0 0 0 * * ?") public void cleanUpProcessInstances() { runtimeService.deleteProcessInstancesByProcessDefinitionKey("leaveProcess", true); }
2. 安全风险
未授权访问
@PreAuthorize("hasRole('ROLE_ADMIN') or #taskId == authentication.name") public ResponseEntity<String> completeTask(...) { // ... }SQL注入防范
String safeQuery = "SELECT * FROM act_ru_task WHERE task_id_ = '" + taskId + "'";
3. 异常处理
事务管理
@Transactional public void startProcessInstance(...) { // ... }异常日志记录
try { // ... } catch (Exception e) { logger.error("流程处理异常", e); throw new RuntimeException("流程处理异常", e); }
九、常见问题与踩坑
1. 流程无法启动
原因:未正确配置数据库连接
解决:检查application.yml中数据库配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/flowable?useSSL=false&serverTimezone=UTC
username: root
password: 1234562. 任务处理失败
原因:未正确设置assignee
解决:确保在启动流程时传递assignee参数
3. 流程图显示异常
原因:未正确部署流程定义
解决:确保BPMN文件路径正确,使用createDeployment()方法部署
4. 性能瓶颈
原因:频繁查询流程定义
解决:使用缓存机制,如Redis缓存流程定义信息
十、最佳实践
1. 推荐方案
- 使用Flowable的BPMN2.0标准定义流程
- 与现有权限系统集成,实现角色绑定
- 使用REST API实现前后端分离
- 对关键流程添加事件监听器
- 对高频流程启用缓存机制
2. 不推荐场景
- 需要快速开发的简单审批流程(建议使用表单模板)
- 对性能要求极高的场景(建议使用异步处理)
- 需要实时处理的场景(建议使用消息队列)
十一、总结
通过将Flowable工作流引擎与若依(RuoYi-Vue)框架整合,可以构建出功能完善的业务流程管理系统。本文深入探讨了流程定义、流程实例、任务处理等核心机制,并提供了完整的代码示例和案例分析。在实际开发中,需要注意安全风险、性能优化和异常处理等问题。建议在需要复杂审批流程的业务场景中使用该方案,在简单流程或需要快速开发的场景中选择其他方案。通过合理的设计和实现,可以充分发挥Flowable和若依框架的优势,构建高效、可维护的业务流程管理系统。
评论已关闭