Flowable 工作流使用教程

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 核心组件详解
  1. ProcessEngine

    • 配置管理
    • 数据源管理
    • 命令拦截器
    • 事件处理
  2. RepositoryService

    • 流程定义管理
    • 部署包管理
    • 流程资源管理
  3. RuntimeService

    • 流程实例管理
    • 执行流管理
    • 流程变量管理
    • 信号和消息处理
  4. TaskService

    • 任务创建和删除
    • 任务查询和认领
    • 任务委派和转交
    • 任务附件和评论
  5. HistoryService

    • 历史活动记录
    • 历史任务记录
    • 历史变量记录
    • 历史表单记录
1.3.2 数据库架构

Flowable 的核心表结构:

  1. 通用表

    • ACT_GE_PROPERTY: 系统属性
    • ACT_GE_BYTEARRAY: 二进制数据存储
  2. 流程定义表

    • ACT_RE_DEPLOYMENT: 部署信息
    • ACT_RE_PROCDEF: 流程定义
    • ACT_RE_MODEL: 模型信息
  3. 运行时表

    • ACT_RU_EXECUTION: 执行实例
    • ACT_RU_TASK: 运行时任务
    • ACT_RU_VARIABLE: 运行时变量
  4. 历史表

    • ACT_HI_PROCINST: 历史流程实例
    • ACT_HI_TASKINST: 历史任务实例
    • ACT_HI_ACTINST: 历史活动实例

1.4 流程生命周期管理

1.4.1 流程定义生命周期
  1. 设计阶段

    • 使用建模工具创建 BPMN 文件
    • 定义流程变量和表单
    • 配置任务处理人和候选组
    • 设置业务规则和条件表达式
  2. 部署阶段

    • 验证流程定义的正确性
    • 解析 BPMN 文件
    • 生成流程资源文件
    • 存储到数据库中
  3. 版本控制

    • 多版本并存机制
    • 版本升级策略
    • 历史版本处理
1.4.2 流程实例生命周期
  1. 启动阶段

    • 创建流程实例
    • 初始化流程变量
    • 触发开始事件
    • 创建首个任务
  2. 执行阶段

    • 任务的创建和完成
    • 流程变量的更新
    • 分支条件的判断
    • 事件的处理
  3. 结束阶段

    • 完成所有活动
    • 触发结束事件
    • 清理运行时数据
    • 生成历史记录

1.5 高级流程控制机制

1.5.1 事件机制
  1. 定时事件

    • 固定时间触发
    • 周期性触发
    • 持续时间触发
  2. 消息事件

    • 消息发送和接收
    • 消息中间事件
    • 消息边界事件
  3. 信号事件

    • 全局信号广播
    • 信号捕获
    • 信号触发器
1.5.2 错误处理机制
  1. 错误边界事件

    • 错误定义
    • 错误捕获
    • 错误处理流程
  2. 补偿机制

    • 补偿事件定义
    • 补偿处理器
    • 事务补偿
  3. 取消机制

    • 取消边界事件
    • 取消结束事件
    • 事务取消
1.5.3 多实例特性
  1. 并行多实例

    • 实例创建规则
    • 完成条件设置
    • 变量处理机制
  2. 串行多实例

    • 顺序执行控制
    • 实例间数据传递
    • 中断处理

1.6 表达式语言支持

1.6.1 UEL 表达式
  1. 值表达式

    ${user.name}
    ${process.variables.amount > 1000}
    
  2. 方法表达式

    ${userService.findUser(userId)}
    ${dateUtil.format(date, 'yyyy-MM-dd')}
    
  3. 条件表达式

    ${approved == true}
    ${amount >= 1000 && level == 'high'}
    
1.6.2 Spring 表达式集成
  1. Bean 引用

    ${@userService.getCurrentUser()}
    ${@configurationBean.getThreshold()}
    
  2. Spring EL

    #{systemProperties['java.version']}
    #{T(java.lang.Math).random()}
    

1.7 任务分配策略

1.7.1 静态分配
  1. 固定分配人

    <userTask id="approveTask" name="审批任务" flowable:assignee="manager" />
    
  2. 候选人组

    <userTask id="reviewTask" name="审核任务" flowable:candidateGroups="leaders" />
    
1.7.2 动态分配
  1. 表达式分配

    <userTask id="handleTask" name="处理任务" 
              flowable:assignee="${taskHandler}" />
    
  2. 监听器分配

    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. 注意事项

  1. 流程定义文件必须以 .bpmn20.xml 结尾
  2. 确保流程定义中的用户任务都有合适的处理人或候选组
  3. 建议使用 Spring 的事务管理来确保数据一致性
  4. 注意流程变量的作用域和生命周期
  5. 建议对敏感操作添加权限控制

10. 常见问题排查

  1. 流程部署失败:检查 BPMN 文件格式是否正确
  2. 任务无法完成:检查任务是否存在以及用户权限
  3. 流程卡住:使用 Flowable 提供的管理工具查看流程状态
  4. 数据库异常:检查数据库连接和表结构

11. 参考资源

### Flowable 中驳回操作引起脏数据解决方案 在处理 Flowable 流程引擎中的驳回操作时,如果未正确配置或管理流程实例的状态转换逻辑,则可能导致数据库中存在不一致的数据记录,即所谓的“脏数据”。为了有效预防和修复此类问题,建议采取以下措施: #### 1. 数据一致性校验机制 确保每次执行驳回动作前都对当前任务及其上下文进行全面验证。这可以通过自定义服务类来实现,在其中加入必要的业务规则判断,防止非法状态迁移的发生[^1]。 ```java public class CustomTaskService extends TaskServiceImpl { @Override public void complete(String taskId, String userId, Map<String, Object> variables) { // 自定义的前置检查逻辑 checkPreconditions(taskId); super.complete(taskId, userId, variables); } private void checkPreconditions(String taskId){ // 实现具体的条件检测方法 } } ``` #### 2. 使用事件监听器捕获异常情况 通过注册全局级别的 `ExecutionListener` 或者针对特定节点设置局部监听器的方式监控整个生命周期内的关键事件点。一旦发现有不符合预期的行为发生(比如意外终止),可以立即触发补偿事务来回滚之前的操作,从而保持系统的稳定性和可靠性[^2]。 ```xml <serviceTask id="someTask" name="Some Service Task"> <!-- 定义其他属性 --> <extensionElements> <flowable:executionListener event="start" class="com.example.MyStartEventListener"/> <flowable:executionListener event="end" class="com.example.MyEndEventListener"/> </extensionElements> </serviceTask> ``` #### 3. 增强日志记录功能以便事后分析 增强应用程序的日志级别,并确保所有重要的变更都被详细记载下来。当出现问题时能够快速定位原因所在,同时也便于后续优化改进工作流设计。 ```properties logging.level.org.flowable=DEBUG logging.file.name=./logs/flowable.log ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翱翔-蓝天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

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

抵扣说明:

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

余额充值