RuoYi-Vue工作流引擎:Flowable流程设计与实现

RuoYi-Vue工作流引擎:Flowable流程设计与实现

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

你是否还在为企业流程管理系统的开发效率低下而烦恼?审批流程僵化、个性化需求难以满足、开发周期长等问题是否一直困扰着你?本文将带你深入了解如何基于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系统中。其技术架构如下:

mermaid

环境搭建与配置

依赖引入

在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绘制的请假流程示例:

  1. 打开流程设计器页面,创建新的流程模型。
  2. 拖拽左侧工具栏中的"开始事件"、"用户任务"、"结束事件"等节点到画布中。
  3. 连接各节点,形成完整的流程路径。
  4. 设置每个用户任务的办理人、优先级等属性。

绘制完成的请假流程如下:

mermaid

流程定义文件

流程设计完成后,会生成.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中提出,也可以参与项目的开发和贡献。

相关资源

点赞+收藏+关注,获取更多RuoYi-Vue开发实战教程!下期预告:《RuoYi-Vue集成Camunda工作流引擎》。

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

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

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

抵扣说明:

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

余额充值