杰瑞科技汇

Activiti工作流教程,如何快速上手?

Activiti 工作流完整教程

目录

  1. 第一部分:Activiti 基础入门
    • 1 什么是工作流和 BPMN?
    • 2 什么是 Activiti?
    • 3 为什么选择 Activiti?
    • 4 核心概念(流程引擎、服务、部署、流程定义、流程实例等)
    • 5 环境搭建:第一个 "Hello World" 程序
  2. 第二部分:核心 API 与服务
    • 1 ProcessEngine:流程引擎
    • 2 Service 层详解:RepositoryService, RuntimeService, TaskService, HistoryService
    • 3 使用 Service 进行基本操作
  3. 第三部分:BPMN 2.0 基础元素
    • 1 流程图基本结构:<process>, <startEvent>, <endEvent>
    • 2 任务:<userTask> (用户任务), <serviceTask> (服务任务)
    • 3 网关:<exclusiveGateway> (排他网关), <parallelGateway> (并行网关)
    • 4 流程变量:<sequenceFlow> 的条件表达式
  4. 第四部分:实战案例:一个简单的请假流程
    • 1 需求分析
    • 2 使用 Activiti Designer 绘制流程图
    • 3 部署流程定义
    • 4 启动流程实例
    • 5 查询和处理任务
    • 6 完成任务并结束流程
  5. 第五部分:进阶特性
    • 1 表单与任务:使用 TaskListenerExecutionListener
    • 2 嵌套流程与调用活动
    • 3 事件监听器
    • 4 多实例任务(会签/或签)
    • 5 Spring/Spring Boot 集成
  6. 第六部分:最佳实践与总结
    • 1 项目结构建议
    • 2 版本管理
    • 3 学习资源推荐

第一部分:Activiti 基础入门

1 什么是工作流和 BPMN?

  • 工作流:对业务流程进行自动化管理,将工作从一个参与者传递到另一个参与者,直至完成,它关注的是“业务流程的自动化”。
  • BPMN (Business Process Model and Notation):一种为业务流程建模而设计的图形化标准,它使用一套标准化的符号来绘制流程图,使得业务人员和技术人员能够无障碍地沟通,Activiti 完全支持 BPMN 2.0 标准。

2 什么是 Activiti?

Activiti 是一个开源的、灵活的、轻量级的 业务流程管理工作流引擎,它基于 Apache 2.0 许可证,完全实现了 BPMN 2.0 规范,你可以用它来创建、执行、管理和监控业务流程。

Activiti工作流教程,如何快速上手?-图1
(图片来源网络,侵删)

3 为什么选择 Activiti?

  • 标准规范:基于 BPMN 2.0,流程图可读性强,易于维护。
  • 轻量级:核心 jar 包小,易于集成到任何 Java 应用中。
  • 功能强大:支持丰富的流程元素,如用户任务、服务任务、网关、事件、多实例等。
  • 活跃的社区:拥有庞大的用户和开发者社区,文档和案例丰富。
  • 与企业级集成:可以与 Spring、Spring Boot 等主流框架无缝集成。

4 核心概念

在开始编码前,必须理解这几个核心概念:

  1. 流程引擎:Activiti 的核心,负责管理和执行所有流程,通过 ProcessEngine 类来创建和获取。
  2. 部署:将你的流程定义(通常是 .bpmn20.xml 文件)发布到 Activiti 中,使其可以被引擎识别和执行。
  3. 流程定义:一次部署的产物,描述了一个业务流程的静态结构,可以理解为流程的“蓝图”。
  4. 流程实例:流程定义的一次具体执行。“请假流程”是流程定义,“张三提交的请假申请”就是流程实例。
  5. 任务:流程执行过程中的一个工作单元,通常需要人来处理(用户任务)或系统自动处理(服务任务)。
  6. 服务:Activiti 提供的 API 接口,用于与引擎交互,如 RuntimeService(运行时)、TaskService(任务)等。

5 环境搭建:第一个 "Hello World" 程序

目标:部署一个最简单的流程,并启动它。

步骤 1:添加 Maven 依赖

pom.xml 中添加 Activiti 的核心依赖:

Activiti工作流教程,如何快速上手?-图2
(图片来源网络,侵删)
<dependencies>
    <!-- Activiti Core -->
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-engine</artifactId>
        <version>7.0.0.GA</version> <!-- 建议使用较新稳定版 -->
    </dependency>
    <!-- MySQL 数据库驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.28</version>
    </dependency>
    <!-- 连接池 -->
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>5.0.1</version>
    </dependency>
</dependencies>

步骤 2:配置 activiti.cfg.xml

src/main/resources 目录下创建 activiti.cfg.xml 文件,这是 Activiti 的配置文件。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 配置流程引擎配置信息 -->
    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <!-- 数据库相关配置 -->
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activiti7?characterEncoding=UTF-8&amp;serverTimezone=UTC" />
        <property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver" />
        <property name="jdbcUsername" value="root" />
        <property name="jdbcPassword" value="password" />
        <!-- 如果数据库表不存在,则自动创建 -->
        <property name="databaseSchemaUpdate" value="true" />
        <!-- 指定我们的流程定义文件部署位置 -->
        <property name="deploymentResources" value="classpath*:/diagrams/*.bpmn20.xml" />
    </bean>
    <!-- 配置流程引擎 -->
    <bean id="processEngine" class="org.activiti.engine.impl.ProcessEngineImpl" factory-bean="processEngineConfiguration" factory-method="buildProcessEngine" />
</beans>

步骤 3:创建一个简单的 BPMN 流程

src/main/resources/diagrams 目录下创建 hello.bpmn20.xml 文件。

Activiti工作流教程,如何快速上手?-图3
(图片来源网络,侵删)
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             targetNamespace="http://www.activiti.org/test">
    <process id="helloWorld" name="Hello World Process">
        <startEvent id="startEvent" name="Start Event"/>
        <sequenceFlow id="flow1" sourceRef="startEvent" targetRef="endEvent"/>
        <endEvent id="endEvent" name="End Event"/>
    </process>
</definitions>

这个流程图只有一个开始事件和一个结束事件,通过一个顺序流连接。

步骤 4:编写 Java 代码

创建一个 Main 类来启动流程。

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
public class HelloWorld {
    public static void main(String[] args) {
        // 1. 创建流程引擎
        // 默认会加载 classpath 下的 activiti.cfg.xml 文件
        ProcessEngine processEngine = ProcessEngineConfiguration
                .createProcessEngineConfigurationFromResourceDefault()
                .buildProcessEngine();
        // 2. 获取 RepositoryService,用于部署流程
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3. 部署流程定义(如果配置了 deploymentResources,这一步可以省略)
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("diagrams/hello.bpmn20.xml")
                .deploy();
        System.out.println("流程部署成功,ID: " + deployment.getId());
        // 4. 获取 RuntimeService,用于启动流程实例
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 5. 启动流程实例,key 对应 bpmn 文件中的 process id
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("helloWorld");
        System.out.println("流程实例启动成功,ID: " + processInstance.getId());
        System.out.println("流程实例是否结束: " + processInstance.isEnded());
    }
}

运行结果

  1. 程序会自动在 MySQL 数据库中创建 25 张 Activiti 相关的表。
  2. 控制台会输出流程部署 ID 和流程实例 ID。
  3. 查看 act_ru_execution 表,可以看到一条流程实例正在运行的记录。
  4. 由于流程只有一个开始和结束节点,实例会立即结束,再次运行 processInstance.isEnded() 会返回 true

第二部分:核心 API 与服务

Activiti 的 API 被组织成一系列的 Service,每个 Service 负责一个特定的功能领域。

1 ProcessEngine:流程引擎

这是所有操作的入口,通过 ProcessEngineConfiguration 构建,在 Spring/Spring Boot 环境中,通常由容器管理。

2 Service 层详解

服务名称 作用 主要方法
RepositoryService 仓库服务,管理流程定义(部署、删除、查询等),不涉及运行时数据。 createDeployment(), deploy(), deleteDeployment(), createProcessDefinitionQuery()
RuntimeService 运行时服务,管理流程实例(启动、查询、变量设置等)。 startProcessInstanceByKey(), startProcessInstanceById(), createExecutionQuery(), setVariable()
TaskService 任务服务,管理用户任务(查询、完成、认领、委派等)。 createTaskQuery(), completeTask(), claim(), addCandidateUser()
HistoryService 历史服务,查询历史数据(已完成的流程实例、任务等),只读。 createHistoricProcessInstanceQuery(), createHistoricTaskInstanceQuery()
ManagementService 管理服务,管理和查询引擎信息(如数据库表信息、作业等)。 getDatabaseTableNames(), createJobQuery()

3 使用 Service 进行基本操作

TaskService 为例,处理任务:

// 假设我们已经有一个流程实例在运行,并且生成了一个任务
// 1. 查询当前用户的任务
List<Task> tasks = taskService.createTaskQuery()
        .taskAssignee("zhangsan") // 指定处理人
        .list();
for (Task task : tasks) {
    System.out.println("任务ID: " + task.getId());
    System.out.println("任务名称: " + task.getName());
    System.out.println("任务处理人: " + task.getAssignee());
    System.out.println("流程实例ID: " + task.getProcessInstanceId());
}
// 2. 完成任务
if (!tasks.isEmpty()) {
    String taskId = tasks.get(0).getId();
    // 可以在完成任务时设置变量
    taskService.complete(taskId, "comment", "任务已完成,审批通过。");
    System.out.println("任务 " + taskId + " 已完成。");
}

第三部分:BPMN 2.0 基础元素

1 流程图基本结构

  • <process>:流程的根元素,id 是唯一标识。
  • <startEvent>:流程的起点。
  • <endEvent>:流程的终点,可以有多个。

2 任务

  • <userTask>:用户任务,需要人工处理。
    • 属性:id (唯一), name (显示名), assignee (默认处理人)。
    • 示例:
      <userTask id="submitLeave" name="提交请假申请" assignee="employee"/>
  • <serviceTask>:服务任务,由系统自动执行。
    • 通常需要指定 class 属性,指向一个 Java 类(该类需实现 JavaDelegate 接口)。
    • 示例:
      <serviceTask id="sendEmail" name="发送邮件" activiti:class="com.example.SendEmailTask"/>

3 网关

网关用来控制流程的流向。

  • <exclusiveGateway>:排他网关,相当于 if-else,必须有一个出口条件为 true

    • 通过 <sequenceFlow>conditionExpression 设置条件。
    • 示例:
      <exclusiveGateway id="decision" name="请假天数判断"/>
      <sequenceFlow id="flow_to_manager" sourceRef="decision" targetRef="managerTask">
          <conditionExpression xsi:type="tFormalExpression">${days > 3}</conditionExpression>
      </sequenceFlow>
      <sequenceFlow id="flow_to_hr" sourceRef="decision" targetRef="hrTask">
          <conditionExpression xsi:type="tFormalExpression">${days &lt;= 3}</conditionExpression>
      </sequenceFlow>
  • <parallelGateway>:并行网关,将流程分成多个分支,所有分支都执行完后才汇聚。

4 流程变量

流程变量是贯穿整个流程实例的数据,用于在任务间传递信息和控制流程流向。

  • 设置变量:在启动流程或完成任务时设置。

    // 启动时设置
    Map<String, Object> variables = new HashMap<>();
    variables.put("employee", "zhangsan");
    variables.put("days", 5);
    variables.put("reason", "年假");
    runtimeService.startProcessInstanceByKey("leaveProcess", variables);
    // 完成任务时设置
    taskService.complete(taskId, "approved", true);
  • 使用变量:在 BPMN 表达式中使用 ${variableName} 来引用。


第四部分:实战案例:一个简单的请假流程

目标:实现一个员工提交申请 -> 经理审批 -> 流程结束的完整流程。

1 需求分析

  1. 员工(employee)提交请假申请,需要指定请假天数。
  2. 如果请假天数 > 3 天,由部门经理(manager)审批。
  3. 如果请假天数 <= 3 天,由人力资源(hr)审批。
  4. 审批通过后,流程结束。

2 使用 Activiti Designer 绘制流程图

  1. 下载并安装 Activiti Eclipse DesignerActiviti Modeler

  2. 新建 BPMN 2.0 Diagram。

  3. 拖拽元素,绘制如下流程图:

  4. 关键配置

    • 任务节点
      • 提交请假申请assignee = ${employee} (动态指定处理人)
      • 经理审批assignee = manager
      • HR审批assignee = hr
    • 网关节点
      • 请假天数判断:类型为 Exclusive Gateway
      • 连接到 经理审批 的流:条件为 ${days > 3}
      • 连接到 HR审批 的流:条件为 ${days <= 3}
  5. 将画好的流程图保存为 leaveProcess.bpmn20.xml,并放入 src/main/resources/diagrams 目录。

3 部署流程定义

这部分代码与 "Hello World" 类似,确保你的 activiti.cfg.xml 配置正确。

// ... 获取 processEngine ...
RepositoryService repositoryService = processEngine.getRepositoryService();
// 如果配置了 deploymentResources,部署会自动完成
// repositoryService.createDeployment().addClasspathResource("diagrams/leaveProcess.bpmn20.xml").deploy();
System.out.println("请假流程部署成功。");

4 启动流程实例

RuntimeService runtimeService = processEngine.getRuntimeService();
// 设置流程变量
Map<String, Object> variables = new HashMap<>();
variables.put("employee", "zhangsan"); // 员工
variables.put("manager", "lisi");      // 经理
variables.put("hr", "wangwu");        // HR
variables.put("days", 5);             // 请假5天
variables.put("reason", "结婚纪念日");
// 启动流程实例
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leaveProcess", variables);
System.out.println("请假流程实例启动成功,ID: " + processInstance.getId());

5 查询和处理任务

lisi(经理)应该能看到一个待办任务。

// 1. 经理查询自己的任务
TaskService taskService = processEngine.getTaskService();
List<Task> managerTasks = taskService.createTaskQuery()
        .taskAssignee("lisi") // 指定经理
        .list();
System.out.println("经理的任务数量: " + managerTasks.size());
for (Task task : managerTasks) {
    System.out.println("经理任务ID: " + task.getId() + ", 任务名: " + task.getName());
    // 2. 经理完成任务(审批通过)
    taskService.complete(task.getId());
    System.out.println("经理已审批通过任务: " + task.getId());
}

6 完成任务并结束流程

经理完成任务后,流程会走向 结束事件,整个流程实例结束。

你可以通过 HistoryService 来查询历史记录,验证流程是否正确执行。

HistoryService historyService = processEngine.getHistoryService();
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
        .processInstanceId(processInstance.getId())
        .singleResult();
System.out.println("流程实例最终状态: " + historicProcessInstance.getEndTime()); // 如果有结束时间,说明流程已结束

第五部分:进阶特性

1 表单与任务

在实际应用中,任务通常关联一个表单,Activiti 本身不管理表单数据,但可以通过流程变量来传递。

  • 获取任务变量

    Map<String, Object> variables = taskService.getVariables(taskId);
    String reason = (String) variables.get("reason");
  • 使用监听器:可以在任务创建或完成时执行自定义逻辑。

    • 实现 TaskListener 接口。
    • userTask 中配置 <taskListener event="create" class="com.example.MyTaskListener"/>

2 嵌套流程与调用活动

当一个流程比较复杂时,可以将其拆分为多个子流程,然后在主流程中通过 <callActivity> 来调用子流程。

3 事件监听器

Activiti 在流程生命周期中会触发多种事件(如流程开始、任务创建、结束等),你可以实现相应的监听器接口来响应这些事件。

  • ExecutionListener: 监听流程执行事件。
  • TaskListener: 监听任务事件。
  • EventListener: 监听所有事件。

4 多实例任务

用于实现“会签”(所有人都需同意)或“或签”(只要有一个人同意即可)的场景。 通过配置 multiInstanceLoopCharacteristics 实现。

5 Spring/Spring Boot 集成

这是目前最主流的使用方式,Activiti 提供了与 Spring 深度集成的能力。

  • Spring Boot Starter:只需添加 activiti-spring-boot-starter 依赖,并配置 application.properties,即可自动配置 ProcessEngine
    # application.properties
    spring.activiti.database-schema-update=true
    spring.activiti.process-definition-location-pattern=classpath*:/diagrams/*.bpmn20.xml
  • 优点:无需手动管理 ProcessEngineService 会自动注入为 Spring Bean,事务管理也更加方便。

第六部分:最佳实践与总结

1 项目结构建议

src/
├── main/
│   ├── java/
│   │   └── com/
│   │       └── example/
│   │           ├── activiti/
│   │           │   ├── listener/    // 监听器
│   │           │   ├── service/     // 业务服务
│   │           │   └── task/        // JavaDelegate 任务类
│   │           └── Application.java // Spring Boot 启动类
│   └── resources/
│       ├── activiti.cfg.xml          // 如果不使用 Spring Boot
│       ├── application.properties    // Spring Boot 配置
│       └── diagrams/
│           ├── hello.bpmn20.xml
│           └── leaveProcess.bpmn20.xml

2 版本管理

  • 流程定义是会迭代的,当流程修改后,重新部署会生成一个新的版本。
  • 使用 ProcessDefinitionQuery 可以查询不同版本的流程定义。
  • 启动流程实例时,可以指定版本号,或者使用最新的版本(startProcessInstanceByKey 默认使用最新版本)。

3 学习资源推荐

Activiti 是一个功能强大且灵活的工作流引擎,掌握它的关键在于:

  1. 理解核心概念:流程定义、实例、任务、服务等。
  2. 精通 BPMN 2.0:学会用图形化语言描述业务逻辑。
  3. 熟练使用 API:知道在什么场景下使用哪个 Service
  4. 动手实践:从简单的 "Hello World" 开始,逐步构建复杂的业务流程。

希望这份教程能帮助你顺利开启 Activiti 之旅!

分享:
扫描分享到社交APP
上一篇
下一篇