Bootstrap

activiti7 | 测试用例

目录

1、在idea中安装插件​编辑

 2、导入activiti7 jar依赖

3、添加 activiti 文件

4、创建数据库25个表

5、部署第一个流程

6、部署多个流程

 7、启动流程实例

8、个人任务查询

9、完成个人任务

10、使用zip批量部署流程

11、查询流程定义

12、删除流程定义

13、流程资源文件下载

14、关联activi业务

15、监听器

16、流程变量

16.1 在属性上使用UEL表达式

16.2 在连线上使用UEL表达式

16.3 使用 Global变量控制流程(测试)

16.4 local变量

17、组任务

17.1 拾取组任务

17.2 归还组任务

17.3 数据库表操作

17.3.1查询当前任务执行表

17.3.2查询任务参与者

18、任务交接(改变负责人)

19、网关

测试代码用例一

 测试代码用例二


1、在idea中安装插件

 2、导入activiti7 jar依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zhang</groupId>
    <artifactId>activiti01</artifactId>
    <version>1.0-SNAPSHOT</version>
    <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>
        </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>8.0.20</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>

</project>

3、添加 activiti 文件

activiti.cfg.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 数据源 -->

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/activiti?useUnicode=true&amp;characterEncoding=utf8&amp;nullCatalogMeansCurrent=true&amp;useSSL=false&amp;useLegacyDatetimeCode=false&amp;serverTimezone=UTC"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="maxActive" value="3" />
        <property name="maxIdle" value="1" />
    </bean>


    <!-- 工作流引擎配置bean -->
    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
        <!-- 数据源 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 使用spring事务管理器 -->
        <property name="transactionManager" ref="transactionManager"/>
        <!--flase: 默认值。activiti在启动时,会对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常。(生产
                    环境常用)
            true: activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建。(开发时常用)
            create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)。(单元测试常用)
            drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)。-->
        <!-- 数据库策略 -->
        <!--        <property name="databaseSchemaUpdate" value="drop-create"/>-->
        <property name="databaseSchemaUpdate" value="true"/>
    </bean>
    <!-- 流程引擎 -->
    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
        <property name="processEngineConfiguration" ref="processEngineConfiguration"/>
    </bean>
    <!-- 资源服务service -->
    <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
    <!-- 流程运行service -->
    <bean id="runtimeService" factory-bean="processEngine"  factory-method="getRuntimeService"/>
    <!-- 任务管理service -->
    <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/>
    <!-- 历史管理service -->
    <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService"/>
    <!-- 事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 传播行为 -->
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="insert*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
            <tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    <!-- 切面,根据具体项目修改切点配置
    <aop:config proxy-target-class="true">
        <aop:advisor advice-ref="txAdvice"
                     pointcut="execution(*com.itheima.service.impl..(..))"/>
    </aop:config>-->
</beans>

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=%d{ISO8601} %-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=f:\act\activiti.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n

4、画流程图

4、创建数据库25个表

    /**
     * 创建数据库25个表
     */
    @org.junit.Test
    public void Test00() {
        // 1、默认
//        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        RepositoryService repositoryService = processEngine.getRepositoryService();
//        repositoryService.createDeployment();

//        2、自定义配置
        ProcessEngine engine = ProcessEngineConfiguration
                .createProcessEngineConfigurationFromResource("activiti.cfg.xml")
                .buildProcessEngine();
        System.out.println("engine = " + engine);
    }

5、部署第一个流程

流程只有一个,且有唯一的key标识。只有部署了流程,才可以启动我们的流程实例。

比如张三请假、李四也请假了,他们可以共用一个流程。但是,有不同的流程实例id。

    /**
     * 部署流程定义
     */
    @org.junit.Test
    public void Test02() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deployment = repositoryService
                .createDeployment()
                .name("流程部署")
                .addClasspathResource("bpmn/evection.bpmn20.xml")
                .deploy();
        System.out.println("deployment.getName() = " + deployment.getName());
        System.out.println("deployment.getId() = " + deployment.getId());
        System.out.println("deployment.getCategory() = " + deployment.getCategory());
        System.out.println("deployment.getDeploymentTime() = " + deployment.getDeploymentTime());
        System.out.println("deployment.getTenantId() = " + deployment.getTenantId());
        System.out.println("deployment.getKey() = " + deployment.getKey());
    }

6、部署多个流程

企业不可能一个个部署项目。效率低,开发人员、用户感人。

使用zip批量部署。

    /**
     * 通过zip完成多文件流程定义部署
     */
    @org.junit.Test
    public void Test06() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();

        InputStream zipInputStream = this.getClass()
                .getClassLoader()
                .getResourceAsStream("bpmn/evection.zip");
        if (zipInputStream != null) {

            ZipInputStream stream = new ZipInputStream(zipInputStream);
            Deployment deployment = repositoryService.createDeployment()
                    .addZipInputStream(stream)
                    .deploy();
            System.out.println("deployment.getId() = " + deployment.getId());
            System.out.println("deployment.getName() = " + deployment.getName());
        }
    }

 7、启动流程实例

 流程实例(ProcessInstance)代表流程定义的执行实例。一个流程实例包括了所有的运行节点。我们可以利用这个对象来了解当前流程实例的进度等信息。例如:用户或程序按照流程定义内容发起一个流程,这就是一个流程实例。

比如,张三提交了一个请假申请单。

测试用例代码:

    /**
     * 启动流程实例
     */
    @org.junit.Test
    public void Test03() {
        // 启动第一个流程实例
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        ProcessInstance evection = runtimeService.startProcessInstanceByKey("evection");

        System.out.println("evection.getId() = " + evection.getId());
        System.out.println("evection.getProcessInstanceId() = " + evection.getProcessInstanceId());
        // 当前活动ID
        System.out.println("evection.getActivityId() = " + evection.getActivityId());

    }

8、个人任务查询

流程实例的参与者,可以看到自己的任务信息。比如,经理是任务中间人,如果张三提交了一个请假申请,作为经理,jack可以看到自己的任务。

    /**
     * 查询个人任务
     */
    @org.junit.Test
    public void Test04() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        String assignee = "zhangsan";
        List<Task> tasks = taskService
                .createTaskQuery()
                .processDefinitionKey("evection") // 流程实例key:evection
                .taskAssignee(assignee)
                .list();

        if (tasks.size() > 0) {
            for (Task task : tasks) {
                System.out.println("task.getAssignee() = " + task.getAssignee());
                System.out.println("task.getProcessInstanceId() = " + task.getProcessInstanceId());
                System.out.println("task.getName() = " + task.getName());
                System.out.println("task.getId() = " + task.getId());
                System.out.println("==========================");
            }
        } else {
            System.out.println(assignee + "暂时没有任务");
        }
    }

控制台sql: 

SELECT DISTINCT
	RES.* 
FROM
	ACT_RU_TASK RES
	INNER JOIN ACT_RE_PROCDEF D ON RES.PROC_DEF_ID_ = D.ID_ 
WHERE
	RES.ASSIGNEE_ = 'zhangsan' 
	AND D.KEY_ = 'evection'
ORDER BY
	RES.ID_ ASC 

9、完成个人任务

    /**
     * 完成个人任务
     */
    @org.junit.Test
    public void Test05() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        String assignee = "jack";
        String taskId = "72505";
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .singleResult();

        if (task != null) {
            System.out.println("task.getAssignee() = " + task.getAssignee());
            System.out.println("task.getProcessInstanceId() = " + task.getProcessInstanceId());
            System.out.println("task.getName() = " + task.getName());
            System.out.println("task.getId() = " + task.getId());
            System.out.println("==========================");
            taskService.complete(task.getId());
        } else {
            System.out.println(assignee + "暂时没有任务了");
        }
    }

10、使用zip批量部署流程

 用例代码:

    @org.junit.Test
    public void Test05() {
        // 完成个人任务
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();

        InputStream zipInputStream = this.getClass()
                .getClassLoader()
                .getResourceAsStream("bpmn/evection.zip");
        if (zipInputStream != null) {

            ZipInputStream stream = new ZipInputStream(zipInputStream);
            Deployment deployment = repositoryService.createDeployment()
                    .addZipInputStream(stream)
                    .deploy();
            System.out.println("deployment.getId() = " + deployment.getId());
            System.out.println("deployment.getName() = " + deployment.getName());
        }
    }

11、查询流程定义

    /**
     * 查询流程定义
     */
    @org.junit.Test
    public void Test06() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        ProcessDefinitionQuery processDefinitionQuery = repositoryService
                .createProcessDefinitionQuery();

        List<ProcessDefinition> processDefinitions = processDefinitionQuery
                .processDefinitionKey("evection")
                .orderByProcessDefinitionVersion()
                .desc()
                .list();
        if (processDefinitions.size() > 0) {
            for (ProcessDefinition item : processDefinitions) {
                System.out.println("item.getId() = " + item.getId());
                System.out.println("item.getName() = " + item.getName());
                System.out.println("item.getDeploymentId() = " + item.getDeploymentId());
                System.out.println("==================");
            }
        }
    }

12、删除流程定义

    /**
     * 删除部署
     */
    @org.junit.Test
    public void Test07() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();

        String deleteDeployId = "1";
        repositoryService.deleteDeployment(deleteDeployId);

        // 即使该部署已经有了示例在跑,级联删除,不管流程实例是否在运行中,也照样删
//        repositoryService.deleteDeployment(deleteDeployId,true);
    }

13、流程资源文件下载

领导要看流程图,看看流程怎么走的;

开发人员也想看看;

项目经理也要看。

这时候开发人员就只能给他们看了。

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

解决方案有:

1、jdbc对blob类型,clob类型数据读取出来,保存到文件目录

2、使用activiti的api来实现

使用commons-io.jar 解决IO的操作

引入commons-io依赖包

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
    @org.junit.Test
    public void  Test10() throws IOException {
//        1、得到引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        2、获取repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
//        3、得到查询器:ProcessDefinitionQuery,设置查询条件,得到想要的流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("evection")
                .singleResult();
//        4、通过流程定义信息,得到部署ID
        String deploymentId = processDefinition.getDeploymentId();
//        5、通过repositoryService的方法,实现读取图片信息和bpmn信息
//        png图片的流
        String pngName = processDefinition.getDiagramResourceName();
        InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, pngName);
//        bpmn文件的流
        String bpmnName = processDefinition.getResourceName();
        InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, bpmnName);
//        6、构造OutputStream流
        File file_png = new File("d:/evectionflow01.png");
        File file_bpmn = new File("d:/evectionflow01.bpmn");
        FileOutputStream bpmnOut = new FileOutputStream(file_bpmn);
        FileOutputStream pngOut = new FileOutputStream(file_png);
//        7、输入流,输出流的转换
        IOUtils.copy(pngInput,pngOut);
        IOUtils.copy(bpmnInput,bpmnOut);
//        8、关闭流
        pngOut.close();
        bpmnOut.close();
        pngInput.close();
        bpmnInput.close();

    }

14、关联activi业务

实际工作中,启动流程实例时,指定的businesskey,就会在act_ru_execution 流程实例的执行表中存储businesskey。

比如:出差流程启动一个流程实例,就可以将出差单的id作为业务标识存储到activiti中,将来查询activiti的流程实例信息就可以获取出差单的id从而关联查询业务系统数据库得到出差单信息。

    /**
     * 实现 BusinessKey关联
     * <p>
     * 在启动流程实例时,指定的BusinessKey,
     * 就会在`act_ru_execution`的流程实例的执行表中存储BusinessKey。
     */
    @org.junit.Test
    public void Test12() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();

        //  args1: 流程定义的key,这个key是字符串类型的,往往是申请单的主键ID,
        //          也可以是拼接的字符串,只要我们能最后取到这个ID就行了,
        //         取到后,我们就可以使用activiti查询任务了
        // args2: 需要关联的表的唯一主键,比如用户表的ID字段
        ProcessInstance instance = runtimeService
                .startProcessInstanceByKey("evection", "1001");

        System.out.println("instance.getBusinessKey() = " + instance.getBusinessKey());
    }

15、监听器

package com.zhang;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;

/**
 * @Author lgz
 * @Description activiti 监听器
 * @Date 2023/10/14.
 */

public class TaskListener implements ExecutionListener {

    @Override
    public void notify(DelegateExecution delegateExecution) {
        String event = delegateExecution.getEventName();
        if ("start".equals(event)) {
            System.out.println("start event");
        } else if ("end".equals(event)) {
            System.out.println("end event");
        } else if ("take".equals(event)) {
            System.out.println("take event");
        }
    }

}

16、流程变量

流程不可能一直是直线。如果当前有个需求,出差天数大于3天的,让总经理审批,否则让财务小姐姐去审批,那么就有一个问题,这个天数如何控制,这个天数就可以用activiti的流程变量来做了。

16.1 在属性上使用UEL表达式

可以在 assignee 处设置 UEL 表达式,表达式的值为任务的负责人,比如: ${assignee}, assignee 就是一个流程变量名称。

Activiti获取UEL表达式的值,即流程变量assignee的值 ,将assignee的值作为任务的负责人进行任务分配

16.2 在连线上使用UEL表达式

可以在连线上设置UEL表达式,决定流程走向。

比如:${price<10000} 。price就是一个流程变量名称,uel表达式结果类型为布尔类型。

如果UEL表达式是true,要决定 流程执行走向。

16.3 使用 Global变量控制流程(测试)

需求:员工创建出差申请单,由部门经理审核,部门经理审核通过后出差3天及以下由人财务直接审批,3天以上先由总经理审核,总经理审核通过再由财务审批。

建pojo类:

package com.zhang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

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

/**
 * @Author lgz
 * @Description
 * @Date 2023/10/14.
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Evection implements Serializable {
    private Long id;
    /**
     * 出差单名称
     */
    private String evectionName ;
    /**
     * 出差天数
     */
    private Double day;
    private Date startTime;
    private Date endTime;
    /**
     * 目的地
     */
    private String destination;

    private String reason;
}

启动流程时,设置变量

 部署后,启动实例,测试代码如下

    /**
     * 启动流程一个实例
     * 并且设置流程变量
     * 全局变量
     */
    @Test
    public void Test06() {
        Map<String, Object> map = new HashMap<String, Object>();

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();

        Evection evection = new Evection();
        evection.setDay(2d);
//    evection是bpmn文件的流程变量    ${evection.day>3}
        map.put("evection", evection);
        map.put("assignee01", "张三");
        map.put("assignee02", "总经理jack");
        map.put("assignee03", "财务lily");
        String definitionKey = "evectionGlobal";
        runtimeService.startProcessInstanceByKey(definitionKey, map);
    }

测试是否走分支:

天数小于3天:

    /**
     * 完成个人任务
     * 看看Test06()方法设置的流程变量是否有效
     * 并且设置流程变量
     * 全局变量
     */
    @Test
    public void Test07(){
        String definitionKey = "evectionGlobal";


        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        Task task = taskService.createTaskQuery()
                .processDefinitionKey(definitionKey)
                .taskAssignee("张三")
                .singleResult();
        if (task != null) {
            taskService.complete(task.getId());
            System.out.println("完成任务======");
        }

    }

16.4 local变量

任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大, 称为 local 变量。 Local 变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响。Local 变量名也可以和 global 变量名相同,没有影响。

17、组任务

在流程定义中在任务结点的 assignee 固定设置任务负责人,在流程定义时将参与者固定设置在.bpmn 文件中,如果临时任务负责人变更则需要修改流程定义,系统可扩展性差。

针对这种情况可以给任务设置多个候选人,可以从候选人中选择参与者来完成任务。

设置多个候选人,如果张三没有上班,我们可以让李四审核,如果李四也不在,就让王五来审核。

他们都可以完成一个实例任务流程。

   <userTask id="sid-6a7e9238-f1fd-4327-84d2-a5005d1bbc20" 
name="经理审批" activiti:candidateUsers="lisi,wangwu"/>

部署、启动、查询: 


    /**
     * 部署流程定义
     * 组任务、候选人
     *
     */
    @Test
    public void Test011(){
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deployment = repositoryService
                .createDeployment()
                .name("出差申请-组任务")
                .addClasspathResource("bpmn/evecton-candidate.bpmn20.xml")
                .deploy();
        System.out.println("deployment.getName() = " + deployment.getName());
        System.out.println("deployment.getId() = " + deployment.getId());
        System.out.println("deployment.getCategory() = " + deployment.getCategory());
        System.out.println("deployment.getDeploymentTime() = " + deployment.getDeploymentTime());
        System.out.println("deployment.getTenantId() = " + deployment.getTenantId());
        System.out.println("deployment.getKey() = " + deployment.getKey());
    }

    /**
     * 启动流程一个实例
     */
    @Test
    public void Test09(){
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        String definitionKey = "evectonCandidate";
        runtimeService.startProcessInstanceByKey(definitionKey);
    }

    /**
     * 部署流程定义
     * 组任务、候选人
     *
     */
    @Test
    public void Test08(){
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskServicea = processEngine.getTaskService();
        String definitionKey = "evectonCandidate";
        String candidateUser = "wangwu";
        List<Task> tasks = taskServicea.createTaskQuery()
                .processDefinitionKey(definitionKey)
                .taskCandidateUser(candidateUser)
                .list();
        if (tasks.size() > 0) {
            for (Task task : tasks) {
                System.out.println("task.getAssignee() = " + task.getAssignee());
                System.out.println("task.getProcessInstanceId() = " + task.getProcessInstanceId());
                System.out.println("task.getName() = " + task.getName());
                System.out.println("task.getId() = " + task.getId());
                System.out.println("==========================");
            }
        }
    }

17.1 拾取组任务

候选人变成负责人

    /**
     * 拾取组任务
     * 组任务、候选人
     */
    @Test
    public void Test12() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        String candidateUser = "wangwu";
        String taskId = "75002";
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskCandidateUser(candidateUser)
                .singleResult();
        if (task != null) {
            taskService.claim(taskId, candidateUser);
            System.out.println(candidateUser + "拾取成功!");
        }
    }

拾取任务后,别的候选人就做不了任务了,如果手滑点错了,又不想审批流程,这时候就可以归还任务了。

17.2 归还组任务

    /**
     * 归还组任务
     * 组任务、候选人
     */
    @Test
    public void Test13() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        String candidateUser = "wangwu";
        String taskId = "75002";
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskAssignee(candidateUser)
                .singleResult();
        if (task != null) {
            taskService.setAssignee(taskId, null);
            System.out.println(candidateUser + "归还成功!");
        }
    }

17.3 数据库表操作

17.3.1查询当前任务执行表

SELECT * FROM act_ru_task 

任务执行表,记录当前执行的任务,由于该任务当前是组任务,所有assignee为空,当拾取任务后该字段就是拾取用户的id

17.3.2查询任务参与者

SELECT * FROM act_ru_identitylink

任务参与者,记录当前参考任务用户或组,当前任务如果设置了候选人,会向该表插入候选人记录,有几个候选就插入几个

与act_ru_identitylink对应的还有一张历史表act_hi_identitylink,向act_ru_identitylink插入记录的同时也会向历史表插入记录。任务完成  

18、任务交接(改变负责人)

把当前任务交接给另一个人。

    /**
     * 交接任务,把任务的负责人交给别的人做
     * 组任务、候选人
     */
    @Test
    public void Test15() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        String assignee = "wangwu";
        String candidateUser = "lisi";
        String taskId = "75002";

        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskAssignee(assignee)
                .singleResult();
        if (task != null) {
            taskService.setAssignee(taskId, candidateUser);
            System.out.println(assignee + "归还成功!" + candidateUser + "成了该任务的负责人!!");
        }
    }

19、网关

排他:如果分支都不符合条件,就走其中的小的id

并行:如果有两个并行分支,项目经理批准了,流程不会走到下一步,需要同一个分支的其他人审批通过,才能走到下一个分支

包含网关:如果有三个并行分支,出差天数大于3天,项目经理批准了,出差天数小于3天,人事小姐姐批准,另一个分支,不管是那种情况,人事经理都可以审批,并且,3个分支审批通过后,才可以走到下一步,需要同一个分支的其他人审批通过,才能走到下一个分支。

测试代码用例一

package com.zhang;

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 java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.zip.ZipInputStream;


/**
 * @Author lgz
 * @Description activiti7 Test测试用例
 * @Date 2023/7/13.
 */
public class Test {

    /**
     * 创建activiti7的25张表
     */
    @org.junit.Test
    public void Test01() {
        // 1、默认配置
//        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        RepositoryService repositoryService = processEngine.getRepositoryService();
//        repositoryService.createDeployment();

//        2、自定义配置
        ProcessEngine engine = ProcessEngineConfiguration
                .createProcessEngineConfigurationFromResource("activiti.cfg.xml")
                .buildProcessEngine();
        System.out.println("engine = " + engine);
    }

    /**
     * 部署流程定义
     */
    @org.junit.Test
    public void Test02() {
        // 1、部署第一个流程
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deployment = repositoryService
                .createDeployment()
                .name("第一个流程部署")
                .addClasspathResource("bpmn/evection.bpmn20.xml")
                .deploy();
        System.out.println("deployment.getName() = " + deployment.getName());
        System.out.println("deployment.getId() = " + deployment.getId());
        System.out.println("deployment.getCategory() = " + deployment.getCategory());
        System.out.println("deployment.getDeploymentTime() = " + deployment.getDeploymentTime());
        System.out.println("deployment.getTenantId() = " + deployment.getTenantId());
        System.out.println("deployment.getKey() = " + deployment.getKey());
    }

    /**
     * 启动流程实例
     */
    @org.junit.Test
    public void Test03() {
        // 启动第一个流程实例
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        ProcessInstance evection = runtimeService.startProcessInstanceByKey("evection");

        System.out.println("evection.getId() = " + evection.getId());
        System.out.println("evection.getProcessInstanceId() = " + evection.getProcessInstanceId());
        // 当前活动ID
        System.out.println("evection.getActivityId() = " + evection.getActivityId());

    }

    /**
     * 查询个人任务
     */
    @org.junit.Test
    public void Test04() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        String assignee = "zhangsan";
        List<Task> tasks = taskService
                .createTaskQuery()
                .processDefinitionKey("evection") // 流程实例key:evection
                .taskAssignee(assignee)
                .list();

        if (tasks.size() > 0) {
            for (Task task : tasks) {
                System.out.println("task.getAssignee() = " + task.getAssignee());
                System.out.println("task.getProcessInstanceId() = " + task.getProcessInstanceId());
                System.out.println("task.getName() = " + task.getName());
                System.out.println("task.getId() = " + task.getId());
                System.out.println("==========================");
            }
        } else {
            System.out.println(assignee + "暂时没有任务");
        }
    }

    /**
     * 完成个人任务
     */
    @org.junit.Test
    public void Test05() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        String assignee = "jack";
        Task task = taskService.createTaskQuery()
                .taskId("72505")
                .singleResult();

        if (task != null) {
            System.out.println("task.getAssignee() = " + task.getAssignee());
            System.out.println("task.getProcessInstanceId() = " + task.getProcessInstanceId());
            System.out.println("task.getName() = " + task.getName());
            System.out.println("task.getId() = " + task.getId());
            System.out.println("==========================");
            taskService.complete(task.getId());
        } else {
            System.out.println(assignee + "暂时没有任务了");
        }
    }

    /**
     * 通过zip完成多文件流程定义部署
     */
    @org.junit.Test
    public void Test06() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();

        InputStream zipInputStream = this.getClass()
                .getClassLoader()
                .getResourceAsStream("bpmn/evection.zip");
        if (zipInputStream != null) {

            ZipInputStream stream = new ZipInputStream(zipInputStream);
            Deployment deployment = repositoryService.createDeployment()
                    .addZipInputStream(stream)
                    .deploy();
            System.out.println("deployment.getId() = " + deployment.getId());
            System.out.println("deployment.getName() = " + deployment.getName());
        }
    }

    /**
     * 查询流程定义
     */
    @org.junit.Test
    public void Test07() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        ProcessDefinitionQuery processDefinitionQuery = repositoryService
                .createProcessDefinitionQuery();

        List<ProcessDefinition> processDefinitions = processDefinitionQuery
                .processDefinitionKey("evection")
                .orderByProcessDefinitionVersion()
                .desc()
                .list();

        if (processDefinitions.size() > 0) {
            for (ProcessDefinition item : processDefinitions) {
                System.out.println("item.getId() = " + item.getId());
                System.out.println("item.getName() = " + item.getName());
                System.out.println("item.getDeploymentId() = " + item.getDeploymentId());
                System.out.println("==================");
            }
        }
    }

    /**
     * 删除流程部署
     */
    @org.junit.Test
    public void Test08() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();

        String deleteDeployId = "82501";

        // 即使该部署已经有了示例在跑,也照样删
        repositoryService.deleteDeployment(deleteDeployId, true);
    }

    /**
     * 文件下载
     *
     * @throws IOException
     */
    @org.junit.Test
    public void Test10() throws IOException {
//        1、得到引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        2、获取repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
//        3、得到查询器:ProcessDefinitionQuery,设置查询条件,得到想要的流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("evection")
                .singleResult();
//        4、通过流程定义信息,得到部署ID
        String deploymentId = processDefinition.getDeploymentId();
//        5、通过repositoryService的方法,实现读取图片信息和bpmn信息
//        png图片的流
        String pngName = processDefinition.getDiagramResourceName();
        InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, pngName);
//        bpmn文件的流
        String bpmnName = processDefinition.getResourceName();
        InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, bpmnName);
//        6、构造OutputStream流
        File file_png = new File("d:/evectionflow01.png");
        File file_bpmn = new File("d:/evectionflow01.bpmn");
        FileOutputStream bpmnOut = new FileOutputStream(file_bpmn);
        FileOutputStream pngOut = new FileOutputStream(file_png);
//        7、输入流,输出流的转换
        IOUtils.copy(pngInput, pngOut);
        IOUtils.copy(bpmnInput, bpmnOut);
//        8、关闭流,不要忘记了关流,会耗资源
        pngOut.close();
        bpmnOut.close();
        pngInput.close();
        bpmnInput.close();
    }

    /**
     * 查看历史信息
     * 每完成一个任务,activiti都会在历史表记录相关的信息
     */
    @org.junit.Test
    public void Test11() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        HistoryService historyService = defaultProcessEngine.getHistoryService();
        HistoricActivityInstanceQuery query = historyService
                .createHistoricActivityInstanceQuery()
                .orderByHistoricActivityInstanceStartTime().asc();

        List<HistoricActivityInstance> histories = query.processInstanceId("5001").list();

        if (histories.size() > 0) {
            for (HistoricActivityInstance item : histories) {
                System.out.println(item.getActivityId());
                System.out.println(item.getActivityName());
                System.out.println(item.getProcessDefinitionId());
                System.out.println(item.getProcessInstanceId());
                System.out.println("<==========================>");
            }
        }
    }

    /**
     * 实现 BusinessKey关联
     * <p>
     * 在启动流程实例时,指定的BusinessKey,
     * 就会在`act_ru_execution`的流程实例的执行表中存储BusinessKey。
     */
    @org.junit.Test
    public void Test12() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();

        //  args1: 流程定义的key,这个key是字符串类型的,往往是申请单的主键ID,
        //          也可以是拼接的字符串,只要我们能最后取到这个ID就行了,
        //         取到后,我们就可以使用activiti查询任务了
        // args2: 需要关联的表的唯一主键,比如用户表的ID字段
        ProcessInstance instance = runtimeService
                .startProcessInstanceByKey("evection", "1001");

        System.out.println("instance.getBusinessKey() = " + instance.getBusinessKey());
    }

    /**
     * 实现全部流程实例挂起与激活
     */
    @org.junit.Test
    public void Test13() {
        //        获取processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //        获取repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //        查询流程定义的对象
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().
                processDefinitionKey("evection").
                singleResult();
        //        得到当前流程定义的实例是否都为暂停状态
        boolean suspended = processDefinition.isSuspended();
        //        流程定义id
        String processDefinitionId = processDefinition.getId();
        //        判断是否为暂停
        if (suspended) {
            //         如果是暂停(挂起了),可以执行激活操作 ,参数1 :流程定义id ,参数2:是否激活,参数3:激活时间
            repositoryService
                    .activateProcessDefinitionById(processDefinitionId,
                            true,
                            null
                    );
            System.out.println("流程定义:" + processDefinitionId + ",已激活");
        } else {
            //          如果是激活状态,可以暂停,参数1 :流程定义id ,参数2:是否暂停,参数3:暂停时间
            repositoryService.suspendProcessDefinitionById(processDefinitionId,
                    true,
                    null);
            System.out.println("流程定义:" + processDefinitionId + ",已挂起");
        }

    }

    /**
     * 实现单个流程实例挂起与激活
     */
    @org.junit.Test
    public void Test14() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId("10001")
                .singleResult();
        if (processInstance.isSuspended()) {
            runtimeService.activateProcessInstanceById(processInstance.getId());
            System.out.println("actived!");
        } else {
            runtimeService.suspendProcessInstanceById(processInstance.getId());
            System.out.println("suspended!");
        }

    }
}

 测试代码用例二

package com.zhang;

import com.zhang.pojo.Evection;
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;

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

/**
 * @Author lgz
 * @Description activiti7 Test测试用例二
 * @Date 2023/7/14.
 */
public class Test02 {
    /**
     * 部署流程定义
     * uel表达式
     */
    @Test
    public void Test00() {
        // 1、部署第一个流程
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deployment = repositoryService
                .createDeployment()
                .name("出差申请-UEL")
                .addClasspathResource("bpmn/evection-uel.bpmn20.xml")
                .deploy();
        System.out.println("deployment.getName() = " + deployment.getName());
        System.out.println("deployment.getId() = " + deployment.getId());
        System.out.println("deployment.getCategory() = " + deployment.getCategory());
        System.out.println("deployment.getDeploymentTime() = " + deployment.getDeploymentTime());
        System.out.println("deployment.getTenantId() = " + deployment.getTenantId());
        System.out.println("deployment.getKey() = " + deployment.getKey());
    }

    /**
     * 启动流程实例
     */
    @Test
    public void Test01() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("assignee0", "张三");
        map.put("assignee1", "总经理Jack");
        ProcessInstance evectionUel = runtimeService.startProcessInstanceByKey("evectionUel", map);

        System.out.println("evection.getId() = " + evectionUel.getId());
        System.out.println("evection.getProcessInstanceId() = " + evectionUel.getProcessInstanceId());
        // 当前活动ID
        System.out.println("evection.getActivityId() = " + evectionUel.getActivityId());
    }


    /**
     * 部署流程定义
     * 监听
     */
    @Test
    public void Test03() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deployment = repositoryService
                .createDeployment()
                .name("出差申请-listener")
                .addClasspathResource("bpmn/demo-listen.bpmn20.xml")
                .deploy();
        System.out.println("deployment.getName() = " + deployment.getName());
        System.out.println("deployment.getId() = " + deployment.getId());
        System.out.println("deployment.getCategory() = " + deployment.getCategory());
        System.out.println("deployment.getDeploymentTime() = " + deployment.getDeploymentTime());
        System.out.println("deployment.getTenantId() = " + deployment.getTenantId());
        System.out.println("deployment.getKey() = " + deployment.getKey());
    }

    /**
     * 启动第一个流程实例
     * 监听
     */
    @Test
    public void Test04() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        ProcessInstance evection = runtimeService.startProcessInstanceByKey("testListener");
        System.out.println("evection.getId() = " + evection.getId());
        System.out.println("evection.getProcessInstanceId() = " + evection.getProcessInstanceId());
        // 当前活动ID
        System.out.println("evection.getActivityId() = " + evection.getActivityId());
    }

    /**
     * 部署流程定义
     * 流程变量
     * 全局变量
     */
    @Test
    public void Test05() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deployment = repositoryService
                .createDeployment()
                .name("出差申请-全局变量")
                .addClasspathResource("bpmn/evection-global.bpmn20.xml")
                .deploy();
        System.out.println("deployment.getName() = " + deployment.getName());
        System.out.println("deployment.getId() = " + deployment.getId());
        System.out.println("deployment.getCategory() = " + deployment.getCategory());
        System.out.println("deployment.getDeploymentTime() = " + deployment.getDeploymentTime());
        System.out.println("deployment.getTenantId() = " + deployment.getTenantId());
        System.out.println("deployment.getKey() = " + deployment.getKey());
    }


    /**
     * 启动流程一个实例
     * 并且设置流程变量
     * 全局变量
     */
    @Test
    public void Test06() {
        Map<String, Object> map = new HashMap<String, Object>();

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();

        Evection evection = new Evection();
        evection.setDay(2d);
//    evection是bpmn文件的流程变量    ${evection.day>3}
        map.put("evection", evection);
        map.put("assignee01", "张三");
        map.put("assignee02", "总经理jack");
        map.put("assignee03", "财务lily");
        String definitionKey = "evectionGlobal";
        runtimeService.startProcessInstanceByKey(definitionKey, map);
    }

    /**
     * 完成个人任务
     * 看看Test06()方法设置的流程变量是否有效
     * 并且设置流程变量
     * 全局变量
     */
    @Test
    public void Test07() {
        String definitionKey = "evectionGlobal";


        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        Task task = taskService.createTaskQuery()
                .processDefinitionKey(definitionKey)
                .taskAssignee("张三")
                .singleResult();
        if (task != null) {
            taskService.complete(task.getId());
            System.out.println("完成任务======");
        }
    }

    /**
     * 部署流程定义
     * 组任务、候选人
     */
    @Test
    public void Test011() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deployment = repositoryService
                .createDeployment()
                .name("出差申请-组任务")
                .addClasspathResource("bpmn/evecton-candidate.bpmn20.xml")
                .deploy();
        System.out.println("deployment.getName() = " + deployment.getName());
        System.out.println("deployment.getId() = " + deployment.getId());
        System.out.println("deployment.getCategory() = " + deployment.getCategory());
        System.out.println("deployment.getDeploymentTime() = " + deployment.getDeploymentTime());
        System.out.println("deployment.getTenantId() = " + deployment.getTenantId());
        System.out.println("deployment.getKey() = " + deployment.getKey());
    }

    /**
     * 启动流程一个实例
     */
    @Test
    public void Test09() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        String definitionKey = "evectonCandidate";
        runtimeService.startProcessInstanceByKey(definitionKey);
    }

    /**
     * 部署流程定义
     * 组任务、候选人
     */
    @Test
    public void Test08() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        String definitionKey = "evectonCandidate";
        String candidateUser = "wangwu";
        List<Task> tasks = taskService.createTaskQuery()
                .processDefinitionKey(definitionKey)
                .taskCandidateUser(candidateUser)
                .list();
        if (tasks.size() > 0) {
            for (Task task : tasks) {
                System.out.println("task.getAssignee() = " + task.getAssignee());
                System.out.println("task.getProcessInstanceId() = " + task.getProcessInstanceId());
                System.out.println("task.getName() = " + task.getName());
                System.out.println("task.getId() = " + task.getId());
                System.out.println("==========================");
            }
        }
    }


    /**
     * 拾取组任务
     * 组任务、候选人
     */
    @Test
    public void Test12() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        String candidateUser = "wangwu";
        String taskId = "75002";
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskCandidateUser(candidateUser)
                .singleResult();
        if (task != null) {
            taskService.claim(taskId, candidateUser);
            System.out.println(candidateUser + "拾取成功!");
        }
    }

    /**
     * 归还组任务
     * 组任务、候选人
     */
    @Test
    public void Test13() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        String candidateUser = "wangwu";
        String taskId = "75002";
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskAssignee(candidateUser)
                .singleResult();
        if (task != null) {
            taskService.setAssignee(taskId, null);
            System.out.println(candidateUser + "归还成功!");
        }
    }

    /**
     * 交接任务,把任务的负责人交给别的人做
     * 组任务、候选人
     */
    @Test
    public void Test15() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        String assignee = "wangwu";
        String candidateUser = "lisi";
        String taskId = "75002";

        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskAssignee(assignee)
                .singleResult();
        
        if (task != null) {
            taskService.setAssignee(taskId, candidateUser);
            System.out.println(assignee + "归还成功!" + candidateUser + "成了该任务的负责人!!");
        }
    }


    /**
     * 排他网关
     */
    @Test
    public void Test16() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deployment = repositoryService
                .createDeployment()
                .name("出差申请-排他网关")
                .addClasspathResource("bpmn/evection-exclusive.bpmn20.xml")
                .deploy();
        
        System.out.println("deployment.getName() = " + deployment.getName());
        System.out.println("deployment.getId() = " + deployment.getId());
        System.out.println("deployment.getCategory() = " + deployment.getCategory());
        System.out.println("deployment.getDeploymentTime() = " + deployment.getDeploymentTime());
        System.out.println("deployment.getTenantId() = " + deployment.getTenantId());
        System.out.println("deployment.getKey() = " + deployment.getKey());
    }
}

;