SpringBoot + Activiti快速入门
2024-11-06 10:03 阅读(208)

序言

在工作中经常会有一些业务需求,需要使用到工作流,所以今天写这篇关于activiti的使用教程,帮助大家快速入门

1. 什么是工作流

工作流是一类能够完全或者部分自动执行的经营过程,它根据一系列规则、文档、信息或任务,在不同的参与者之间进行传递与执行。简单来说,工作流就是业务流程的自动化,它通过定义任务的顺序、规则和参与者,使得业务流程可以更加高效、准确地运行。

1.1 应用场景

工作流的应用场景非常多,凡是需要设计到流程的地方都会用到,比如:


企业资源规划(ERP)系统:在企业的生产、采购、销售等各个环节都有广泛应用。例如,通过工作流管理生产订单的下达、原材料的采购、产品的加工和发货等流程。

客户关系管理(CRM)系统:用于管理客户服务流程,如客户投诉处理。从客户提交投诉开始,工作流可以引导客服人员受理、调查、解决投诉,并记录整个过程。

内容管理系统(CMS):在内容发布方面发挥作用,比如管理文章的撰写、审核、发布等流程。


1.2 工作流的实现方式

大多数的工作流框架都是使用工作流引擎来实现的,通过工作流引擎来实现状态管理、流程控制等,比如Activiti中的ProcessEngine对象,就是里面的一个核心对象,提供了访问其他信息service的方法。

2.Activiti7

Activiti7 就是是一个轻量级的、开源的工作流引擎,它基于 Java 语言开发,主要用于业务流程管理(BPM)。它遵循 BPMN(业务流程建模语言)2.0 标准,能够帮助开发人员轻松地构建、部署和管理工作流。

BPMN2 是一种标准化的图形化流程建模语言,用于业务流程的可视化表示、定义和交换。它提供了一套丰富的符号和语义规则,使得业务分析师、流程设计师和开发人员能够共同协作,准确地描述从简单到复杂的业务流程。总的来说就是用来建模业务流程的标准规则,一个一个的符号。

2.1 Activiti使用

一般在使用的时候,都是使用IDEA插件的方式,支持在IDEA中编辑流程图。 在IDEA中搜索Activiti BPMN visualizer然后下载插件,下载完成之后重启IDEA

2.2 环境配置

创建数据库

CREATE DATABSE activiti DEFAULT CHARACTER SET utf8mb4

在IDEA中创建SpringBoot项目,依赖和YML配置如下:


<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.0.4.RELEASE</version>
       <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>SpringBoot-Activity7</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>SpringBoot-Activity7</name>
    <description>SpringBoot-Activity7</description>

    <properties>
       <java.version>8</java.version>
       <activiti.version>7.0.0.SR1</activiti.version>
    </properties>

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

       <dependency>
          <groupId>org.mybatis.spring.boot</groupId>
          <artifactId>mybatis-spring-boot-starter</artifactId>
          <version>3.0.3</version>
       </dependency>

       <dependency>
          <groupId>org.activiti</groupId>
          <artifactId>activiti-spring-boot-starter</artifactId>
          <version>${activiti.version}</version>
       </dependency>

       <dependency>
          <groupId>com.mysql</groupId>
          <artifactId>mysql-connector-j</artifactId>
          <version>8.0.31</version>
          <scope>runtime</scope>
       </dependency>

       <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <optional>true</optional>
       </dependency>

       <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
       </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>
spring:
  application:
    name: SpringBoot-Activiti7
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/activity?useUnicode=true&characterEncoding=utf8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
  activiti:
    db-history-used: true    #默认为false,如何不配置则activiti不会生成历史记录相关表
    history-level: full 

以上的工作做完以后,我们需要在resource资源路径下,创建activiti的配置文件,文件名为activiti-cfg.xml,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">


    <!--    配置数据库连接池-->
    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl"
                  value="jdbc:mysql://localhost:3306/activity?useUnicode=true&characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

    <!--    配置activity引擎-->
    <bean id="processEngineConfiguration"
          class="org.activiti.spring.SpringProcessEngineConfiguration">
        <property name="dataSource" ref="dataSource"/>

        <!-- 设置历史级别 -->
        <property name="history" value="full"/>

        <!--
              activity数据库表处理策略
              create-drop: 每次启动activity引擎,会删除表重新创建表
              true: 启动activity引擎时,会根据表的结构,自动创建表
              false: 启动activity引擎时,不会自动创建表,需要手动创建表
              drop-create: 每次启动activity引擎,会删除表重新创建表
        -->
        <property name="databaseSchemaUpdate" value="create-drop"/>
        <property name="dbHistoryUsed" value="true"/>
     </bean>
</beans>

注意这里的数据库必须配置,这是Activiti连接数据的必备条件,和项目中的数据库配置没有关联


2.3 创建BPMN文件

下载完以上的插件后,我们在resource文件下,创建bpmn文件,命名为evection

文件扩展名称不相同不要觉得奇怪,我们继续下一步即可。


在创建的bpmn文件中右击,选择View BPMN (Activiti) Diagram

然后会进入到如下界面:

在这个界面,我们就可以使用画图的方式来编辑bpmn文件了。


2.4 编辑BPMN文件

比如我们要设计一个请假流程,那么该如何操作呢?首先右击先建一个开始节点

空白区域,修改id为OwnerEvection

修改这个流程模版的名称,也就是修改name属性

然后右击新建任务,这里选择User Task

点击用户任务,设置Name和Assignee属性

意识就是,设置任务名称为创建出差申请,负责人为zhangsan。 接下来其他的节点依次创建,步骤和上述类似

各个节点节点之间使用竖线连接,做到这一步就算搞定了,然后将这个BPMN文件导出为PNG图片,放在项目的资源路径下

这样就算大功告成了

3.流程部署

接下来,我们使用Java代码的方式来部署流程,把BPMN对应的数据和信息保存到数据库当中。

创建ProcessEngine对象时,会自动在数据库当中帮助我们创建25张表。如果发现缺少历史信息记录表的话,查看对应的activiti-cfg.xml文件和YAML配置信息是否缺少


/**
 * 部署
 */
@Test
public void createProcessEngine() {
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    System.out.println(processEngine);
}

部署完成以后,我们来启动流程实例


/**
 * 启动流程实例
 */
@Test
public void testDeployment() {
    // 1.创建 ProcessEngine 对象
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2.使用ProcessEngine对象创建操作数据库服务RepositoryService对象
    RepositoryService repositoryService = processEngine.getRepositoryService();
    // 3.使用RepositoryService对象进行流程部署,定义一个流程名字,把bpmn文件和png文件部署到数据库中
    Deployment deploy = repositoryService.createDeployment()
            .name("出差申请") // 流程名字
            .addClasspathResource("bpmn/evection.bpmn20.xml") // 资源文件   bpmn配置文件
            .addClasspathResource("png/evection.png") // 资源文件   png流程图
            .disableSchemaValidation()   //  禁止校验文件
            .deploy();// 部署

    // 4.输出部署信息
    System.out.println("部署ID:" + deploy.getId());
    System.out.println("部署名称:" + deploy.getName());
}

创建实例完成后,测试完成任务。 此时任务负责人为zhangsan

以下代码,根据id模拟zhangsan已完成任务

// 根据任务id完成个人任务
@Test
public void testCompletTask() {
    // 1 获取流程引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2 获取service
    TaskService taskService = processEngine.getTaskService();
    // 3 根据任务id完成任务
    taskService.complete("e865941d-9b1e-11ef-9ef7-28cdc46f3daf");
}

zhangsan任务完成后,任务自动传递给下一个负责人lisi

获取lisi的任务列表,代码如下:

/**
 * 获取任务列表
 */
@Test
public void testSelectTodoTaskList() {
    //任务负责人
    String assignee = "lisi";
    //创建ProcessEngine对象
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    //获取TaskService
    TaskService taskService = processEngine.getTaskService();
    //获取任务集合
    List<Task> taskList = taskService.createTaskQuery()
            .processDefinitionKey("OwnerEvection")
            .taskAssignee(assignee)
            .list();
    //遍历任务列表
    for (Task task : taskList) {
        System.out.println("流程定义id = " + task.getProcessDefinitionId());
        System.out.println("流程实例id = " + task.getProcessInstanceId());
        System.out.println("任务id = " + task.getId());
        System.out.println("任务名称 = " + task.getName());
    }
}

完成lisi的任务,任务就会自动传递给下一个任务负责人


// 根据任务id完成个人任务
@Test
public void testCompletTaskById() {
    // 1 获取流程引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2 获取service
    TaskService taskService = processEngine.getTaskService();
    // 3 获取lisi在OwnerEvection中对应的任务 我们已知只有一个任务 可使用singleResult获取一个结果集
    Task task = taskService.createTaskQuery()
            .processDefinitionKey("OwnerEvection") // 流程的key
            .taskAssignee("lisi")   // 要查询的负责人
            .singleResult();// 因为可能有多个待办  所以是一个集合

    System.out.println("流程实例ID:" + task.getProcessInstanceId());
    System.out.println("任务ID:" + task.getId());
    System.out.println("任务负责人:" + task.getAssignee());
    System.out.println("任务名称:" + task.getName());

    // 4 获取lisi的完成任务
    taskService.complete(task.getId());
}

总的代码如下


    ```
@Test
    public void testCompletTaskAll() {
        // 1 获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2 获取service
        TaskService taskService = processEngine.getTaskService();
        Task task = null;

        // 3 获取zhangsan在myEvection中对应的任务 我们已知只有一个任务 可使用singleResult获取一个结果集
//         task = taskService.createTaskQuery()
//                .processDefinitionKey("OwnerEvection") // 流程的key
//                .taskAssignee("zhangsan")   // 要查询的负责人
//                .singleResult();// 因为可能有多个待办  所以是一个集合
//        taskService.complete(task.getId());

        task = taskService.createTaskQuery()
                .processDefinitionKey("OwnerEvection") // 流程的key
                .taskAssignee("lisi")   // 要查询的负责人
                .singleResult();// 因为可能有多个待办  所以是一个集合
        taskService.complete(task.getId());


        task = taskService.createTaskQuery()
                .processDefinitionKey("OwnerEvection") // 流程的key
                .taskAssignee("wangwu")   // 要查询的负责人
                .singleResult();// 因为可能有多个待办  所以是一个集合
        taskService.complete(task.getId());


        task = taskService.createTaskQuery()
                .processDefinitionKey("OwnerEvection") // 流程的key
                .taskAssignee("zhaolou")   // 要查询的负责人
                .singleResult();// 因为可能有多个待办  所以是一个集合
        taskService.complete(task.getId());

    }

运行之后,任务审批表就不会有数据了,因为财务审批就是最后一个流程,所以的任务都已经完成

总结

至此,Activit的基本入门都已经结束了,除此之外,Activit还支持根据细粒度化的流程控制,功能非常强大。