Flowable 工作流使用教程
1. Flowable 简介
Flowable 是一个轻量级的业务流程引擎,基于 BPMN 2.0 规范实现。它可以帮助开发者将业务流程可视化,并提供了强大的流程控制和管理功能。Flowable 适用于各种业务场景,如审批流程、工单处理、订单履行等。
1. Flowable 深入理论
1.1 工作流基础概念
工作流(Workflow)是对工作流程及其各个环节的系统描述,它定义了:
- 业务过程(Process): 完整的工作流程定义
- 活动(Activity): 工作流程中的具体任务节点
- 转移(Transition): 活动之间的连接
- 参与者(Participant): 执行活动的人或系统
- 工作项(WorkItem): 具体的工作任务实例
1.2 BPMN 2.0 详解
BPMN(业务流程模型和标记法)是一个国际化的建模语言标准,包含以下核心要素:
1.2.1 流对象(Flow Objects)
-
事件(Events)
- 开始事件:触发流程的起点
- 中间事件:流程执行过程中发生的事件
- 结束事件:标志流程的结束
-
活动(Activities)
- 任务(Tasks):最基本的工作单元
- 子流程(Sub-Processes):包含其他活动的复合活动
-
网关(Gateways)
- 排他网关(Exclusive):基于条件的单路选择
- 并行网关(Parallel):并发执行多个分支
- 包容网关(Inclusive):可同时选择多个分支
- 复杂网关(Complex):复杂的分支合并逻辑
1.2.2 连接对象(Connecting Objects)
- 序列流(Sequence Flow): 活动执行的顺序
- 消息流(Message Flow): 不同参与者之间的通信
- 关联(Association): 连接附加信息和制品
1.2.3 泳道(Swimlanes)
- 池(Pool): 表示主要参与者
- 道(Lane): 对池的细分,表示具体角色
1.3 Flowable 架构设计
1.3.1 核心组件详解
-
ProcessEngine
- 配置管理
- 数据源管理
- 命令拦截器
- 事件处理
-
RepositoryService
- 流程定义管理
- 部署包管理
- 流程资源管理
-
RuntimeService
- 流程实例管理
- 执行流管理
- 流程变量管理
- 信号和消息处理
-
TaskService
- 任务创建和删除
- 任务查询和认领
- 任务委派和转交
- 任务附件和评论
-
HistoryService
- 历史活动记录
- 历史任务记录
- 历史变量记录
- 历史表单记录
1.3.2 数据库架构
Flowable 的核心表结构:
-
通用表
- ACT_GE_PROPERTY: 系统属性
- ACT_GE_BYTEARRAY: 二进制数据存储
-
流程定义表
- ACT_RE_DEPLOYMENT: 部署信息
- ACT_RE_PROCDEF: 流程定义
- ACT_RE_MODEL: 模型信息
-
运行时表
- ACT_RU_EXECUTION: 执行实例
- ACT_RU_TASK: 运行时任务
- ACT_RU_VARIABLE: 运行时变量
-
历史表
- ACT_HI_PROCINST: 历史流程实例
- ACT_HI_TASKINST: 历史任务实例
- ACT_HI_ACTINST: 历史活动实例
1.4 流程生命周期管理
1.4.1 流程定义生命周期
-
设计阶段
- 使用建模工具创建 BPMN 文件
- 定义流程变量和表单
- 配置任务处理人和候选组
- 设置业务规则和条件表达式
-
部署阶段
- 验证流程定义的正确性
- 解析 BPMN 文件
- 生成流程资源文件
- 存储到数据库中
-
版本控制
- 多版本并存机制
- 版本升级策略
- 历史版本处理
1.4.2 流程实例生命周期
-
启动阶段
- 创建流程实例
- 初始化流程变量
- 触发开始事件
- 创建首个任务
-
执行阶段
- 任务的创建和完成
- 流程变量的更新
- 分支条件的判断
- 事件的处理
-
结束阶段
- 完成所有活动
- 触发结束事件
- 清理运行时数据
- 生成历史记录
1.5 高级流程控制机制
1.5.1 事件机制
-
定时事件
- 固定时间触发
- 周期性触发
- 持续时间触发
-
消息事件
- 消息发送和接收
- 消息中间事件
- 消息边界事件
-
信号事件
- 全局信号广播
- 信号捕获
- 信号触发器
1.5.2 错误处理机制
-
错误边界事件
- 错误定义
- 错误捕获
- 错误处理流程
-
补偿机制
- 补偿事件定义
- 补偿处理器
- 事务补偿
-
取消机制
- 取消边界事件
- 取消结束事件
- 事务取消
1.5.3 多实例特性
-
并行多实例
- 实例创建规则
- 完成条件设置
- 变量处理机制
-
串行多实例
- 顺序执行控制
- 实例间数据传递
- 中断处理
1.6 表达式语言支持
1.6.1 UEL 表达式
-
值表达式
${user.name} ${process.variables.amount > 1000}
-
方法表达式
${userService.findUser(userId)} ${dateUtil.format(date, 'yyyy-MM-dd')}
-
条件表达式
${approved == true} ${amount >= 1000 && level == 'high'}
1.6.2 Spring 表达式集成
-
Bean 引用
${@userService.getCurrentUser()} ${@configurationBean.getThreshold()}
-
Spring EL
#{systemProperties['java.version']} #{T(java.lang.Math).random()}
1.7 任务分配策略
1.7.1 静态分配
-
固定分配人
<userTask id="approveTask" name="审批任务" flowable:assignee="manager" />
-
候选人组
<userTask id="reviewTask" name="审核任务" flowable:candidateGroups="leaders" />
1.7.2 动态分配
-
表达式分配
<userTask id="handleTask" name="处理任务" flowable:assignee="${taskHandler}" />
-
监听器分配
public class TaskAssignmentListener implements TaskListener { @Override public void notify(DelegateTask delegateTask) { // 动态计算处理人 String assignee = calculateAssignee(delegateTask); delegateTask.setAssignee(assignee); } }
2. 环境搭建
2.1 Maven 依赖
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.7.2</version>
</dependency>
2.2 数据库配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/flowable?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
flowable:
database-schema-update: true
3. 核心概念
3.1 主要组件
- ProcessEngine: 流程引擎,负责管理和执行流程
- RepositoryService: 流程定义的管理和部署
- RuntimeService: 流程实例的管理和控制
- TaskService: 用户任务管理
- HistoryService: 历史数据管理
- IdentityService: 用户和用户组管理
- FormService: 表单数据管理
3.2 BPMN 基本元素
- 开始事件(StartEvent): 流程的起点
- 结束事件(EndEvent): 流程的终点
- 用户任务(UserTask): 需要人工处理的任务
- 服务任务(ServiceTask): 自动执行的任务
- 排他网关(ExclusiveGateway): 根据条件选择一条路径
- 并行网关(ParallelGateway): 并行执行多条路径
4. 实战示例
4.1 创建流程定义文件
在 resources/processes
目录下创建 leave-process.bpmn20.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:flowable="http://flowable.org/bpmn"
targetNamespace="Examples">
<process id="leaveProcess" name="请假流程">
<startEvent id="start" name="开始"/>
<userTask id="submitForm" name="提交请假单"
flowable:assignee="${initiator}"/>
<userTask id="leaderApprove" name="领导审批"
flowable:candidateGroups="leaders"/>
<exclusiveGateway id="approveDecision" name="审批决定"/>
<endEvent id="approveEnd" name="审批通过"/>
<endEvent id="rejectEnd" name="审批拒绝"/>
<sequenceFlow sourceRef="start" targetRef="submitForm"/>
<sequenceFlow sourceRef="submitForm" targetRef="leaderApprove"/>
<sequenceFlow sourceRef="leaderApprove" targetRef="approveDecision"/>
<sequenceFlow sourceRef="approveDecision" targetRef="approveEnd">
<conditionExpression>${approved == true}</conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="approveDecision" targetRef="rejectEnd">
<conditionExpression>${approved == false}</conditionExpression>
</sequenceFlow>
</process>
</definitions>
4.2 Java 代码实现
@Service
public class LeaveProcessService {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@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());
}
// 启动流程
public ProcessInstance startProcess(String userId, String businessKey) {
Map<String, Object> variables = new HashMap<>();
variables.put("initiator", userId);
return runtimeService.startProcessInstanceByKey("leaveProcess", businessKey, variables);
}
// 获取用户任务
public List<Task> getUserTasks(String userId) {
return taskService.createTaskQuery()
.taskAssignee(userId)
.orderByTaskCreateTime().desc()
.list();
}
// 获取组任务
public List<Task> getGroupTasks(String groupId) {
return taskService.createTaskQuery()
.taskCandidateGroup(groupId)
.orderByTaskCreateTime().desc()
.list();
}
// 完成任务
public void completeTask(String taskId, Map<String, Object> variables) {
taskService.complete(taskId, variables);
}
}
4.3 控制器实现
@RestController
@RequestMapping("/workflow")
public class WorkflowController {
@Autowired
private LeaveProcessService leaveProcessService;
@PostMapping("/deploy")
public String deployProcess() {
leaveProcessService.deployProcess();
return "流程部署成功";
}
@PostMapping("/start")
public String startProcess(@RequestParam String userId, @RequestParam String businessKey) {
ProcessInstance instance = leaveProcessService.startProcess(userId, businessKey);
return "流程启动成功,实例ID: " + instance.getId();
}
@GetMapping("/tasks/user/{userId}")
public List<Map<String, Object>> getUserTasks(@PathVariable String userId) {
List<Task> tasks = leaveProcessService.getUserTasks(userId);
return tasks.stream().map(task -> {
Map<String, Object> map = new HashMap<>();
map.put("id", task.getId());
map.put("name", task.getName());
map.put("createTime", task.getCreateTime());
map.put("assignee", task.getAssignee());
return map;
}).collect(Collectors.toList());
}
@PostMapping("/tasks/complete/{taskId}")
public String completeTask(@PathVariable String taskId, @RequestParam Boolean approved) {
Map<String, Object> variables = new HashMap<>();
variables.put("approved", approved);
leaveProcessService.completeTask(taskId, variables);
return "任务完成";
}
}
5. 常用 API 示例
5.1 流程定义查询
@Autowired
private RepositoryService repositoryService;
public List<ProcessDefinition> getProcessDefinitions() {
return repositoryService.createProcessDefinitionQuery()
.orderByProcessDefinitionVersion().desc()
.list();
}
5.2 流程实例查询
@Autowired
private RuntimeService runtimeService;
public List<ProcessInstance> getActiveProcessInstances() {
return runtimeService.createProcessInstanceQuery()
.active()
.orderByProcessInstanceId().desc()
.list();
}
5.3 历史数据查询
@Autowired
private HistoryService historyService;
// 查询已完成的流程实例
public List<HistoricProcessInstance> getCompletedProcessInstances() {
return historyService.createHistoricProcessInstanceQuery()
.finished()
.orderByProcessInstanceEndTime().desc()
.list();
}
// 查询流程活动历史
public List<HistoricActivityInstance> getProcessActivityHistory(String processInstanceId) {
return historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceStartTime().asc()
.list();
}
5.4 任务操作
@Autowired
private TaskService taskService;
// 认领任务
public void claimTask(String taskId, String userId) {
taskService.claim(taskId, userId);
}
// 设置任务变量
public void setTaskVariables(String taskId, Map<String, Object> variables) {
taskService.setVariables(taskId, variables);
}
// 获取任务表单数据
public Map<String, Object> getTaskFormData(String taskId) {
return taskService.getVariables(taskId);
}
6. 最佳实践
6.1 异常处理
try {
taskService.complete(taskId);
} catch (FlowableObjectNotFoundException e) {
throw new BusinessException("任务不存在");
} catch (FlowableException e) {
throw new BusinessException("流程处理异常");
}
6.2 事务管理
@Transactional
public void processLeaveRequest(String taskId, boolean approved) {
// 更新业务数据
leaveRequestMapper.updateStatus(taskId, approved);
// 完成任务
Map<String, Object> variables = new HashMap<>();
variables.put("approved", approved);
taskService.complete(taskId, variables);
}
6.3 流程监听器
public class TaskCreateListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
// 任务创建时的处理逻辑
String taskName = delegateTask.getName();
String processInstanceId = delegateTask.getProcessInstanceId();
// 可以发送通知、记录日志等
System.out.println("任务创建: " + taskName + ", 流程实例ID: " + processInstanceId);
}
}
6.4 流程变量管理
// 设置流程变量
runtimeService.setVariable(processInstanceId, "status", "审核中");
// 设置多个流程变量
Map<String, Object> variables = new HashMap<>();
variables.put("applicant", "张三");
variables.put("days", 3);
variables.put("reason", "家庭事务");
runtimeService.setVariables(processInstanceId, variables);
// 获取流程变量
Integer days = (Integer) runtimeService.getVariable(processInstanceId, "days");
7. 高级特性
7.1 动态表单
@Autowired
private FormService formService;
// 获取表单属性
public List<FormProperty> getTaskFormProperties(String taskId) {
TaskFormData formData = formService.getTaskFormData(taskId);
return formData.getFormProperties();
}
// 提交表单
public void submitTaskForm(String taskId, Map<String, String> properties) {
formService.submitTaskFormData(taskId, properties);
}
7.2 流程图生成
@Autowired
private RepositoryService repositoryService;
@Autowired
private RuntimeService runtimeService;
public InputStream getProcessDiagram(String processInstanceId) {
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(processInstanceId)
.singleResult();
String processDefinitionId = processInstance.getProcessDefinitionId();
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
ProcessEngineConfiguration processEngineConfiguration =
ProcessEngines.getDefaultProcessEngine().getProcessEngineConfiguration();
ProcessDiagramGenerator diagramGenerator = processEngineConfiguration.getProcessDiagramGenerator();
return diagramGenerator.generateDiagram(
bpmnModel, "png",
runtimeService.getActiveActivityIds(processInstanceId),
Collections.emptyList(),
processEngineConfiguration.getActivityFontName(),
processEngineConfiguration.getLabelFontName(),
processEngineConfiguration.getAnnotationFontName(),
processEngineConfiguration.getClassLoader(),
1.0,
true);
}
7.3 自定义服务任务
public class SendEmailTask implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) {
// 获取流程变量
String email = (String) execution.getVariable("email");
String content = (String) execution.getVariable("content");
// 执行邮件发送逻辑
System.out.println("发送邮件到: " + email + ", 内容: " + content);
// 设置执行结果
execution.setVariable("emailSent", true);
}
}
8. 与业务系统集成
8.1 业务关联
// 启动流程时关联业务ID
String businessKey = "LEAVE-" + leaveId;
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(
"leaveProcess", businessKey, variables);
// 通过业务ID查询流程实例
ProcessInstance instance = runtimeService.createProcessInstanceQuery()
.processInstanceBusinessKey(businessKey)
.singleResult();
8.2 消息事件
// 发布消息事件
runtimeService.messageEventReceived("leaveApproved", executionId);
// 启动消息事件
runtimeService.startProcessInstanceByMessage("newLeaveRequest", variables);
9. 注意事项
- 流程定义文件必须以 .bpmn20.xml 结尾
- 确保流程定义中的用户任务都有合适的处理人或候选组
- 建议使用 Spring 的事务管理来确保数据一致性
- 注意流程变量的作用域和生命周期
- 建议对敏感操作添加权限控制
10. 常见问题排查
- 流程部署失败:检查 BPMN 文件格式是否正确
- 任务无法完成:检查任务是否存在以及用户权限
- 流程卡住:使用 Flowable 提供的管理工具查看流程状态
- 数据库异常:检查数据库连接和表结构