惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Check Point Blog
GbyAI
GbyAI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
U
Unit 42
美团技术团队
NISL@THU
NISL@THU
C
Cisco Blogs
SecWiki News
SecWiki News
N
Netflix TechBlog - Medium
Forbes - Security
Forbes - Security
Cloudbric
Cloudbric
雷峰网
雷峰网
T
Tailwind CSS Blog
博客园 - 司徒正美
The Register - Security
The Register - Security
L
LangChain Blog
S
Security Affairs
Hacker News - Newest:
Hacker News - Newest: "LLM"
B
Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
Threat Research - Cisco Blogs
I
InfoQ
S
Schneier on Security
L
Lohrmann on Cybersecurity
量子位
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Martin Fowler
Martin Fowler
Schneier on Security
Schneier on Security
F
Fortinet All Blogs
TaoSecurity Blog
TaoSecurity Blog
K
Kaspersky official blog
Google DeepMind News
Google DeepMind News
Cisco Talos Blog
Cisco Talos Blog
PCI Perspectives
PCI Perspectives
Attack and Defense Labs
Attack and Defense Labs
WordPress大学
WordPress大学
Microsoft Azure Blog
Microsoft Azure Blog
H
Help Net Security
Project Zero
Project Zero
The GitHub Blog
The GitHub Blog
D
Docker
N
News | PayPal Newsroom
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
H
Hacker News: Front Page
云风的 BLOG
云风的 BLOG
Microsoft Security Blog
Microsoft Security Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 聂微东
Webroot Blog
Webroot Blog
MongoDB | Blog
MongoDB | Blog

Flowable 中文文档 Blog

Flowable 开发环境搭建指南 · Flowable 中文文档 Flowable 后端脚本 · Flowable 中文文档 ​​AI赋能Flowable:破解传统BPM的响应延迟与决策盲区​​ · Flowable 中文文档 Flowable 后端表达式 · Flowable 中文文档 Flowable中的四种核心流程控制模式:会签、或签、分支与并行 · Flowable 中文文档 Flowable 案例迁移 · Flowable 中文文档 Flowable 自动部署模型 · Flowable 中文文档 Flowable-UI 入门指南:从零开始的 BPM 之旅 · Flowable 中文文档 Flowable 数据库表结构详解 · Flowable 中文文档 BPMN、CMMN和DMN:工作流引擎三剑客的深度对比 · Flowable 中文文档 工作流引擎介绍与选型指南 · Flowable 中文文档 欢迎来到 Flowable 中文博客 · Flowable 中文文档
Spring Boot集成Flowable工作流开发教程 · Flowable 中文文档
2025-03-12 · via Flowable 中文文档 Blog

Flowable 作为一个强大的开源工作流引擎,不仅支持传统的 BPMN 工作流,还提供了 CMMN 案例管理的能力,能够同时应对结构化和非结构化的业务场景。

本文将通过一个实际的服务台(Helpdesk)系统示例,详细介绍如何使用 Spring Boot 集成 Flowable,实现 BPMN 工作流与 CMMN 案例管理的完美结合。通过这个示例,你将学习到:

  • 如何在 Spring Boot 项目中集成 Flowable
  • BPMN 和 CMMN 的最佳实践及应用场景
  • 工作流引擎的核心 API 使用方法
  • 服务台系统的完整实现流程

让我们开始这段整合之旅吧!

1. BPMN vs CMMN

在开始之前,让我们先了解 BPMN 和 CMMN 的区别:

1.1 BPMN(Business Process Model and Notation)

  • 适用于结构化的业务流程
  • 强调顺序流控制流
  • 流程是预定义的,步骤相对固定
  • 典型应用:请假审批、报销流程等

1.2 CMMN(Case Management Model and Notation)

  • 适用于非结构化的业务场景
  • 强调灵活性适应性
  • 任务可以动态启动和完成
  • 典型应用:客服工单、医疗诊断等

2. 项目环境

  • JDK 8+
  • Spring Boot 2.7.x
  • Flowable 6.8.0(包含 BPMN 和 CMMN 引擎)
  • Maven

3. 项目初始化

3.1 添加依赖

首先创建一个 Spring Boot 项目,在 pom.xml 中添加以下依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.flowable</groupId>
    <artifactId>flowable-springboot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.18</version>
    </parent>

    <properties>
        <java.version>8</java.version>
        <flowable.version>6.8.0</flowable.version>
    </properties>

    <dependencies>
        <!-- Spring Boot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Flowable -->
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-spring-boot-starter-rest</artifactId>
            <version>${flowable.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-spring-boot-starter-basic</artifactId>
            <version>${flowable.version}</version>
        </dependency>

        <!-- Database -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

3.2 配置文件

src/main/resources/application.yml 中添加以下配置:

server:
  port: 8080

spring:
  datasource:
    url: jdbc:h2:mem:flowable;DB_CLOSE_DELAY=-1
    username: sa
    password:
    driver-class-name: org.h2.Driver
  h2:
    console:
      enabled: true
      path: /h2-console

flowable:
  database-schema-update: true
  async-executor-activate: false
  bpmn:
    enabled: true
  cmmn:
    enabled: true

4. 流程与案例模型

4.1 BPMN 流程模型

Helpdesk BPMN 流程模型

src/main/resources/processes 目录下创建 helpdesk.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="http://flowable.org/examples">

    <process id="leaveProcess" name="Leave Process">
        <startEvent id="startEvent" name="Start"/>
        <sequenceFlow id="flow1" sourceRef="startEvent" targetRef="submitTask"/>

        <userTask id="submitTask" name="Submit Leave Request"
                  flowable:assignee="${applicant}"/>
        <sequenceFlow id="flow2" sourceRef="submitTask" targetRef="approveTask"/>

        <userTask id="approveTask" name="Approve Leave Request"
                  flowable:candidateGroups="managers"/>
        <sequenceFlow id="flow3" sourceRef="approveTask" targetRef="endEvent"/>

        <endEvent id="endEvent" name="End"/>
    </process>

</definitions> 

4.2 CMMN 案例模型

Helpdesk CMMN 案例模型

src/main/resources/cases 目录下创建 helpdesk-case.cmmn.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/CMMN/20151109/MODEL"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:flowable="http://flowable.org/cmmn"
             xmlns:cmmndi="http://www.omg.org/spec/CMMN/20151109/CMMNDI"
             xmlns:dc="http://www.omg.org/spec/CMMN/20151109/DC"
             xmlns:di="http://www.omg.org/spec/CMMN/20151109/DI"
             targetNamespace="http://www.flowable.org/casedef"
             exporter="Flowable Open Source Modeler"
             exporterVersion="6.8.0">

    <case id="helpDeskCase" name="Help Desk Case" flowable:initiatorVariableName="initiator">
        <documentation>Help Desk Case for handling support requests</documentation>
        <casePlanModel id="casePlanModel" flowable:formFieldValidation="true">
            <planItem id="planItem1" name="Register Request" definitionRef="sid-D23F3A7F-E35E-491B-A801-CAE2A8DF141D"></planItem>
            <planItem id="planItem2" name="Handle Request" definitionRef="sid-43B74981-CB5A-441E-ABDD-D0509AD0A4F8">
                <entryCriterion id="sid-C006CACE-99AC-47CD-AF5D-6102F52D856A" sentryRef="sentry1"></entryCriterion>
            </planItem>

            <sentry id="sentry1">
                <planItemOnPart id="sentryOnPart1" sourceRef="planItem1">
                    <standardEvent>complete</standardEvent>
                </planItemOnPart>
            </sentry>

            <humanTask id="sid-D23F3A7F-E35E-491B-A801-CAE2A8DF141D" name="Register Request" flowable:formFieldValidation="true"></humanTask>
            <humanTask id="sid-43B74981-CB5A-441E-ABDD-D0509AD0A4F8" name="Handle Request" flowable:formFieldValidation="true"></humanTask>
        </casePlanModel>
    </case>

    <cmmndi:CMMNDI>
        <cmmndi:CMMNDiagram id="CMMNDiagram_helpdeskCase">
            <cmmndi:CMMNShape id="CMMNShape_casePlanModel" cmmnElementRef="casePlanModel">
                <dc:Bounds height="714.0" width="718.0" x="40.0" y="40.0"></dc:Bounds>
                <cmmndi:CMMNLabel></cmmndi:CMMNLabel>
            </cmmndi:CMMNShape>
            <cmmndi:CMMNShape id="CMMNShape_planItem1" cmmnElementRef="planItem1">
                <dc:Bounds height="80.0" width="100.0" x="167.0" y="189.57881699604252"></dc:Bounds>
                <cmmndi:CMMNLabel></cmmndi:CMMNLabel>
            </cmmndi:CMMNShape>
            <cmmndi:CMMNShape id="CMMNShape_planItem2" cmmnElementRef="planItem2">
                <dc:Bounds height="80.0" width="100.0" x="555.0" y="185.0"></dc:Bounds>
                <cmmndi:CMMNLabel></cmmndi:CMMNLabel>
            </cmmndi:CMMNShape>
            <cmmndi:CMMNShape id="CMMNShape_sid-C006CACE-99AC-47CD-AF5D-6102F52D856A" cmmnElementRef="sid-C006CACE-99AC-47CD-AF5D-6102F52D856A">
                <dc:Bounds height="22.0" width="14.0" x="547.6330130435323" y="218.57881699604252"></dc:Bounds>
                <cmmndi:CMMNLabel></cmmndi:CMMNLabel>
            </cmmndi:CMMNShape>
            <cmmndi:CMMNEdge id="CMMNEdge_sid-E0987438-F457-41CD-9AD9-61A0E53EC4D0" cmmnElementRef="planItem1" targetCMMNElementRef="sid-C006CACE-99AC-47CD-AF5D-6102F52D856A">
                <di:extension>
                    <flowable:docker type="source" x="50.0" y="40.0"></flowable:docker>
                    <flowable:docker type="target" x="7.0" y="11.0"></flowable:docker>
                </di:extension>
                <di:waypoint x="266.95000000000005" y="229.57881699604252"></di:waypoint>
                <di:waypoint x="547.6330130435323" y="229.57881699604252"></di:waypoint>
                <cmmndi:CMMNLabel></cmmndi:CMMNLabel>
            </cmmndi:CMMNEdge>
        </cmmndi:CMMNDiagram>
    </cmmndi:CMMNDI>
</definitions> 

5. 控制器实现

5.1 BPMN 流程控制器

@RestController
@RequestMapping("/bpmn")
@RequiredArgsConstructor
public class BpmnController {
    private final RuntimeService runtimeService;
    private final TaskService taskService;
    private final HistoryService historyService;
    private final RepositoryService repositoryService;
    
    @PostMapping("/process/start")
    public Map<String, Object> startProcess(@RequestBody Map<String, Object> variables) {
        variables.put("initiator", variables.getOrDefault("userId", "unknown"));
        
        ProcessInstance processInstance = runtimeService.createProcessInstanceBuilder()
                .processDefinitionKey("helpDeskProcess")
                .variables(variables)
                .start();
                
        Map<String, Object> result = new HashMap<>();
        result.put("processInstanceId", processInstance.getId());
        result.put("processDefinitionId", processInstance.getProcessDefinitionId());
        result.put("variables", variables);
        return result;
    }
    
    // ... 其他 BPMN 相关接口
}

5.2 CMMN 案例控制器

@RestController
@RequestMapping("/cmmn")
@RequiredArgsConstructor
public class CmmnController {
    private final CmmnRuntimeService cmmnRuntimeService;
    private final CmmnTaskService cmmnTaskService;
    private final CmmnHistoryService cmmnHistoryService;
    private final CmmnRepositoryService cmmnRepositoryService;
    
    // ... 其他代码见GitHub仓库
}

6. API 测试

6.1 BPMN 流程接口测试

# 启动流程
curl -X POST "http://localhost:8080/bpmn/process/start" \
     -H "Content-Type: application/json" \
     -d '{"userId": "john"}'

# 查询任务
curl "http://localhost:8080/bpmn/tasks?assignee=john"

# 完成任务
curl -X POST "http://localhost:8080/bpmn/tasks/{taskId}/complete" \
     -H "Content-Type: application/json" \
     -d '{"approved": true}'

6.2 CMMN 案例接口测试

# 启动案例
curl -X POST "http://localhost:8080/cmmn/helpdesk/start" \
     -H "Content-Type: application/json" \
     -d '{"userId": "john"}'

# 查询任务
curl "http://localhost:8080/cmmn/tasks?assignee=john"

# 完成任务
curl -X POST "http://localhost:8080/cmmn/tasks/69e07941-d34a-11ee-9b85-0242ac110002/complete" \
     -H "Content-Type: application/json" \
     -d '{"analysis": "网络连接问题"}'

# 查询支持组任务
curl "http://localhost:8080/cmmn/tasks?candidateGroup=support"

# 认领任务
curl -X POST "http://localhost:8080/cmmn/tasks/7a1b8c52-d34a-11ee-9b85-0242ac110002/claim?userId=mary"

7. Flowable API 说明

7.1 BPMN 相关 API

RuntimeService

  • 主要用于管理运行中的流程实例
// 启动流程实例
ProcessInstance processInstance = runtimeService.createProcessInstanceBuilder()
    .processDefinitionKey("helpDeskProcess")
    .variables(variables)
    .start();

// 触发信号事件
runtimeService.signalEventReceived("signalName");

// 设置流程变量
runtimeService.setVariable(processInstanceId, "varName", value);

// 删除流程实例
runtimeService.deleteProcessInstance(processInstanceId, "reason");

TaskService

  • 负责管理和操作用户任务
// 查询任务
List<Task> tasks = taskService.createTaskQuery()
    .taskAssignee("john")
    .active()
    .list();

// 完成任务
taskService.complete(taskId);

// 认领任务
taskService.claim(taskId, userId);

// 设置任务变量
taskService.setVariable(taskId, "varName", value);

RepositoryService

  • 管理流程定义和部署
// 部署流程定义
Deployment deployment = repositoryService.createDeployment()
    .addClasspathResource("processes/helpdesk.bpmn20.xml")
    .deploy();

// 查询流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
    .processDefinitionKey("helpDeskProcess")
    .latestVersion()
    .singleResult();

HistoryService

  • 访问历史数据
// 查询历史流程实例
List<HistoricProcessInstance> historicProcessInstances = historyService
    .createHistoricProcessInstanceQuery()
    .finished()
    .list();

// 查询历史任务
List<HistoricTaskInstance> historicTasks = historyService
    .createHistoricTaskInstanceQuery()
    .taskAssignee("john")
    .finished()
    .list();

7.2 CMMN 相关 API

CmmnRuntimeService

  • 管理运行中的案例实例
// 启动案例实例
CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder()
    .caseDefinitionKey("helpDeskCase")
    .variables(variables)
    .start();

// 终止案例实例
cmmnRuntimeService.terminateCaseInstance(caseInstanceId);

// 查询案例实例
CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceQuery()
    .caseInstanceId(caseInstanceId)
    .singleResult();

CmmnTaskService

  • 管理案例中的人工任务
// 查询任务
List<Task> tasks = cmmnTaskService.createTaskQuery()
    .taskAssignee("john")
    .list();

// 完成任务
cmmnTaskService.complete(taskId, variables);

// 认领任务
cmmnTaskService.claim(taskId, userId);

// 委派任务
cmmnTaskService.delegateTask(taskId, userId);

CmmnRepositoryService

  • 管理案例定义和部署
// 部署案例定义
CmmnDeployment deployment = cmmnRepositoryService.createDeployment()
    .addClasspathResource("cases/helpdesk.cmmn")
    .deploy();

// 查询案例定义
CaseDefinition caseDefinition = cmmnRepositoryService.createCaseDefinitionQuery()
    .caseDefinitionKey("helpDeskCase")
    .latestVersion()
    .singleResult();

CmmnHistoryService

  • 访问案例历史数据
// 查询历史案例实例
List<HistoricCaseInstance> historicCases = cmmnHistoryService
    .createHistoricCaseInstanceQuery()
    .finished()
    .list();

// 查询历史任务
List<HistoricTaskInstance> historicTasks = cmmnHistoryService
    .createHistoricTaskInstanceQuery()
    .taskAssignee("john")
    .finished()
    .list();

// 查询历史变量
List<HistoricVariableInstance> historicVariables = cmmnHistoryService
    .createHistoricVariableInstanceQuery()
    .caseInstanceId(caseInstanceId)
    .list();

7.3 查询 API 的通用方法

Flowable 的查询 API 提供了丰富的链式调用方法:

// 通用的查询方法
.asc()/.desc()           // 排序
.listPage(start, size)   // 分页查询
.count()                 // 计数
.singleResult()          // 获取单个结果
.list()                  // 获取列表结果

// 时间相关查询
.before(date)            // 在指定时间之前
.after(date)             // 在指定时间之后

// 排序方法
.orderByTaskCreateTime()
.orderByProcessInstanceId()
.orderByCaseInstanceId()

7.4 变量处理

Flowable 支持多种类型的变量:

// 设置变量
Map<String, Object> variables = new HashMap<>();
variables.put("stringVar", "value");
variables.put("numberVar", 123);
variables.put("dateVar", new Date());
variables.put("booleanVar", true);

// 在流程/案例中使用变量
runtimeService.setVariables(processInstanceId, variables);
cmmnRuntimeService.setVariables(caseInstanceId, variables);

// 获取变量
Map<String, Object> processVariables = runtimeService.getVariables(processInstanceId);
Map<String, Object> caseVariables = cmmnRuntimeService.getVariables(caseInstanceId);

8. BPMN 和 CMMN 的应用场景

8.1 BPMN 适用场景

  • 标准化的审批流程
  • 固定步骤的业务流程
  • 需要严格控制流程顺序的场景

8.2 CMMN 适用场景

  • 动态变化的服务请求
  • 需要灵活处理的客户案例
  • 基于知识工作者判断的任务

9. 最佳实践

  1. 选择合适的模型

    • 对于结构化、固定流程,使用 BPMN
    • 对于非结构化、动态场景,使用 CMMN
    • 可以在同一系统中结合使用两种模型
  2. 流程与案例的集成

    • BPMN 流程可以调用 CMMN 案例
    • CMMN 案例可以触发 BPMN 流程
    • 根据业务需求灵活组合
  3. 数据共享

    • 流程和案例可以共享变量
    • 使用统一的数据存储
    • 保持数据一致性

10. 注意事项

  1. 本项目使用 H2 内存数据库,重启后数据会丢失
  2. 实际生产环境建议使用 MySQL 等持久化数据库
  3. 需要根据实际业务需求调整模型
  4. 建议添加适当的权限控制机制

11. 源码地址

完整源码请访问:GitHub - flowable-springboot-starter

12. 参考文档