Activiti工作流介绍-1

一 Activiti工作流介绍

1 Activiti 概述

1.1 Activiti

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

1.2 BPM

BPM(Business Process Management) : 即业务流程管理, 是一种以规范化的构造端到端的卓越业务流程为中心,以持续的提高组织业务绩效为目的系统化方法,常见商业管理如EMBA/MBA等均将BPM包含在内.

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

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

1.3 BPMN符号简介

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

image-20210116151711152

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

image-20210116151838914

tips: BPMN图形其实就是通过XML表示业务流程,用文本编辑器打开,里面就是xml文件.

2 Activiti使用步骤

1 部署Activiti

​ Activiti是一个工作流引擎(jar包API), 业务系统访问Activiti的接口,就可以方便操作流程相关数据,把工作流环境和业务环境集成.

2 流程定义

​ 使用Activiti流程建模工具(Acitivity-designer)定义业务流程(bpmn文件).

3 路程定义部署

​ Activiti部署业务流程定义,使用activiti提供的api把流程定义的内容存储,在activiti执行过程中可以查询定义的内容,activiti把流程定义内容存储在数据库中.

4 启动一个流程实例

​ 流程实例:ProcessInstance,启动一个流程实例表示开始一次业务流程的运行.

​ 在员工请假流程定义部署完成后,张三请假启动一个流程实例,李四请假也启动一个流程实例,两个流程的执行互不干涉影响.

5 用户查询待办任务

​ 通过activiti查询当前流程执行到了哪一步,当前用户需要办理什么任务.

6 用户办理任务

​ 用户查询待办任务后,可以办理某个任务.

7 流程结束

​ 当任务办理完成,且没有下一个任务节点,流程实例就完成了.

二 Activiti环境

1 开发环境

jdk1.8 / Mysql 5 / Tomcat8.5 / IDEA

Activiti7.0.0.Beta1(默认支持Spring5,注意版本号Beta后面是数字1)

2 准备Activiti7

1 从官网下载. http://activiti.org/download.html

2 在Maven导入坐标

    <dependencies>
        <!--activiti核心-->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-engine</artifactId>
            <version>7.0.0.Beta1</version>
        </dependency>
    </dependencies>

3 Activiti的数据库支持

1 Activiti支持的数据库

image-20210116154445177

2 在Mysql生成表

1 先创建数据库activiti(数据库名任意)
CREATE DATABASE activiti DEFAULT CHARACTER SET utf8;
2 创建java工程

​ 使用IDEA创建java的maven项目,取名activiti-demo

3 导入maven坐标
1 pom.xml文件
    <!--    当前项目编码和JDK版本-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>

        <slf4j.version>1.6.6</slf4j.version>
        <log4j.version>1.2.12</log4j.version>
        <activiti.version>7.0.0.Beta1</activiti.version>
    </properties>

    <dependencies>
        <!--activiti核心-->
        <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>
        </dependency>
        <!--activiti 云支持-->
        <dependency>
            <groupId>org.activiti.cloud</groupId>
            <artifactId>activiti-cloud-services-api</artifactId>
            <version>${activiti.version}</version>
        </dependency>
        <dependency>
            <groupId>aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.5.4</version>
        </dependency>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</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>

        <!--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>

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.8.RELEASE</version>
        </dependency>
    </dependencies>
2 log4j.properties
log4j.rootLogger=debug, CONSOLE, LOGFILE
log4j.logger.org.apache.axis.enterprise=fatal, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8610} %-6R[%15.15t] %-5p %30.30.c %c - %m\n

log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\act\activiti.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8610} %-6R[%15.15t] %-5p %30.30.c %c - %m\n
4 activiti配置文件

​ 使用activiti提供的默认方式来创建mysql的表,需要在resources目录下创建activiti.cfg.xml文件.(文件的位置,文件的名称都不能修改)

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
       
        <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/activiti"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
        
        <!--数据库策略 true -数据库已经存在相应的表,直接使用,不存在,则创建表-->
        <property name="databaseSchemaUpdate" value="true"/>
    	</bean>
         
</beans>       
5 创建测试类,生成表
    @Test
    public void testCreateDbTable() {
    
    

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        System.out.println(processEngine);
    }
6 表结构介绍
表分类 表名 解释
一般数据
ACT_GE_BYTEARRAY 通用的流程定义和流程资源
ACT_GE_PROPERTY 系统相关属性
流程历史记录
ACT_HI_ACTINST 历史的流程实例
ACT_HI_ATACHMENT 历史的流程附件
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_IDNTITYLINK 运行时用户关系信息,存储任务节点与参与者的相关信息
ACT_RU_JOB 运行时作业
ACT_RU_TASK 运行时任务
ACT_RU_VARIABLE 运行时变量表

三 Activiti类关系图

1 类关系图

image-20210116164210582

​ 在新版本中dentityService,FormService两个Service已经删除了.

2 activiti.cfg.xml

​ activiti的引擎配置文件,包括ProcessEngineConfiguration的定义,数据源定义,事务管理等,类似一个spring的配置文件.

3 流程引擎配置类

​ 流程引擎的配置类(ProcessEngineConfiguration),通过配置类可以创建工作流引擎ProcessEngine.

1 StandaloneProcessEngineConfiguration

​ 使用该类来创建ProcessEngine,Activiti会自己处理事务. (优化: 数据源可以使用连接池)

        <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/activiti"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
        
        <!--数据库策略 true -数据库已经存在相应的表,直接使用,不存在,则创建表-->
        <property name="databaseSchemaUpdate" value="true"/>
    	</bean>

2 SpringProcessEngineConfiguration

​ 和Spring整合,使用该类,配置事务,让Spring管理

    <bean id="dataSource"
          class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/activiti"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
        <property name="maxActive" value="3"/>
        <property name="maxIdle" value="1"/>
    </bean>

    <!--事务管理器-->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
        <!--数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--spring事务管理-->
        <property name="transactionManager" ref="transactionManager"/>
        <!--数据库策略-->
        <property name="databaseSchemaUpdate" value="drop-create"/>
    </bean>

    <!--流程引擎-->
    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
        <property name="processEngineConfiguration" ref="processEngineConfiguration"/>
    </bean>

4 工作流引擎创建

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

1 默认创建方式

​ 固定activiti.cfg.xml文件名和路径,且activiti文件中有ProcessEngineConfiguration的配置,可以使用ProcessEngines工具类直接创建

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

2 一般创建方式

     ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();

5 Service服务接口

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

1 Service创建方式

​ 通过ProcessEngine创建Service

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

2 Service功能说明

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

四 Activiti入门操作

创建工作流的步骤:

  • 定义流程: 按照BPMN,使用流程定义工具,用流程符号把整个流程描述出来.
  • 部署流程: 把画好的流程定义文件,加载到数据库中,生成表的数据.
  • 启动流程: 使用java代码来操作数据库中表内容

1 流程符号(BPMN2.0)

事件 Event

image-20210116172249624

活动 Activiti

image-20210116172306662

网关 Gateway

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nYg300VC-1610808984400)(assets/image-20210116172335147.png)]

image-20210116172602396

image-20210116172647901

image-20210116172729787

image-20210116172842258

image-20210116172759455

流向 Flow

image-20210116172925582

2 流程设计器的使用

前提在IDEA中安装插件actBPM,创建一个BPMN文件

image-20210116173418662

1 设计一个请假流程

image-20210116173647742

2 指定任务负责人

image-20210116173735328

3 生成png文件

1 先复制bpmn文件,把后缀改为xml

2 按照下图操作,得到png,保存图片

image-20210116174320806

image-20210116174642403

3 activiti入门操作

1 流程部署

    /**
     * 测试流程部署
     */
    @Test
    public void testDeployment() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //3使用service进行流程的部署,定义一个流程的名字,把bpmn和png部署到数据中
        Deployment deploy = repositoryService.createDeployment()
                .name("出差申请流程")
                .addClasspathResource("bpmn/evection.png")
                .addClasspathResource("bpmn/evection.bpmn")
                .deploy();

        //4输出部署信息
        System.out.println(deploy.getId() + "  流程部署id");
        System.out.println(deploy.getName() + "  流程部署的名称");

    }

总结:

1 使用流程设计器,使用流程符号,画出流程图

​ bpmn文件,png文件

​ 都是流程资源文件,用来描述流程中需要的节点,节点负责人

​ 出差申请流程,请假申请流程,报销申请流程,…

2 把流程的资源文件,进行部署

上传到数据库中,使用java代码来进行流程部署

一次部署操作:

ACT_RE_DEPLOYMENT 会生成一条记录

ACT_RE_PROCDEF 生成流程定义信息

3 deployment 和procdef表 一对多的关系

​ 在procdef表中可以有多条记录,每条记录 对应一个流程的定义信息

2 启动流程实例

    /**
     * 启动流程实例
     */
    @Test
    public void teststartProcess() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //3根据流程定义的id启动流程
        String processInstanceByKey = "myEvection";
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processInstanceByKey);
    
        //4输出内容
        System.out.println(processInstance.getProcessDefinitionId() + "  流程实例的id");
        System.out.println(processInstance.getId() + "  流程实例id");
        System.out.println(processInstance.getActivityId() + "  当前活动的id");
        
    }

3 个人任务查询

    /**
     * 个人任务的查询
     */
    @Test
    public void testFindPersonTaskList() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //3根据流程的key 和任务的负责人 查询任务
        String assignee = "zhangsan";
        String definitionKey = "myEvection";
        List<Task> taskList = taskService.createTaskQuery()
                .processDefinitionKey(definitionKey)//流程key
                .taskAssignee(assignee)//要查询的负责人
                .list();

        //4输出内容
        for (Task task : taskList) {
    
    
            System.out.println(task.getProcessDefinitionId() + "  当前任务的实例的id");
            System.out.println(task.getId() + "  当前任务的id");
            System.out.println(task.getName() + "  当前任务的名称");
            System.out.println(task.getAssignee() + "  当前任务的负责人");

        }

    }

4 个人任务完成

   /**
     * 完成个人任务
     */
    @Test
    public void completTask() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //3根据任务id 完成(张三)任务
/*        String taskId = "2505";
        taskService.complete(taskId);*/
        
		//4 根据指派人和实例key获取个人任务
        String definitionKey = "myEvection";
        String assignee = "rose";
        Task task = taskService.createTaskQuery()
                .processDefinitionKey(definitionKey)//流程实例key
                .taskAssignee(assignee)//任务指派人
                .singleResult();//单个结果

        taskService.complete(task.getId());
        System.out.println("任务完成");
    }

5 使用zip方式进行流程部署

    /**
     * 使用zip方式部署
     */
    @Test
    public void testZipDeployment() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //3使用service进行流程的部署,定义一个流程的名字,zip部署
        InputStream inputStream = this.getClass()
                .getClassLoader()
                .getResourceAsStream("bpmn/bpmn.zip");
        System.out.println(inputStream);

        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        Deployment deploy = repositoryService
            	.createDeployment()//创建部署
                .addZipInputStream(zipInputStream)//添加zip输入流
                .name("请假流程")//流程名称
                .key("myEvection")//实例key
                .deploy();

        //4输出部署信息
        System.out.println(deploy.getId() + "  流程部署id");
        System.out.println(deploy.getName() + "  流程部署的名称");

    }

五 流程操作

1 流程定义信息查询

    /**
     * 查询流程定义
     */
    @Test
    public void queryProcessDefinition() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();

        ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery();

        String key = "myEvection";
        List<ProcessDefinition> definitionList = definitionQuery.processDefinitionKey(key)
                .orderByProcessDefinitionVersion()
                .desc()
                .list();
        for (ProcessDefinition processDefinition : definitionList) {
    
    
            System.out.println("流程定义ID " + processDefinition.getId());
            System.out.println("流程定义名称 " + processDefinition.getName());
            System.out.println("流程定义key " + processDefinition.getKey());
            System.out.println("流程定义部署ID " + processDefinition.getDeploymentId());
            System.out.println("流程定义版本号 " + processDefinition.getVersion());
        }


    }

2流程删除

    /**
     * 流程定义删除
     */
    @Test
    public void deleteDeployMent() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();

/*		//普通删除流程部署信息
        String deployMentId = "15001";
        repositoryService.deleteDeployment(deployMentId);
*/
        /**
         * 删除流程部署信息
         * 当前流程如果没有完成,想要删除的话,需要特殊的方式 原理就是 级联删除
         */
        String deployMentId = "1";
        repositoryService.deleteDeployment(deployMentId, true);

        System.out.println("删除成功");
    }

3流程资源下载

    /**
     * 下载 资源文件
     * 方案1 使用Activiti的api,来下载资源文件
     * 方案2 自己写代码从数据库中下载文件,使用jdbc对blob 类型,clob类型读取出来,保存到文件目录
     * 解决IO操作: commons-io.jar
     */
    @Test
    public void getDeployment() throws IOException {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2获取RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //3 获取查询对象,查询流程定义信息
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("myEvection")
                .singleResult();
        //4通过流程定义信息,获取部署ID
        String deploymentId = processDefinition.getDeploymentId();
        //5通过RepositoryService,传递部署id参数,读取资源信息(png和bpmn)
        //5.1 获取png
        //从流程定义表中,获取png图片的目录和名字
        String pngName = processDefinition.getDiagramResourceName();
        InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, pngName);

        //5.2 获取bpmn
        String bpmnName = processDefinition.getResourceName();
        InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, bpmnName);

        //6构造OutputStream流
        File pngFile = new File("d/evection.png");
        File bpmnFile = new File("d/evection.bpmn");
        FileOutputStream pngOutStream = new FileOutputStream(pngFile);
        FileOutputStream bpmnOutStream = new FileOutputStream(bpmnFile);
        //7输入流,输出流的转换
        IOUtils.copy(bpmnInput, bpmnOutStream);
        IOUtils.copy(pngInput, pngOutStream);
        //8关闭流
        bpmnOutStream.close();
        pngOutStream.close();
        bpmnInput.close();
        pngInput.close();

    }

4流程历史信息的查看

    /**
     * 查看历史信息
     */
    @Test
    public void findHistoryInfo() {
    
    
        //获取引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //获取HistoryService
        HistoryService historyService = processEngine.getHistoryService();
        //获取actinst表的查询对象
        HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();

        //查询actinst表
        //1 使用流程实例id查询
        //2 使用流程定义id查询
//        String processInstanceId = "7501";

        String processDefinitionId = "myEvection:1:5004";
        List<HistoricActivityInstance> list = historicActivityInstanceQuery
//                .processInstanceId(processInstanceId)
                .processDefinitionId(processDefinitionId)
                .orderByHistoricActivityInstanceStartTime()
                .asc()
                .list();
        //输出
        for (HistoricActivityInstance instance : list) {
    
    

            System.out.println(instance.getActivityId()+"活动id");
            System.out.println(instance.getActivityName()+"活动名称");
            System.out.println(instance.getProcessDefinitionId()+"定义id");
            System.out.println(instance.getProcessInstanceId()+"实例id");
            System.out.println("================");
        }

    }

六 流程实例

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

一个流程实例包含了所有的运行节点.

image-20210116201911655

2 启动流程实例 并添加Businesskey(业务标识)

    /**
     * 添加业务key 到Activiti表
     */
    @Test
    public void addBusinessKey() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //3 启动流程的过程中,添加businessKey
        String processDefinitionKey = "myEvection";
        String businessKey = "1001";
        ProcessInstance processInstance = runtimeService
                .startProcessInstanceByKey(processDefinitionKey, businessKey);

        System.out.println("businessKey : " + processInstance.getBusinessKey());
    }

3 挂起和激活流程定义

流程处于激活状态才能向下进行,即任务处理人可以完成任务;挂起状态任务不能完成

1 流程定义的全部挂起和激活

    /**
     * 全部流程的挂起和激活
     */
    @Test
    public void suspendAllProcessInstance() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();

        //3查询流程定义,获取流程定义的查询对象
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("myEvection")
                .singleResult();
        //4 获取当前流程定义的实例是否是挂起状态
        boolean suspended = processDefinition.isSuspended();
        //5 获取流程定义的id
        String definitionId = processDefinition.getId();
        if (suspended) {
    
    
            //6 挂机状态,可以激活的操作 参数1:流程定义id 参数2: 是否激活 参数3:激活时间
            repositoryService.activateProcessDefinitionById(definitionId,
                    true,
                    null);
            System.out.println("流程定义id : " + definitionId + "已激活");
        } else {
    
    
            //7 激活状态,改为挂起装填  参数1:流程定义id 参数2: 是否激活 参数3:激活时间
            repositoryService.suspendProcessDefinitionById(definitionId,
                    true,
                    null);
            System.out.println("流程定义id : " + definitionId + "已挂起");
        }

    }

2 单个流程的挂起和激活

    /**
     * 单个流程的挂起和激活
     */
    @Test
    public void suspendProcessInstance() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取RepositoryService
        RuntimeService runtimeService = processEngine.getRuntimeService();

        //3查询流程定义,获取流程定义的查询对象
        String processInstanceId = "10001";
        ProcessInstance processInstance = runtimeService
                .createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
        //4 获取当前流程定义的实例是否是挂起状态
        boolean suspended = processInstance.isSuspended();
        //5 获取流程定义的id
        String InstanceId = processInstance.getId();
        if (suspended) {
    
    
            //6 挂机状态,可以激活的操作 参数1:流程定义id 参数2: 是否激活 参数3:激活时间
            runtimeService.activateProcessInstanceById(InstanceId);
            System.out.println("流程实例id : " + InstanceId + "已激活");
        } else {
    
    
            //7 激活状态,改为挂起装填  参数1:流程定义id 参数2: 是否激活 参数3:激活时间
            runtimeService.suspendProcessInstanceById(InstanceId);
            System.out.println("流程实例id : " + InstanceId + "已挂起");
        }

    }

七 个人任务

1 分配任务负责人

1 固定分配

image-20210116203607676

2 表达式分配

Activiti使用UEL表达式,UEL是java EE6规范的一部分,UEL(Unified Expression Language)统一表达式语言,activiti支持两个UEL表达式:UEL-value和UEL-method

1UEL-value

image-20210116203923168

2UEL-method

image-20210116204031894

3 UEL-value和UEL-method结合

${UserService.findAll(emp)} UserService是Spring容器的一个bean,findAll是该bean的一个流程变量,emp作为参数传到findAll方法中.

4 其他

表达式支持解析基础类型,bean,list,array,map,条件判断.

${order.price>100 && order.price<200}

    /**
     * 启动流程
     */
    @Test
    public void teststartProcess() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //3根据流程定义的id启动流程
        String processInstanceByKey = "evection-global";

        Map<String, Object> variablesMap = new HashMap<>();
        variablesMap.put("assignee0", "张三");
        variablesMap.put("assignee1", "李四");
        variablesMap.put("assignee2", "王五");
        variablesMap.put("assignee3", "赵六");

        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processInstanceByKey, variablesMap);

        //4输出内容
        System.out.println(processInstance.getProcessDefinitionId() + "  流程实例的id");
        System.out.println(processInstance.getId() + "  流程实例id");
        System.out.println(processInstance.getActivityId() + "  当前活动的id");

    }

3 监听器分配

image-20210116205757245

public class MyTaskListen implements TaskListener {
    
    

    /**
     * 使用监听器,指定任务负责人
     * @param delegateTask
     */
    @Override
    public void notify(DelegateTask delegateTask) {
    
    
        //判断是否是创建申请
        if ( "出差申请".equals(delegateTask.getName()) && "create".equals(delegateTask.getEventName())) {
    
    
            //指派任务负责人
            delegateTask.setAssignee("张三");
        }else {
    
    
            delegateTask.setAssignee("李四");
        }
        
    }
}

2 查询任务

    /**
     * 个人任务的查询
     */
    @Test
    public void testFindPersonTaskList() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //3根据流程的key 和任务的负责人 查询任务
        String assignee = "zhangsan";
        String definitionKey = "myEvection";
        List<Task> taskList = taskService.createTaskQuery()
                .processDefinitionKey(definitionKey)//流程key
                .taskAssignee(assignee)//要查询的负责人
                .list();

        //4输出内容
        for (Task task : taskList) {
    
    
            System.out.println(task.getProcessDefinitionId() + "  当前任务的实例的id");
            System.out.println(task.getId() + "  当前任务的id");
            System.out.println(task.getName() + "  当前任务的名称");
            System.out.println(task.getAssignee() + "  当前任务的负责人");

        }

    }

3 办理任务

   /**
     * 完成个人任务
     */
    @Test
    public void completTask() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //3根据任务id 完成(张三)任务
/*        String taskId = "2505";
        taskService.complete(taskId);*/
        
		//4 根据指派人和实例key获取个人任务
        String definitionKey = "myEvection";
        String assignee = "rose";
        Task task = taskService.createTaskQuery()
                .processDefinitionKey(definitionKey)//流程实例key
                .taskAssignee(assignee)//任务指派人
                .singleResult();//单个结果

        taskService.complete(task.getId());
        System.out.println("任务完成");
    }

八 流程变量

1 什么是流程变量

流程变量: activiti在管理工作流时根据管理需要设置的变量

2 流程变量类型

image-20210116210607105

3 流程变量作用域

流程变量的作用域可以是一个流程实例,或是一个任务task,或一个执行实例.

1 global变量

流程变量的默认作用域是流程实例,当一个流程变量的作用域为流程实例时,可以称为global变量.

global变量中变量名不允许重复,设置相同名称的变量,后设置的值会覆盖前设置的变量值.

2 local变量

任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大,称为local变量.

4 流程变量的使用方法

1 在属性上使用UEL表达式

​ 在assignee处设置UEL表达式,如 ${assignee}

2 在连线上使用UEL表达式

​ 如 ${price<100}

5 使用Global变量控制流程

1 创建pojo对象

// 实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Evection implements Serializable {
    
    
    
    private Long id;
    private String evectionName;
    private Double num;
    private Date beginTime;
    private Date endTime;
    private String reason;
    private String desraption;
}  

2 启动流程时设置变量

	/**
     * 启动流程
     */
    @Test
    public void teststartProcess() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //3根据流程定义的id启动流程
        String processInstanceByKey = "evection-global";
        //指定连线条件
        Evection evection = new Evection();
        evection.setNum(3.0);

        Map<String, Object> variablesMap = new HashMap<>();
        variablesMap.put("evection", evection);
        //指定任务人
        variablesMap.put("assignee0", "张三");
        variablesMap.put("assignee1", "李四");
        variablesMap.put("assignee2", "王五");
        variablesMap.put("assignee3", "赵六");

        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processInstanceByKey, variablesMap);

        //4输出内容
        System.out.println(processInstance.getProcessDefinitionId() + "  流程实例的id");
        System.out.println(processInstance.getId() + "  流程实例id");
        System.out.println(processInstance.getActivityId() + "  当前活动的id");

    }

3任务办理时设置变量

    @Test
    public void completTask() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //3根据任务id 完成(张三)任务

        String definitionKey = "myEvection";
        String assignee = "zhangsan";
        String processInstanceId = "10001";
        Task task = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .taskAssignee(assignee)
                .singleResult();
        //设置变量
        Map<String, Object> variablesMap = new HashMap<>();
        variablesMap.put("assignee0", "张三");
        variablesMap.put("assignee1", "李四");
        variablesMap.put("assignee2", "王五");
        variablesMap.put("assignee3", "赵六");

        taskService.complete(task.getId(),variablesMap);
    }        

4 通过当前流程实例设置

    @Test
    public void setGlobalVariableByExecutionId() {
    
    
        //当前流程实例执行id,通常设置为当前执行的流程实例
        String executionId = "2601";
        // 创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //3创建出差pojo对象
        Evection evection = new Evection();
        //设置天数
        evection.setNum(3d);

        //通过流程实例, id设置流程变量
        runtimeService.setVariable(executionId,"evection",evection);
        //一次性设置多个值
       // runtimeService.setVariable(executionId,variables);

    }

5 通过当前任务设置

    @Test
    public void setGlobalVariableByTaskId() {
    
    
        //当前待办任务id
        String taskId = "2601";
        // 创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //3创建出差pojo对象
        Evection evection = new Evection();
        //设置天数
        evection.setNum(3d);

        //通过流程实例, id设置流程变量
        taskService.setVariable(taskId,"evection",evection);
        //一次性设置多个值
        // taskService.setVariable(taskId,variables);

    }

6 设置local变量

1 任务办理时设置

    @Test
    public void completTask() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //3根据任务id 完成(张三)任务

        String definitionKey = "myEvection";
        String assignee = "zhangsan";
        String processInstanceId = "10001";
        Task task = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .taskAssignee(assignee)
                .singleResult();
        //设置变量
        Map<String, Object> variablesMap = new HashMap<>();
        variablesMap.put("assignee0", "张三");
        variablesMap.put("assignee1", "李四");
        variablesMap.put("assignee2", "王五");
        variablesMap.put("assignee3", "赵六");
        
		//设置local变量,作用域为该任务
        taskService.setVariablesLocal(taskId,variables);
        //完成任务
        taskService.complete(task.getId());
    }        

2 通过当前任 设置

    @Test
    public void setGlobalVariableByTaskId() {
    
    
        //当前待办任务id
        String taskId = "2601";
        // 创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //3创建出差pojo对象
        Evection evection = new Evection();
        //设置天数
        evection.setNum(3d);

        //通过流程实例, id设置流程变量
        taskService.setVariableLocal(taskId,"evection",evection);
        //一次性设置多个值
        // taskService.setVariableLocal(taskId,variables);

    }

九 组任务

1 组任务办理流程

a 查询组任务

指定候选人,查询该候选人当前的待办任务. 候选人不能立即办理任务

b 拾取任务

该组任务的所有所有的候选人都能拾取.

将候选人的组任务,变成个人任务,原来候选人就变成了该任务的负责人.

如果拾取后不想办理? 需要将拾取的任务,归还到组任务里面,个人任务就变成了组任务.

c 查询个人任务

查询方式桶个人任务部分,根据assignee查询用户负责的个人任务.

2 查询组任务

    @Test
    public void findGroupTaskList() {
    
    
        //流程定义key
        String processDefinitionKey = "evection3";
        //任务候选人
        String candidateUser = "lisi";
        // 创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //查询组任务
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey(processDefinitionKey)
                .taskCandidateOrAssigned(candidateUser)
                .list();

        for (Task task : list) {
    
    
            System.out.println("==============================");
            System.out.println(task.getProcessDefinitionId() + "  当前任务的实例的id");
            System.out.println(task.getId() + "  当前任务的id");
            System.out.println(task.getName() + "  当前任务的名称");
            System.out.println(task.getAssignee() + "  当前任务的负责人");
        }

    }

3 拾取组任务

    @Test
    public void claimTask() {
    
    
        // 创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //要拾取任务id
        String taskId = "6302";
        String userId = "lisi";
        
        //查询组任务
        Task task= taskService.createTaskQuery()
                .taskId(taskId)
                .taskCandidateUser(userId)
                .singleResult();

        if (task != null){
    
    
            //拾取任务
            taskService.claim(taskId,userId);
            System.out.println("任务拾取完成");
        }
    }

4 查询个人待办业务

    /**
     * 个人任务的查询
     */
    @Test
    public void testFindPersonTaskList() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //3根据流程的key 和任务的负责人 查询任务
        String assignee = "zhangsan";
        String definitionKey = "myEvection";
        List<Task> taskList = taskService.createTaskQuery()
                .processDefinitionKey(definitionKey)//流程key
                .taskAssignee(assignee)//要查询的负责人
                .list();

        //4输出内容
        for (Task task : taskList) {
    
    
            System.out.println(task.getProcessDefinitionId() + "  当前任务的实例的id");
            System.out.println(task.getId() + "  当前任务的id");
            System.out.println(task.getName() + "  当前任务的名称");
            System.out.println(task.getAssignee() + "  当前任务的负责人");

        }

    }

5 办理个人业务

   /**
     * 完成个人任务
     */
    @Test
    public void completTask() {
    
    
        //1创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //3根据任务id 完成(张三)任务
        String taskId = "2505";
        taskService.complete(taskId);
        System.out.println("任务完成");
    }

6 归还组任务

    @Test
    public void setAssigneeToGroupTask() {
    
    
        // 创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //要拾取任务id
        String taskId = "6004";
        String userId = "zhangsan";

        //查询组任务
        Task task= taskService.createTaskQuery()
                .taskId(taskId)
                .taskAssignee(userId)
                .singleResult();

        if (task != null){
    
    
            //如果设置为null,归还组任务,否则该任务没有负责人
            taskService.setAssignee(taskId,null);
        }
    }

7 任务交接

@Test   
public void setAssigneeToCandidateUser() {
    
    
        // 创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //要拾取任务id
        String taskId = "6004";
        String userId = "zhangsan";
        //将任务给其他候选人
        String candidateuser = "zhangsan";

        //查询组任务
        Task task= taskService.createTaskQuery()
                .taskId(taskId)
                .taskAssignee(userId)
                .singleResult();

        if (task != null){
    
    
            //如果设置为null,归还组任务,否则该任务没有负责人
            taskService.setAssignee(taskId,candidateuser);
        }
    }

十 网关

1 排他网关(ExclusiveGate

排他网关,用来在流程中实现决策,当流程执行到这个网关,所有分支都会判断条件是否为true,如果为true则执行该分支.

image-20210116223503265

2 并行网关(ParallelGateway)

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

  • fork分支: 并行后的所有外出顺序流,为每一个顺序流都创建一个并发分支
  • join汇聚: 所有达到并行网关,在此等待的进入分支,直到所有进入顺序流的分支都达到以后,流程就会通过汇聚网关.

所有进入的顺序流,然后再切分成多个并行分支.

与其他网关的主要区别是,并行网关不会解析条件,及时顺序流中定义了条件,也会被忽略.

image-20210116224004642

3 包含网关(InclusiveGateway)

包含网关可以看做事排他网关和并行网关的结合体.和排他网关一样,你可以在外出顺序流上定义条件,包含网关会解析他们,但是主要的区别是包含网关可以选择多于一条顺序流,这个并行网关一样.

image-20210116225033057

包含网关:

  • 分支:所有外出顺序流的条件都会被解析,结果为true的顺序流会以并行方式继续执行,会为每一个顺序流创建一个分支.
  • 汇聚:所有并行分支达到网关,会进入等待状态,直到每个包含流程token的进入顺序流的分支都达到.包含网关只会等待被选中执行的进入顺序流,在汇聚之后,流程会穿过包含网关继续执行.

**小结:**在分支时,需要判断条件,符合条件的分支,将会执行,符合条件的分支最终才进行汇聚.

4 事件网关 (EventGateway)

事件网关: 根据事件判断流向,网关的每个外出顺序都要连接到一个中间捕获事件.当流程达到一个基于事件网关,网关会进入等待状态,会暂停执行,与此同时,会为每个外出顺序流创建相对的事件订阅.

猜你喜欢

转载自blog.csdn.net/ABestRookie/article/details/112695555