Activit7之流程定义、流程实例、个人任务、流程变量、组任务、网关详解

流程定义

流程定义是按照bpmn2.0标准去描述业务流程,通常使用设计工具对业务流程进行建模。使用工具设计器绘制流程,生成两个文件:XXX.bpmn和XXX.png

部署流程定义

    public static void main(String[] args) {
    
    
        //创建ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //得到RepositoryService实例
        RepositoryService repositoryService = processEngine.getRepositoryService();

		// 将指定的bpm文件和图片文件保存在activiti数据库
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("loan.bpmn")
                .addClasspathResource("loan.png")
                .name("借款申请流程")
                .deploy();

        //输出部署信息
        System.out.println(deployment.getName());
        System.out.println(deployment.getId());
    }

查询流程定义

    public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();

        //获取ProcessDefinitionQuery对象,可认为是一个查询器
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();

        //查询当前所有流程定义
        // 查询条件:流程定义的key
        List<ProcessDefinition> list = processDefinitionQuery.processDefinitionKey("loan")
                // 设置排序方式,根据流程定义的版本号进行排序
                .orderByProcessDefinitionVersion()
                .desc().list();

        //输出流程定义信息
        for (ProcessDefinition processDefinition : list) {
    
    
            System.out.println("流程定义ID:" + processDefinition.getId());
            System.out.println("流程定义名称:" + processDefinition.getName());
            System.out.println("流程定义的Key:" + processDefinition.getKey());
            System.out.println("流程定义的版本号:" + processDefinition.getVersion());
            System.out.println("流程部署的ID:" + processDefinition.getDeploymentId());
        }
    }
流程定义ID:loan:1:4
流程定义名称:借款申请流程
流程定义的Key:loan
流程定义的版本号:1
流程部署的ID:1

删除流程定义

/**
     * 当流程定义已有流程实例启动,即有流程未审批结束时,删除流程定义则失败
     * 可以使用repositoryService.deleteDeployment("1",true)进行强制删除
     * true:级联删除,会先删除没有完成的流程结点,最后删除流程定义信息
     * false:不级联,不会删除没有完成的流程结点,直接删除流程定义信息
     *
     * @param args
     */
    public static void main(String[] args) {
    
    

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();

        // 流程部署id
        String deploymentId = "2064";

        //删除流程定义
        repositoryService.deleteDeployment(deploymentId);
        
        //repositoryService.deleteDeployment(deploymentId, true);
    }

流程定义资源查询

流程定义对象获取流程定义资源

	@Test
    public void getProcessResources() throws IOException {
    
    
        // 流程定义id
        String processDefinitionId = "loan:1:4";
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();

        // 流程定义对象
        ProcessDefinition processDefinition = repositoryService
                .createProcessDefinitionQuery()
                .processDefinitionId(processDefinitionId).singleResult();

        //获取bpmn
        String resource_bpmn = processDefinition.getResourceName();
        //获取png
        String resource_png = processDefinition.getDiagramResourceName();
        // 资源信息
        System.out.println("bpmn:" + resource_bpmn);
        System.out.println("png:" + resource_png);

        File file_png = new File("d:/loan.png");
        File file_bpmn = new File("d:/loan.bpmn");

        byte[] b = new byte[1024];
        int len = -1;

        // 输出bpmn
        InputStream resourceAsStream = null;
        resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resource_bpmn);
        FileOutputStream fileOutputStream = new FileOutputStream(file_bpmn);

        while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
    
    
            fileOutputStream.write(b, 0, len);
        }

        // 输出图片
        resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resource_png);
        fileOutputStream = new FileOutputStream(file_png);
        while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
    
    
            fileOutputStream.write(b, 0, len);
        }
		
		resourceAsStream.close();
        fileOutputStream.close();
    }

查询流程部署信息获取流程定义资源

	@Test
    public void getProcessResources2() throws IOException {
    
    
        //流程部署id
        String deploymentId = "1";
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();

        //读取资源
        List<String> resources = repositoryService.getDeploymentResourceNames(deploymentId);
        String resource_png = null;
        String resource_bpmn = null;
        //获取图片
        for (String resource_name : resources) {
    
    
            if (resource_name.indexOf(".png") >= 0) {
    
    
                resource_png = resource_name;
            } else {
    
    
                resource_bpmn = resource_name;
            }
        }

        File file_png = new File("d:/loan.png");
        File file_bpmn = new File("d:/loan.bpmn");

        byte[] b = new byte[1024];
        int len = -1;

        // 输出bpmn
        InputStream resourceAsStream = null;
        resourceAsStream = repositoryService.getResourceAsStream(deploymentId, resource_bpmn);
        FileOutputStream fileOutputStream = new FileOutputStream(file_bpmn);

        while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
    
    
            fileOutputStream.write(b, 0, len);
        }

        // 输出图片
        resourceAsStream = repositoryService.getResourceAsStream(deploymentId, resource_png);
        fileOutputStream = new FileOutputStream(file_png);
        while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
    
    
            fileOutputStream.write(b, 0, len);
        }

		resourceAsStream.close();
        fileOutputStream.close();
    }

查看流程历史信息

即使流程定义已经删除,流程执行的历史信息依然保存在activiti的 act_hi_*相关的表中。通过 HistoryService 来查看相关的历史记录

	@Test
    public void historyQuery() {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //获取HistoryService
        HistoryService historyService = processEngine.getHistoryService();
        //获取HistoricActivitiInstanceQuery对象
        HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
        //设置流程实例的id
        historicActivityInstanceQuery.processInstanceId("2501");

        //执行查询
        List<HistoricActivityInstance> list = historicActivityInstanceQuery
                .orderByHistoricActivityInstanceStartTime().asc().list();

        for (HistoricActivityInstance instance : list) {
    
    
            System.out.println(instance.getActivityId());
            System.out.println(instance.getActivityName());
            System.out.println(instance.getProcessDefinitionId());
            System.out.println(instance.getProcessInstanceId());
            System.out.println("=============================");
        }
    }
_2
StartEvent
loan:1:4
2501
=============================
_9
填写表单信息
loan:1:4
2501
=============================
_3
项目经理
loan:1:4
2501
=============================

流程实例

流程实例就是用户按照流程定义内容发起一个流程

启动流程实例

流程定义部署在activiti后,就可以去管理该流程的执行,流程可以执行多次,每个执行互不影响,每个执行是单独的流程实例

执行流程首先需要启动流程实例

    @Test
    public void startInstance(){
    
    
        //得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //得到RunService对象
        RuntimeService runtimeService = processEngine.getRuntimeService();

        //创建流程实例,根据流程定义key启动流程
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("loan");

        //输出实例的相关信息
        System.out.println("流程部署ID" + processInstance.getDeploymentId());
        System.out.println("流程定义ID" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例ID" + processInstance.getId());
        System.out.println("活动ID" + processInstance.getActivityId());
    }
流程部署ID:null
流程定义ID:loan:1:4
流程实例ID:2501
活动ID:null

业务标识之Businesskey

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

Businesskey即业务标识,通常为业务表的主键,业务标识和流程实例一 一对应。

    @Test
    public void startInstance(){
    
    
        //得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //得到RunService对象
        RuntimeService runtimeService = processEngine.getRuntimeService();

       // 业务Key 通常为业务表的主键
        String businessKey="123456";

        //创建流程实例,根据流程定义key启动流程
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("loan",businessKey);

        //输出实例的相关信息
        System.out.println("流程部署ID:" + processInstance.getDeploymentId());
        System.out.println("流程定义ID:" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例ID:" + processInstance.getId());
        System.out.println("活动ID:" + processInstance.getActivityId());
    }
流程部署ID:null
流程定义ID:loan:1:4
流程实例ID:7501
活动ID:null

在这里插入图片描述

启动流程实例,操作数据库表

SELECT * FROM act_ru_execution #流程实例执行表,记录当前流程实例的执行情况
在这里插入图片描述

如果当前只有一个分支,一个流程实例只有一条记录且执行表的主键 id 和流程实例id相同

如果当前有多个分支正在运行则该执行表中有多条记录,存在执行表的主键和流程实例id不相同的记录。 

不论当前有几个分支总会有一条记录的执行表的主键和流程例实例id相同

一个流程实例运行完成,此表中与流程实例相关的记录删除

SELECT * FROM act_ru_task #任务执行表,记录当前执行的任务
在这里插入图片描述

启动流程实例,流程当前执行到第一个任务结点,此表会插入一条记录表示当前任务的执行情况,如果任务完成则记录删除。

SELECT * FROM act_ru_identitylink #任务参与者,记录当前参与任务的用户或组
在这里插入图片描述
SELECT * FROM act_hi_procinst #流程实例历史表
在这里插入图片描述

流程实例启动,会在此表插入一条记录,流程实例运行完成记录也不会删除。

SELECT * FROM act_hi_taskinst #任务历史表,记录所有任务

在这里插入图片描述
开始一个任务,不仅在act_ru_task表插入记录,也会在历史任务表插入一条记录,任务历史表的主
键就是任务id,任务完成此表记录不删除。

SELECT * FROM act_hi_actinst #活动历史表,记录所有活动
在这里插入图片描述
活动包括任务,所以此表中不仅记录了任务,还记录了流程执行过程的其它活动,比如开始事件、
结束事件。

查询流程实例

流程在运行过程中可以查询流程实例的状态,当前运行结点等信息

 @Test
    public void queryProcessInstance() {
    
    

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取RunTimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();

        // 流程定义key
        String processDefinitionKey = "loan";

        List<ProcessInstance> list = runtimeService
                .createProcessInstanceQuery()
                .processDefinitionKey(processDefinitionKey)//
                .list();

        for (ProcessInstance processInstance : list) {
    
    
            System.out.println("流程实例id:" + processInstance.getProcessInstanceId());
            System.out.println("所属流程定义id:" + processInstance.getProcessDefinitionId());
            System.out.println("是否执行完成:" + processInstance.isEnded());
            System.out.println("是否暂停:" + processInstance.isSuspended());
            System.out.println(" 当 前 活 动 标 识 : " + processInstance.getActivityId());
            System.out.println("=============================");
        }
    }
流程实例id:2501
所属流程定义id:loan:1:4
是否执行完成:false
是否暂停:false
当前活动标识 : null
业务标识Key: :123456

挂起、激活流程实例

全部流程实例挂起

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

    @Test
    public void suspendOrActivateProcessDefinition() {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //获取RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();

        //查询流程定义的对象
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("loan").singleResult();

        // 根据定义id获取流程定义
        ProcessDefinition processDefinition2 = repositoryService
                .createProcessDefinitionQuery()
                .processDefinitionId("loan:1:4").singleResult();

        //当前流程定义的实例是否为暂停状态
        boolean suspended = processDefinition.isSuspended();
        String processDefinitionId = processDefinition.getId();

        if (suspended) {
    
    
            //是暂停,进行激活操作,将流程定义下的所有流程实例全部激活
            repositoryService.activateProcessDefinitionById(processDefinitionId, true, null);
            System.out.println("流程定义:" + processDefinitionId + "激活");
        } else {
    
    
        	// 如果激活则挂起,将流程定义下的所有流程实例全部挂起
            repositoryService.suspendProcessDefinitionById(processDefinitionId, true, null);
            System.out.println("流程定义:" + processDefinitionId + "挂起");
        }
    }

单个流程实例挂起

操作流程实例对象,针对单个流程执行挂起操作,某个流程实例挂起则此流程不再继续执行,完成该流程实例的当前任务将报异常

    @Test
    public void suspendOrActiveProcessInstance() {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();

        //查询流程实例对象
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId("2501").singleResult();

        //当前流程定义的实例是否为暂停状态
        boolean suspended = processInstance.isSuspended();
        String processInstanceId = processInstance.getId();

        if (suspended) {
    
    
            //是暂停,进行激活操作
            runtimeService.activateProcessInstanceById(processInstanceId);
            System.out.println("流程:" + processInstanceId + "激活");
        } else {
    
    
            //如果激活则挂起
            runtimeService.suspendProcessInstanceById(processInstanceId);
            System.out.println("流程:" + processInstanceId + "挂起");
        }

个人任务

分配任务的负责人

固定分配

在进行业务流程建模时指定固定的任务负责人,任务只管一步一步执行任务,执行到每一个任务将按照 bpmn 的配置去分配任务负责人
在这里插入图片描述

UEL表达式分配

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

1.UEL-value

定义方式一:assignee变量是activiti的一个流程变量
在这里插入图片描述
定义方式二:user是activiti的一个流程变量,user.assignee表示通过调用user的getter方法获取值
在这里插入图片描述
2.UEL-method
loanService是spring容器中的一个 bean,表示调用该bean的getUserId()方法
在这里插入图片描述
3.UEL-method与UEL-value结合使用

loanService是一个bean,getUser是该bean 的一个方法,id是activiti流程变量,id作为参数传到 loanService.getUser方法中
在这里插入图片描述
4.注意点

使用表达式分配,必须保证在任务执行过程中表达式执行成功,例如:任务使用表达式${user.userId},当执行该任务时必须保证user在流程变量中存在,否则activiti异常

表达式分配任务负责人示例

定义任务并分配流程变量
在这里插入图片描述
启动流程实例时设置流程变量

public static void main(String[] args) {
    
    
        //得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //得到RunService对象
        RuntimeService runtimeService = processEngine.getRuntimeService();

        //定义流程变量
        Map<String, Object> variables = new HashMap<>();
        //设置流程变量assignee
        variables.put("assignee", "小白");
        variables.put("assignee2", "大白");

        //创建流程实例,根据流程定义key启动流程
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("loan", variables);

        //输出实例的相关信息
        System.out.println("流程部署ID" + processInstance.getDeploymentId());
        System.out.println("流程定义ID" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例ID" + processInstance.getId());
        System.out.println("活动ID" + processInstance.getActivityId());
    }

监听器分配

任务监听器是发生对应的任务相关事件时执行自定义 java 逻辑或表达式

使用监听器分配方式,按照监听事件去执行监听类的notify方法,方法如果不能正常执行也会影响任务的执行。

添加监听器
在这里插入图片描述
可选Event

Create:任务创建后触发

Assignment:任务分配后触发

Delete:任务完成后触发

All:所有事件发生都触发

定义任务监听类,且类必须实现org.activiti.engine.delegate.TaskListener接口

public class TaskListener implements TaskListener {
    
    
    @Override
    public void notify(DelegateTask delegateTask) {
    
    
        //指定任务负责人
        delegateTask.setAssignee("小白");
    }
}

设置监听器信息
在这里插入图片描述

查询任务

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

 public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 创建TaskService
        TaskService taskService = processEngine.getTaskService();

        // 流程定义key
        String processDefinitionKey = "loan";
        // 任务负责人
        String assignee = "小白";

        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey(processDefinitionKey)
                .includeProcessVariables().taskAssignee(assignee).list();

        for (Task task : list) {
    
    
            System.out.println("流程实例id:" + task.getProcessInstanceId());
            System.out.println("任务id:" + task.getId());
            System.out.println("任务负责人:" + task.getAssignee());
            System.out.println("任务名称:" + task.getName());
        }
    }
流程实例id:2501
任务id:5002
任务负责人:小白
任务名称:项目经理

查询任务关联businessKey查询

查询待办任务时,通过businessKey业务key关联查询业务方面的信息

public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 创建TaskService
        TaskService taskService = processEngine.getTaskService();
        // 创建runtimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();

        // 流程定义key
        String processDefinitionKey = "loan";
        // 任务负责人
        String assignee = "user1";
        // 通过taskService查询任务
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey(processDefinitionKey)
                .includeProcessVariables().taskAssignee(assignee).list();

        for (Task task : list) {
    
    
            // 以task对象获取流程实例id
            String processInstanceId = task.getProcessInstanceId();
            // 以流程实例id查询流程实例对象
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            // 获取业务Key,通过业务key查询流程表单详细信息
            String businessKey = processInstance.getBusinessKey();

            System.out.println("流程实例id:" + processInstanceId);
            System.out.println("任务id:" + task.getId());
            System.out.println("任务负责人:" + task.getAssignee());
            System.out.println("任务名称:" + task.getName());
            System.out.println("业务Key:" + businessKey);
        }
    }
流程实例id:7501
任务id:7505
任务负责人:user1
任务名称:填写表单信息
业务Key123456

办理任务

指定任务 id,调用TaskService完成任务

  public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        String taskId = "7505";
        String assignee = "user2";

        // 创建TaskService
        TaskService taskService = processEngine.getTaskService();
        // 查询是否有需要办理的任务
        Task task = taskService.createTaskQuery().taskId(taskId)
                .taskAssignee(assignee).singleResult();

        if (task != null) {
    
    
            taskService.complete(taskId);
        }
    }

流程变量

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

流程变量类型

String 
Integer 
Short 
Long 
Double 
Boolean 
Date 
Serializable

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

流程变量作用域

流程变量的作用域默认是一个流程实例(processInstance),也可以是一个任务(task)或一个执行实例
(execution)

三个作用域中流程实例的范围最大,可以称为global变量,任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大,为称为local变量

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

Local变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响

Local变量名也可以和 global变量名相同,没有影响

流程变量的使用方法

在绘制流程图时,通过UEL表达式使用流程变量

1.在assignee处设置UEL表达式,表达式的值为任务的负责人,如:${assignee},assignee 就是一个流程变量名称。Activiti获取UEL表达式的值 ,即流程变量assignee的值 ,将assignee的值作为任务的负责人进行任务分配

2.在连线上设置UEL表达式,决定流程走向,如: m o n e y < = 2000 和 {money<=2000}和 money<=2000{money>2000}: money就是一个流程变量名称,uel表达式结果类型为布尔类型

使用Global 变量控制流程

绘制流程图并部署流程定义

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

部署流程定义

    public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        // 部署流程定义
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("loan.bpmn")
                .addClasspathResource("loan.png")
                .name("借款申请流程")
                .deploy();
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

创建Serializable类型对象

/**
 * 必须实现Serializable接口,否则在存储该对象时就报异常
 */
public class Loan implements Serializable {
    
    

    private Double money;


    public Double getMoney() {
    
    
        return money;
    }

    public void setMoney(Double money) {
    
    
        this.money = money;
    }
}

启动流程时设置

在启动流程时设置流程变量,变量的作用域是整个流程实例,流程变量使用 Map存储,同一个流程实例设置变量map 中 key 相同,后者覆盖前者。

    public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();

        // 流程定义的key
        String key = "loan";
        Map<String, Object> map = new HashMap<>();

        // 定义流程变量
        Loan loan = new Loan();
        loan.setMoney(1500D);
        map.put("loan", loan);
        map.put("startUser", "发起人");
        map.put("dept", "部门经理");
        map.put("finance", "财务出纳");

        //启动流程实例,并且设置流程变量的值
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key, map);

        System.out.println(processInstance.getName());
        System.out.println(processInstance.getProcessDefinitionId());
    }

查询流程及办理

  public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        String key = "loan";
        Task task = taskService.createTaskQuery().processDefinitionKey(key)
                .taskAssignee("发起人").singleResult();

        //task!=null,说明当前用户有任务,进行办理
        if (task != null) {
    
    
            System.out.println("流程实例id:" + task.getProcessInstanceId());
            System.out.println("任务id:" + task.getId());
            System.out.println("任务负责人:" + task.getAssignee());
            System.out.println("任务名称:" + task.getName());
            taskService.complete(task.getId());
        }
    }
流程实例id:25001
任务id:25006
任务负责人:发起人
任务名称:填写流程表单

由于money条件<=2000,路由环节直接走到财务,查询财务出纳任务:

    public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        // 流程定义key
        String processDefinitionKey = "loan";
        // 任务负责人
        String assignee = "财务出纳";
        Task task = taskService.createTaskQuery()
                .processDefinitionKey(processDefinitionKey)
                .includeProcessVariables().taskAssignee(assignee).singleResult();

        if (task != null) {
    
    
            System.out.println("流程实例id:" + task.getProcessInstanceId());
            System.out.println("任务id:" + task.getId());
            System.out.println("任务负责人:" + task.getAssignee());
            System.out.println("任务名称:" + task.getName());
        }
    }
流程实例id:25001
任务id:30006
任务负责人:财务出纳
任务名称:财务出纳

任务办理时设置

在完成任务时设置流程变量,该流程变量只有在该任务完成后其它结点才可使用该变量,它的作用
域是整个流程实例,如果设置的流程变量的key在流程实例中已存在相同的名字则后设置的变量替换前边设置的变量。

    public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        //查询当前用户是否有任务
        String key = "loan";
        Task task = taskService.createTaskQuery().processDefinitionKey(key)
                .taskAssignee("发起人").singleResult();

        //初始化参数
        Map<String, Object> map = new HashMap<>();
        // 定义流程变量
        Loan loan = new Loan();
        loan.setMoney(1500D);
        map.put("loan", loan);
        map.put("finance", "财务出纳");

        //task!=null,当前用户有任务
        if (task != null) {
    
    
            //完成任务时,设置流程变量的值
            taskService.complete(task.getId(), map);
        }
    }

通过当前流程实例设置

通过流程实例 id 设置全局变量,该流程实例必须未执行完成。

 public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();

        //当前流程实例执行id,通常设置为当前执行的流程实例
        String executionId = "2601";
        //初始化参数
        Map<String, Object> map = new HashMap<>();
        // 定义流程变量
        Loan loan = new Loan();
        loan.setMoney(2500D);
        map.put("loan", loan);

        //通过流程实例id设置流程变量 流程实例的id,流程变量名,流程变量名所对应的值
        runtimeService.setVariable(executionId, "loan", map);

        //设置多个值
        //runtimeService.setVariables(executionId, map)
    }

通过当前任务设置

任务id必须是当前待办任务id

    public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //当前待办任务id
        String taskId = "2501";
        TaskService taskService = processEngine.getTaskService();

        //初始化参数
        Map<String, Object> map = new HashMap<>();
        // 定义流程变量
        Loan loan = new Loan();
        loan.setMoney(2500D);
        map.put("loan", loan);

        //通过任务设置流程变量
        taskService.setVariable(taskId, "loan", loan);
        
        //一次设置多个值
        //taskService.setVariables(taskId, variables)
    }

涉及数据库表

设置流程变量会在当前执行流程变量表插入记录,同时也会在历史流程变量表也插入记录。

act_ru_variable
当前流程变量表,记录当前运行流程实例可使用的流程变量,包括 global和 local变量
在这里插入图片描述

Id_:主键

Type_:变量类型

Name_:变量名称

Execution_id_:所属流程实例执行 id,global和 local变量都存储

Proc_inst_id_:所属流程实例 id,global和 local变量都存储

Task_id_:所属任务 id,local变量存储

Bytearray_:serializable 类型变量存储对应act_ge_bytearray 表的 id

Double_:double 类型变量值

Long_:long类型变量值

Text_:text 类型变量值

act_hi_varinst
历史流程变量表,记录所有已创建的流程变量,包括 global和 local变量
在这里插入图片描述

设置local流程变量

任务办理时设置

任务办理时设置 local流程变量,当前运行的流程实例只能在该任务结束前使用,任务结束该变量无
法在当前流程实例使用,可以通过查询历史任务查询。设置作用域为任务的 local变量,每个任务可以设置同名的变量,互不影响。

 @Test
    public void test() {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        //任务id
        String taskId = "30006";

        // 定义流程变量
        Map<String, Object> variables = new HashMap<String, Object>();
        Loan loan = new Loan();
        loan.setMoney(1500D);

        //变量名:loan,变量值:loan对象
        variables.put("loan", loan);
            
        // 设置local变量,作用域为该任务
        taskService.setVariablesLocal(taskId, variables);
        taskService.complete(taskId);
    }

通过当前任务设置

任务 id 必须是当前待办任务 id,在act_ru_task表中存在

    @Test
    public void test() {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        //任务id
        String taskId = "30006";

        // 定义流程变量
        Map<String, Object> variables = new HashMap<String, Object>();
        Loan loan = new Loan();
        loan.setMoney(1500D);

        //通过任务设置流程变量
        taskService.setVariableLocal(taskId, "loan", loan);

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

查询历史流程变量

    @Test
    public void test() {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        HistoryService historyService = processEngine.getHistoryService();

        // 创建历史任务查询对象
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery();

        // 查询某流程实例关联的变量
        historicTaskInstanceQuery.processInstanceId("25001");

        // 查询结果包括local变量
        historicTaskInstanceQuery.includeTaskLocalVariables();

        List<HistoricTaskInstance> list = historicTaskInstanceQuery.list();
        for (HistoricTaskInstance historicTaskInstance : list) {
    
    
            System.out.println("任务id:" + historicTaskInstance.getId());
            System.out.println("任务名称:" + historicTaskInstance.getName());
            System.out.println("任务负责人:" + historicTaskInstance.getAssignee());
            System.out.println("任务local变量:" + historicTaskInstance.getTaskLocalVariables());
        }
    }

组任务

Candidate-users 候选人

在流程定义中,在任务结点的assignee固定设置任务负责人,如果临时任务负责人变更则需要修改流程定义,可扩展性差。针对这种情况可以给任务设置多个候选人,可以从候选人中选择参与者来完成任务。

设置任务候选人

在流程图中任务节点的配置中设置 candidate-users(候选人),多个候选人之间用逗号分开

在这里插入图片描述

办理组任务

将绘制的流程图进行部署

 Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("loan.bpmn")
                .addClasspathResource("loan.png")
                .name("借款申请流程")
                .deploy();

启动流程实例

            String key = "loan";
            Map<String, Object> map = new HashMap<>();
            // 定义流程变量
            Loan loan = new Loan();
            loan.setMoney(3500D);
            map.put("loan", loan);
            map.put("startUser", "发起人");
            //map.put("dept", "部门经理");
            map.put("finance", "财务出纳");
            ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key,map);

查询任务并办理

    public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("loan")
                .taskAssignee("发起人")
                .singleResult();

        if (task!=null){
    
    
            System.out.println("流程实例id:" + task.getProcessInstanceId());
            System.out.println("任务id:" + task.getId());
            System.out.println("任务负责人:" + task.getAssignee());
            System.out.println("任务名称:" + task.getName());

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

候选人查询组任务

根据候选人查询组任务,候选人员未拾取组任务,则只是一个候选人,并不是任务的执行人

 public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        //流程定义的key
        String key = "loan";
        // 候选用户
        String candidate_users = "dept1";

        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey(key)
                .taskCandidateUser(candidate_users)
                .list();
      
        for (Task task : list) {
    
    
           System.out.println("流程实例id:" + task.getProcessInstanceId());
            System.out.println("任务id:" + task.getId());
            System.out.println("任务负责人:" + task.getAssignee());
            System.out.println("任务名称:" + task.getName());
            // null:dept1是一个候选人,并不是一个执行人
            System.out.println("任务的执行人:" + task.getAssignee());
        }
    }

候选人拾取组任务

候选人员拾取组任务后该任务变为自己的个人任务,即使该用户不是候选人也能拾取

    public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        //流程定义的key
        String key = "loan";
        // 候选用户
        String candidate_users = "dept1";

        Task task = taskService.createTaskQuery()
                .processDefinitionKey(key)
                .taskCandidateUser(candidate_users)
                .singleResult();

        if (task != null) {
    
    
            //参数任务ID  具体的候选用户
            taskService.claim(task.getId(), candidate_users);
        }
    }

候选人查询个人待办任务

      public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        //流程定义的key  候选用户
        String key = "loan";
        String assignee = "dept1";

        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey(key)
                .taskAssignee(assignee)
                .list();

        for (Task task : list) {
    
    
            System.out.println("流程实例id:" + task.getProcessInstanceId());
            System.out.println("任务id:" + task.getId());
            System.out.println("任务负责人:" + task.getAssignee());
            System.out.println("任务名称:" + task.getName());
            System.out.println("任务的执行人:" + task.getAssignee());
        }
    }
流程实例id:2501
任务id:5002
任务负责人:dept1
任务名称:部门经理
任务的执行人:dept1

候选人办理个人任务

    public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        String key = "loan";
        String assignee = "dept1";

        Task task = taskService.createTaskQuery()
                .processDefinitionKey(key)
                .taskAssignee(assignee)
                .singleResult();

        if (task != null) {
    
    
            taskService.complete(task.getId());
        }
    }

归还组任务

如果个人不想办理该组任务,可以归还组任务,归还后该用户不再是该任务的负责人。

    public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        String key = "loan";
        String assignee = "dept1";

        Task task = taskService.createTaskQuery()
                .processDefinitionKey(key)
                .taskAssignee(assignee)
                .singleResult();
        
        if (task != null) {
    
    
            // 如果设置为null则归还组任务,即任务没有负责人
            taskService.setAssignee(task.getId(), null);
        }
    }

任务交接

    public static void main(String[] args) {
    
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();

        String key = "loan";
        String assignee = "dept1";

        Task task = taskService.createTaskQuery()
                .processDefinitionKey(key)
                .taskAssignee(assignee)
                .singleResult();


        if (task != null) {
    
    
            String taskId = task.getId();

            // 将任务交给其它候选人办理
            String candidateuser = "dept2";

            // 根据候选人和组任务id查询,如果有记录说明候选人有资格拾取该任务
            Task task2 = taskService.createTaskQuery().taskId(taskId)
                    .taskCandidateUser(candidateuser).singleResult();

            if (task2 != null) {
    
    
                // 可以进行交接
                // 通过setAssignee方法也可以将任务委托给其它用户,被委托用户可以不是候选人
                taskService.setAssignee(taskId, candidateuser);
            }
        }
    }

涉及数据库表

act_ru_task
任务执行表,记录当前执行的任务,如果该任务当前是组任务,所有assignee为空,当拾取任务后该字段就是拾取用户的Id标识
在这里插入图片描述

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

在这里插入图片描述

与act_ru_identitylink对应的还有一张历史表 act_hi_identitylink,向 act_ru_identitylink 插入记录的同
时也会向历史表插入记录
在这里插入图片描述

网关

排他网关

排他网关(异或(XOR)网关,基于数据的排他网关),用来在流程中实现决策。

当流程执行到网关,所有分支都会判断条件是否为true,如果为true则执行该分支。

排他网关只会选择一个为true的分支执行,即使有两个分支条件都为true,排他网关也会只选择一条分支去执行。默认使用任务节点id值最小的分支。

在这里插入图片描述

不用排他网关也可以实现分支,如使用流程变量控制

使用流程变量控制流程走向,如果条件都不满足,不使用排他网关,流程就结束,是异常结束。

如果使用排他网关决定分支的走向,经过排他网关必须要有一条且只有一条分支走,如果从网关出去的线所有条件都不满足则系统抛出异常。

分支条件都满足时,分支都执行
在这里插入图片描述

当分支都满足条件且引入排他网关后,排他网关必须要有一条且只有一条分支走,网关默认选择任务节点Id值最小的路径执行。
在这里插入图片描述
在这里插入图片描述

并行网关

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

如果同一个并行网关有多个进入和多个外出顺序流, 它就同时具有分支和汇聚功能。 这时,网关会先汇聚所有进入的顺序流,然后再切分成多个并行分支。

分支:

并行后的所有外出顺序流,为每个顺序流都创建一个并发分支。

汇聚:

所有到达并行网关,在此等待的进入分支, 直到所有进入顺序流的分支都到达以后, 流程就会通过汇聚网关。

区别:

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

用途:

并行网关在业务应用中常用于会签任务,会签任务即多个参与者共同办理的任务。

在这里插入图片描述
并行网关执行过程:

1.在第一个ParallelGateway处,切分成2个并行分支,act_ru_execution流程实例的执行表记录当前流程实例有两个分支在运行,act_ru_task当前任务表记录两个待执行任务

2.并行任务执行不分前后,当执行某任务后,act_ru_task当前任务表记录的对应任务删除,act_ru_execution流程实例的执行表记录该执行任务分支在并行网关的汇聚结点

3.当所有分支任务都完成,都到达汇聚结点后,即A、B都办理任务后在第二个ParallelGateway处汇聚,并行网关执行完成

包含网关

包含网关具有排他网关和并行网关的特点。

可以在外出顺序流上定义条件,包含网关能解析

包含网关可以选择多于一条的顺序流,与并行网关一样

包含网关的功能是基于进入和外出顺序流的

分支:

所有外出顺序流的条件都会被解析,结果为true 的顺序流会以并行方式继续执行, 会为每个顺序流创建一个分支

汇聚:

所有符合条件的并行分支到达包含网关,会进入等待状态, 直到每个进入顺序流的分支都到达, 在汇聚之后,流程会穿过包含网关继续执行。	

在这里插入图片描述
包含网关执行过程:

当执行到第一个包含网关时,act_ru_execution流程实例执行表记录包含网关分支以及符合条件的分支,同时当前任务表act_ru_task记录符合条件分支的待执行任务,在并行等待执行

当一个分支执行后到第二个包含网关汇聚,act_ru_execution流程实例执行表记录当前任务包含网关汇聚结点信息

先到汇聚结点的分支,要等待其它分支到汇聚,等所有分支走到汇聚,包含网关就执行完成,最后分支和汇聚就从act_ru_execution流程实例执行表删除

猜你喜欢

转载自blog.csdn.net/qq_38628046/article/details/120753769