一、你的业务流程是不是也遇到了这些问题?
公司的审批流程越来越复杂,从请假、报销到采购,各种流程满天飞。更糟糕的是,这些流程都是靠Excel表格和邮件来管理的,经常出现审批延迟、流程混乱、数据丢失的问题。
"每次有新员工入职,都要花半天时间给他讲各种审批流程,"朋友无奈地说,"更麻烦的是,流程一变,所有相关的人都要重新学习。"
这样的场景,作为后端开发的你,有没有想过用工作流引擎来解决这个问题?
二、传统流程管理的困境
在传统的开发模式中,我们通常是这样处理业务流程的:
- 硬编码:将流程逻辑直接写在代码中
- 状态字段:使用数据库字段来记录流程状态
- if-else:使用大量的条件判断来处理流程分支
- 邮件/Excel:使用邮件或Excel来传递审批信息
这种方式在流程简单的情况下工作得很好。但随着业务的发展,问题就暴露出来了:
1. 流程变更困难
每次流程变更,都需要修改代码、重新测试、重新部署,非常耗时耗力。
2. 流程缺乏可视化
流程逻辑散落在代码中,难以理解和维护。新加入的开发者需要花很多时间才能理解整个流程。
3. 审批效率低下
审批人需要定期检查邮件或系统,容易错过审批,导致流程延迟。
4. 数据难以追踪
流程的执行情况、审批历史等信息难以追踪和分析。
三、工作流引擎:业务流程的救星
为了解决这些问题,工作流引擎应运而生。工作流引擎可以帮助我们:
- 可视化建模:通过图形化界面设计流程
- 灵活配置:通过配置而不是代码来定义流程
- 自动执行:自动推动流程的执行
- 实时监控:实时监控流程的执行状态
在众多的工作流引擎中,Flowable 是一个非常优秀的选择。
四、Flowable简介
Flowable 是一个开源的、轻量级的工作流引擎,基于Activiti 5.x 分支开发而来。它提供了:
- BPMN 2.0 标准:完全支持BPMN 2.0标准
- 丰富的API:提供了丰富的Java API
- 高性能:经过优化的执行引擎
- 易集成:易于集成到Spring Boot应用中
- 可视化工具:提供了Flowable Modeler、Flowable Admin等可视化工具
五、Flowable核心概念
在使用Flowable之前,我们需要了解几个核心概念:
1. BPMN
BPMN(Business Process Model and Notation)是业务流程模型和标记法的标准。它使用图形化的方式来描述业务流程。
2. 流程定义(Process Definition)
流程定义是业务流程的蓝图,使用BPMN 2.0 XML格式存储。它定义了流程的结构、任务、网关等。
3. 流程实例(Process Instance)
流程实例是流程定义的一次执行。当我们启动一个流程时,就创建了一个流程实例。
4. 任务(Task)
任务是流程中需要人或系统执行的步骤。常见的任务类型有:
- 用户任务(User Task):需要人执行的任务
- 服务任务(Service Task):需要系统执行的任务
- 脚本任务(Script Task):执行脚本的任务
- 发送任务(Send Task):发送消息的任务
5. 网关(Gateway)
网关用于控制流程的分支和合并。常见的网关有:
- 排他网关(Exclusive Gateway):二选一或多选一
- 并行网关(Parallel Gateway):并行执行多个分支
- 包容网关(Inclusive Gateway):可以同时执行多个分支
六、Spring Boot集成Flowable
1. 添加依赖
在Spring Boot项目的pom.xml中添加Flowable依赖:
<dependencies>
<!-- Flowable Spring Boot Starter -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.8.0</version>
</dependency>
<!-- Flowable UI (可选,用于开发环境) -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-ui-modeler</artifactId>
<version>6.8.0</version>
</dependency>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
</dependencies>
2. 配置数据库
在application.yml中配置数据库连接:
spring:
datasource:
url: jdbc:mysql://localhost:3306/flowable?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# Flowable配置
flowable:
database-schema-update: true
async-executor-activate: true
3. 启动应用
启动Spring Boot应用,Flowable会自动创建所需的数据库表。
七、Flowable实战:请假流程
1. 设计流程
首先,我们需要设计一个请假流程。使用Flowable Modeler(或其他BPMN建模工具)创建一个流程定义:
- 开始事件:流程的起点
- 用户任务:员工填写请假单
- 用户任务:部门经理审批
- 排他网关:根据审批结果决定下一步
- 用户任务:人力资源审批(如果请假天数超过3天)
- 结束事件:流程的终点
2. 部署流程
将设计好的流程定义文件(.bpmn20.xml)部署到Flowable中:
@Service
public class ProcessDeployService {
@Autowired
private RepositoryService repositoryService;
/**
* 部署流程
*/
public void deployProcess() {
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("processes/leave-process.bpmn20.xml")
.name("请假流程")
.deploy();
System.out.println("流程部署成功,部署ID:" + deployment.getId());
}
}
3. 启动流程
当员工提交请假申请时,启动一个流程实例:
@Service
public class LeaveService {
@Autowired
private RuntimeService runtimeService;
/**
* 提交请假申请
*/
public String submitLeave(String employeeId, int days, String reason) {
// 设置流程变量
Map<String, Object> variables = new HashMap<>();
variables.put("employeeId", employeeId);
variables.put("days", days);
variables.put("reason", reason);
variables.put("managerId", getManagerId(employeeId)); // 获取部门经理ID
// 启动流程实例
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leaveProcess", variables);
return "请假申请提交成功,流程ID:" + processInstance.getId();
}
/**
* 获取部门经理ID
*/
private String getManagerId(String employeeId) {
// 这里应该从数据库或缓存中获取
return "manager1";
}
}
4. 查询任务
审批人登录系统后,可以查询待处理的任务:
@Service
public class TaskService {
@Autowired
private org.flowable.task.api.TaskService taskService;
/**
* 查询待处理任务
*/
public List<org.flowable.task.api.Task> getTasks(String assignee) {
return taskService.createTaskQuery()
.taskAssignee(assignee)
.active()
.list();
}
}
5. 完成任务
审批人处理完任务后,完成任务:
@Service
public class TaskService {
@Autowired
private org.flowable.task.api.TaskService taskService;
/**
* 完成任务
*/
public void completeTask(String taskId, boolean approved) {
Map<String, Object> variables = new HashMap<>();
variables.put("approved", approved);
taskService.complete(taskId, variables);
}
}
6. 监听流程事件
我们可以通过监听器来处理流程中的各种事件:
@Component
public class LeaveProcessListener {
@Autowired
private EmailService emailService;
/**
* 监听流程结束事件
*/
@EventListener
public void onProcessEnd(ProcessCompletedEvent event) {
ProcessInstance processInstance = event.getProcessInstance();
String processDefinitionId = processInstance.getProcessDefinitionId();
// 只处理请假流程
if ("leaveProcess".equals(processDefinitionId)) {
// 获取流程变量
String employeeId = (String) processInstance.getProcessVariables().get("employeeId");
boolean approved = (boolean) processInstance.getProcessVariables().get("approved");
// 发送邮件通知
if (approved) {
emailService.sendEmail(employeeId, "请假申请已通过", "您的请假申请已通过审批");
} else {
emailService.sendEmail(employeeId, "请假申请已拒绝", "您的请假申请未通过审批");
}
}
}
}
八、Flowable高级特性
1. 流程变量
流程变量用于在流程执行过程中传递数据:
// 设置流程变量
variables.put("employeeId", employeeId);
variables.put("days", days);
// 获取流程变量
String employeeId = (String) runtimeService.getVariable(executionId, "employeeId");
2. 表达式
Flowable支持使用UEL表达式来动态设置任务的处理人、流程条件等:
<!-- 动态设置任务处理人 -->
<userTask id="managerApproval" name="部门经理审批">
<humanPerformer>
<resourceAssignmentExpression>
<formalExpression>${managerId}</formalExpression>
</resourceAssignmentExpression>
</humanPerformer>
</userTask>
<!-- 动态设置网关条件 -->
<sequenceFlow id="flow4" sourceRef="exclusiveGateway" targetRef="hrApproval">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${days > 3 && approved == true}]]>
</conditionExpression>
</sequenceFlow>
3. 监听器
监听器用于在流程执行的特定时刻执行自定义逻辑:
- 执行监听器:监听流程执行事件
- 任务监听器:监听任务事件
- 全局监听器:监听所有流程事件
4. 子流程
对于复杂的流程,可以使用子流程来分解:
<subProcess id="subProcess" name="子流程">
<startEvent id="subStartEvent" />
<!-- 子流程内容 -->
<endEvent id="subEndEvent" />
</subProcess>
5. 多实例
对于需要多个人处理的任务,可以使用多实例:
<userTask id="meetingTask" name="会议讨论" camunda:asyncBefore="true">
<multiInstanceLoopCharacteristics isSequential="false">
<loopCardinality>3</loopCardinality>
<completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.6}</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
九、Flowable监控与管理
1. Flowable Admin
Flowable Admin是一个Web应用,用于管理和监控Flowable流程:
- 流程实例管理:查看、挂起、激活流程实例
- 任务管理:查看、分配、完成任务
- 历史数据:查看流程执行历史
- 用户管理:管理用户和组
2. 自定义监控
我们也可以通过Flowable的API来实现自定义监控:
@Service
public class ProcessMonitorService {
@Autowired
private HistoryService historyService;
/**
* 获取流程执行统计
*/
public Map<String, Object> getProcessStats() {
Map<String, Object> stats = new HashMap<>();
// 获取已完成的流程数量
long completedCount = historyService.createHistoricProcessInstanceQuery()
.finished()
.count();
// 获取正在执行的流程数量
long runningCount = historyService.createHistoricProcessInstanceQuery()
.unfinished()
.count();
// 获取平均执行时间
// ...
stats.put("completedCount", completedCount);
stats.put("runningCount", runningCount);
return stats;
}
}
十、实战经验总结
- 流程设计要合理:流程要简洁明了,避免过于复杂的分支
- 变量命名要规范:使用有意义的变量名,便于理解和维护
- 权限控制要严格:确保只有授权用户才能执行相应的任务
- 异常处理要完善:对流程执行过程中的异常进行合理处理
- 监控要到位:实时监控流程的执行状态,及时发现和解决问题
- 性能要优化:对于高并发场景,要合理配置Flowable的线程池和缓存
十一、Flowable的适用场景
Flowable适用于以下场景:
- 审批流程:请假、报销、采购等审批流程
- 业务流程:订单处理、客户服务、供应链管理等
- 工作流:任务分配、进度跟踪、状态管理等
- 流程自动化:自动触发、自动执行、自动通知等
十二、写在最后
Flowable是一个功能强大、易于集成的工作流引擎,它可以帮助我们从繁琐的流程管理中解放出来,让业务流程更加规范、高效、透明。
当然,Flowable并不是银弹,它也有自己的适用场景和局限性。在使用Flowable之前,我们需要根据业务需求和系统架构来决定是否使用它。
希望这篇文章能给你带来一些启发,帮助你在实际项目中更好地应用Flowable。
如果你在使用Flowable的过程中有其他经验或困惑,欢迎在评论区留言交流!
服务端技术精选,专注分享后端开发实战经验,让技术落地更简单。
如果你觉得这篇文章有用,欢迎点赞、在看、分享三连!