从零玩转Activiti7工作流-2021-09-12-16-22-07

Posted 杨不易呀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从零玩转Activiti7工作流-2021-09-12-16-22-07相关的知识,希望对你有一定的参考价值。

title: 从零玩转Activiti7工作流
date: 2021-09-12 16:22:08.51
updated: 2021-12-26 17:43:12.171
url: https://www.yby6.com/archives/2021-09-12-16-22-07
categories: 
- 工作流
tags: 

Activiti

讲师:波波

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

课程内容的介绍

  1. Activiti基础篇
  2. Activiti进阶篇
  3. Activiti整合篇

一、Activiti基础篇

1.工作流介绍

1.1 工作流概念介绍

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

1.2 工作流系统

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

1.3 适用行业

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

1.4 具体应用

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

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

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

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

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

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

1.5 实现方式

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

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

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

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

2.Activiti介绍

2.1 介绍

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

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

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

2.1.1 BPM

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

2.1.2 BPM软件

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

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

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

2.1.3 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的最终版本。

具体发展历史如下:

![clip_image002-1573894913998](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\clip_image002-1573894913998.jpg)

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

Event

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

![clip_image002-1573894954565](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\clip_image002-1573894954565.jpg)

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

![clip_image002-1573894978125](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\clip_image002-1573894978125.jpg)

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   x="130.0" y="160.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
        <omgdc:Bounds   x="210.0" y="150.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
        <omgdc:Bounds   x="360.0" y="150.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">
        <omgdc:Bounds   x="510.0" y="150.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
        <omgdc:Bounds   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>

2.2 使用步骤

部署activiti

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

流程定义

使用activiti流程建模工具(activity-designer)定义业务流程(.bpmn文件) 。

.bpmn文件就是业务流程定义文件,通过xml定义业务流程。

流程定义部署

activiti部署业务流程定义(.bpmn文件)。

使用activiti提供的api把流程定义内容存储起来,在Activiti执行过程中可以查询定义的内容

Activiti执行把流程定义内容存储在数据库中

启动一个流程实例

流程实例也叫:ProcessInstance

启动一个流程实例表示开始一次业务流程的运行。

在员工请假流程定义部署完成后,如果张三要请假就可以启动一个流程实例,如果李四要请假也启动一个流程实例,两个流程的执行互相不影响。

用户查询待办任务(Task)

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

用户办理任务

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

流程结束

当任务办理完成没有下一个任务结点了,这个流程实例就完成了。

3.Activiti应用

3.1Activiti的基本使用

3.1.1 创建Maven项目

​ 创建一个普通的Maven项目,并添加相关的依赖

    <properties>
        <slf4j.version>1.6.6</slf4j.version>
        <log4j.version>1.2.12</log4j.version>
        <activiti.version>7.0.0.Beta1</activiti.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-engine</artifactId>
            <version>$activiti.version</version>
        </dependency>
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring</artifactId>
            <version>$activiti.version</version>
        </dependency>
        <!-- bpmn 模型处理 -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-bpmn-model</artifactId>
            <version>$activiti.version</version>
        </dependency>
        <!-- bpmn 转换 -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-bpmn-converter</artifactId>
            <version>$activiti.version</version>
        </dependency>
        <!-- bpmn json数据转换 -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-json-converter</artifactId>
            <version>$activiti.version</version>
        </dependency>
        <!-- bpmn 布局 -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-bpmn-layout</artifactId>
            <version>$activiti.version</version>
            <exclusions>
                <exclusion>
                    <groupId>com.github.jgraph</groupId>
                    <artifactId>jgraphx</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- activiti 云支持 -->
        <dependency>
            <groupId>org.activiti.cloud</groupId>
            <artifactId>activiti-cloud-services-api</artifactId>
            <version>$activiti.version</version>
        </dependency>
        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>
        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
        <!-- 链接池 -->
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!-- log start -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>$log4j.version</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>$slf4j.version</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>$slf4j.version</version>
        </dependency>
    </dependencies>

3.1.2 log4j

添加一个日志文件log4j.properties

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%dISO8601 %-6r[%15.15t] %-5p %30.30c %x - %m\\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\\log\\act\\activiti.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%dISO8601 %-6r[%15.15t] %-5p %30.30c %x - %m\\n

3.1.3 添加Activiti配置文件

我们在本案例中使用的数据库是mysql8.0.

Activiti的默认的使用方式是要求我们在resources下创建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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration" id="processEngineConfiguration">
        <property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="jdbcUrl" value="jdbc:mysql:///activiti2?characterEncoding=utf-8&amp;nullCatalogMeansCurrent=true&amp;serverTimezone=UTC" />

        <property name="jdbcUsername" value="root" />
        <property name="jdbcPassword" value="123456" />
        <property name="databaseSchemaUpdate" value="true" />
        <!--<property name="dataSource" ref="dataSource" />-->
    </bean>
    <bean class="org.apache.commons.dbcp.BasicDataSource" id="dataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
                <property name="url" value="jdbc:mysql:///activiti2?characterEncoding=utf-8&amp;nullCatalogMeansCurrent=true&amp;serverTimezone=UTC" />

        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="maxActive" value="3" />
        <property name="maxIdle" value="2" />
    </bean>
</beans>

3.1.4 Java程序生成表结构

创建一个工具类,调用Activiti的工具类来生成activiti需要的表结构

public class Test01 

    /**
     * 生成Activiti的相关的表结构
     */
    @Test
    public void test01()
        // 使用classpath下的activiti.cfg.xml中的配置来创建 ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        System.out.println(engine);
    

执行的效果

![image-20210517210155782](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210517210155782.png)

执行完成后我们查看数据库,在其中创建了25张表,结果如下:

![image-20210517210259536](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210517210259536.png)

3.2 表结构介绍

3.2.1 表的命名规则和作用

看到刚才创建的表,我们发现Activiti 的表都以 ACT_ 开头。

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

3.2.2 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.3 ProcessEngine创建方式

​ 前面使用的是getDefaultProcessEngine()方法来加载classpath下的 activiti.cfg.xml文件,有些情况下我们可能没有按照默认的方式来处理,那这时我们应该怎么办呢?

    /**
     * 自定义的方式来加载配置文件
     */
    @Test
    public void test02()
        // 首先创建ProcessEngineConfiguration对象
        ProcessEngineConfiguration configuration =
                ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        // 通过ProcessEngineConfiguration对象来创建 ProcessEngine对象
        ProcessEngine processEngine = configuration.buildProcessEngine();
    

3.4 Servcie服务接口

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

3.4.1 Service创建方式

通过ProcessEngine创建Service

方式如下:

RuntimeService runtimeService = processEngine.getRuntimeService();
RepositoryService repositoryService = processEngine.getRepositoryService();
TaskService taskService = processEngine.getTaskService();

3.4.2 Service总览

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 系统的日常维护。

3.5 流程绘制

3.5.1 绘制插件

​ 由于Idea 在2019年之后就没有再更新维护Activiti的设计工具了,那么在高版本的IDEA中我们就没法使用actiBPM插件来绘制了,这时可以选择降低版本来使用,或者使用我们给大家提供的Eclipse来实现流程的设计。

![image-20210518091819931](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518091819931.png)

我们提供给大家的Eclipse是已经集成好了Activiti插件的。

![image-20210518091905869](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518091905869.png)

创建一个Activiti项目

![image-20210518091935005](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518091935005.png)

3.5.2 绘制流程

使用滑板来绘制流程,通过从右侧把图标拖拽到左侧的面板,最终的效果

![image-20210518092614975](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518092614975.png)

指定流程的主键

![image-20210518092724158](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518092724158.png)

指定任务的负责人

在Properties视图中指定每个任务节点的负责人:

![image-20210518092955563](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518092955563.png)

Assignee : 审批的负责人 是谁来进行审批

经理审批:lisi

总经理审批:wangwu

财务审批:xiaoming

当我们设置完成后保存文件,会同时生成png图片

![image-20210518093156624](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518093156624.png)

然后将这两个文件拷贝到IDEA项目中即可

![image-20210518093405860](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518093405860.png)

3.5.3 图标介绍

流程符号

BPMN 2.0是业务流程建模符号2.0的缩写。

它由Business Process Management Initiative这个非营利协会创建并不断发展。作为一种标识,BPMN 2.0是使用一些符号来明确业务流程设计流程图的一整套符号规范,它能增进业务建模时的沟通效率。

目前BPMN2.0是最新的版本,它用于在BPM上下文中进行布局和可视化的沟通。

接下来我们先来了解在流程设计中常见的 符号。

BPMN2.0的基本符合主要包含:

事件 Event

![1574522151044](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\1574522151044.png)

活动 Activity

活动是工作或任务的一个通用术语。一个活动可以是一个任务,还可以是一个当前流程的子处理流程; 其次,你还可以为活动指定不同的类型。常见活动如下:

![1574562726375](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\1574562726375.png)

网关 GateWay

网关用来处理决策,有几种常用网关需要了解:

![1574563600305](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\1574563600305.png)

排他网关 (x)

——只有一条路径会被选择。流程执行到该网关时,按照输出流的顺序逐个计算,当条件的计算结果为true时,继续执行当前网关的输出流;

​ 如果多条线路计算结果都是 true,则会执行第一个值为 true 的线路。如果所有网关计算结果没有true,则引擎会抛出异常。

​ 排他网关需要和条件顺序流结合使用,default 属性指定默认顺序流,当所有的条件不满足时会执行默认顺序流。

并行网关 (+)

——所有路径会被同时选择

​ 拆分 —— 并行执行所有输出顺序流,为每一条顺序流创建一个并行执行线路。

​ 合并 —— 所有从并行网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下执行。

包容网关 (+)

—— 可以同时执行多条线路,也可以在网关上设置条件

​ 拆分 —— 计算每条线路上的表达式,当表达式计算结果为true时,创建一个并行线路并继续执行

​ 合并 —— 所有从并行网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下执行。

事件网关 (+)

—— 专门为中间捕获事件设置的,允许设置多个输出流指向多个不同的中间捕获事件。当流程执行到事件网关后,流程处于等待状态,需要等待抛出事件才能将等待状态转换为活动状态。

流向 Flow

流是连接两个流程节点的连线。常见的流向包含以下几种:

![1574563937457](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\1574563937457.png)

流程设计器使用

Palette(画板)

Connection—连接

Event---事件

Task---任务

Gateway---网关

Container—容器

Boundary event—边界事件

Intermediate event- -中间事件

4. Activiti流程操作

4.1 流程的部署

将上面在设计器中定义的流程部署到activiti数据库中,就是我们讲的流程部署。

通过调用Activiti的api将流程定义的bpmn和png两个文件一个一个添加部署到activiti中,还可以将两个文件打车zip包部署。

4.1.1 单个文件部署

分别将bpmn文件和png图片分别部署

    /**
     * 实现文件的单个部署
     */
    @Test
    public void test03()
        // 1.获取ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RepositoryService进行部署操作
        RepositoryService service = engine.getRepositoryService();
        // 3.使用RepositoryService进行部署操作
        Deployment deploy = service.createDeployment()
                .addClasspathResource("bpmn/evection.bpmn") // 添加bpmn资源
                .addClasspathResource("bpmn/evection.png") // 添加png资源
                .name("出差申请流程")
                .deploy();// 部署流程
        // 4.输出流程部署的信息
        System.out.println("流程部署的id:" + deploy.getId());
        System.out.println("流程部署的名称:" + deploy.getName());
    

日志中查看到相关的输出信息

![image-20210518095505079](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518095505079.png)

4.1.2 部署zip文件

将bpmn文件和png文件两个打包为一个zip文件,统一上传

![image-20210518100625200](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518100625200.png)

  /**
     * 通过一个zip文件来部署操作
     */
    @Test
    public void test04()        
        // 定义zip文件的输入流      
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("bpmn/evection.zip");
        // 对 inputStream 做装饰     
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = engine.getRepositoryService();
        Deployment deploy = repositoryService.createDeployment()
                .addZipInputStream(zipInputStream)
                .name("出差申请流程").deploy();
        // 4.输出流程部署的信息      
        System.out.println("流程部署的id:" + deploy.getId());
        System.out.println("流程部署的名称:" + deploy.getName());
    

上传后的数据库中的数据和单个文件上传其实是一样的。

4.1.3 操作数据表

流程定义部署后操作activiti中的三张表

act_re_deployment: 流程定义部署表,每部署一次就增加一条记录

![image-20210518100938027](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518100938027.png)

act_re_procdef :流程定义表,部署每个新的流程定义都会在这张表中增加一条记录

![image-20210518101000521](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518101000521.png)

act_ge_bytearray :流程资源表,流程部署的 bpmn文件和png图片会保存在该表中

![image-20210518101022380](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518101022380.png)

4.2 启动流程实例

流程定义部署在Activiti后就可以通过工作流管理业务流程,也就是说上边部署的出差申请流程可以使用了。

针对该流程,启动一个流程表示发起一个新的出差申请单,这就相当于Java类和Java对象的关系,类定义好了后需要new创建一个对象使用,当然可以new出多个对象来,对于出差申请流程,张三可以发起一个出差申请单需要启动一个流程实例。


    /**
     * 启动一个流程实例
     */
    @Test
    public void test05() 
        // 1.创建ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RuntimeService对象
        RuntimeService runtimeService = engine.getRuntimeService();
        // 3.根据流程定义的id启动流程
        String id = "evection";
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(id);
        //4.输出相关的流程实例信息
        System.out.println("流程定义的ID:" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例的ID:" + processInstance.getId());
        System.out.println("当前活动的ID:" + processInstance.getActivityId());
    


输出内容:

![image-20210518102613350](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518102613350.png)

启动流程实例涉及到的表结构

act_hi_actinst 流程实例执行历史

act_hi_identitylink 流程的参与用户的历史信息

act_hi_procinst 流程实例历史信息

act_hi_taskinst 流程任务历史信息

act_ru_execution 流程执行信息

act_ru_identitylink 流程的参与用户信息

act_ru_task 任务信息

4.3 任务查找

流程启动后,任务的负责人就可以查询自己当前能够处理的任务了,查询出来的任务都是当前用户的待办任务


输出结果

![image-20210518104109224](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518104109224.png)

4.4 流程任务处理

任务负责人查询出来了待办的人,选择任务进行处理,完成任务

      /**
     * 流程任务的处理
     */
    @Test
    public void test07() 
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        Task task = taskService.createTaskQuery()
//                根据key查找流程任务
                .processDefinitionKey("start")
//                经办人 张三
                .taskAssignee("张三").singleResult();
        // 完成任务 提交审批
        taskService.complete(task.getId());
    

zhangsan处理了这个操作后,流程就流转到了 lisi处

![image-20210518104526601](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518104526601.png)

然后就是不同的用户登录,然后查询任务处理任务,直到任务流程走完。

4.5 流程定义的查询

查询流程相关的信息,包括流程的定义,流程的部署,流程定义的版本

   
 /**
     * 查询流程的定义
     */
    @Test
    public void test08() 
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = engine.getRepositoryService();
        //获取一个 ProcessDefinitionQuery对象 用来查询操作
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        List<ProcessDefinition> list = processDefinitionQuery.processDefinitionKey("start")
                .orderByProcessDefinitionVersion() // 安装版本排序
                .desc() // 倒序
                .list();

        //输出流程定义的信息
        for (ProcessDefinition processDefinition : list) 
            System.out.println("流程定义的ID:" + processDefinition.getId());
            System.out.println("流程定义的name:" + processDefinition.getName());
            System.out.println("流程定义的key:" + processDefinition.getKey());
            System.out.println("流程定义的version:" + processDefinition.getVersion());
            System.out.println("流程部署的id:" + processDefinition.getDeploymentId());
            System.out.println("---------------------------------------------------------");
        
    

输出结果

流程定义的ID:evection:1:12504流程定义的name:出差申请单流程定义的key:evection流程定义的version:1流程部署的id:12501

4.6 流程的删除

 /**
     * 删除流程
   
     */
    @Test
    public void test09() 
    // 查看的表 : ACT_RE_DEPLOYMENT
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = engine.getRepositoryService();
        // 删除流程定义,如果该流程定义已经有了流程实例启动则删除时报错
//        repositoryService.deleteDeployment("10001");
        // 设置为TRUE 级联删除流程定义,及时流程有实例启动,也可以删除,设置为false 非级联删除操作。
        repositoryService.deleteDeployment("1", true);
    

注意:项目开发中级联删除操作的权限一般只开发给超级管理员使用。

4.7 流程资源的下载

现在我们的流程资源文件已经上传到了数据库中,如果其他用户想要查看这些资源,可以从数据库中把这些资源下载到本地。

解决方案:

  1. jdbc对blob类型处理clob类型数据读取出来就可以了。
  2. 使用activiti的api来实现操作。

使用activiti的api来操作我们需要添加commons-io的依赖

        <dependency>            <groupId>commons-io</groupId>            <artifactId>commons-io</artifactId>            <version>2.6</version>        </dependency>

实现代码

    /**     * 读取数据库中的资源文件     */    @Test    public void test10() throws Exception        // 1.得到ProcessEngine对象        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();        // 2.获取RepositoryService对象        RepositoryService repositoryService = engine.getRepositoryService();        // 3.得到查询器        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery()                .processDefinitionKey("evection")                .singleResult();        // 4.获取流程部署的id        String deploymentId = definition.getDeploymentId();        // 5.通过repositoryService对象的相关方法 来获取图片信息和bpmn信息        // png图片        InputStream pngInput = repositoryService                .getResourceAsStream(deploymentId, definition.getDiagramResourceName());        // bpmn 文件的流        InputStream bpmnInput = repositoryService                .getResourceAsStream(deploymentId, definition.getResourceName());        // 6.文件的保存        File filePng = new File("d:/evection.png");        File fileBpmn = new File("d:/evection.bpmn");        OutputStream pngOut = new FileOutputStream(filePng);        OutputStream bpmnOut = new FileOutputStream(fileBpmn);        IOUtils.copy(pngInput,pngOut);        IOUtils.copy(bpmnInput,bpmnOut);        pngInput.close();        pngOut.close();        bpmnInput.close();        bpmnOut.close();    

4.8 流程历史信息查看

即使流程定义已经被删除了,流程执行的实例信息通过前面的分析,依然保存在Activiti的act_hi_* 的相关表结构中,所以我们还是可以查询流程的执行的历史信息,可以通过HistoryService来查看

    /**     * 流程历史信息查看     */    @Test    public void test11()        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();        // 查看历史信息我们需要通过 HistoryService来实现        HistoryService historyService = engine.getHistoryService();        // 获取 actinst 表的查询对象        HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();        instanceQuery.processDefinitionId("evection:1:12504");        instanceQuery.orderByHistoricActivityInstanceStartTime().desc();        List<HistoricActivityInstance> list = instanceQuery.list();        // 输出查询的结果        for (HistoricActivityInstance hi : list)             System.out.println(hi.getActivityId());            System.out.println(hi.getActivityName());            System.out.println(hi.getActivityType());            System.out.println(hi.getAssignee());            System.out.println(hi.getProcessDefinitionId());            System.out.println(hi.getProcessInstanceId());            System.out.println("-----------------------");            

输出结果

usertask3总经理审批userTaskwangwuevection:1:1250415001-----------------------usertask2经理审批userTasklisievection:1:1250415001-----------------------usertask1创建请假单userTaskzhansanevection:1:1250415001-----------------------startevent1StartstartEventnullevection:1:1250415001-----------------------

二、Activiti进阶篇

1.流程实例

1.1 什么是流程实例

流程实例(ProcessInstance)代表流程定义的执行实例

一个流程实例包括了所有的运行节点,我们可以利用这个对象来了解当前流程实例的进度等信息

例如:用户或者程序安装流程定义的内容发起了一个流程,这个就是一个流程实例

![image-20210518141329930](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518141329930.png)

1.2 业务管理

​ 流程定义部署在Activiti后,我们就可以在系统中通过Activiti去管理流程的执行,但是如果我们要将我们的流程实例和业务数据关联,这时我们需要使用到Activiti中预留的BusinessKey(业务标识)来关联

![image-20210518143240066](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518143240066.png)

实现代码:

    /**     * 启动流程实例,添加businessKey     */    @Test    public void test01()        // 1.获取ProcessEngine对象        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();        // 2.获取RuntimeService对象        RuntimeService runtimeService = processEngine.getRuntimeService();        // 3.启动流程实例        ProcessInstance instance = runtimeService                .startProcessInstanceByKey("evection", "1001");        // 4.输出processInstance相关属性        System.out.println("businessKey = "+instance.getBusinessKey());    

![image-20210518144011917](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518144011917.png)

1.3 流程实例的挂起和激活

​ 在实际场景中可能由于流程变更需要将当前运行的流程暂停而不是删除,流程暂停后将不能继续执行。

1.3.1 全部流程挂起

​ 操作流程的定义为挂起状态,该流程定义下边所有的流程实例全部暂停。

流程定义为挂起状态,该流程定义将不允许启动新的流程实例,同时该流程定义下的所有的流程实例都将全部挂起暂停执行。

    /**     * 全部流程挂起实例与激活     */    @Test    public void test02()       // 1.获取ProcessEngine对象        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();        // 2.获取RepositoryService对象        RepositoryService repositoryService = engine.getRepositoryService();        // 3.查询流程定义的对象        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()                .processDefinitionKey("evection")                .singleResult();        // 4.获取当前流程定义的状态        boolean suspended = processDefinition.isSuspended();        String id = processDefinition.getId();        // 5.如果挂起就激活,如果激活就挂起        if(suspended)            // 表示当前定义的流程状态是 挂起的            repositoryService.activateProcessDefinitionById(                    id // 流程定义的id            ,true // 是否激活            ,null // 激活时间            );            System.out.println("流程定义:" + id + ",已激活");        else            // 非挂起状态,激活状态 那么需要挂起流程定义            repositoryService.suspendProcessDefinitionById(                    id // 流程id                    ,true // 是否挂起                    ,null // 挂起时间            );            System.out.println("流程定义:" + id + ",已挂起");            

挂起流程定义后,对于的实例对象中的状态会修改为2

![image-20210518151926036](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518151926036.png)

然后再去操作对于的流程实例会抛异常信息

![image-20210518152004324](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518152004324.png)

我们再将挂起的流程转变为激活状态,对于的状态值会从2更新为1

![image-20210518152115713](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518152115713.png)

然后就是业务流程可以正常处理了

1.3.2 单个实例挂起

操作流程实例对象,针对单个流程执行挂起操作,某个流程实例挂起则此流程不再继续执行,当前流程定义的其他流程实例是不受干扰的。完成该流程实例的当前任务会抛异常

    /**     * 单个流程实例挂起与激活     */    @Test    public void test03()        // 1.获取ProcessEngine对象        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();        // 2.获取RuntimeService        RuntimeService runtimeService = engine.getRuntimeService();        // 3.获取流程实例对象        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()                .processInstanceId("25001")                .singleResult();        // 4.获取相关的状态操作        boolean suspended = processInstance.isSuspended();        String id = processInstance.getId();        if(suspended)            // 挂起--》激活            runtimeService.activateProcessInstanceById(id);            System.out.println("流程定义:" + id + ",已激活");        else            // 激活--》挂起            runtimeService.suspendProcessInstanceById(id);            System.out.println("流程定义:" + id + ",已挂起");            

然后我们可以在数据库中查看到状态的更新

![image-20210518153037776](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518153037776.png)

2. 个人任务

2.1 分配任务责任人

2.1.1 固定分配

在进行业务流程建模的时候指定固定的任务负责人:

![image-20210518161104632](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518161104632.png)

在Properties视图中,填写Assiginee项为任务负责人

2.1.2 表达式分配

在Activiti中支持使用UEL表达式,UEL表达式是Java EE6 规范的一部分, UEL(Unified Expression Language) 即 统一表达式语音, Activiti支持两种UEL表达式: UEL-value 和UEL-method

UEL-value

![image-20210518161513735](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518161513735.png)

在assignee中使用流程变量处理

![image-20210518161552652](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518161552652.png)

![image-20210518161620415](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518161620415.png)

![image-20210518161649311](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518161649311.png)

![image-20210518161708611](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518161708611.png)

然后我们可以来操作

首先我们需要将定义的流程部署到Activiti数据库中

    /**     * 先将新定义的流程部署到Activiti中数据库中     */    @Test    public void test01()        // 1.获取ProcessEngine对象        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();        // 2.获取RepositoryService进行部署操作        RepositoryService service = engine.getRepositoryService();        // 3.使用RepositoryService进行部署操作        Deployment deploy = service.createDeployment()                .addClasspathResource("bpmn/evection-uel.bpmn") // 添加bpmn资源                .addClasspathResource("bpmn/evection-uel.png") // 添加png资源                .name("出差申请流程-UEL")                .deploy();// 部署流程        // 4.输出流程部署的信息        System.out.println("流程部署的id:" + deploy.getId());        System.out.println("流程部署的名称:" + deploy.getName());    

部署成功后我们需要启动一个新的流程实例,然后在流程实例创建的其实关联UEL表达式

    /**     * 创建一个流程实例     *    给流程定义中的 UEL表达式赋值     */    @Test    public void test02()      // 获取流程引擎        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();        // 获取RuntimeService对象        RuntimeService runtimeService = processEngine.getRuntimeService();        // 设置 assignee 的取值,        Map<String,Object> map = new HashMap<>();        map.put("assignee0","张三");        map.put("assignee1","李四");        map.put("assignee2","王五");        map.put("assignee3","赵财务");        // 创建流程实例        runtimeService.startProcessInstanceByKey("evection-uel",map);    

启动成功后我们在 act_ru_variable中可以看到UEL表达式对应的赋值信息

![image-20210518163344275](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518163344275.png)

UEL-method

![image-20210518163633595](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518163633595.png)

userBean 是 spring 容器中的一个 bean,表示调用该 bean 的 getUserId()方法。

UEL-method 与 UEL-value 结合

再比如:
$ldapService.findManagerForEmployee(emp)
ldapService 是 spring 容器的一个 bean,findManagerForEmployee 是该 bean 的一个方法,emp 是 activiti
流程变量, emp 作为参数传到 ldapService.findManagerForEmployee 方法中。

其它

表达式支持解析基础类型、 bean、 list、 array 和 map,也可作为条件判断。
如下:
$order.price > 100 && order.price < 250

2.1.3 监听器分配

可以使用监听器来完成很多Activiti的流程业务。

我们在此处使用监听器来完成负责人的指定,那么我们在流程设计的时候就不需要指定assignee

Event选项

![image-20210518164413956](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518164413956.png)

create:任务创建后触发assignment:任务分配后触发Delete:任务完成后触发All:所有事件都触发

自定义的监听器

import org.activiti.engine.delegate.DelegateTask;import org.activiti.engine.delegate.TaskListener;public class MyTaskListener implements TaskListener     @Override    public void notify(DelegateTask delegateTask)         if("创建请假单".equals(delegateTask.getName())        && "create".equals(delegateTask.getEventName()))            // 指定任务的负责人            delegateTask.setAssignee("张三-Listener");            

测试代码

/** * 先将新定义的流程部署到Activiti中数据库中 */@Testpublic void test01()    // 1.获取ProcessEngine对象    ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();    // 2.获取RepositoryService进行部署操作    RepositoryService service = engine.getRepositoryService();    // 3.使用RepositoryService进行部署操作    Deployment deploy = service.createDeployment()            .addClasspathResource("bpmn/evection-listener.bpmn") // 添加bpmn资源            .addClasspathResource("bpmn/evection-listener.png") // 添加png资源            .name("出差申请流程-UEL")            .deploy();// 部署流程    // 4.输出流程部署的信息    System.out.println("流程部署的id:" + deploy.getId());    System.out.println("流程部署的名称:" + deploy.getName());/** * 创建一个流程实例 *    给流程定义中的 UEL表达式赋值 */@Testpublic void test02()  // 获取流程引擎    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();    // 获取RuntimeService对象    RuntimeService runtimeService = processEngine.getRuntimeService();    // 创建流程实例    runtimeService.startProcessInstanceByKey("evection-listener");

![image-20210518165520969](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518165520969.png)

![image-20210518165644992](D:\\29-activity7工作流\\11.【课堂笔记】 activiti\\img\\image-20210518165644992.png)

2.2 查询任务

查询任务负责人的待办任务

代码如下:

// 查询当前个人待执行的任务@Testpublic void findPersonalTaskList()     // 流程定义key    String processDefinitionKey = "myEvection1";    // 任务负责人    String assignee = "张三";    // 获取TaskService    TaskService taskService = processEngine.getTaskService();    List<Task> taskList = taskService.createTaskQuery()    	.processDefinitionKey(processDefinitionKey)    	.includeProcessVariables()        .taskAssignee(assignee)        .list();    for (Task task : taskList)         System.out.println("----------------------------");        System.out.println("流程实例id: " + task.getProcessInstanceId());        System.out.println("任务id: " + task.getId());        System.out.println("任务负责人: " + task.getAssignee());        System.out.println("任务名称: " + task.getName());    

关联 businessKey

需求:
在 activiti 实际应用时,查询待办任务可能要显示出业务系统的一些相关信息。

比如:查询待审批出差任务列表需要将出差单的日期、 出差天数等信息显示出来。

出差天数等信息在业务系统中存在,而并没有在 activiti 数据库中存在,所以是无法通过 activiti 的 api 查询到出差天数等信息。
实现:
在查询待办任务时,通过 businessKey(业务标识 )关联查询业务系统的出差单表,查询出出差天数等信息。

@Test    public void findProcessInstance()//        获取processEngine        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//        获取TaskService        TaskService taskService = processEngine.getTaskService();//        获取RuntimeService        RuntimeService runtimeService = processEngine.getRuntimeService();//        查询流程定义的对象        Task task = taskService.createTaskQuery()                .processDefinitionKey("myEvection1")                .taskAssignee("张三")                .singleResult();//        使用task对象获取实例id        String processInstanceId = task.getProcessInstanceId();//          使用实例id,获取流程实例对象        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()                .processInstanceId(processInstanceId)                .singleResult();//        使用processInstance,得到 businessKey        String businessKey = processInstance.getBusinessKey();        System.out.println("businessKey=="+businessKey);    

2.3 办理任务

注意:在实际应用中,完成任务前需要校验任务的负责人是否具有该任务的办理权限 。

/**     * 完成任务,判断当前用户是否有权限     */    @Test    public void completTask()         //任务id        String taskId = "15005";//        任务负责人        String assingee = "张三";        //获取processEngine        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();        // 创建TaskService        TaskService taskService = processEngine.getTaskService();//        完成任务前,需要校验该负责人可以完成当前任务//        校验方法://        根据任务id和任务负责人查询当前任务,如果查到该用户有权限,就完成        Task task = taskService.createTaskQuery()                .taskId(taskId)                .taskAssignee(assingee)                .singleResult();        if(task != null)            taskService.complete(taskId);            System.out.println("完成任务");            

3.流程变量

3.1、什么是流程变量

流程变量在 activiti 中是一个非常重要的角色,流程运转有时需要靠流程变量,业务系统和 activiti
结合时少不了流程变量,流程变量就是 activiti 在管理工作流时根据管理需要而设置的变量。
比如:在出差申请流程流转时如果出差天数大于 3 天则由总经理审核,否则由人事直接审核, 出差天
数就可以设置为流程变量,在流程流转时使用。

注意:虽然流程变量中可以存储业务数据可以通过activiti的api查询流程变量从而实现 查询业务数据,但是不建议这样使用,因为业务数据查询由业务系统负责,activiti设置流程变量是为了流程执行需要而创建。

3.2、流程变量类型

如果将 pojo 存储到流程变量中,必须实现序列化接口 serializable,

15-从零玩转JavaWeb-封装思想

配套详细讲解视频

什么是封装

封装的好处

 

一、什么是封装

 技术分享图片

 

二、封装的好处

 技术分享图片

   以下是使用封装前与封装之后的代码对比

技术分享图片

 

 技术分享图片

技术分享图片

以上代码使用封装之后

技术分享图片

 

 技术分享图片

 

代码-软件在群文件共享当中

技术分享图片

 

以上是关于从零玩转Activiti7工作流-2021-09-12-16-22-07的主要内容,如果未能解决你的问题,请参考以下文章

从零玩转SpringSecurity+JWT整合前后端分离-从零玩转springsecurityjwt整合前后端分离

从零玩转Java和word模板-从零玩转java和word模板

从零玩转Docker之docker-compose-azdocker-compose

从零玩转第三方登录之WeChat公众号扫码关注登陆 -wechatgzh

带你从零玩转云服务器

15-从零玩转JavaWeb-封装思想