Activiti工作流基础

一、认识Activiti

官网地址:https://www.activiti.org/
Activiti项目是一项新的基于Apache许可的开源BPM平台,从基础开始构建,旨在提供支持新的BPMN 2.0标准,包括支持对象管理组(OMG),面对新技术的机遇,诸如互操作性和云架构,提供技术实现。

1、创建工作流引擎

1、引入依赖

 <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.12</version>
    </dependency>
     <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.6</version>
    </dependency>

    <dependency>
      <groupId>org.activiti</groupId>
      <artifactId>activiti-engine</artifactId>
      <version>6.0.0</version>
    </dependency>
    <dependency>
      <groupId>org.activiti</groupId>
      <artifactId>activiti-spring</artifactId>
      <version>6.0.0</version>
    </dependency>
    <!--bpmn 模型处理-->
    <dependency>
      <groupId>org.activiti</groupId>
      <artifactId>activiti-bpmn-model</artifactId>
      <version>6.0.0</version>
    </dependency>
    <!--bpmn 转换-->
    <dependency>
      <groupId>org.activiti</groupId>
      <artifactId>activiti-bpmn-converter</artifactId>
      <version>6.0.0</version>
    </dependency>
    <!--bpmn json数据转换-->
    <dependency>
      <groupId>org.activiti</groupId>
      <artifactId>activiti-json-converter</artifactId>
      <version>6.0.0</version>
    </dependency>
    <!--bpmn 布局-->
    <dependency>
      <groupId>org.activiti</groupId>
      <artifactId>activiti-bpmn-layout</artifactId>
      <version>6.0.0</version>
      <scope>test</scope>
    </dependency>
    <!--activiti 云支持-->
    <dependency>
      <groupId>org.activiti.cloud</groupId>
      <artifactId>activiti-cloud-services-api</artifactId>
      <version>7.0.0.Beta1</version>
    </dependency>

    <!--mysql驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.41</version>
    </dependency>
    <!--mybatis-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.4</version>
    </dependency>
    <!--数据库连接池-->
    <dependency>
      <groupId>commons-dbcp</groupId>
      <artifactId>commons-dbcp</artifactId>
      <version>1.4</version>
    </dependency>
  </dependencies>

2、编写日志配置文件

log4j.rootLogger=INFO,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.conversionPattern=%d %p [%c] - %m%n

3、编写activiti配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!--在默认方式下,bean的id固定为:processEngineConfiguration-->

    <!--配置数据库连接池-->
    <bean id="database" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///act?characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="12345678"/>
        <property name="maxActive" value="3"/>
        <property name="maxIdle" value="1"/>
    </bean>

    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <!--配置数据库信息-->
        <!--<property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>-->
        <!--<property name="jdbcUrl" value="jdbc:mysql:///act?characterEncoding=UTF-8"/>-->
        <!--<property name="jdbcUsername" value="root"/>-->
        <!--<property name="jdbcPassword" value="12345678"/>-->

        <!--使用数据库连接池-->
        <property name="dataSource" ref="database"/>
        <!--activiti数据库表生成策略,true表示数据表如果存在直接使用,如果不存在则创建-->
        <property name="databaseSchemaUpdate" value="true"/>
    </bean>

</beans>

4、创建测试类,生成数据库表

package com.yzs;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.junit.Test;

public class ActivitiTest {
    
    

    //使用activiti提供的两种方式来创建数据表
    @Test
    public void testCreateDbTable(){
    
    
        //默认创建方式
        //ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //一般创建方式
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml", "processEngineConfiguration");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        System.out.println(processEngine);
    }
}

二、Activiti入门

创建activiti工作流流程:

  • 定义流程:按照BPMN的规范,使用流程定义工具,用流程符号把整个流程描述出来。
  • 部署流程:把画好的流程定义文件,加载到数据库中,生成表的数据。
  • 启动流程:使用java代码来操作数据库表中的内容。
service名称 service作用
RepositoryService 资源管理类
RuntimeService 流程运行管理类
TaskService 任务管理类
HistoryService 历史管理类
ManagerService 引擎管理类

测试用例代码如下:

package com.yzs;

import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.io.IOUtils;
import org.junit.Test;

import java.io.*;
import java.util.List;
import java.util.zip.ZipInputStream;

public class ActivitiDemo {
    
    

    /**
     * 测试流程部署
     */
    @Test
    public void testDeployment(){
    
    
        //1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //3、使用service进行流程部署,定义流程名字,将bpmn部署到数据库中
        Deployment deploy = repositoryService.createDeployment()
                .name("出差申请流程")
                .addClasspathResource("bpmn/evection.bpmn")
                .deploy();
        //4、输出部署信息
        System.out.println("流程部署id="+deploy.getId());
        System.out.println("流程部署名字="+deploy.getName());
    }

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

    /**
     * 查询个人待执行任务
     */
    @Test
    public void testFindPersonalTaskList(){
    
    
        //1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //3、使用流程key、任务的负责人来查询任务
        List<Task> taskList = taskService.createTaskQuery()
                .processDefinitionKey("myEvection")
                .taskAssignee("zhangsan")
                .list();
        //4、输出任务信息
        for (Task task:taskList){
    
    
            System.out.println("流程实例id="+task.getProcessInstanceId());
            System.out.println("任务id="+task.getId());
            System.out.println("任务名称="+task.getName());
            System.out.println("任务负责人="+task.getAssignee());
        }
    }

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

    /**
     * 使用zip包进行批量部署
     */
    @Test
    public void deployProcessByZip(){
    
    
        //1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //3、流程部署 读取资源包文件,构造成inputStream
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("bpmn/evection.zip");
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        Deployment deploy = repositoryService.createDeployment()
                .addZipInputStream(zipInputStream)
                .deploy();
        //4、输出部署信息
        System.out.println("流程部署id="+deploy.getId());
        System.out.println("流程部署名字="+deploy.getName());
    }

    /**
     * 查询流程定义
     */
    @Test
    public void queryProcessDefinition(){
    
    
        //1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //3、获取ProcessDefinitionQuery对象
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.processDefinitionKey("myEvection")
                .orderByProcessDefinitionVersion()
                .desc()
                .list();
        //4、输出信息
        for (ProcessDefinition processDefinition:processDefinitionList){
    
    
            System.out.println("流程定义id="+processDefinition.getId());
            System.out.println("流程定义名称="+processDefinition.getName());
            System.out.println("流程定义key="+processDefinition.getKey());
            System.out.println("流程定义版本="+processDefinition.getVersion());
        }
    }

    /**
     * 删除流程部署信息
     */
    @Test
    public void deleteDeployment(){
    
    
        //1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //3、通过部署id来删除
        String deploymentId = "1";
        repositoryService.deleteDeployment(deploymentId);

        //当前流程如果尚未完成,想要删除需要使用级联方式
        //repositoryService.deleteDeployment(deploymentId,true);
    }

    /**
     * 下载资源文件
     */
    @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、png名字、bpmn名字
        String deploymentId = processDefinition.getDeploymentId();
        String pngName = processDefinition.getDiagramResourceName();
        String bpmnName = processDefinition.getResourceName();
        //5、传递部署id,读取资源信息(png、bpmn)
        InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, pngName);
        InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, bpmnName);
        //6、构造OutputStream
        File pngFile = new File("d:/evection.png");
        File bpmnFile = new File("d:/evection.bpmn");
        FileOutputStream pngOutput = new FileOutputStream(pngFile);
        FileOutputStream bpmnOutput = new FileOutputStream(bpmnFile);
        //7、输入流与输出流的转换
        IOUtils.copy(pngInput,pngOutput);
        IOUtils.copy(bpmnInput,bpmnOutput);
        //8、关闭流
        pngOutput.close();
        bpmnOutput.close();
        pngInput.close();
        bpmnInput.close();
    }

    /**
     * 查看历史信息
     */
    @Test
    public void findHistoryInfo(){
    
    
        //1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取HistoryService
        HistoryService historyService = processEngine.getHistoryService();
        //3、获取actinst表查询对象
        HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
        //4、查询表内容
        List<HistoricActivityInstance> list = historicActivityInstanceQuery.processInstanceId("2501").orderByHistoricActivityInstanceStartTime().asc().list();
        //5、输出信息
        for (HistoricActivityInstance historicActivityInstance : list){
    
    
            System.out.println(historicActivityInstance.getActivityId());
            System.out.println(historicActivityInstance.getActivityName());
            System.out.println(historicActivityInstance.getProcessDefinitionId());
            System.out.println(historicActivityInstance.getProcessInstanceId());
            System.out.println("-----------------------");
        }
    }

     /**
     * 添加业务key到数据表中
     */
    @Test
    public void addBusinessKey(){
    
    
        //1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //3、启动流程,添加businessKey
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myEvection", "1001");
        //4、输出
        System.out.println("businessKey="+processInstance.getBusinessKey());
    }

    /**
     * 全部流程实例的挂起和激活
     */
    @Test
    public void suspendAllProcessInstance(){
    
    
        //1、获取流程引擎
        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 processDefinitionId = processDefinition.getId();
        //6、如果是挂起状态,改为激活状态
        if (suspended){
    
    
            repositoryService.activateProcessDefinitionById(processDefinitionId,true,null);
            System.out.println("流程id="+processDefinitionId+",状态为激活");
        }else {
    
    
            //7、如果是激活状态,改为挂起状态
            repositoryService.suspendProcessDefinitionById(processDefinitionId,true,null);
            System.out.println("流程id="+processDefinitionId+",状态为挂起");
        }
    }

    /**
     * 单个流程实例的挂起与激活
     */
    @Test
    public void suspendSingleProcessInstance(){
    
    
        //1、获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //3、获取流程实例对象
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId("7501")
                .singleResult();
        //4、获取当前流程实例的暂停状态
        boolean suspended = processInstance.isSuspended();
        //5、获取流程实例id
        String processInstanceId = processInstance.getId();
        //6、如果是挂起状态,改为激活状态
        if (suspended){
    
    
            runtimeService.activateProcessInstanceById(processInstanceId);
            System.out.println("流程实例id="+processInstanceId+",状态为激活");
        }else {
    
    
            //7、如果是激活状态,改为挂起状态
            runtimeService.suspendProcessInstanceById(processInstanceId);
            System.out.println("流程实例id="+processInstanceId+",状态为挂起");
        }
    }
}

三、Activiti进阶

1、个人任务之分配任务负责人

方式一:固定分配

在这里插入图片描述

方式二:表达式分配

activiti使用UEL表达式,UEL是JavaEE6规范的一部分,UEL(Unified Expression Language)即统一表达式语言,支持一下两种表达式语言:

  • UEL-value:例如:${assignee0}
  • UEL-method:例如:${UserBean.getUserId}
package com.yzs;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.junit.Test;

import java.util.HashMap;
import java.util.Map;

public class AssigneeUelTest {
    
    

    /**
     * 流程部署
     */
    @Test
    public void testDeployment(){
    
    
        //1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //3、使用service进行流程部署,定义流程名字,将bpmn部署到数据库中
        Deployment deploy = repositoryService.createDeployment()
                .name("出差申请流程")
                .addClasspathResource("bpmn/evection.bpmn")
                .deploy();
        //4、输出部署信息
        System.out.println("部署id="+deploy.getId());
        System.out.println("部署名字="+deploy.getName());
    }

    /**
     * 启动流程实例
     */
    @Test
    public void startAssigneeUel(){
    
    
        //1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //设定Assignee的值,用来替换uel表达式
        Map<String, Object> map = new HashMap<>();
        map.put("assignee0","张三");
        map.put("assignee1","李四");
        map.put("assignee2","王五");
        map.put("assignee3","赵六");
        //3、根据流程定义的id启动流程
        ProcessInstance instance = runtimeService.startProcessInstanceByKey("myEvection",map);
        //4、输出流程信息
        System.out.println("流程定义id="+instance.getProcessDefinitionId());
        System.out.println("流程实例id="+instance.getId());
        System.out.println("当前活动id="+instance.getActivityId());
    }
}

方式三:监听器分配

监听器Event中的选项包含:

  • Create:任务创建后触发
  • Assignment:任务分配后触发
  • Delete:任务完成后触发
  • All:所有事件发生都触发
    在这里插入图片描述
    创建监听类:
package com.yzs;

import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;

public class MyTaskListener implements TaskListener {
    
    
    /**
     * 指定负责人
     * @param delegateTask
     */
    @Override
    public void notify(DelegateTask delegateTask) {
    
    
        if ("创建出差申请".equals(delegateTask.getName()) && "create".equals(delegateTask.getEventName())){
    
    
            delegateTask.setAssignee("xiaoyu");
        }
    }
}

2、流程变量

(1)类型

  • String
  • Integer
  • short
  • long
  • double
  • boolean
  • date
  • binary
  • serializable

注意:如果将pojo存储到流程变量中,必须实现序列化接口serializable,为了防止由于新增字段无法反序列化,需要生成serializable。

(2)作用域

  • globa变量:变量名不允许重复,设置相同名称的变量,后设置的值会覆盖前设置的变量值。
  • local变量:变量名可以相同,作用域互不影响。

(3)使用方式

  • 在属性上使用UEL表达式
  • 在连线上使用UEL表达式

(4)代码实现
编写pojo实体类,实现序列化接口serializable。

package com.yzs;

import java.io.Serializable;
import java.util.Date;

//出差实体类
public class Evection implements Serializable {
    
    
    //出差id
    private String id;
    //出差人
    private String name;
    //出差时间
    private Date time;

    public String getId() {
    
    
        return id;
    }

    public void setId(String id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Date getTime() {
    
    
        return time;
    }

    public void setTime(Date time) {
    
    
        this.time = time;
    }
}

编写测试类

package com.yzs;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.junit.Test;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class VariablesTest {
    
    
    /**
     * 流程部署
     */
    @Test
    public void testDeployment(){
    
    
        //1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //3、使用service进行流程部署,定义流程名字,将bpmn部署到数据库中
        Deployment deploy = repositoryService.createDeployment()
                .name("出差申请流程")
                .addClasspathResource("bpmn/evection.bpmn")
                .deploy();
        //4、输出部署信息
        System.out.println("部署id="+deploy.getId());
        System.out.println("部署名字="+deploy.getName());
    }

    /**
     * 启动流程实例
     */
    @Test
    public void startAssigneeUel(){
    
    
        //1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();

        //设定Assignee的值,用来替换uel表达式
        Evection evection = new Evection();
        evection.setId("1");
        evection.setName("张三");
        evection.setTime(new Date());

        Map<String, Object> map = new HashMap<>();
        map.put("evection",evection);
        map.put("assignee0","张三");
        map.put("assignee1","李四");
        map.put("assignee2","王五");
        map.put("assignee3","赵六");
        //3、根据流程定义的id启动流程
        ProcessInstance instance = runtimeService.startProcessInstanceByKey("myEvection",map);
        //4、输出流程信息
        System.out.println("流程定义id="+instance.getProcessDefinitionId());
        System.out.println("流程实例id="+instance.getId());
        System.out.println("当前活动id="+instance.getActivityId());
    }
}

3、设置globa流程变量的方式

(1)启动流程时设置变量。

   /**
    * 启动流程实例
    */
   @Test
   public void startAssigneeUel(){
    
    
       //1、创建ProcessEngine
       ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
       //2、获取RuntimeService
       RuntimeService runtimeService = processEngine.getRuntimeService();

       //设定Assignee的值,用来替换uel表达式
       Evection evection = new Evection();
       evection.setId("1");
       evection.setName("张三");
       evection.setTime(new Date());

       Map<String, Object> map = new HashMap<>();
       map.put("evection",evection);
       map.put("assignee0","张三");
       map.put("assignee1","李四");
       map.put("assignee2","王五");
       map.put("assignee3","赵六");
       //3、根据流程定义的id启动流程
       ProcessInstance instance = runtimeService.startProcessInstanceByKey("myEvection",map);
       //4、输出流程信息
       System.out.println("流程定义id="+instance.getProcessDefinitionId());
       System.out.println("流程实例id="+instance.getId());
       System.out.println("当前活动id="+instance.getActivityId());
   }

(2)任务办理时设置变量。

	/**
     * 完成任务,判断当前用户是否有权限
     */
    @Test
    public void completTask(){
    
    
        //1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取TaskService
        TaskService taskService = processEngine.getTaskService();
        
        //3、创建变量集合
        Map<String, Object> map = new HashMap<>();
        Evection evection = new Evection();
        evection.setId("1");
        evection.setName("张三");
        evection.setTime(new Date());
        //4、定义流程变量
        map.put("evection",evection);

        //5、校验该负责人可以完成当前任务,查询到就去完成任务
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("myEvection")
                .taskAssignee("张三")
                .singleResult();
        if(task != null){
    
       
	        //6、根据任务id完成任务
	        taskService.complete(task.getId(),map);
        }
    }

(3)通过当前流程实例设置。(该流程实例必须未执行完成)

	@Test
    public void setGlobalVariableByExecutionId(){
    
    
        String executionId = "2601";
        //1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        
        //3、创建变量集合
        Evection evection = new Evection();
        evection.setId("1");
        evection.setName("张三");
        evection.setTime(new Date());
        //4、通过流程实例id设置流程变量
        runtimeService.setVariable(executionId,"evection",evection);

//       一次设置多个值
//      runtimeService.setVariables(executionId,variables);
    }

(4)通过当前任务设置。

	@Test
    public void setGlobalVariableByTaskId(){
    
    
        String taskId = "1404";
        //1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取TaskService
        TaskService taskService = processEngine.getTaskService();
        
        //3、创建变量集合
        Evection evection = new Evection();
        evection.setId("1");
        evection.setName("张三");
        evection.setTime(new Date());
        //4、通过任务设置流程变量
        taskService.setVariable(taskId,"evection",evection);

//       一次设置多个值
//      taskService.setVariables(taskId,variables);

注意:如果连线不设置条件,会走flow序号小的那条线。

4、设置local流程变量的方式

(1)任务办理时设置变量。

    @Test
    public void completTask(){
    
    
    	String taskId = "1404";
        //1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取TaskService
        TaskService taskService = processEngine.getTaskService();
        
        //3、创建变量集合
        Map<String, Object> map = new HashMap<String,Object>();
        Evection evection = new Evection();
        evection.setId("1");
        evection.setName("张三");
        evection.setTime(new Date());
        //4、定义流程变量
        map.put("evection",evection);

        //5、设置local变量,作用域为该任务
        taskService.setVariablesLocal(taskId,map);
        //6、完成任务
        taskService.complete(taskId);
    }

(2)通过当前任务设置。

	@Test
    public void setGlobalVariableByTaskId(){
    
    
        String taskId = "1404";
        //1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取TaskService
        TaskService taskService = processEngine.getTaskService();
        
        //3、创建变量集合
        Evection evection = new Evection();
        evection.setId("1");
        evection.setName("张三");
        evection.setTime(new Date());
        //4、通过任务设置流程变量
        taskService.setVariableLocal(taskId,"evection",evection);

//       一次设置多个值
//      taskService.setVariablesLocal(taskId,variables);

5、组任务

组任务办理流程:查询组任务–>拾取(claim)任务–>查询个人任务–>办理个人任务

/**
     * 查询组任务
     */
    @Test
    public void findGroupTaskList(){
    
    
        //流程定义key
        String key = "myEvection";
        //任务候选人
        String candidateUser = "liming";

        //1、获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //3、查询组任务
        List<Task> taskList = taskService.createTaskQuery()
                .processDefinitionKey(key)
                .taskCandidateUser(candidateUser)
                .list();
        for (Task task:taskList){
    
    
            System.out.println("流程实例id="+task.getProcessInstanceId());
            System.out.println("任务id="+task.getId());
            System.out.println("任务负责人="+task.getAssignee());
        }
    }

    /**
     * 拾取任务
     */
    @Test
    public void claimTask(){
    
    
        //任务id
        String taskId = "65001";
        //任务候选人
        String candidateUser = "liming";


        //1、获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //3、查询组任务
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskCandidateUser(candidateUser)
                .singleResult();
        //拾取任务
        if (task != null){
    
    
            taskService.claim(taskId,candidateUser);
            System.out.println("任务拾取成功");
        }
    }

    /**
     * 归还任务
     */
    @Test
    public void assigneeToGroup(){
    
    
        //任务id
        String taskId = "65001";
        //任务负责人
        String assignee = "liming";


        //1、获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //3、查询组任务
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskAssignee(assignee)
                .singleResult();
        //归还任务,其实就是把任务的负责人设置为空
        if (task != null){
    
    
            taskService.claim(taskId,null);
            System.out.println("任务归还成功");
        }
    }

    /**
     * 交接任务
     */
    @Test
    public void assigneeToCandidateUser(){
    
    
        //任务id
        String taskId = "65001";
        //任务负责人
        String assignee = "liming";
        //任务候选人
        String candidateUser = "lisi";

        //1、获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2、获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //3、查询组任务
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskAssignee(assignee)
                .singleResult();
        //交接任务,其实就是把任务的负责人设置为新的候选人
        if (task != null){
    
    
            taskService.claim(taskId,candidateUser);
            System.out.println("任务交接成功");
        }
    }

6、网关

(1)排他网关

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

注意:排他网关只会选择一个为true的分支执行。如果有两个分支条件都为true,排他网关会选择id值较小的一条分支去执行。

为什么要用排他网关?
不用排他网关也可以实现分支,如:在连线的condition条件上设置分支条件。在连线设置condition条件的缺点:如果条件都不满足,流程就结束了(是异常结束)。如果使用排他网关决定分支的走向,如果从网关出去的线所有条件都不满足则系统抛出异常。

(2)并行网关

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

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

注意:如果同一个并行网关有多个进入和多个外出顺序流,它就同时具有分支和汇聚功能。这时,网关会先汇聚所有进入的顺序流,然后再切分成多个并行分支。与其他网关的主要区别是,并行网关不会解析条件。即使顺序流中定义了条件,也会被忽略。

(3)包含网关

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

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

(4)事件网关

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

注意:基于事件网关的外出顺序流和普通顺序流不同,这些顺序流不会真的"执行", 相反它们让流程引擎去决定执行到基于事件网关的流程需要订阅哪些事件。 要考虑以下条件:

基于事件网关必须有两条或以上外出顺序流;
基于事件网关后,只能使用intermediateCatchEvent类型(activiti不支持基于事件网关后连接ReceiveTask。);
连接到事件网关的中间捕获事件必须只有一个入口顺序流。

猜你喜欢

转载自blog.csdn.net/fish332/article/details/118308271