SpringBoot + Flowable + 自定义节点:企业级可视化工作流引擎实现

一、传统工作流痛点与解决方案

1.1 传统硬编码流程的问题

  • 开发效率低:每个流程(请假、报销、采购等)需独立开发状态机逻辑,代码重复率高
  • 维护成本高:流程变更需重新开发部署,响应业务变化慢
  • 灵活性差:业务人员无法自主配置流程,依赖技术团队

1.2 解决方案:可视化工作流引擎

基于 SpringBoot + Flowable + 自定义节点,实现:

  • 可视化流程定义:通过BPMN 2.0标准定义流程,支持拖拽设计
  • 灵活扩展:自定义业务节点适配复杂场景(如动态审批人、条件分支)
  • 低代码配置:业务人员可通过界面调整流程,无需代码开发

二、技术选型与架构设计

2.1 核心技术栈

  • Flowable:基于BPMN 2.0的企业级工作流引擎,支持流程定义、实例管理、任务调度
  • SpringBoot:快速集成Flowable,提供自动配置、AOP、事件监听等能力
  • 自定义节点:通过JavaDelegate、ExpressionCondition等扩展业务逻辑

2.2 系统架构模块

模块 功能描述
流程定义管理 BPMN流程的部署、查询、版本控制
流程实例管理 流程启动、暂停、终止,支持流程变量传递
任务管理 待办任务查询、审批、分配,支持任务状态跟踪
自定义节点 扩展业务逻辑(如动态审批人、数据校验、通知发送)
流程监控 流程执行状态、耗时统计、异常报警
权限控制 任务访问权限校验,确保数据安全性

三、核心实现:从基础配置到流程运行

3.1 Flowable基础配置

配置流程引擎,连接数据库并启用必要组件:

@Configuration  
@EnableProcessApplication  
public class FlowableConfig {  
    @Bean  
    public ProcessEngineConfiguration processEngineConfiguration() {  
        ProcessEngineConfiguration config = ProcessEngineConfiguration  
            .createStandaloneProcessEngineConfiguration();  
        // 数据库配置(MySQL示例)  
        config.setJdbcUrl("jdbc:mysql://localhost:3306/flowable?useUnicode=true&characterEncoding=utf8");  
        config.setJdbcUsername("root");  
        config.setJdbcPassword("password");  
        config.setJdbcDriver("com.mysql.cj.jdbc.Driver");  
        // 自动创建表(生产环境建议手动执行脚本)  
        config.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);  
        // 启用异步执行器(处理定时任务、异步节点)  
        config.setAsyncExecutorActivate(true);  
        return config;  
    }  

    @Bean  
    public ProcessEngine processEngine() {  
        return processEngineConfiguration().buildProcessEngine();  
    }  
}  

3.2 流程定义与实例管理

流程部署与启动

通过RepositoryService部署BPMN流程定义,RuntimeService启动流程实例:

@Service  
public class ProcessDefinitionService {  
    @Autowired private RepositoryService repositoryService;  
    @Autowired private RuntimeService runtimeService;  

    // 部署BPMN流程(支持XML字符串或文件)  
    public String deployProcess(String processName, String bpmnXml) {  
        Deployment deployment = repositoryService.createDeployment()  
            .name(processName)  
            .addString(processName + ".bpmn", bpmnXml) // BPMN XML定义  
            .deploy();  
        return deployment.getId(); // 返回部署ID  
    }  

    // 启动流程实例(传递业务参数)  
    public String startProcess(String processDefinitionKey, Map<String, Object> variables) {  
        ProcessInstance instance = runtimeService.startProcessInstanceByKey(  
            processDefinitionKey, variables); // processDefinitionKey对应BPMN中的process id  
        return instance.getId(); // 返回流程实例ID  
    }  
}  

3.3 任务管理:待办与审批

通过TaskService处理任务分配、完成,支持查询用户待办:

@Service  
public class TaskService {  
    @Autowired private org.flowable.task.api.TaskService taskService;  

    // 获取用户待办任务  
    public List<TaskDto> getTodoTasks(String assignee) {  
        return taskService.createTaskQuery()  
            .taskAssignee(assignee) // 按处理人查询  
            .orderByTaskCreateTime().desc()  
            .list().stream()  
            .map(this::convertToDto) // 转换为DTO  
            .collect(Collectors.toList());  
    }  

    // 完成任务(传递审批结果等变量)  
    public void completeTask(String taskId, Map<String, Object> variables) {  
        taskService.complete(taskId, variables); // variables包含审批结果(如approved: true)  
    }  

    // 任务分配(支持动态调整处理人)  
    public void assignTask(String taskId, String assignee) {  
        taskService.setAssignee(taskId, assignee);  
    }  
}  

四、自定义节点:业务逻辑扩展核心

4.1 自定义业务逻辑节点(JavaDelegate)

实现JavaDelegate接口,在流程中嵌入自定义业务逻辑(如通知发送、数据校验):

@Component  
public class NotificationNode implements JavaDelegate {  
    @Autowired private EmailService emailService;  

    @Override  
    public void execute(DelegateExecution execution) {  
        // 从流程变量获取参数  
        String employeeId = (String) execution.getVariable("employeeId");  
        String processInstanceId = execution.getProcessInstanceId();  

        // 执行业务逻辑(发送审批通知)  
        emailService.send(  
            employeeId,  
            "流程通知",  
            "您的流程" + processInstanceId + "已到达审批节点"  
        );  

        // 记录执行日志  
        execution.setVariable("notificationTime", new Date());  
    }  
}  

BPMN中引用节点:在serviceTask中配置flowable:class指向该类:

<serviceTask id="notificationTask" name="发送通知"  
    flowable:class="com.example.node.NotificationNode"/>  

4.2 动态任务分配节点

根据业务规则动态确定审批人(如“直属领导→部门领导→总经理”):

@Component  
public class DynamicApproverNode implements JavaDelegate {  
    @Autowired private UserService userService;  

    @Override  
    public void execute(DelegateExecution execution) {  
        String employeeId = (String) execution.getVariable("employeeId");  
        Integer leaveDays = (Integer) execution.getVariable("leaveDays");  

        // 根据请假天数动态确定审批人  
        String approverId;  
        if (leaveDays > 7) {  
            approverId = userService.getManagerByLevel(employeeId, "general"); // 总经理  
        } else if (leaveDays > 3) {  
            approverId = userService.getManagerByLevel(employeeId, "department"); // 部门领导  
        } else {  
            approverId = userService.getManagerByLevel(employeeId, "direct"); // 直属领导  
        }  

        // 设置下一个任务的处理人(通过流程变量传递给 userTask)  
        execution.setVariable("approverId", approverId);  
    }  
}  

BPMN中使用动态分配:在userTask中通过表达式引用变量:

<userTask id="approveTask" name="审批" flowable:assignee="${approverId}"/>  

4.3 条件分支节点(ExpressionCondition)

根据流程变量动态决定流程走向(如金额阈值判断):

@Component  
public class ExpenseConditionNode implements ExpressionCondition {  
    @Override  
    public boolean evaluate(DelegateExecution execution) {  
        // 报销金额 > 5000 需CEO审批  
        Double amount = (Double) execution.getVariable("expenseAmount");  
        return amount > 5000;  
    }  
}  

BPMN中配置分支条件

<exclusiveGateway id="amountGateway" name="金额判断"/>  
<sequenceFlow id="toCeo" sourceRef="amountGateway" targetRef="ceoApproval">  
    <conditionExpression xsi:type="tFormalExpression">  
        ${expenseAmount > 5000}  
    </conditionExpression>  
</sequenceFlow>  

五、典型场景示例:请假与报销流程

5.1 请假流程实现

流程定义(BPMN核心节点)
<process id="leaveProcess" name="请假流程" isExecutable="true">  
    <startEvent id="start"/>  
    <!-- 填写请假单 -->  
    <userTask id="fillLeave" name="填写请假单" flowable:assignee="${employeeId}"/>  
    <!-- 动态确定审批人 -->  
    <serviceTask id="determineApprover" flowable:class="com.example.node.DynamicApproverNode"/>  
    <!-- 审批任务 -->  
    <userTask id="approveTask" name="审批" flowable:assignee="${approverId}"/>  
    <!-- 结束 -->  
    <endEvent id="end"/>  

    <sequenceFlow sourceRef="start" targetRef="fillLeave"/>  
    <sequenceFlow sourceRef="fillLeave" targetRef="determineApprover"/>  
    <sequenceFlow sourceRef="determineApprover" targetRef="approveTask"/>  
    <sequenceFlow sourceRef="approveTask" targetRef="end"/>  
</process>  
流程服务层实现
@Service  
public class LeaveProcessService {  
    @Autowired private ProcessDefinitionService processService;  
    @Autowired private TaskService taskService;  

    // 提交请假申请  
    public String submitLeave(LeaveRequest request) {  
        Map<String, Object> variables = new HashMap<>();  
        variables.put("employeeId", request.getEmployeeId());  
        variables.put("leaveDays", request.getLeaveDays());  
        // 启动流程实例  
        return processService.startProcess("leaveProcess", variables);  
    }  

    // 审批请假  
    public void approveLeave(String taskId, boolean approved) {  
        Map<String, Object> variables = new HashMap<>();  
        variables.put("approved", approved);  
        taskService.completeTask(taskId, variables);  
    }  
}  

5.2 报销流程:金额分支与财务审核

通过排他网关实现金额分级审批:

  • ≤1000元:部门领导审批
  • 1000~5000元:财务审批
  • 5000元:CEO审批

BPMN核心片段

<exclusiveGateway id="amountCheck"/>  
<!-- 部门领导审批(≤1000) -->  
<sequenceFlow sourceRef="amountCheck" targetRef="deptApproval">  
    <conditionExpression>${expenseAmount <= 1000}</conditionExpression>  
</sequenceFlow>  
<!-- 财务审批(1000~5000) -->  
<sequenceFlow sourceRef="amountCheck" targetRef="financeApproval">  
    <conditionExpression>${expenseAmount > 1000 && expenseAmount <= 5000}</conditionExpression>  
</sequenceFlow>  
<!-- CEO审批(>5000) -->  
<sequenceFlow sourceRef="amountCheck" targetRef="ceoApproval">  
    <conditionExpression>${expenseAmount > 5000}</conditionExpression>  
</sequenceFlow>  

六、高级特性:监听器与流程监控

6.1 流程监听器(ExecutionListener)

监控流程生命周期事件(启动、结束、节点流转):

@Component  
public class ProcessListener implements ExecutionListener {  
    @Override  
    public void notify(DelegateExecution execution) {  
        String eventName = execution.getEventName();  
        if ("start".equals(eventName)) {  
            // 流程启动时记录日志  
            log.info("流程启动: {}", execution.getProcessInstanceId());  
        } else if ("end".equals(eventName)) {  
            // 流程结束时更新业务状态  
            String businessKey = execution.getVariable("businessKey");  
            businessService.updateStatus(businessKey, "completed");  
        }  
    }  
}  

6.2 任务监听器(TaskListener)

处理任务创建、分配、完成事件(如发送待办通知):

@Component  
public class TaskCreateListener implements org.flowable.task.api.TaskListener {  
    @Autowired private NotificationService notificationService;  

    @Override  
    public void notify(DelegateTask task) {  
        if ("create".equals(task.getEventName())) {  
            // 任务创建时发送通知给处理人  
            notificationService.sendTodo(task.getAssignee(), task.getName());  
        }  
    }  
}  

6.3 流程监控与指标

通过HistoryService查询流程历史,结合Prometheus监控关键指标:

@Service  
public class ProcessMonitorService {  
    @Autowired private HistoryService historyService;  

    // 查询流程执行时长  
    public long getProcessDuration(String processInstanceId) {  
        HistoricProcessInstance instance = historyService  
            .createHistoricProcessInstanceQuery()  
            .processInstanceId(processInstanceId)  
            .singleResult();  
        return instance.getDurationInMillis();  
    }  

    // 记录流程启动指标(配合Prometheus)  
    public void recordProcessStart(String processKey) {  
        MeterRegistry counter = ...; // 注入MeterRegistry  
        counter.counter("process.start", "processKey", processKey).increment();  
    }  
}  

七、生产级优化与最佳实践

7.1 性能优化

  • 流程实例缓存:通过Redis缓存高频访问的流程实例(如待办任务)
  • 批量任务处理:使用CompletableFuture异步批量完成任务,提升吞吐量
  • 数据库优化:合理配置连接池,索引流程实例ID、任务处理人等字段

7.2 安全措施

  • 权限控制:校验用户是否为任务合法处理人(TaskPermissionService
  • 数据脱敏:流程变量中敏感信息(如银行卡号)脱敏存储
  • 防重放攻击:通过nonce机制防止任务重复提交

7.3 流程设计规范

  • 单一职责:一个流程专注一个业务场景(如请假流程、报销流程分离)
  • 异常处理:通过BPMNError定义业务异常,支持流程回退或终止
  • 版本控制:流程定义支持版本管理,避免新旧流程冲突

八、总结

通过 SpringBoot + Flowable + 自定义节点,可构建灵活、可扩展的企业级工作流引擎,核心优势:

  • 标准化:基于BPMN 2.0,支持可视化设计与版本管理
  • 低代码:业务人员通过界面配置流程,减少开发依赖
  • 高扩展:自定义节点适配复杂业务逻辑,如动态审批、条件分支
  • 易维护:流程与业务逻辑解耦,变更无需代码重构

适用于企业OA、审批系统、供应链管理等场景,助力业务流程数字化与自动化。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐