Activiti工作流案例介绍

创建设计图

在项目resources文件中 创建 diagrams 文件夹
在这里插入图片描述

在该文件夹下创建一个

在这里插入图片描述

输入自己定义的名字

在这里插入图片描述

File name改成helloWorld 然后点击Finish;

在这里插入图片描述

这里 中间区域,是我们用来绘制流程图标的。右侧是绘制流程图标的工具箱,下面的Properties是属性视图,我们目前看到的是整个helloWorld流程图的属性;

这里我们可以把Process(流程)的Id和Name改下(后面我们可以通过代码能够获取到);

在这里插入图片描述

然后我们来画流程图,任何流程,都必须有一个开始事件节点和结束事件节点;

在这里插入图片描述

我们在右侧的工具箱里会看到有个StartEvent和EndEvent。我们先点下 然后拖到中间的绘图区域即可;

当然每个节点的属性我们都可以看到,而且可以设置,我们可以点击选中一个节点,然后在属性视图上看到所以值;

在这里插入图片描述

我们会看到这里插件都给我们设置了初识属性值,我们可以改 ,也可以不改,都行;

接下来我们在搞一个用户任务节点(我们以后开发最常用的节点),我们拖一个到中间绘图区域;

在这里插入图片描述

这里的任务节点,必须要有一个人去处理这个任务,而且我们在实际开发中,根据实际业务,给这个用户任务节点取个名字,

当然我们这里是初识,所以就搞个HelloWorld名字,然后分配给“java_fujun”这个人;

在这里插入图片描述

我们再把任务分配给“java_fujun”:

在这里插入图片描述

我们这个helloWorld流程比较简单,就一个任务节点,最后我们就是连线,

我们选择右侧下方的Connection下的SequenceFlow 然后只要从两个地方拉一下即可

在这里插入图片描述

我们可以看到设计好后,左上角是有一个未保存的(*)提示,我们ctrl+s保存下。这时候,我们会在disgrams包下发现

自动生成了一个对应的png文件;

在这里插入图片描述

Activiti HelloWorld实现

前面我们讲解了流程绘制,今天的话,我们要来部署流程定义,启动流程实例,查看任务以及完成任务;把一个最简单的HelloWorld流程用代码实现并且走完流程。

我们先建一个单元测试类HelloWorldProcess

首先第一步,我们要操作流程,必须获取流程引擎实例;

/**
 * 获取默认的流程引擎实例 会自动读取activiti.cfg.xml文件 
 */
private ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();

第二步,我们需要把前面我们绘制的流程定义图,部署下(底层是解析XML,然后把数据存到数据库的表中去);

/**
 * 部署流程定义
 */
@Test
public void deploy(){
    // 获取部署对象
    Deployment deployment=processEngine.getRepositoryService() // 部署Service
                 .createDeployment()  // 创建部署
                 .addClasspathResource("diagrams/helloWorld.bpmn")  // 加载资源文件
                 .addClasspathResource("diagrams/helloWorld.png")   // 加载资源文件
                 .name("HelloWorld流程")  // 流程名称
                 .deploy(); // 部署
    System.out.println("流程部署ID:"+deployment.getId());
    System.out.println("流程部署Name:"+deployment.getName());
}

第三步:我们要启动流程实例,这样一个流程才开始;

/**
 * 启动流程实例
 */
@Test
public void start(){
    // 启动并获取流程实例
    ProcessInstance processInstance=processEngine.getRuntimeService() // 运行时流程实例Service
        .startProcessInstanceByKey("myFirstProcess"); // 流程定义表的KEY字段值
    System.out.println("流程实例ID:"+processInstance.getId());
    System.out.println("流程定义ID:"+processInstance.getProcessDefinitionId());
}

第四步:启动流程后,我们流程会走到helloWorld节点,我们来查看下"java_fujun"这个用户的任务;

/**
 * 查看任务
 */
@Test
public void findTask(){
    // 查询并且返回任务即可
    List<Task> taskList=processEngine.getTaskService() // 任务相关Service
            .createTaskQuery()  // 创建任务查询
            .taskAssignee("java_fujun") // 指定某个人
            .list(); 
    for(Task task:taskList){
        System.out.println("任务ID:"+task.getId());
        System.out.println("任务名称:"+task.getName());
        System.out.println("任务创建时间:"+task.getCreateTime());
        System.out.println("任务委派人:"+task.getAssignee());
        System.out.println("流程实例ID:"+task.getProcessInstanceId());
    }
}

第五步:我们来完成helloWorld节点任务,让流程走完;

/**
 * 完成任务
 */
@Test
public void completeTask(){
    processEngine.getTaskService() // 任务相关Service
            .complete("2504"); // 指定要完成的任务ID
}

OK,前面仅仅是走流程的代码,我们下面来细讲下原理,数据库的表发生了什么;

这里有个很重要的概念,流程定义和流程实例的关系。大家可以把流程定义和流程实例的关系,理解成类和对象的关系;

流程定义就是一个模版,流程实例就是通过模版搞出来的具体的可用的东西。

所以后面涉及到的流程定义id name;流程实例id name大家不要晕。先把关系搞清楚。其他的都简单;

OK 然后我们来运行deploy方法,部署流程定义,这时候我们的流程定义表会发生一些变化;

首先act_re_deployment 流程定义部署表,插入了一条数据;

在这里插入图片描述

然后act_re_prodef 流程定义表也会有插入一条数据;

在这里插入图片描述

这里有流程定义id name key version等重要信息;后面可以通过接口来获取这些数据;

还有一个act_ge_bytearray表 用来存资源信息;

在这里插入图片描述

我们可以看到,把两个资源文件都存了 包括名称 以及文件内容;

以上是部署流程定义 数据库表里发生的事情;

然后我们继续 ,下面来启动流程实例;

运行start方法;

启动流程,数据库流程运行表也会发生相应的变化;

首先是运行时流程任务表:act_ru_task;插入了一条任务数据;

在这里插入图片描述

这个表很重要,ID_是任务id 数据2504 PROC_INST_ID_是流程实例ID 2501 以及Name 创建时间等;

接下来是act_ru_execution 运行时流程执行表;

在这里插入图片描述

当然我们这里是用具体的用户去执行的,至于group组的概念,后面单独讲;

流程实例启动完,接下来就到了helloWorld任务节点;

我们这时候可以来查看下"Java_fujun"任务

运行findTask方法,控制台输出;

任务ID:2504
任务名称:HelloWorld
任务创建时间:Mon Aar 11 15:30:41 CST 2019
任务委派人:java_zhangwei
流程实例ID:2501

说明这个用户有任务可以执行;

我们继续走流程 执行completeTask方法;

执行完后,流程其实就已经走完了。

这时候我们再运行findTask,啥都没有输入,已经没有任务了;

OK 流程执行完,数据库表会发生什么变化呢?

首先ru开头的运行时候所有表的数据都没了,因为现在流程都走完了。不需要那些数据了;

然后在hi开头的表里,存了不少数据,主要是用来归档查询用的;

act_hi_taskinst 历史流程实例任务表加了一条任务数据;

act_hi_procinst 历史流程实例实例表加了一条流程实例相关信息的数据(包括开始时间,结束时间等等信息);

act_hi_identitylink 历史流程实例参数者的表加了一条数据;

act_hi_actinst 历史活动节点表加了三条流程活动节点信息的数据(每个流程实例具体的执行活动节点的信息);

Activiti流程定义部署之ZIP方式

前面的话,我们使用的是classpath加载资源文件方式来部署流程定义的,但是这种方式有局限性,只能适合小项目,固定写死的流程;

实际项目的话,需要来动态导入流程定义文件,通过把bpmn和png文件打包成zip压缩包,然后用户界面直接导入到系统,然后解析,部署流程定义;

Activiti是支持这种方式的。今天我们来实现下这种方式;

首先第一步,把bpmn和png文件打成zip压缩包,放到diagrams文件夹下;

在这里插入图片描述

前面我们使用的是classpath加载流程定义文件;

我们新建一个测试类 ProcessDefinition


package com.fujun.activiti.test;
 
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.repository.Deployment;
import org.junit.Test;
 
public class ProcessDefinition {
 
    /**
     * 获取默认的流程引擎实例 会自动读取activiti.cfg.xml文件 
     */
    private ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
    /**
     * 部署流程定义使用classpath方式
     */
    @Test
    public void deployWithClassPath(){
        // 获取部署对象
        Deployment deployment=processEngine.getRepositoryService() // 部署Service
                     .createDeployment()  // 创建部署
                     .addClasspathResource("diagrams/helloWorld.bpmn")  // 加载资源文件
                     .addClasspathResource("diagrams/helloWorld.png")   // 加载资源文件
                     .name("HelloWorld流程")  // 流程名称
                     .deploy(); // 部署
        System.out.println("流程部署ID:"+deployment.getId());
        System.out.println("流程部署Name:"+deployment.getName());
    }
}

下面我们用zip方式来实现,新建一个deployWithZip方法:

/**
 * 部署流程定义使用zip方式
 */
@Test
public void deployWithZip(){
    InputStream inputStream=this.getClass()  // 获取当前class对象
                        .getClassLoader()   // 获取类加载器
                        .getResourceAsStream("diagrams/helloWorld.zip"); // 获取指定文件资源流
    ZipInputStream zipInputStream=new ZipInputStream(inputStream); // 实例化zip输入流对象
    // 获取部署对象
    Deployment deployment=processEngine.getRepositoryService() // 部署Service
                 .createDeployment()  // 创建部署
                 .name("HelloWorld流程2")  // 流程名称
                 .addZipInputStream(zipInputStream)  // 添加zip是输入流
                 .deploy(); // 部署
    System.out.println("流程部署ID:"+deployment.getId());
    System.out.println("流程部署Name:"+deployment.getName());
}

我们运行这个测试类:


SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
流程部署ID:7501
流程部署Name:HelloWorld流程2

说明已经部署成功了;

我们来看下相关表:

这里我们再来把几个关键表拎出来,好好熟悉下:

act_re_deployment 流程定义部署表:

在这里插入图片描述

我们会发现,这里多了一条记录;

act_re_procdef 流程定义表

在这里插入图片描述

流程定义表里,我们发现VERSION_字段 版本升级了,KEY依然是一样的;

act_ge_bytearry 资源文件表

在这里插入图片描述

资源表里相应的多里两条记录;

这里再提一个表 act_ge_property 属性表

在这里插入图片描述

Activiti之排他网关

Activiti之排他网关

所谓排他网关 顾名思义 执行到该网关,根据条件只能走一条执行线路;

在右侧 palette中 的Gateway 有个 ExclusiveGateway 即为默认网关;

在这里插入图片描述

我们绘制新的流程定义图标:

在这里插入图片描述

这里我们规定 根据请假天数,来具体让谁来审批,

请假天数小于3天,班长审批;

请假天数小于7天,大于等于3天,班主任审批;

请假天数大于等于7天,校长审批;

这里我们依然用表达式来实现;

在这里插入图片描述

班长审批连线表达式;

在这里插入图片描述

班主任审批连线表达式;

至于校长审批,我们不需要再设置表达式了,排他网关可以指定默认的执行线路;

我们找到校长审批的id;

在这里插入图片描述

是flow11;

然后我们选中 排他网关,设置默认执行的线路;
在这里插入图片描述

我们给下执行代码:

package com.fujun.gateway;
 
 
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
 
public class ExclusiveGatewayTest {
 
    /**
     * 获取默认流程引擎实例,会自动读取activiti.cfg.xml文件
     */
    private ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
     
    /**
     * 部署流程定义
     */
    @Test
    public void deploy(){
        Deployment deployment=processEngine.getRepositoryService() // 获取部署相关Service
                .createDeployment() // 创建部署
                .addClasspathResource("diagrams/StudentLeaveProcess3.bpmn") // 加载资源文件
                .addClasspathResource("diagrams/StudentLeaveProcess3.png") // 加载资源文件
                .name("学生请假流程3") // 流程名称
                .deploy(); // 部署
        System.out.println("流程部署ID:"+deployment.getId()); 
        System.out.println("流程部署Name:"+deployment.getName());
    }
     
    /**
     * 启动流程实例
     */
    @Test
    public void start(){
        ProcessInstance pi=processEngine.getRuntimeService() // 运行时Service
            .startProcessInstanceByKey("studentLevaeProcess3"); // 流程定义表的KEY字段值
        System.out.println("流程实例ID:"+pi.getId());
        System.out.println("流程定义ID:"+pi.getProcessDefinitionId()); 
    }
     
     
    /**
     * 查看任务
     */
    @Test
    public void findTask(){
        List<Task> taskList=processEngine.getTaskService() // 任务相关Service
            .createTaskQuery() // 创建任务查询
            .taskAssignee("赵六") // 指定某个人
            .list();
        for(Task task:taskList){
            System.out.println("任务ID:"+task.getId()); 
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务创建时间:"+task.getCreateTime());
            System.out.println("任务委派人:"+task.getAssignee());
            System.out.println("流程实例ID:"+task.getProcessInstanceId());
        }
    }
    /**
     * 完成任务
     */
    @Test
    public void completeTask(){
        processEngine.getTaskService() // 任务相关Service
            .complete("237504");
    }
    @Test
    public void completeTask2(){
        Map<String, Object> variables=new HashMap<String,Object>();
        variables.put("days", 8);
        processEngine.getTaskService() // 任务相关Service
            .complete("235004", variables); //完成任务的时候,设置流程变量
    }
}

Activiti之并行网关

Activiti之并行网关

所谓并行网关 顾名思义 执行到该网关,会有多条线路同时并行执行,当都执行完才继续执行后面的;

在这里插入图片描述

右侧 ParallelGateway就是并行网关;

我们修改后的业务是 学生请假审批提交,班长和班主任审批,当他们都审批完 才最终让校长审批。

package com.fujun.gateway;
import java.util.List;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
public class ParallelGatewayTest {
    /**
     * 获取默认流程引擎实例,会自动读取activiti.cfg.xml文件
     */
    private ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
    /**
     * 部署流程定义
     */
    @Test
    public void deploy(){
        Deployment deployment=processEngine.getRepositoryService() // 获取部署相关Service
                .createDeployment() // 创建部署
                .addClasspathResource("diagrams/StudentLeaveProcess4.bpmn") // 加载资源文件
                .addClasspathResource("diagrams/StudentLeaveProcess4.png") // 加载资源文件
                .name("学生请假流程4") // 流程名称
                .deploy(); // 部署
        System.out.println("流程部署ID:"+deployment.getId());() 
        System.out.println("流程部署Name:"+deployment.getName());
    }
    /**
     * 启动流程实例
     */
    @Test
    public void start(){
        ProcessInstance pi=processEngine.getRuntimeService() // 运行时Service
            .startProcessInstanceByKey("studentLevaeProcess4"); // 流程定义表的KEY字段值
        System.out.println("流程实例ID:"+pi.getId());
        System.out.println("流程定义ID:"+pi.getProcessDefinitionId()); 
    }

    /**
     * 查看任务
     */
    @Test
    public void findTask(){
        List<Task> taskList=processEngine.getTaskService() // 任务相关Service
            .createTaskQuery() // 创建任务查询
            .taskAssignee("张三") // 指定某个人
            .list();
        for(Task task:taskList){
            System.out.println("任务ID:"+task.getId()); 
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务创建时间:"+task.getCreateTime());
            System.out.println("任务委派人:"+task.getAssignee());
            System.out.println("流程实例ID:"+task.getProcessInstanceId());
        }
    }

    /**
     * 完成任务
     */
    @Test
    public void completeTask(){
        processEngine.getTaskService() // 任务相关Service
            .complete("265003");
    }
}

Activiti之个人任务分配

Activiti之个人任务分配

分配方式一 直接流程图配置中写死

在这里插入图片描述

这种方式前面讲过 直接在流程图中 Main config Assignee 中写死具体分配的任务执行人;

package com.fujun.taskassign;
 
 
import java.util.List;
 
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
public class AssignTest01 { 
    /**
     * 获取默认流程引擎实例,会自动读取activiti.cfg.xml文件
     */
    private ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
    /**
     * 部署流程定义
     */
    @Test
    public void deploy(){
        Deployment deployment=processEngine.getRepositoryService() // 获取部署相关Service
                .createDeployment() // 创建部署
                .addClasspathResource("diagrams/StudentLeaveProcess5.bpmn") // 加载资源文件
                .addClasspathResource("diagrams/StudentLeaveProcess5.png") // 加载资源文件
                .name("学生请假流程5") // 流程名称
                .deploy(); // 部署
        System.out.println("流程部署ID:"+deployment.getId()); 
        System.out.println("流程部署Name:"+deployment.getName());
    }
    /**
     * 启动流程实例
     */
    @Test
    public void start(){
        ProcessInstance pi=processEngine.getRuntimeService() // 运行时Service
            .startProcessInstanceByKey("studentLevaeProcess5"); // 流程定义表的KEY字段值
        System.out.println("流程实例ID:"+pi.getId());
        System.out.println("流程定义ID:"+pi.getProcessDefinitionId()); 
    }
    /**
     * 查看任务
     */
    @Test
    public void findTask(){
        List<Task> taskList=processEngine.getTaskService() // 任务相关Service
            .createTaskQuery() // 创建任务查询
            .taskAssignee("张三") // 指定某个人
            .list();
        for(Task task:taskList){
            System.out.println("任务ID:"+task.getId()); 
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务创建时间:"+task.getCreateTime());
            System.out.println("任务委派人:"+task.getAssignee());
            System.out.println("流程实例ID:"+task.getProcessInstanceId());
        }
    }
    /**
     * 完成任务
     */
    @Test
    public void completeTask(){
        processEngine.getTaskService() // 任务相关Service
            .complete("272504");
    }
}

分配方式二 使用流程变量

在这里插入图片描述

我们设置流程变量 Assignee ${userId}

我们在启动流程的时候设置流程变量即可;


package com.fujun.taskassign;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
public class AssignTest2 {
    /**
     * 获取默认流程引擎实例,会自动读取activiti.cfg.xml文件
     */
    private ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
    /**
     * 部署流程定义
     */
    @Test
    public void deploy(){
        Deployment deployment=processEngine.getRepositoryService() // 获取部署相关Service
                .createDeployment() // 创建部署
                .addClasspathResource("diagrams/StudentLeaveProcess6.bpmn") // 加载资源文件
                .addClasspathResource("diagrams/StudentLeaveProcess6.png") // 加载资源文件
                .name("学生请假流程6") // 流程名称
                .deploy(); // 部署
        System.out.println("流程部署ID:"+deployment.getId()); 
        System.out.println("流程部署Name:"+deployment.getName());
    }
    /**
     * 启动流程实例
     */
    @Test
    public void start(){
        Map<String,Object> variables=new HashMap<String,Object>();
        variables.put("userId", "张三2");
        ProcessInstance pi=processEngine.getRuntimeService() // 运行时Service
            .startProcessInstanceByKey("studentLevaeProcess6",variables); // 流程定义表的KEY字段值
        System.out.println("流程实例ID:"+pi.getId());
        System.out.println("流程定义ID:"+pi.getProcessDefinitionId()); 
    }
    /**
     * 查看任务
     */
    @Test
    public void findTask(){
        List<Task> taskList=processEngine.getTaskService() // 任务相关Service
            .createTaskQuery() // 创建任务查询
            .taskAssignee("张三2") // 指定某个人
            .list();
        for(Task task:taskList){
            System.out.println("任务ID:"+task.getId()); 
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务创建时间:"+task.getCreateTime());
            System.out.println("任务委派人:"+task.getAssignee());
            System.out.println("流程实例ID:"+task.getProcessInstanceId());
        }
    }
    /**
     * 完成任务
     */
    @Test
    public void completeTask(){
        processEngine.getTaskService() // 任务相关Service
            .complete("282505");
    }
}

分配方式三 TaskListener监听实现
我们定义一个监听类 MyTaskListener 实现 TaskListener接口:

package com.fujun.taskassign;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
public class MyTaskListener implements TaskListener{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public void notify(DelegateTask delegateTask) {
        // TODO Auto-generated method stub
        delegateTask.setAssignee("李四"); // 指定办理人
    }
}

在这里插入图片描述

package com.fujun.taskassign;
import java.util.List;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
public class AssignTest3 {
    /**
     * 获取默认流程引擎实例,会自动读取activiti.cfg.xml文件
     */
    private ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
    /**
     * 部署流程定义
     */
    @Test
    public void deploy(){
        Deployment deployment=processEngine.getRepositoryService() // 获取部署相关Service
                .createDeployment() // 创建部署
                .addClasspathResource("diagrams/StudentLeaveProcess7.bpmn") // 加载资源文件
                .addClasspathResource("diagrams/StudentLeaveProcess7.png") // 加载资源文件
                .name("学生请假流程6") // 流程名称
                .deploy(); // 部署
        System.out.println("流程部署ID:"+deployment.getId()); 
        System.out.println("流程部署Name:"+deployment.getName());
    }
    /**
     * 启动流程实例
     */
    @Test
    public void start(){
        ProcessInstance pi=processEngine.getRuntimeService() // 运行时Service
            .startProcessInstanceByKey("studentLevaeProcess7"); // 流程定义表的KEY字段值
        System.out.println("流程实例ID:"+pi.getId());
        System.out.println("流程定义ID:"+pi.getProcessDefinitionId()); 
    }
    /**
     * 查看任务
     */
    @Test
    public void findTask(){
        List<Task> taskList=processEngine.getTaskService() // 任务相关Service
            .createTaskQuery() // 创建任务查询
            .taskAssignee("李四") // 指定某个人
            .list();
        for(Task task:taskList){
            System.out.println("任务ID:"+task.getId()); 
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务创建时间:"+task.getCreateTime());
            System.out.println("任务委派人:"+task.getAssignee());
            System.out.println("流程实例ID:"+task.getProcessInstanceId());
        }
    }
    /**
     * 完成任务
     */
    @Test
    public void completeTask(){
        processEngine.getTaskService() // 任务相关Service
            .complete("290004");
    }
}

Activiti之多用户任务分配

Activiti之多用户任务分配

我们在开发的时候,有一种情况是这样的,

我们有一个任务,可以让多个用户中的任何一个人办理即可,比如某个审批任务,

张三,李四,王五他们中的任何一人办理下都行,这时候,我们用到多用户任务分配。

方式一,直接流程图配置中写死

在这里插入图片描述

这里我们分配三个人 中间用逗号隔开。


package com.fujun.multiUserTaskAssign;
import java.util.List;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
public class AssignTest1 {
    /**
     * 获取默认流程引擎实例,会自动读取activiti.cfg.xml文件
     */
    private ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
    /**
     * 部署流程定义
     */
    @Test
    public void deploy(){
        Deployment deployment=processEngine.getRepositoryService() // 获取部署相关Service
                .createDeployment() // 创建部署
                .addClasspathResource("diagrams/multiUserProcess.bpmn") // 加载资源文件
                .addClasspathResource("diagrams/multiUserProcess.png") // 加载资源文件
                .name("学生请假流程5") // 流程名称
                .deploy(); // 部署
        System.out.println("流程部署ID:"+deployment.getId()); 
        System.out.println("流程部署Name:"+deployment.getName());
    }
    /**
     * 启动流程实例
     */
    @Test
    public void start(){
        ProcessInstance pi=processEngine.getRuntimeService() // 运行时Service
            .startProcessInstanceByKey("multiUserProcess"); // 流程定义表的KEY字段值
        System.out.println("流程实例ID:"+pi.getId());
        System.out.println("流程定义ID:"+pi.getProcessDefinitionId()); 
    }
    /**
     * 查看任务
     */
    @Test
    public void findTask(){
        List<Task> taskList=processEngine.getTaskService() // 任务相关Service
            .createTaskQuery() // 创建任务查询
            //.taskAssignee("李四") // 指定某个人
            .taskCandidateUser("张三") // 候选人查询
            .list();
        for(Task task:taskList){
            System.out.println("任务ID:"+task.getId()); 
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务创建时间:"+task.getCreateTime());
            System.out.println("任务委派人:"+task.getAssignee());
            System.out.println("流程实例ID:"+task.getProcessInstanceId());
        }
    }
    /**
     * 完成任务
     */
    @Test
    public void completeTask(){
        processEngine.getTaskService() // 任务相关Service
            .complete("305004");
    }
}

这里有几点说明下:

1,任务查询的时候 ,我们用 taskCandidateUser 候选人查询方法,不能用taskAssignee

2,启动流程实例后,我们在act_ru_identitylink表,

在这里插入图片描述

我们可以看到 activit的设计很巧妙, 在流程图里配置的用户 全是参与者participant,然后还有一份候选人candidate,

候选人绑定任务id,参与者绑定流程实例ID,这里我们可以通过Activiti的接口来增加或者减少候选人,大家自行查下文档。

我们用张三,李四,王五中的任何一人,都能查询到任务,最后任何一人完整任务即可;

方式二:使用流程变量
在这里插入图片描述

我们启动流程的时候设置流程变量的值,其他的和上面一样,

上代码:

package com.fujun.multiUserTaskAssign;


import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;

public class AssignTest2 {

    /**
     * 获取默认流程引擎实例,会自动读取activiti.cfg.xml文件
     */
    private ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
    /**
     * 部署流程定义
     */
    @Test
    public void deploy(){
        Deployment deployment=processEngine.getRepositoryService() // 获取部署相关Service
                .createDeployment() // 创建部署
                .addClasspathResource("diagrams/multiUserProcess2.bpmn") // 加载资源文件
                .addClasspathResource("diagrams/multiUserProcess2.png") // 加载资源文件
                .name("学生请假流程5") // 流程名称
                .deploy(); // 部署
        System.out.println("流程部署ID:"+deployment.getId()); 
        System.out.println("流程部署Name:"+deployment.getName());
    }
    /**
     * 启动流程实例
     */
    @Test
    public void start(){
        Map<String,Object> variables=new HashMap<String,Object>();
        variables.put("userIds", "张三,李四,王五");
        ProcessInstance pi=processEngine.getRuntimeService() // 运行时Service
            .startProcessInstanceByKey("multiUserProcess2",variables); // 流程定义表的KEY字段值
        System.out.println("流程实例ID:"+pi.getId());
        System.out.println("流程定义ID:"+pi.getProcessDefinitionId()); 
    }
    /**
     * 查看任务
     */
    @Test
    public void findTask(){
        List<Task> taskList=processEngine.getTaskService() // 任务相关Service
            .createTaskQuery() // 创建任务查询
            //.taskAssignee("李四") // 指定某个人
            .taskCandidateUser("张三") // 候选人查询
            .list();
        for(Task task:taskList){
            System.out.println("任务ID:"+task.getId()); 
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务创建时间:"+task.getCreateTime());
            System.out.println("任务委派人:"+task.getAssignee());
            System.out.println("流程实例ID:"+task.getProcessInstanceId());
        }
    }
    /**
     * 完成任务
     */
    @Test
    public void completeTask(){
        processEngine.getTaskService() // 任务相关Service
            .complete("317505");
    }
}

分配方式三 TaskListener监听实现

我们定义一个监听类 MyTaskListener 实现 TaskListener接口:

package com.fujun.multiUserTaskAssign;

import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
public class MyTaskListener implements TaskListener{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public void notify(DelegateTask delegateTask) {
        // TODO Auto-generated method stub
        delegateTask.addCandidateUser("张三");
        delegateTask.addCandidateUser("李四");
        delegateTask.addCandidateUser("王五");
    }
 
}

在这里插入图片描述

package com.fujun.multiUserTaskAssign;
 
 
import java.util.List;
 
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
 
public class AssignTest3 {
 
    /**
     * 获取默认流程引擎实例,会自动读取activiti.cfg.xml文件
     */
    private ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
     
    /**
     * 部署流程定义
     */
    @Test
    public void deploy(){
        Deployment deployment=processEngine.getRepositoryService() // 获取部署相关Service
                .createDeployment() // 创建部署
                .addClasspathResource("diagrams/multiUserProcess3.bpmn") // 加载资源文件
                .addClasspathResource("diagrams/multiUserProcess3.png") // 加载资源文件
                .name("学生请假流程5") // 流程名称
                .deploy(); // 部署
        System.out.println("流程部署ID:"+deployment.getId()); 
        System.out.println("流程部署Name:"+deployment.getName());
    }
     
    /**
     * 启动流程实例
     */
    @Test
    public void start(){
        ProcessInstance pi=processEngine.getRuntimeService() // 运行时Service
            .startProcessInstanceByKey("multiUserProcess3"); // 流程定义表的KEY字段值
        System.out.println("流程实例ID:"+pi.getId());
        System.out.println("流程定义ID:"+pi.getProcessDefinitionId()); 
    }
     
     
    /**
     * 查看任务
     */
    @Test
    public void findTask(){
        List<Task> taskList=processEngine.getTaskService() // 任务相关Service
            .createTaskQuery() // 创建任务查询
            //.taskAssignee("李四") // 指定某个人
            .taskCandidateUser("张三") // 候选人查询
            .list();
        for(Task task:taskList){
            System.out.println("任务ID:"+task.getId()); 
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务创建时间:"+task.getCreateTime());
            System.out.println("任务委派人:"+task.getAssignee());
            System.out.println("流程实例ID:"+task.getProcessInstanceId());
        }
    }
     
     
    /**
     * 完成任务
     */
    @Test
    public void completeTask(){
        processEngine.getTaskService() // 任务相关Service
            .complete("325004");
    }
     
 
}

Activiti之内置用户组设计表以及IdentityService

Activiti之内置用户组设计表

Activiti给我们提供了一套内置的用户和组设计表;

用户和组(或者叫做角色),多对多关联,通过关联表实现;

我们来看下,

在这里插入图片描述

四个表,

act_id_group 用户组表;

act_id_user 用户表;

act_id_membership 用户与组的关联表,用来实现多对多;

act_id_info 用户信息表;

首先来看下用户表:

在这里插入图片描述

这里的设计可能和我们想象的不一样,比如_ID,字符串类型 我们直接可以把他当作用户名

FIRST_ LAST_ 是英文命名习惯 EMAIL_ PWD 邮箱 密码 字段 等等。
接下来看下组表:

在这里插入图片描述

ID_ 依然是字符串类型 还有NAME_ TYPE_字段

再看下重要的关联表:

在这里插入图片描述

只有两个字段 USER_ID_ 和 GROUP_ID_ 分别关联用户表的主键和组表的主键;

我们看下架构设计:

在这里插入图片描述

最后一个是用户信息表,主要是用来扩展用户信息,以及可以实现组织机构层次关系,比如雇员领导用户设计;

在这里插入图片描述

这里USE_ID_ 可以关联用户表的主键 KEY_ VALUE_可以扩展用户信息(虽然这个是一种冗余设计),PARENT_ID可以实现层次设计;

这里表了解即可;我们不做重点讲解;

这个是activiti给我们内置的一个用户组设计,

这里说明下:正常的企业级项目都有自己的组织机构用户权限设置表,所以一般不会用到内置的;

但是假如一个很小的系统,例如 学生请假系统 就那么几十个用户,两三中角色,那我们就可以用内置的,用内置的更加方便;

Activiti提供了一个Service来专门操作用户组表,那就是 IdentityService 身份信息Service

我们可以用过IdentityService来添加修改用户信息,组信息,也可以删除用户信息,组信息,以及维护他们的关联关系;

我们给下演示代码,视频里会详细讲解:

package com.fujun.groupAssign;
 
import org.activiti.engine.IdentityService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.User;
import org.activiti.engine.impl.persistence.entity.GroupEntity;
import org.activiti.engine.impl.persistence.entity.UserEntity;
import org.junit.Test;
 
public class IdentityTest {
 
    /**
     * 获取默认流程引擎实例,会自动读取activiti.cfg.xml文件
     */
    private ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
     
    /**
     * 添加用户测试
     */
    @Test
    public void testSaveUser(){
        IdentityService identityService=processEngine.getIdentityService();
        User user1=new UserEntity(); // 实例化用户实体
        user1.setId("lisi");
        user1.setEmail("234@qq.com");
        user1.setPassword("123456");
        identityService.saveUser(user1); // 添加用户
    }
     
    /**
     * 测试删除用户
     */
    @Test
    public void testDeleteUser(){
        IdentityService identityService=processEngine.getIdentityService();
        identityService.deleteUser("zhangsan"); 
    }
     
    /**
     * 测试添加组
     */
    @Test
    public void testSaveGroup(){
        IdentityService identityService=processEngine.getIdentityService();
        Group group=new GroupEntity(); // 实例化组实体
        group.setId("test");
        identityService.saveGroup(group);
    }
     
    /**
     * 测试删除组
     */
    @Test
    public void testDeleteGroup(){
        IdentityService identityService=processEngine.getIdentityService();
        identityService.deleteGroup("test");
    }
     
    /**
     * 测试添加用户和组关联关系
     */
    @Test
    public void testSaveMembership(){
        IdentityService identityService=processEngine.getIdentityService();
        identityService.createMembership("lisi", "test");
    }
     
    /**
     * 测试删除用户和组关联关系
     */
    @Test
    public void testDeleteMembership(){
        IdentityService identityService=processEngine.getIdentityService();
        identityService.deleteMembership("lisi", "test");
    }
 
}

Activiti之组任务分配

Activiti之组任务分配

前面我们讲到了activiti内置的用户和组的表设计,我们现在给下数据,然后来讲解组任务分配;

用户表:

在这里插入图片描述

角色表:

在这里插入图片描述

用户和角色关系表:

在这里插入图片描述

这里的话lisi,zhangli用户都是dev开发组角色;

接下来我们说下组任务分配的概念,我们在实际业务开发过程中,某一个审批任务节点可以分配一个角色(或者叫做组),

然后属于这个角色的任何一个用户都可以去完成这个任务节点的审批;

这里的话,依然有两种方式来实现:

方式一,直接流程图配置中写死

首先来配置下流程图设计:

在这里插入图片描述

这里我们设置dev角色或者叫做组 开发角色可以审批这个节点;

只要是属于dev角色的用户,都可以查询到任务;

我们给下参考代码:


package com.fujun.groupAssign;
 
 
import java.util.List;
 
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
 
public class AssignTest1 {
 
    /**
     * 获取默认流程引擎实例,会自动读取activiti.cfg.xml文件
     */
    private ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
     
    /**
     * 部署流程定义
     */
    @Test
    public void deploy(){
        Deployment deployment=processEngine.getRepositoryService() // 获取部署相关Service
                .createDeployment() // 创建部署
                .addClasspathResource("diagrams/GroupProcess.bpmn") // 加载资源文件
                .addClasspathResource("diagrams/GroupProcess.png") // 加载资源文件
                .name("学生请假流程") // 流程名称
                .deploy(); // 部署
        System.out.println("流程部署ID:"+deployment.getId()); 
        System.out.println("流程部署Name:"+deployment.getName());
    }
     
    /**
     * 启动流程实例
     */
    @Test
    public void start(){
        ProcessInstance pi=processEngine.getRuntimeService() // 运行时Service
            .startProcessInstanceByKey("groupProcess"); // 流程定义表的KEY字段值
        System.out.println("流程实例ID:"+pi.getId());
        System.out.println("流程定义ID:"+pi.getProcessDefinitionId());
    }

    /**
     * 查看任务
     */
    @Test
    public void findTask(){
        List<Task> taskList=processEngine.getTaskService() // 任务相关Service
            .createTaskQuery() // 创建任务查询
            //.taskAssignee("李四") // 指定某个人
            .taskCandidateUser("zhangsan") // 指定候选人
            .list();
        for(Task task:taskList){
            System.out.println("任务ID:"+task.getId()); 
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务创建时间:"+task.getCreateTime());
            System.out.println("任务委派人:"+task.getAssignee());
            System.out.println("流程实例ID:"+task.getProcessInstanceId());
        }
    }

    /**
     * 完成任务
     */
    @Test
    public void completeTask(){
        processEngine.getTaskService() // 任务相关Service
            .complete("347504");
    }
}

这里说明一点 查询候选人 依然要用 taskCandidateUser

这里 zhangsan ,lisi 都属于dev角色,所以这两个人当中任何一个人都能查询到任务,任何一个人办理都行;

方式二:使用流程变量

我们设置下流程变量

在这里插入图片描述

我们启动流程的设置具体的值:

我们给下测试代码:



package com.fujun.groupAssign;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
 
public class AssignTest2 {
 
    /**
     * 获取默认流程引擎实例,会自动读取activiti.cfg.xml文件
     */
    private ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
    /**
     * 部署流程定义
     */
    @Test
    public void deploy(){
        Deployment deployment=processEngine.getRepositoryService() // 获取部署相关Service
                .createDeployment() // 创建部署
                .addClasspathResource("diagrams/GroupProcess2.bpmn") // 加载资源文件
                .addClasspathResource("diagrams/GroupProcess2.png") // 加载资源文件
                .name("学生请假流程") // 流程名称
                .deploy(); // 部署
        System.out.println("流程部署ID:"+deployment.getId()); 
        System.out.println("流程部署Name:"+deployment.getName());
    }
    /**
     * 启动流程实例
     */
    @Test
    public void start(){
        Map<String,Object> variables=new HashMap<String,Object>();
        variables.put("groupId", "dev");
        ProcessInstance pi=processEngine.getRuntimeService() // 运行时Service
            .startProcessInstanceByKey("groupProcess2",variables); // 流程定义表的KEY字段值
        System.out.println("流程实例ID:"+pi.getId());
        System.out.println("流程定义ID:"+pi.getProcessDefinitionId()); 
    }
    /**
     * 查看任务
     */
    @Test
    public void findTask(){
        List<Task> taskList=processEngine.getTaskService() // 任务相关Service
            .createTaskQuery() // 创建任务查询
            //.taskAssignee("李四") // 指定某个人
            .taskCandidateUser("zhangsan") // 指定候选人
            .list();
        for(Task task:taskList){
            System.out.println("任务ID:"+task.getId()); 
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务创建时间:"+task.getCreateTime());
            System.out.println("任务委派人:"+task.getAssignee());
            System.out.println("流程实例ID:"+task.getProcessInstanceId());
        }
    }
    /**
     * 完成任务
     */
    @Test
    public void completeTask(){
        processEngine.getTaskService() // 任务相关Service
            .complete("355005");
    }
}
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JTZ001

你的鼓励是我创作的最大动力?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值