RuoYi-Vue工作流引擎:Flowable流程设计与实现
你是否还在为企业流程管理系统的开发效率低下而烦恼?审批流程僵化、个性化需求难以满足、开发周期长等问题是否一直困扰着你?本文将带你深入了解如何基于RuoYi-Vue快速集成Flowable工作流引擎,通过可视化设计与编码实现,轻松构建灵活高效的企业级流程管理系统。读完本文,你将掌握从环境搭建到流程部署的完整流程,以及常见业务场景的解决方案。
RuoYi-Vue工作流引擎概述
RuoYi-Vue是基于SpringBoot、Spring Security、JWT、Vue & Element的前后端分离权限管理系统,其工作流模块集成了Flowable引擎,提供了流程设计、部署、运行、监控的全生命周期管理。工作流引擎作为系统的核心组件,能够将业务流程抽象为可配置的模型,实现流程的自动化流转和可视化管理。
核心功能模块
RuoYi-Vue工作流引擎主要包含以下功能模块:
- 流程设计器:基于Flowable Modeler的可视化流程设计工具,支持拖拽式绘制流程图。
- 流程管理:提供流程定义的部署、激活、挂起、删除等操作。
- 任务管理:处理流程运行中的个人任务、组任务、候选任务等。
- 流程监控:实时监控流程实例的运行状态,包括流程进度、任务执行情况等。
技术架构
工作流引擎基于Flowable 6.x版本构建,采用Spring Boot自动配置方式集成到RuoYi-Vue系统中。其技术架构如下:
环境搭建与配置
依赖引入
在RuoYi-Vue项目中,需要在pom.xml中引入Flowable相关依赖。打开项目根目录下的pom.xml文件,添加以下依赖配置:
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-process</artifactId>
<version>6.7.2</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-ui-modeler-rest</artifactId>
<version>6.7.2</version>
</dependency>
数据库配置
Flowable需要使用数据库存储流程定义、实例、任务等数据。在RuoYi-Vue的数据库配置文件ruoyi-admin/src/main/resources/application-druid.yml中,添加Flowable相关配置:
spring:
datasource:
druid:
# 已有的数据库配置...
flowable:
database-schema-update: true
async-executor-activate: true
history-level: full
配置类实现
创建Flowable配置类com.ruoyi.framework.config.FlowableConfig.java,配置流程引擎的相关参数和监听器:
@Configuration
public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {
@Override
public void configure(SpringProcessEngineConfiguration configuration) {
// 设置流程字体
configuration.setActivityFontName("宋体");
configuration.setLabelFontName("宋体");
configuration.setAnnotationFontName("宋体");
// 添加全局流程监听器
configuration.setEventListeners(Arrays.asList(new GlobalProcessListener()));
}
}
流程设计与定义
流程设计器集成
RuoYi-Vue集成了Flowable Modeler作为流程设计器,用户可以通过浏览器访问流程设计页面。在前端路由配置文件ruoyi-ui/src/router/index.js中,添加流程设计器的路由:
{
path: '/flow/model',
component: Layout,
hidden: true,
children: [
{
path: 'index',
component: () => import('@/views/flow/model/index'),
name: 'FlowModel',
meta: { title: '流程设计', icon: 'form' }
}
]
}
绘制请假流程示例
以下是使用Flowable Modeler绘制的请假流程示例:
- 打开流程设计器页面,创建新的流程模型。
- 拖拽左侧工具栏中的"开始事件"、"用户任务"、"结束事件"等节点到画布中。
- 连接各节点,形成完整的流程路径。
- 设置每个用户任务的办理人、优先级等属性。
绘制完成的请假流程如下:
流程定义文件
流程设计完成后,会生成.bpmn20.xml格式的流程定义文件。以下是请假流程的定义文件示例(leave-process.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/examples">
<process id="leave-process" name="请假流程" isExecutable="true">
<startEvent id="startEvent1"/>
<userTask id="fillLeaveForm" name="填写请假单" assignee="${applyUserId}"/>
<userTask id="deptManagerApproval" name="部门经理审批" assignee="${deptManagerId}"/>
<userTask id="generalManagerApproval" name="总经理审批" assignee="${generalManagerId}"/>
<userTask id="hrFiling" name="人事归档" assignee="${hrUserId}"/>
<endEvent id="endEvent1"/>
<sequenceFlow id="flow1" sourceRef="startEvent1" targetRef="fillLeaveForm"/>
<sequenceFlow id="flow2" sourceRef="fillLeaveForm" targetRef="deptManagerApproval"/>
<sequenceFlow id="flow3" sourceRef="deptManagerApproval" targetRef="decision1"/>
<exclusiveGateway id="decision1" name="审批结果"/>
<sequenceFlow id="flow4" sourceRef="decision1" targetRef="generalManagerApproval">
<conditionExpression xsi:type="tFormalExpression">${approvalResult == 'approve'}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow5" sourceRef="decision1" targetRef="endEvent1">
<conditionExpression xsi:type="tFormalExpression">${approvalResult == 'reject'}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow6" sourceRef="generalManagerApproval" targetRef="decision2"/>
<exclusiveGateway id="decision2" name="审批结果"/>
<sequenceFlow id="flow7" sourceRef="decision2" targetRef="hrFiling">
<conditionExpression xsi:type="tFormalExpression">${approvalResult == 'approve'}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow8" sourceRef="decision2" targetRef="endEvent1">
<conditionExpression xsi:type="tFormalExpression">${approvalResult == 'reject'}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow9" sourceRef="hrFiling" targetRef="endEvent1"/>
</process>
</definitions>
流程部署与运行
流程部署服务
创建流程部署服务类com.ruoyi.flow.service.FlowDeployService.java,实现流程定义的部署功能:
@Service
public class FlowDeployService {
@Autowired
private RepositoryService repositoryService;
/**
* 部署流程定义
* @param bpmnFile 流程定义文件
* @return 部署结果
*/
public String deploy(MultipartFile bpmnFile) {
try {
Deployment deployment = repositoryService.createDeployment()
.name(bpmnFile.getOriginalFilename())
.addInputStream(bpmnFile.getOriginalFilename(), bpmnFile.getInputStream())
.deploy();
return "流程部署成功,部署ID:" + deployment.getId();
} catch (Exception e) {
log.error("流程部署失败", e);
throw new BusinessException("流程部署失败:" + e.getMessage());
}
}
}
启动流程实例
创建流程实例服务类com.ruoyi.flow.service.FlowInstanceService.java,实现流程实例的启动功能:
@Service
public class FlowInstanceService {
@Autowired
private RuntimeService runtimeService;
/**
* 启动流程实例
* @param processDefinitionKey 流程定义Key
* @param variables 流程变量
* @return 流程实例ID
*/
public String startProcessInstance(String processDefinitionKey, Map<String, Object> variables) {
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, variables);
return processInstance.getId();
}
}
处理用户任务
创建任务服务类com.ruoyi.flow.service.FlowTaskService.java,实现用户任务的查询、办理等功能:
@Service
public class FlowTaskService {
@Autowired
private TaskService taskService;
/**
* 查询用户任务列表
* @param userId 用户ID
* @return 任务列表
*/
public List<Task> getUserTasks(String userId) {
return taskService.createTaskQuery()
.taskAssignee(userId)
.orderByTaskCreateTime().desc()
.list();
}
/**
* 完成用户任务
* @param taskId 任务ID
* @param variables 任务变量
*/
public void completeTask(String taskId, Map<String, Object> variables) {
taskService.complete(taskId, variables);
}
}
前端界面实现
流程设计器页面
RuoYi-Vue前端提供了流程设计器页面,位于ruoyi-ui/src/views/flow/model/index.vue。该页面集成了Flowable Modeler的前端组件,允许用户通过拖拽方式设计流程。
流程实例管理页面
创建流程实例管理页面ruoyi-ui/src/views/flow/instance/index.vue,用于展示和管理流程实例:
<template>
<div class="app-container">
<el-table v-loading="loading" :data="instanceList" border fit highlight-current-row>
<el-table-column type="index" width="50" label="序号"/>
<el-table-column prop="processInstanceId" label="实例ID" width="180"/>
<el-table-column prop="processDefinitionName" label="流程名称"/>
<el-table-column prop="startTime" label="开始时间" width="180"/>
<el-table-column prop="startUserId" label="发起用户"/>
<el-table-column prop="status" label="状态" width="100">
<template slot-scope="scope">
<el-tag v-if="scope.row.suspended" type="danger">已挂起</el-tag>
<el-tag v-else type="success">运行中</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button type="text" size="small" @click="viewInstance(scope.row)">查看</el-button>
<el-button type="text" size="small" @click="suspendInstance(scope.row)" v-if="!scope.row.suspended">挂起</el-button>
<el-button type="text" size="small" @click="activateInstance(scope.row)" v-if="scope.row.suspended">激活</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="pageNum" :limit.sync="pageSize" @pagination="getList"/>
</div>
</template>
<script>
import { getInstanceList, suspendInstance, activateInstance } from "@/api/flow/instance";
export default {
name: "FlowInstance",
data() {
return {
loading: false,
instanceList: [],
total: 0,
pageNum: 1,
pageSize: 10
};
},
created() {
this.getList();
},
methods: {
getList() {
this.loading = true;
getInstanceList({
pageNum: this.pageNum,
pageSize: this.pageSize
}).then(response => {
this.instanceList = response.rows;
this.total = response.total;
this.loading = false;
});
},
viewInstance(row) {
this.$router.push({ path: '/flow/instance/view/' + row.processInstanceId });
},
suspendInstance(row) {
this.$confirm('确定要挂起该流程实例吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
suspendInstance(row.processInstanceId).then(response => {
this.$message({
message: '流程实例已挂起',
type: 'success'
});
this.getList();
});
});
},
activateInstance(row) {
this.$confirm('确定要激活该流程实例吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
activateInstance(row.processInstanceId).then(response => {
this.$message({
message: '流程实例已激活',
type: 'success'
});
this.getList();
});
});
}
}
};
</script>
任务办理页面
创建任务办理页面ruoyi-ui/src/views/flow/task/index.vue,用于展示用户的待办任务并办理:
<template>
<div class="app-container">
<el-table v-loading="loading" :data="taskList" border fit highlight-current-row>
<el-table-column type="index" width="50" label="序号"/>
<el-table-column prop="taskId" label="任务ID" width="180"/>
<el-table-column prop="processInstanceId" label="实例ID" width="180"/>
<el-table-column prop="processDefinitionName" label="流程名称"/>
<el-table-column prop="taskName" 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="small" @click="handleTask(scope.row)">办理</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="pageNum" :limit.sync="pageSize" @pagination="getList"/>
</div>
</template>
<script>
import { getTaskList, completeTask } from "@/api/flow/task";
export default {
name: "FlowTask",
data() {
return {
loading: false,
taskList: [],
total: 0,
pageNum: 1,
pageSize: 10
};
},
created() {
this.getList();
},
methods: {
getList() {
this.loading = true;
getTaskList({
pageNum: this.pageNum,
pageSize: this.pageSize,
userId: this.$store.getters.userId
}).then(response => {
this.taskList = response.rows;
this.total = response.total;
this.loading = false;
});
},
handleTask(row) {
this.$router.push({ path: '/flow/task/handle/' + row.taskId });
}
}
};
</script>
流程监控与分析
流程历史数据查询
创建流程历史服务类com.ruoyi.flow.service.FlowHistoryService.java,用于查询流程历史数据:
@Service
public class FlowHistoryService {
@Autowired
private HistoryService historyService;
/**
* 查询流程实例历史
* @param processInstanceId 流程实例ID
* @return 流程实例历史
*/
public HistoricProcessInstance getHistoricProcessInstance(String processInstanceId) {
return historyService.createHistoricProcessInstanceQuery()
.processInstanceId(processInstanceId)
.singleResult();
}
/***
* 查询流程任务历史
* @param processInstanceId 流程实例ID
* @return 任务历史列表
*/
public List<HistoricTaskInstance> getHistoricTaskInstances(String processInstanceId) {
return historyService.createHistoricTaskInstanceQuery()
.processInstanceId(processInstanceId)
.orderByTaskCreateTime().asc()
.list();
}
}
流程监控仪表盘
RuoYi-Vue提供了流程监控仪表盘页面ruoyi-ui/src/views/flow/monitor/index.vue,用于展示流程的运行状态、任务完成情况等统计信息。
常见问题与解决方案
流程部署失败
问题描述:部署流程时提示"表不存在"错误。
解决方案:检查Flowable的数据库配置,确保spring.flowable.database-schema-update属性设置为true,Flowable会自动创建所需的数据库表。
任务办理人无法看到任务
问题描述:启动流程实例后,任务办理人无法看到待办任务。
解决方案:检查流程定义中用户任务的assignee属性是否正确设置,确保与系统中的用户ID匹配。可以通过以下代码查询任务的办理人:
List<Task> tasks = taskService.createTaskQuery()
.taskAssignee(userId)
.list();
流程变量传递错误
问题描述:流程变量传递不正确,导致条件判断失败。
解决方案:确保在启动流程实例或完成任务时,正确设置流程变量。例如:
Map<String, Object> variables = new HashMap<>();
variables.put("approvalResult", "approve");
taskService.complete(taskId, variables);
总结与展望
本文详细介绍了RuoYi-Vue工作流引擎的设计与实现,包括环境搭建、流程设计、实例管理、任务办理等方面。通过集成Flowable工作流引擎,RuoYi-Vue能够满足企业级应用的流程管理需求,提高业务流程的自动化程度和灵活性。
未来,RuoYi-Vue工作流引擎将进一步优化,支持更多高级功能,如动态表单、流程版本管理、流程仿真等,为用户提供更加完善的流程管理解决方案。
如果你对RuoYi-Vue工作流引擎有任何疑问或建议,欢迎在项目的Issue中提出,也可以参与项目的开发和贡献。
相关资源:
- 官方文档:doc/若依环境使用手册.docx
- 工作流模块源码:ruoyi-framework/src/main/java/com/ruoyi/framework/config/FlowableConfig.java
- 前端流程设计器:ruoyi-ui/src/views/flow/model/index.vue
- 数据库脚本:sql/ry_20250522.sql
点赞+收藏+关注,获取更多RuoYi-Vue开发实战教程!下期预告:《RuoYi-Vue集成Camunda工作流引擎》。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



