SpringBoot集成Activiti7工作流简单使用

723 阅读11分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第22天,点击查看活动详情

前言

1、工作流介绍

1. 概念

工作流(Workflow),就是通过计算机对业务流程自动化执行管理。它主要解决的是“使在多个参与者之间按照某种预定义的规则自动进行传递文档、信息或任务的过程,从而实现某个预期的业务目标,或者促使此目标的实现”。

2. 工作流系统

一个软件系统中具有工作流的功能,我们把它称为工作流系统,一个系统中工作流的功能是什么?就是对系统的业务流程进行自动化管理,所以工作流是建立在业务流程的基础上,所以一个软件的系统核心根本上还是系统的业务流程,工作流只是协助进行业务流程管理。即使没有工作流业务系统也可以开发运行,只不过有了工作流可以更好的管理业务流程,提高系统的可扩展性。

3. 适用行业

消费品行业,制造业,电信服务业,银证险等金融服务业,物流服务业,物业服务业,物业管理,大中型进出口贸易公司,政府事业机构,研究院所及教育服务业等,特别是大的跨国企业和集团公司。

4. 具体应用
  1. 关键业务流程:订单、报价处理、合同审核、客户电话处理、供应链管理等

  2. 行政管理类:出差申请、加班申请、请假申请、用车申请、各种办公用品申请、购买申请、日报周报等凡是原来手工流转处理的行政表单。

  3. 人事管理类:员工培训安排、绩效考评、职位变动处理、员工档案信息管理等。

  4. 财务相关类:付款请求、应收款处理、日常报销处理、出差报销、预算和计划申请等。

  5. 客户服务类:客户信息管理、客户投诉、请求处理、售后服务管理等。

  6. 特殊服务类:ISO系列对应流程、质量管理对应流程、产品数据信息管理、贸易公司报关处理、物流公司货物跟踪处理等各种通过表单逐步手工流转完成的任务均可应用工作流软件自动规范地实施。

5. 实现方式

在没有专门的工作流引擎之前,我们之前为了实现流程控制,通常的做法就是采用状态字段的值来跟踪流程的变化情况。这样不用角色的用户,通过状态字段的取值来决定记录是否显示。

针对有权限可以查看的记录,当前用户根据自己的角色来决定审批是否合格的操作。如果合格将状态字段设置一个值,来代表合格;当然如果不合格也需要设置一个值来代表不合格的情况。

这是一种最为原始的方式。通过状态字段虽然做到了流程控制,但是当我们的流程发生变更的时候,这种方式所编写的代码也要进行调整。

那么有没有专业的方式来实现工作流的管理呢?并且可以做到业务流程变化之后,我们的程序可以不用改变,如果可以实现这样的效果,那么我们的业务系统的适应能力就得到了极大提升。

2、Activiti7概述

1. 介绍

Alfresco软件在2010年5月17日宣布Activiti业务流程管理(BPM)开源项目的正式启动,其首席架构师由业务流程管理BPM的专家 Tom Baeyens担任,Tom Baeyens就是原来jbpm的架构师,而jbpm是一个非常有名的工作流引擎,当然activiti也是一个工作流引擎。

Activiti是一个工作流引擎, activiti可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言BPMN2.0进行定义,业务流程按照预先定义的流程进行执行,实现了系统的流程由activiti进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,从而提高系统的健壮性,同时也减少了系统开发维护成本。

Activiti官方网站

2. BPM

BPM(Business Process Management),即业务流程管理,是一种规范化的构造端到端的业务流程,以持续的提高组织业务效率。常见商业管理教育如EMBA、MBA等均将BPM包含在内。

3. BPM软件

BPM软件就是根据企业中业务环境的变化,推进人与人之间、人与系统之间以及系统与系统之间的整合及调整的经营方法与解决方案的IT工具。

通过BPM软件对企业内部及外部的业务流程的整个生命周期进行建模、自动化、管理监控和优化,使企业成本降低,利润得以大幅提升。

BPM软件在企业中应用领域广泛,凡是有业务流程的地方都可以BPM软件进行管理,比如企业人事办公管理、采购流程管理、公文审批流程管理、财务管理等。

4. BPMN

BPMN(Business Process Model AndNotation)- 业务流程模型和符号 是由BPMI(BusinessProcess Management Initiative)开发的一套标准的业务流程建模符号,使用BPMN提供的符号可以创建业务流程。

2004年5月发布了BPMN1.0规范.BPMI于2005年9月并入OMG(The Object Management Group对象管理组织)组织。OMG于2011年1月发布BPMN2.0的最终版本。

BPMN 是目前被各 BPM 厂商广泛接受的 BPM 标准。Activiti 就是使用 BPMN 2.0 进行流程建模、流程执行管理,它包括很多的建模符号,比如:

Event

用一个圆圈表示,它是流程中运行过程中发生的事情。

image.png

活动用圆角矩形表示,一个流程由一个活动或多个活动组成 image.png

一、安装Activiti环境

高版本IDEA actiBPM 插件已经无法安装,可以选择安装Activiti BPMN visualizer

image.png

新建一个.bpmn的文件,文件存放位置自己定义

image.png

在创建好的文件中任意位置右键,选择 View BPMN Diagram,打开可视化界面(流程定义的界面)

image.png

进入可视化编辑器,右键 start events –> start event 画一个开始事件

image.png

1671170516259.png

二、springboot集成

1. 添加pom依赖

<!--添加activiti和SpringBoot整合的依赖
            MyBatis版本会有冲突,所以需要排除,所需数据库的依赖根据需求添加-->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter</artifactId>
            <version>7.0.0.SR1</version>
            <exclusions>
                <exclusion>
                    <artifactId>commons-io</artifactId>
                    <groupId>commons-io</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>commons-lang3</artifactId>
                    <groupId>org.apache.commons</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>mybatis</artifactId>
                    <groupId>org.mybatis</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--activiti可以绘制流程的的依赖-->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-image-generator</artifactId>
            <version>7.0.0.SR1</version>
            <exclusions>
                <exclusion>
                    <artifactId>commons-io</artifactId>
                    <groupId>commons-io</groupId>
                </exclusion>
            </exclusions>
        </dependency>

2. 修改yml配置文件

编辑一下 .yml 配置文件,需要在 spring 节点下新增关于 Activiti7 的配置

spring:

    # activiti工作流
    activiti:
        #1.flase:默认值。activiti在启动时,对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常
        #2.true: activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建
        #3.create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)
        #4.drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)
        database-schema-update: true
        # 检测历史信息表是否存在,activiti7默认不生成历史信息表,开启历史表
        db-history-used: true
        # 历史记录存储等级
        history-level: full
        check-process-definitions: true
    
    #不同配置文件中存在id或者name相同的bean定义,后面加载的bean定义会覆盖前面的bean定义
    main:
        allow-bean-definition-overriding: true

三、启动项目,生成对应表结构

项目成功启动,会在数据库生成 act_前缀开头的25张表,那就代表我们成功的将 Activiti7 和 SpringBoot项目整合到一起了

表结构如下:

表分类表名称表含义
 act_evt_log事件处理日志表
一般数据act_ge_bytearray通用的流程定义和流程资源
 act_ge_property系统相关属性
流程历史记录act_hi_actinst历史的流程实例
 act_hi_attachment历史的流程附件
 act_hi_comment历史的说明性信息
 act_hi_detail历史的流程运行中的细节信息
 act_hi_identitylink历史的流程运行过程中用户关系
 act_hi_procinst历史的流程实例
 act_hi_taskinst历史的任务实例
 act_hi_varinst历史的流程运行中的变量信息
用户用户组表act_id_group身份信息-组信息
 act_id_info身份信息-组信息
 act_id_membership身份信息-用户和组关系的中间表
 act_id_user身份信息-用户信息
 act_procdef_info死信任务
流程定义表act_re_deployment部署单元信息
 act_re_model模型信息
 act_re_procdef已部署的流程定义
运行实例表act_ru_deadletter_job执行失败任务表
 act_ru_event_subscr运行时事件
 act_ru_execution运行时流程执行实例
 act_ru_identitylink运行时用户关系信息
 act_ru_job运行时作业
 act_ru_suspended_job运行时暂停任务
 act_ru_task运行时任务
 act_ru_timer_job运行时定时任务
 act_ru_variable运行时变量表

四、使用API测试

接下来就写几个方法模拟一下相关流程:

Service总览

Service接口说明
RepositoryServiceActiviti的资源管理接口
RuntimeServiceActiviti的流程运行管理接口
TaskServiceActiviti的任务管理接口
HistoryServiceActiviti的历史管理接口
ManagementServiceActiviti的引擎管理接口
  • RepositoryService,是Activiti的资源管理接口,提供了管理和控制流程发布包和流程定义的操作。使用工作流建模工具设计的业务流程图需要使用此Service将流程定义文件的内容部署到计算机中。
  • RuntimeService,是Activiti的流程运行管理接口,可以从这个接口中获取很多关于流程执行相关的信息。
  • TaskService,是Activiti的任务管理接口,可以从这个接口中获取任务的信息。
  • HistoryService,是Activiti的历史管理类,可以查询历史信息,执行流程时,引擎会包含很多数据(根据配置),比如流程实例启动时间,任务的参与者,完成任务的时间,每个流程实例的执行路径,等等。
  • ManagementService,是Activiti的引擎管理接口,提供了对Activiti流程引擎的管理和维护功能,这些功能不在工作流驱动的应用程序中使用,主要用于Activiti系统的日常维护。

创建流程

public void createActiviti() {
    Deployment deployment = repositoryService.createDeployment()
        // 名称
        .name("请假流程")
        // 资源
        .addClasspathResource("acviti/learn.bpmn20.xml")
        .deploy();
    System.out.println("流程id:" + deployment.getId());
    System.out.println("流程名称:" + deployment.getName());
}

image.png 创建一个流程的方式有多种;

  • addClasspathResource通过xml文件路径来创建,上述方式就是如此;
  • addString通过xml字符串的方式创建,第一个参数是文件名(可以自己定义),第二个参数是xml的字符串;
  • addBpmnModel通过创建BpmnModel对象的方式创建流程;
  • addBytes 字节
  • addInputStream 流
  • addZipInputStream 压缩包

执行结果:

image.png

打开act_ge_bytearray表: image.png

打开act_re_deployment表: image.png

打开act_re_procdef表: image.png

开启流程

public void startActiviti() {
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("learn");
    System.out.println("流程id:" + processInstance.getProcessDefinitionId());
    System.out.println("流程实例id:" + processInstance.getId());
    System.out.println("当前活动id:" + processInstance.getActivityId());
}

执行结果: image.png

因为是刚开始流程,所以没有人需要处理,当前活动id为null

这时查看act_hi_actinst就可以看到下一个需要处理的人 image.png

查询任务

public void findTask() {
    List<Task> taskList = taskService.createTaskQuery()
        // 流程id
        .processDefinitionKey("learn")
        // 处理人
        .taskAssignee("张三")
        .list();
    for (Task task : taskList) {
        System.out.println("任务id:" + task.getId());
        System.out.println("任务负责人:" + task.getAssignee());
        System.out.println("任务名称:" + task.getName());
    }

}

注:张三这个处理人,是在画流程图那边添加的

执行结果:

image.png

查询的数据来自于act_ru_task image.png

处理任务

public void handleTask() {
    Task task = taskService.createTaskQuery()
        // 流程id
        .processDefinitionKey("learn")
        // 处理人
        .taskAssignee("张三")
        .singleResult();
    taskService.complete(task.getId());
}

act_hi_actinst表中 处理时间已填充,并添加了一下个处理人 image.png

act_ru_task表,张三 的数据不在了,新增了李四的数据 image.png

完成任务

public void finishHandleTask() {
    Task task = taskService.createTaskQuery()
        // 流程id
        .processDefinitionKey("learn")
        // 处理人
        .taskAssignee("李四")
        .singleResult();
    taskService.complete(task.getId());
}

处理完成后act_ru_task表已经没有数据了

获取历史

public void getHistoryList() {
    List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
        .processDefinitionId("learn:1:f5bb77cb-7cfc-11ed-a505-d4d25271f7c9")
        .list();
    for (HistoricTaskInstance historicTaskInstance : list) {
        System.out.println("开始时间:" + DateUtil.formatDateTime(historicTaskInstance.getStartTime()));
        System.out.println("结束时间:" + DateUtil.formatDateTime(historicTaskInstance.getEndTime()));
        System.out.println("流程名称:" + historicTaskInstance.getName());
        System.out.println("处理人名称:" + historicTaskInstance.getAssignee());
    }
}

执行结果:

image.png

五、网关

1. 排他网关

排他网关(ExclusiveGateway)(异或网关或基于数据的排他网关),用来在流程中实现决策。当流程执行到这个网关的时候,所有分支都会判断条件是否为true,如果为true则执行该分支。

注意: 排他网关只会选择一个为true的分支执行(即使有两个分支条件都为true,排他网关也只会选择一条分支去执行,选择序号小的路径执行)

image.png

2. 并行网关

并行网关(InclusiveGateway)允许将流程分成多条分支,也可以把多条分支汇聚到一起,并行网关的功能是基于进入和外出的顺序流的。

注意:并行网关不会解析条件。即使顺序流中定义了条件,也会被忽略

image.png

3. 包含网关

包含网关可以看做是排他网关和并行网关的结合体。

需求:请假申请大于3天需要由项目经理审批,小于等于3天由技术经理审批,申请必须经过人事助理审批。

image.png