【项目实战】使用Activiti工作流引擎进行开发

参考:https://www.cnblogs.com/xine/p/14553069.html
参考:神思者老师的课程

前言

在软件开发领域中,工作流自动化在简化业务流程和提高效率方面起着至关重要的作用。而在Java应用程序中实现工作流自动化的一个受欢迎选择就是Activiti,这是一个老牌的工作流引擎,能够与Spring Boot框架无缝集成。

在本文中,我们将深入探讨Activiti的特点、优势以及如何在Java项目中使用它来实现工作流自动化。

一、初识Activiti

1.什么是工作流?

在深入了解Activiti之前,让我们先来了解一下什么是工作流。简单来说,工作流是通过计算机协助实现流程自动化控制的一种方式。它主要解决的是在多个参与者之间按照预定义规则传递文档、信息或任务的过程,以实现特定的业务目标或推动目标的实现。

2.Activiti工作流引擎

Activiti是一个基于BPMN 2.0标准的开源工作流引擎。它允许我们自定义BPMN文件,其中声明了业务流程,并将这些BPMN文件交给Activiti引擎来执行。

BPMN文件实际上就是一个XML文件,其中使用不同的标签来定义不同的业务节点。例如:

  • 如果是UserTask节点,工作流引擎在执行到该节点时会自动阻塞,并等待审批人员提供处理结果,然后才能继续执行流程。
  • 如果遇到ServiceTask节点,通常会有与之对应的程序脚本。工作流引擎会自动执行这些程序脚本,完成ServiceTask任务,无需人工干预。

举个例子,我们可以定义一个ServiceTask脚本来自动生成Excel报表文件,并将其通过电子邮件发送给特定部门。这些操作都可以通过定义ServiceTask节点的脚本来实现,并由工作流引擎执行。

3.Activiti的优势

Activiti相对于其他Java领域的开源工作流产品,如Camunda和Flowable,更为简单和轻量级。它适用于小型项目和简单工作流。

与将业务流程硬编码到Java代码中相比,使用工作流引擎的优势在于维护方面。

  • 当需要修改业务流程时,如果没有使用工作流引擎,我们需要修改Java代码,并重新编译和发布项目,这会非常麻烦。
  • 而如果采用了工作流引擎,我们可以将具体业务流程从Java代码中分离出来,以XML文件的形式进行定义。这样,在重构流程时,除非是对流程进行大规模修改,我们几乎不需要重新修改Java代码,只需向Java程序提供新的XML文件即可。

此外,Activiti还支持JavaScript和Java等脚本语言。对于简单的计算、循环和判断等操作,我们可以使用JavaScript脚本来声明。而对于复杂的任务,我们可以定义Java任务类,并将其与ServiceTask节点关联起来。当工作流引擎执行到ServiceTask节点时,就会调用我们创建的Java任务类。

4.BPMN设计器

Activiti本身是一个强大的工作流引擎,但并不包含BPMN设计器。为了定义业务流程,我们需要安装一个BPMN设计器。过去,Eclipse上有一些BPMN设计器插件,但现在这些插件已经不再维护,无法使用。同样,IDEA上的BPMN插件也处于相同的状态,无法使用。

然而,现在有一些Web版本的BPMN设计器可供使用。我们可以通过浏览器访问官方网站,并选择快速开始,以开始使用这些设计器。这些Web版本的设计器通常具有直观的界面和丰富的功能,使我们能够轻松地定义和编辑BPMN流程。

在这里插入图片描述

然后就可以画工作流程了,如下:

在这里插入图片描述

二、SpringBoot项目整合Activiti

Activiti 7.0 是一个强大的工作流引擎,可以帮助我们自动化和管理业务流程。结合Spring Boot的灵活性和简洁性,我们可以创建强大且可扩展的应用程序。本文将展示如何将Activiti 7.0整合到Spring Boot项目中。

我们这里用的是Activiti7.0版本,Activiti7.0不支持1.8的JDK。所以必须是大于1.8的。

1.添加依赖

首先,在Spring Boot项目的pom.xml文件中添加以下依赖项,以引入Activiti 7.0:

<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-spring-boot-starter-basic</artifactId>
    <version>7.0.0</version>
</dependency>

这将为项目提供Activiti 7.0的基本功能。

2.添加配置文件

首先添加Activiti的配置文件

activiti:
  # 设置为true时,Activiti会自动更新数据库模式
  database-schema-update: true
  # 指定Activiti的历史级别为audit
  historyLevel: audit
  # 启用Activiti的数据库历史记录功能
  db-history-used: true

这些是一些配置选项,用于配置Activiti在应用程序中的行为:

  1. activiti.database-schema-update: true: 这个选项指定了Activiti在启动时是否应该自动更新数据库模式。如果设置为true,Activiti会根据需要自动创建或更新数据库表和索引。这对于开发和测试环境非常方便,但在生产环境中可能需要手动管理数据库模式的更新。

  2. activiti.historyLevel: audit:这个选项指定了Activiti的历史级别。历史级别定义了Activiti记录流程实例和任务历史数据的详细程度。audit级别记录了最详细的历史数据,包括流程实例、任务、变量等的创建、更新和删除操作。

  3. activiti.db-history-used: true:这个选项指定了是否启用Activiti的数据库历史记录功能。如果设置为true,Activiti会将历史数据存储在数据库中,以便后续查询和分析。如果设置为false,则不会记录历史数据。

这些配置选项可以根据您的需求进行调整。确保根据环境和应用程序的要求进行适当的配置。

接下来在application.yml文件中,配置数据库连接信息。例如,如果使用的是MySQL数据库,可以添加以下配置:

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/activiti??useSSL=false
      username: root
      password: your_password

确保将上述配置更改为适合您的数据库设置。

3.启动项目

如果项目启动没有任何报错信息,说明工作流项目就已经搭建成功了。

@SpringBootApplication
public class YourApplication {

    public static void main(String[] args) {
        SpringApplication.run(YourApplication.class, args);
    }

}

三、使用Activiti工作流引擎进行开发

我们先用BPMN设计器去定义简单的工作流,然后交给Activiti引擎去执行,咱们体验一下工作流的部署和运行过程。Activiti兼容BPMN1.0和2.0规范,但是建议大家使用BPMN2.0来定义工作流程。

1.设计BPMN文件

在BPMN设计器上面参照下面的例子,拖拽生成一个工作流程。右侧是BPMN流程的ID和名称,然后必须设定成可执行的,否则Activiti无法运行这个BPMN文件。
在这里插入图片描述
上面BPMN流程中的两个服务节点是ServiceTask节点,属于不需要人工干预可以自动执行的节点。

定义好BPMN文件之后,我们选择下载XML格式的文档,方便我们格式化文档内容。
在这里插入图片描述
在IDEA项目中,新建bpmn目录,把下载的XML文件修改名字然后放进去。文件名称必须改成下面的后缀样式,甚至.XML这种大写的后缀都不可以。

在这里插入图片描述
打开这个XML文件,然后在里面的根标签上补上两个属性,只有这样做了,我们编辑这个文件才会有语法提示。结尾的BPMN20.xsd文字是红色的,并不是语法错误,不影响程序运行。
在这里插入图片描述

<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"
                   xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
                   xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
                   xmlns:flowable="http://flowable.org/bpmn" id="diagram_Process_1700583687312"
                   targetNamespace="http://flowable.org/bpmn"
                   xmlns:activiti="http://activiti.org/bpmn"
                   xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">

2.定义任务类

我们拖拽的服务节点属于ServiceTask,是会自动运行的,不需要人工干预。你想让这个节点执行什么功能,必须要声明Java类,把功能代码写到里面。

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;

public class MyService_1 implements JavaDelegate {
    @Override
    public void execute(DelegateExecution delegateExecution) {
        System.out.println("HelloWorld");
    }
}

两个节点对应两个Java类,还得再创建一个:

public class MyService_2 implements JavaDelegate {
    @Override
    public void execute(DelegateExecution delegateExecution) {
        System.out.println("你好世界");
    }
}

接下来我们找到BPMN文件中的两个Task节点,让他们关联上Java类。

<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"
                   xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
                   xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
                   xmlns:flowable="http://flowable.org/bpmn" id="diagram_Process_1700583687312"
                   targetNamespace="http://flowable.org/bpmn"
                   xmlns:activiti="http://activiti.org/bpmn"
                   xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
    <bpmn2:process id="Process_1700583687312" name="业务流程_1700583687312" isExecutable="true">
        <bpmn2:startEvent id="Event_0r7oy1l">
            <bpmn2:extensionElements>
                <flowable:formData/>
            </bpmn2:extensionElements>
            <bpmn2:outgoing>Flow_1wew4mh</bpmn2:outgoing>
        </bpmn2:startEvent>
        <bpmn2:serviceTask id="Activity_0daqsg0" name="服务任务1" flowable:exclusive="false" activiti:class="com.example.workflow.demo_1.MyService_1">
            <bpmn2:incoming>Flow_1wew4mh</bpmn2:incoming>
            <bpmn2:outgoing>Flow_0bhcxay</bpmn2:outgoing>
        </bpmn2:serviceTask>
        <bpmn2:sequenceFlow id="Flow_1wew4mh" sourceRef="Event_0r7oy1l" targetRef="Activity_0daqsg0" />
        <bpmn2:serviceTask id="Activity_0m4d7nx" name="服务任务2" activiti:class="com.example.workflow.demo_1.MyService_2">
            <bpmn2:incoming>Flow_0bhcxay</bpmn2:incoming>
            <bpmn2:outgoing>Flow_0zcquf0</bpmn2:outgoing>
        </bpmn2:serviceTask>
        <bpmn2:sequenceFlow id="Flow_0bhcxay" sourceRef="Activity_0daqsg0" targetRef="Activity_0m4d7nx"/>
        <bpmn2:endEvent id="Event_0r9j4v6">
            <bpmn2:incoming>Flow_0zcquf0</bpmn2:incoming>
        </bpmn2:endEvent>
        <bpmn2:sequenceFlow id="Flow_0zcquf0" sourceRef="Activity_0m4d7nx" targetRef="Event_0r9j4v6"/>
    </bpmn2:process>
    <bpmndi:BPMNDiagram id="BPMNDiagram_1">
        <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1700583687312">
            <bpmndi:BPMNEdge id="Flow_1wew4mh_di" bpmnElement="Flow_1wew4mh">
                <di:waypoint x="168" y="300"/>
                <di:waypoint x="250" y="300"/>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge id="Flow_0bhcxay_di" bpmnElement="Flow_0bhcxay">
                <di:waypoint x="350" y="300"/>
                <di:waypoint x="470" y="300"/>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge id="Flow_0zcquf0_di" bpmnElement="Flow_0zcquf0">
                <di:waypoint x="570" y="300"/>
                <di:waypoint x="702" y="300"/>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNShape id="Event_0r7oy1l_di" bpmnElement="Event_0r7oy1l">
                <dc:Bounds x="132" y="282" width="36" height="36"/>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape id="Activity_0daqsg0_di" bpmnElement="Activity_0daqsg0">
                <dc:Bounds x="250" y="260" width="100" height="80"/>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape id="Event_0r9j4v6_di" bpmnElement="Event_0r9j4v6">
                <dc:Bounds x="702" y="282" width="36" height="36"/>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape id="Activity_0m4d7nx_di" bpmnElement="Activity_0m4d7nx">
                <dc:Bounds x="470" y="260" width="100" height="80"/>
            </bpmndi:BPMNShape>
        </bpmndi:BPMNPlane>
    </bpmndi:BPMNDiagram>
</bpmn2:definitions>

这是各个标签的含义:

<?xml version="1.0" encoding="UTF-8"?>
<!-- 这是BPMN(Business Process Model and Notation)的XML定义文件。 -->
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"
                   xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
                   xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
                   xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
                   xmlns:flowable="http://flowable.org/bpmn"
                   id="diagram_Process_1700583687312"
                   targetNamespace="http://flowable.org/bpmn"
                   xmlns:activiti="http://activiti.org/bpmn"
                   xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">

    <!-- 这是流程定义 -->
    <bpmn2:process id="Process_1700583687312" name="业务流程_1700583687312" isExecutable="true">
        
        <!-- 开始事件 -->
        <bpmn2:startEvent id="startEvent_1">
            <!-- 在此处添加事件的详细信息 -->
        </bpmn2:startEvent>
        
        <!-- 服务任务 -->
        <bpmn2:serviceTask id="serviceTask_1">
            <!-- 在此处添加任务的详细信息 -->
        </bpmn2:serviceTask>
        
        <!-- 序列流 -->
        <bpmn2:sequenceFlow id="sequenceFlow_1" sourceRef="startEvent_1" targetRef="serviceTask_1">
            <!-- 在此处添加序列流的详细信息 -->
        </bpmn2:sequenceFlow>
        
        <!-- 结束事件 -->
        <bpmn2:endEvent id="endEvent_1">
            <!-- 在此处添加事件的详细信息 -->
        </bpmn2:endEvent>
        
    </bpmn2:process>
    
    <!-- BPMN图形定义 -->
    <bpmndi:BPMNDiagram>
        <!-- BPMN平面 -->
        <bpmndi:BPMNPlane>
            <!-- 在此处添加流程图形状的详细信息 -->
        </bpmndi:BPMNPlane>
        
        <!-- BPMN边界 -->
        <bpmndi:BPMNEdge>
            <!-- 在此处添加流程图连线的详细信息 -->
        </bpmndi:BPMNEdge>
        
        <!-- BPMN形状 -->
        <bpmndi:BPMNShape>
            <!-- 在此处添加流程图元素的位置和大小的详细信息 -->
        </bpmndi:BPMNShape>
        
    </bpmndi:BPMNDiagram>
    
</bpmn2:definitions>

BPMN是一种用于描述业务流程的标准化符号和图形表示方法。XML文件中包含了流程定义的各个元素和它们之间的关系。

  • <bpmn2:process>:这是流程的定义,包含了流程的各个元素。

  • id="Process_1700583687312":这是流程的唯一标识符。

  • name="业务流程_1700583687312":这是流程的名称。

  • isExecutable="true":指示流程是否可以执行。

  • <bpmn2:startEvent>:这是开始事件,表示流程的起点。

  • <bpmn2:serviceTask>:这是服务任务,表示流程中的一个具体操作。

  • <bpmn2:sequenceFlow>:这是序列流,表示流程中的连线。

  • <bpmn2:endEvent>:这是结束事件,表示流程的终点。

  • <bpmndi:BPMNDiagram>:这是BPMN图形的定义。

  • <bpmndi:BPMNPlane>:这是BPMN平面,包含了流程图的各个形状。

  • <bpmndi:BPMNEdge>:这是BPMN边界,表示流程图中的连线。

  • <bpmndi:BPMNShape>:这是BPMN形状,表示流程图中的元素的位置和大小。

通过这个XML文件,可以清楚地了解流程的定义和结构,以及各个元素之间的关系。

3.部署工作流

在SpringBoot项目中,Activiti会自动扫描processes目录下面的BPMN流程文件,然后部署到MySQL里面。我们创建的bpmn文件夹只是临时存放bpmn文件的,我们把编辑好的bpmn文件拷贝到processes目录,然后启动SpringBoot项目就自动部署了。
在这里插入图片描述
启动SpringBoot项目的时候,如果控制台输出了下面的提示信息,说明BPMN文件已经部署成功了。
在这里插入图片描述

4.运行工作流

在项目的test目录下的package中创建Demo_1.java测试类,编写Java代码运行工作流。在测试类中,你填写自己的工作流程name名称,不要原封不动的运行下面的代码。

import org.activiti.engine.RuntimeService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest
public class Demo_1 {
    @Resource
    private RuntimeService runtimeService;
    
    @Test
    void run() {
        runtimeService.startProcessInstanceByKey("Process_1700583687312").getProcessInstanceId();
    }
}

测试类运行成功之后,在控制台你会看到输出的HelloWorld和你好世界,也就是说无需人为干预,只要Activiti执行工作流就会自动运行服务节点和任务类。

结论

通过将Activiti 7.0整合到您的Spring Boot项目中,您可以轻松地创建和管理业务流程。使用本文提供的步骤和技巧,您可以开始构建强大且可扩展的应用程序。祝您成功!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

abcccccccccccccccode

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

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

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

打赏作者

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

抵扣说明:

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

余额充值