【activiti 7】spring boot集成activiti 7工作流

前言

1,什么是工作流:

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

2,工作流系统:

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

3, 实现方式:

在没有专门的工作流引擎之前,我们之前为了实现流程控制,通常的做法就是采用状态字段的值来跟踪流程的变化情况。这样不用角色的用户,通过状态字段的取值来决定记录是否显示。
针对有权限可以查看的记录,当前用户根据自己的角色来决定审批是否合格的操作。如果合格将状态字段设置一个值,来代表合格;当然如果不合格也需要设置一个值来代表不合格的情况。
这是一种最为原始的方式。通过状态字段虽然做到了流程控制,但是当我们的流程发生变更的时候,这种方式所编写的代码也要进行调整。
那么有没有专业的方式来实现工作流的管理呢?并且可以做到业务流程变化之后,我们的程序可以不用改变,如果可以实现这样的效果,那么我们的业务系统的适应能力就得到了极大提升。


一、activiti 7概述

1.1 activiti介绍

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

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

官方网站:https://www.activiti.org/

1.2 BPM与BPMN

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

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事件

Event 用一个圆圈表示,它是流程中运行过程中发生的事情。事件的发生会影响到流程的流转.事件包含Start\Intermediate\End三种类型.如下图:
在这里插入图片描述

Activities活动

活动用圆角矩形表示,一个活动多个活动组成,活动的类型分为Task和Sub-Process。如下下图:
在这里插入图片描述

Gateways 网关

网关用菱形表示,用于控制流程的分支和聚合,具体符号表示如下:
在这里插入图片描述

Data 数据

  • Data Objects 数据对象
  • Data Inputs 数据输入
  • Data OutPuts 数据输出
  • Data Stores 数据存储
    在这里插入图片描述

Connecting Objects 连接对象

  • Sequence Flows 序列流:Sequence Flows 用实线实心箭头表示,代表流程中将被执行的活动的执行顺序
  • Message Flows 消息流:Message Flows 用虚线空心箭头表示,第阿宝2个分开的流程参与者直接发送或者接收到的消息流.
  • Associations 结合关系
  • Associations 用点状虚线表示,用于显示活动的输入输出.
  • Data Associations 数据结合关系

Swimlanes 泳道

  • Pools 池
  • Lanes 道

Artifacts 工件

1.Group 组

2.Text Annotation 文本注释

BPMN2-Diagram Types 图类型

1.Private Processes 私有流程

2.Public Processes 共有流程

3.Choreographies Processes 组合流程

相关资源

  1. BPMN2.0规范: http://www.omg.org/spec/BPMN/2.0/
  2. BPMN2编辑器: http://sourceforge.net/projects/bpmn/files/BPMN%20Editor/
  3. BPMN社区: http://www.bpmn123.net

Bpmn图形其实是通过xml表示业务流程,上面的.bpmn文件使用文本编辑器打开:

<?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" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
  <process id="myProcess" name="My process" isExecutable="true">
    <startEvent id="startevent1" name="Start"></startEvent>
    <userTask id="usertask1" name="请假申请"></userTask>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
    <userTask id="usertask2" name="部门经理审核"></userTask>
    <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>
    <userTask id="usertask3" name="总经理复核"></userTask>
    <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow4" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_myProcess">
    <bpmndi:BPMNPlane bpmnElement="myProcess" id="BPMNPlane_myProcess">
      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="130.0" y="160.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
        <omgdc:Bounds height="55.0" width="105.0" x="210.0" y="150.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
        <omgdc:Bounds height="55.0" width="105.0" x="360.0" y="150.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">
        <omgdc:Bounds height="55.0" width="105.0" x="510.0" y="150.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="660.0" y="160.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="165.0" y="177.0"></omgdi:waypoint>
        <omgdi:waypoint x="210.0" y="177.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
        <omgdi:waypoint x="315.0" y="177.0"></omgdi:waypoint>
        <omgdi:waypoint x="360.0" y="177.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
        <omgdi:waypoint x="465.0" y="177.0"></omgdi:waypoint>
        <omgdi:waypoint x="510.0" y="177.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
        <omgdi:waypoint x="615.0" y="177.0"></omgdi:waypoint>
        <omgdi:waypoint x="660.0" y="177.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

二、使用步骤

集成activiti
Activiti是一个工作流引擎(其实就是一堆jar包API),业务系统访问(操作)activiti的接口,就可以方便的操作流程相关数据,这样就可以把工作流环境与业务系统的环境集成在一起。

流程定义
使用activiti流程建模工具(activity-designer)定义业务流程(.bpmn文件) 。
.bpmn文件就是业务流程定义文件,通过xml定义业务流程。

流程定义部署
activiti部署业务流程定义(.bpmn文件)。
使用activiti提供的api把流程定义内容存储起来,在Activiti执行过程中可以查询定义的内容
Activiti执行把流程定义内容存储在数据库中(一次部署可以部署多个流程定义)

启动流程实例
流程实例也叫:ProcessInstance
启动一个流程实例表示开始一次业务流程的运行。
在员工请假流程定义部署完成后,如果张三要请假就可以启动一个流程实例,如果李四要请假也启动一个流程实例,两个流程的执行互相不影响。

用户查询待办任务(Task)
因为现在系统的业务流程已经交给activiti管理,通过activiti就可以查询当前流程执行到哪了,当前用户需要办理什么任务了,这些activiti帮我们管理了,而不需要开发人员自己编写在sql语句查询。

用户办理任务
用户查询待办任务后,就可以办理某个任务,如果这个任务办理完成还需要其它用户办理,比如采购单创建后由部门经理审核,这个过程也是由activiti帮我们完成了。(当用户的任务被办理后,相应的任务节点就会删除)

流程结束
当任务办理完成没有下一个任务结点了,这个流程实例就完成了。(这个时候流程实例就会删除)

三,spring boot集成activiti

3.1 引入依赖

Activiti下载地址:http://activiti.org/download.html ,Maven的依赖如下:

 <!-- 引入Activiti7 -->
 <dependency>
     <groupId>org.activiti</groupId>
     <artifactId>activiti-spring-boot-starter</artifactId>
     <version>7.1.0.M2</version>
     <exclusions>
         <exclusion>
             <groupId>org.mybatis</groupId>
             <artifactId>mybatis</artifactId>
         </exclusion>
         <exclusion>
             <artifactId>spring-security-config</artifactId>
             <groupId>org.springframework.security</groupId>
         </exclusion>
         <exclusion>
             <artifactId>spring-security-crypto</artifactId>
             <groupId>org.springframework.security</groupId>
         </exclusion>
         <exclusion>
             <artifactId>spring-security-web</artifactId>
             <groupId>org.springframework.security</groupId>
         </exclusion>
         <exclusion>
             <artifactId>spring-security-core</artifactId>
             <groupId>org.springframework.security</groupId>
         </exclusion>
         <exclusion>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-actuator</artifactId>
         </exclusion>
         <exclusion>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
         </exclusion>
     </exclusions>
 </dependency>
 <dependency>
     <groupId>org.activiti.dependencies</groupId>
     <artifactId>activiti-dependencies</artifactId>
     <version>7.1.0.M2</version>
     <type>pom</type>
 </dependency>
 <!-- 生成流程图 -->
 <dependency>
     <groupId>org.activiti</groupId>
     <artifactId>activiti-image-generator</artifactId>
     <version>7.1.0.M2</version>
 </dependency>

Database:
activiti运行需要有数据库的支持,支持的数据库有:h2, mysql, oracle, postgres, mssql, db2

3.2 配置yml文件

server:
  port: 8000
spring:
  datasource:
    url: jdbc:mysql://aliyuncs.com:3306/activiti
    username: *****
    password: *****
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      minimum-idle: 0
      maximum-pool-size: 20
      idle-timeout: 10000
      auto-commit: true
      connection-test-query: SELECT 1
  # activiti7配置
  activiti:
    # 自动部署验证设置:true-开启(默认)、false-关闭
    check-process-definitions: false
    # 保存历史数据
    history-level: full
    # 检测历史表是否存在
    db-history-used: true
    # 关闭自动部署
    deployment-mode: never-fail
    # 对数据库中所有表进行更新操作,如果表不存在,则自动创建
    # create_drop:启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)
    # drop-create:启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)
    database-schema-update: true
    # 解决频繁查询SQL问题
    async-executor-activate: false
    #启用异步执行器
    job-executor-activate: false

3.3 安装ide插件流程设计器(BPMN-Activiti-Diagram)

在ide中安装插件

File -> settings -> plugins -> `BPMN-Activiti-Diagram`

安装好后就可以设计流程了。

在resource目录下新建一process个文件夹,new一个BPMN 2.0 file
在这里插入图片描述
选择刚刚新建的BPMN文件,右键找到如下选择,然后开始画流程图(画流程图时,BPMN文件中就会生成对应的xml属性)
在这里插入图片描述
在这里插入图片描述
在这里讲一下流程图下面一些对应的属性含义:

  • name:流程节点的名称或者流程定义的名称
  • key:流程定义key即流程定义的标识,通过properties视图查看流程的key
  • Assignee:在properties视图指定每个任务结点的负责人

画好后可以右键选择导出流程图片:
在这里插入图片描述

3.4 生成表

启动项目,自动在对应的数据库生成25张表
在这里插入图片描述

注意:在activiti 7.1.M版本生成的表会丢失一些字段,我们需要自己补充
运行一段sql补全缺少的表字段

-- ----------------------------
-- 修复Activiti7的M4版本缺失字段Bug
-- ----------------------------
alter table ACT_RE_DEPLOYMENT add column PROJECT_RELEASE_VERSION_ varchar(255) DEFAULT NULL;
alter table ACT_RE_DEPLOYMENT add column VERSION_ varchar(255) DEFAULT NULL;

3.5 表结构简介

表的命名规则和作用
Activiti 的表都以 ACT_ 开头。

第二部分是表示表的用途的两个字母标识。 用途也和服务的 API 对应。

  • ACT_RE :'RE’表示 repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
  • ACT_RU:'RU’表示 runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。
  • ACT_HI:'HI’表示 history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
  • ACT_GE : GE 表示 general。 通用数据, 用于不同场景下

Activiti数据表介绍

表分类 表名 解释
一般数据
[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_RE_DEPLOYMENT] 部署单元信息
[ACT_RE_MODEL] 模型信息
[ACT_RE_PROCDEF] 已部署的流程定义
运行实例表
[ACT_RU_EVENT_SUBSCR] 运行时事件
[ACT_RU_EXECUTION] 运行时流程执行实例
[ACT_RU_IDENTITYLINK] 运行时用户关系信息,存储任务节点与参与者的相关信息
[ACT_RU_JOB] 运行时作业
[ACT_RU_TASK] 运行时任务
[ACT_RU_VARIABLE] 运行时变量表

3.6 工作流引擎及服务

工作流引擎(ProcessEngine),相当于一个门面接口,通过ProcessEngineConfiguration创建processEngine,通过ProcessEngine创建各个service接口。

Service是工作流引擎提供用于进行工作流部署、执行、管理的服务接口,我们使用这些接口可以就是操作服务对应的数据表

但是在springBoot中不需要创建,直接拿来用即可。

下面介绍一下需要用的服务接口

service名称 service作用
RepositoryService activiti的资源管理类
RuntimeService activiti的流程运行管理类
TaskService activiti的任务管理类
HistoryService activiti的历史管理类
ManagerService activiti的引擎管理类

RepositoryService
是activiti的资源管理类,提供了管理和控制流程发布包和流程定义的操作。使用工作流建模工具设计的业务流程图需要使用此service将流程定义文件的内容部署到计算机。

除了部署流程定义以外还可以:查询引擎中的发布包和流程定义。

暂停或激活发布包,对应全部和特定流程定义。 暂停意味着它们不能再执行任何操作了,激活是对应的反向操作。获得多种资源,像是包含在发布包里的文件, 或引擎自动生成的流程图。

获得流程定义的pojo版本, 可以用来通过java解析流程,而不必通过xml。

RuntimeService
Activiti的流程运行管理类。可以从这个服务类中获取很多关于流程执行相关的信息

TaskService
Activiti的任务管理类。可以从这个类中获取任务的信息。

HistoryService
Activiti的历史管理类,可以查询历史信息,执行流程时,引擎会保存很多数据(根据配置),比如流程实例启动时间,任务的参与者, 完成任务的时间,每个流程实例的执行路径,等等。 这个服务主要通过查询功能来获得这些数据。

ManagementService
Activiti的引擎管理类,提供了对 Activiti 流程引擎的管理和维护功能,这些功能不在工作流驱动的应用程序中使用,主要用于 Activiti 系统的日常维护。


四,activiti 的使用

4.1 流程定义查询及部署

 /**
     * 查询流程定义列表
     * */
    @Override
    public Page<ProcessInstanceDto> ProcessDefinition(ActivitiParam param) {
    
    
        Page<ProcessInstanceDto> page = new Page(param.getCurrent(), param.getPageSize());
        Page<ProcessInstanceDto> pg = processDefinitionMapper.ProcessDefinition(page,param);
        if(!pg.getRecords().isEmpty()){
    
    
            pg.getRecords().forEach(processInstance ->{
    
    
                Deployment deployment = repositoryService.createDeploymentQuery()
                        .deploymentId(processInstance.getDeploymentId()).singleResult();
                processInstance.setDeploymentTime(deployment.getDeploymentTime());
            });
        }
        return pg;
    }

这里我没有使用activiti自带的查询,自己写一个查询列表接口

 /**
     * 手动流程部署
     * springboot启动就会自动部署流程
     * 部署时操作的表:act_ge_property(update)
     * act_re_procdef  ,act_re_deployment  ,act_ge_bytearray(insert)
     */
    @Override
    public void initDeployment(MultipartFile file) throws IOException {
    
    
        if(!file.isEmpty()){
    
    
            String fileName = StringUtils.cleanPath(file.getOriginalFilename());
            // 得到输入流(字节流)对象
            InputStream inputStream = file.getInputStream();
            // 文件的扩展名
            String extension = FilenameUtils.getExtension(fileName);
            // zip或者bar类型的文件用ZipInputStream方式部署
            if (extension.equals("zip") || extension.equals("bar")) {
    
    
                ZipInputStream zip = new ZipInputStream(inputStream);
                repositoryService.createDeployment()
                        .addClasspathResource(fileName)
                        .addZipInputStream(zip).deploy();
            } else if (extension.equals("xml")){
    
    
                // xml类型的文件
                repositoryService.createDeployment().addInputStream(fileName,inputStream).deploy();
            }
            return;
        }
        throw new RuntimeException("空文件");
    }
 /**
     * 挂起/激活流程
     */
    @Override
    public void suspendActiveProcessDefinition(ActivitiParam param) {
    
    
        String definitionId = param.getProcessDefinitionId();
        if(param.getSuspensionState()==2){
    
    
//          如果是挂起,可以执行激活的操作,参数1:流程定义id 参数2:是否级联挂起该流程定义下的流程实例,参数3:激活时间
            repositoryService.activateProcessDefinitionById(definitionId,
                    true,
                    new Date());
            System.out.println("流程定义id:"+definitionId+",已激活");
        }else {
    
    
//          如果是激活状态,改为挂起状态,参数1:流程定义id 参数2:是否级联挂起该流程定义下的流程实例 参数3 :暂停的时间
            repositoryService.suspendProcessDefinitionById(definitionId,
                    true,
                    new Date());
            System.out.println("流程定义id:"+definitionId+",已挂起");
        }

    }

在process下面的bpmn文件在项目启动时就会自动部署

4.2 启动流程实例及处理任务

启动流程实例其实就是有人发起一个申请

 /**
     * 初始化流程实例
     * 启动流程实例
     * 部署时操作的表:act_ge_property(update)
     * insert:act_hi_taskinst act_hi_actinst act_hi_procinst act_hi_identitylink
     * act_ru_execution、act_ru_identitylink、act_ru_task
     */
    @Override
    public void initProcessInstance(ActivitiParam param) {
    
    
        // 流程定义KEY(流程图的id,因为在表里存的是key)
        String processDefinitionKey = param.getKey();
        // 业务表KEY(用于把业务数据与Activiti7流程数据相关联)
        String businessKey = "4208169753200945";
        // 业务参数
        Map<String, Object> variables = new HashMap<>(16);
        variables.put("name","***");
        variables.put("time","一天");
        variables.put("description","相亲");
        org.activiti.engine.runtime.ProcessInstance processInstance = this.runtimeService
                .startProcessInstanceByKey(processDefinitionKey, businessKey, variables);
        System.out.println("流程实例ID:" + processInstance.getProcessInstanceId());
    }
 /**
     * 查询我的代办任务
     */
    @RequestMapping("/listTasksByAssignee")
    @ResponseBody
    public List<Task> listTasksByAssignee() {
    
    
        List<Task> tasks = taskService.listTasksByAssignee();
        return tasks;
    }
 /**
     * 完成任务
     */
    @RequestMapping("/completeTask")
    @ResponseBody
    public void completeTask() {
    
    
        taskService.completeTask();
    }

4.3 编辑器对应接口

流程文件存在数据库里的是二进制的xml,取出来后只需转成string即可,保存也是一样

 /**
     * 获取模型xml数据
     * */
    @Override
    public String getModelResource(String modelId) throws Exception {
    
    

        Model model = repositoryService.getModel(modelId);
        if (model == null) {
    
    
            throw new Exception("未找到该模型!");
        }
        try {
    
    
            byte[] modelBytes = repositoryService.getModelEditorSource(model.getId());
            String xmlString = new String(modelBytes, StandardCharsets.UTF_8);
            return xmlString;
        } catch (Exception e) {
    
    
            LOGGER.error("检索流程模型XML时出错", e);
            return "检索流程模型XML时出错";
        }
    }

猜你喜欢

转载自blog.csdn.net/m0_71621983/article/details/131832538