【activiti】流程变量

本文详细介绍了Activiti流程变量的使用,包括其概念、类型、作用域、设置方法以及在不同场景的应用。重点阐述了如何通过流程变量控制流程走向,如出差申请流程中根据出差天数设置变量决定审批路径。同时,提到了设置和查询流程变量的注意事项,如变量的作用域影响和序列化要求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

activiti流程变量

1. 什么是流程变量

流程变量在activiti中是一个非常重要的角色,流程运转有时就需要流程变量,流程变量就是activiti在管理工作流时根据管理需要而设置的变量。

前面我们用到的使用${assignee0}的方式分配负责人,就是流程变量

也可以设置别的流程变量,比如:出差申请流程如果出差天数大于3天由总经理审核,否则由财务审核,这里出差天数就可以设置一个流程变量进行管理。

注意:虽然流程变量中可以存储业务数据,通过activiti查询流程变量实现查询业务数据,但是不建议这么操作,因为业务数据是由业务系统提供的,activiti工作流流程变量只是负责流程执行而创建的。太多的业务数据当做流程变量容易造成数据紊乱。

2. 流程变量类型

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

image-20211205213238706

3. 流程变量的作用域

流程变量的作用域可以是一个流程实例(ProcessInstance),也可以是一个任务(Task)或者是一个执行实例(execution)

3.1 global变量

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

注意:global变量中变量名不允许重复,设置相同的变量名,后设置的值会覆盖之前设置的值。

3.2 local变量

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

local变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同不会互相影响。local也可以和global变量名相同。

4. 流程变量的使用方法
4.1 在属性上使用UEL表达式

可以在向assignee这样的属性上使用UEL表达式,该表达式的值为任务的负责人,比如:${assignee},assignee就是一个流程变量名称。

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

4.2 在连线上使用UEL表达式

可以在连线上使用UEL表达式,决定流程的走向。

比如:${price < 100},price就是一个流程变量的值,uel表达式的结果为布尔值,根据uel表达式的值true,来确定流程的走向。

5. 设置global流程变量

不同的工具设计流程不太一样,请自己选择,本文使用的是Camunda Modeler

5.1 需求

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

image-20211205221259199

5.2 流程定义

**1)出差天数大于3连线条件 **

选中连线,然后设计流程变量条件${num>3},当然也可以设计成${evection.num>3},evection是一个对象且该对象必须要进行序列化。

image-20211205221431057

注意这里的连线是:Conditional Flow,切换成这个连线再设计流程变量

image-20211205221722615

2)出差天数小于等于3连线条件

选中连线,然后设计流程变量条件${num<=3},同样也可以设计成${evection.num<=3},evection是一个对象且该对象必须要进行序列化。

image-20211205222053625

5.3 设计global流程变量

在部门经理审核前设计流程变量,变量值为出差天数,部门经理审核后可以根据流程变量的值来决定流程的走向。

在设计流程变量时,可以在启动的时候设置,也可以在任务办理时设置。

5.4 启动流程时设置流程变量

测试为了方便数据查询,删除数据库,重新部署新的流程。

在启动流程时设置流程变量,变量的作用域是整个流程实例,具体操作是,通过Map设置键值对的方式去设置流程变量,key是流程变量的名称,value是流程变量的值。

注意:这里有个问题,使用Camunda Modeler工具设计的流程配置的负责人assignee变量值,在代码中通过map传入不生效,是由于assignee 的前缀为camunda,activity解析不到该标签。

image-20211205232316715

解决办法:将camunda 替换为 activiti,命名空间改为activity的命名空间

<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" targetNamespace="http://www.activiti.org/processdef" exporter="Camunda Modeler" exporterVersion="3.0.0">

image-20211205232732433

/**
     * 启动流程实例
     */
    @Test
    public void startProcess() {
        //获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //流程定义key
        String key = "evection-variable";
        //定义流程变量map
        Map<String, Object> map = new HashMap<>();
        //设置出差天数,key值就是我们在流程图设计时添加的流程变量名称
        //这里设置出差天数为3,按流程设计,经理审批完是由财务直接审核
        map.put("num", 3);
        //设置负责人流程变量的值
        map.put("assignee0", "张三");
        map.put("assignee1", "李经理");
        map.put("assignee2", "王总经理");
        map.put("assignee3", "赵财务");
        //启动流程实例,将流程变量通过map传入
        //该流程变量的作用域是一个流程实例
        ProcessInstance instance = runtimeService.startProcessInstanceByKey(key, map);

        //输出
        System.out.println("流程定义id:" + instance.getProcessDefinitionId());
        System.out.println("流程实例名称:" + instance.getName());
        System.out.println("流程实例id:" + instance.getProcessInstanceId());
    }

流程实例启动完成后,进行完成个人任务

    /**
     * 完成个人任务
     */
    @Test
    public void completePersonalTask() {
        //流程定义key
        String key = "evection-variable";
        //任务负责人:先完成张三,再完成李经理的,然后根据配置的出差天数流程变量,最后应该是直接有财务直接审批
        //String assignee = "张三";
        String assignee = "李经理";
        //获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //根据流程定义key和任务负责人查询任务
        Task task = taskService.createTaskQuery()
                //查询可能有多个,这里测试只有一条数据可以这么直接查询,建议实际业务根据别的条件进行查询
                .processDefinitionKey(key)
                .taskAssignee(assignee)
                .singleResult();
        if (task != null) {
            taskService.complete(task.getId());
            System.out.println("任务已完成");
        }
    }

任务由李经理执行完成后,根据配置条件,出差天数3天,应该直接有财务直接进行审核,查看act_run_task任务表:

image-20211205233146222

5.5 完成任务时设置流程变量

在完成任务时设置流程变量,该流程变量只有在该任务完成后其他节点才可以使用该变量,作用域是整个流程实例。如果设置的流程变量key在流程实例中已存在,则后设置的会替换之前已设置的流程变量。

这里在完成创建出差申请单任务时设置流程变量,即完成张三的任务

为了演示,删库之后重新部署测试,注意部署完后启动实例,不用给num变量设置值了

启动流程实例后,查询act_ru_variable表只有四个流程变量

image-20211206174735326

    /**
     * 任务办理时设置流程变量
     * 这里测试出差天数num流程变量,所以在启动流程实例的时候不用设置num,只设置任务负责人即可
     */
    @Test
    public void completeTask() {
        //流程定义key
        String key = "evection-variable";
        //任务id
        String taskId = "7501";
        //任务负责人
        String assignee = "张三";
        //获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //       创建变量集合
        Map<String, Object> map = new HashMap<>();
        /**
         * 可以使用对象的方式设置
         * Evection evection = new Evection();
         * evection.setNum(2d);
         * map.put("evection",evection);
         */
        map.put("num", 3);
        //查询任务
        Task task = taskService.createTaskQuery()
                .processDefinitionKey(key)
            	.taskId(taskId)
                .taskAssignee(assignee)
                .singleResult();
        if (task != null) {
            //完成任务并设置流程变量
            taskService.complete(task.getId(), map);
            System.out.println(task.getId() + "任务已完成");
        }
    }

执行上面的代码完成个人任务,并给出差天数num流程变量设置值。

查询act_ru_variable表可以看到出差天数流程变量值正常设置

image-20211206175140641

根据流程图或者act_ru_task表的数据可以看到当前任务由李经理审核完成,用之前完成个人任务的代码执行流程任务

    /**
     * 完成个人任务
     */
    @Test
    public void completePersonalTask() {
        //流程定义key
        String key = "evection-variable";
        //任务负责人:先完成张三,再完成李经理的,然后根据配置的出差天数流程变量,最后应该是直接有财务直接审批
        //String assignee = "张三";
        String assignee = "李经理";
        //获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //根据流程定义key和任务负责人查询任务
        Task task = taskService.createTaskQuery()
                //查询可能有多个,这里测试只有一条数据可以这么直接查询,建议实际业务根据别的条件进行查询
                .processDefinitionKey(key)
                .taskAssignee(assignee)
                .singleResult();
        if (task != null) {
            taskService.complete(task.getId());
            System.out.println("任务已完成");
        }
    }

任务完成后刷新act_ru_task表可以看到流程走到财务了,因为num=3直接由财务审核

image-20211205233146222

5.6 通过当前执行流程实例设置流程变量

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

    /**
     * 通过当前执行的流程实例执行id设置变量
     * 这里测试出差天数num流程变量,所以在启动流程实例的时候不用设置num,只设置任务负责人即可
     */
    @Test
    public void setGlobalVariableByExecutionId() {
        //获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //当前流程实例执行id,通常为当前执行的流程实例
        String executionId = "";
        //获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //       创建变量集合
        Map<String, Object> map = new HashMap<>();
        /**
         * 可以使用对象的方式设置
         * Evection evection = new Evection();
         * evection.setNum(2d);
         * runtimeService.setVariable(executionId, "evection", evection);
         */
        map.put("num", 3);
        runtimeService.setVariables(executionId, map);

        /**
         * 可以通过getVariables获取到已设置的流程变量
         */
        Map<String, Object> variables = runtimeService.getVariables(executionId);
        variables.forEach((k,v) -> {
            System.out.println(k +" "+ v);
        });

    }

为了方便测试数据查看,清空数据库,重新部署,然后启动流程实例,在act_ru_task表拿到EXECUTION_ID的值,该值就是当前流程实例执行ID

image-20211206211355367

执行完成后,再去查看act_ru_variable表可查询到流程变量num的数据。

注意:EXECUTION_ID必须是当前未结束的流程实例的执行id

5.7 通过当前任务设置流程变量

任务id必须是当前待办任务id,在act_ru_task表中存在,如果任务结束,则会报错。

    /**
     * 通过当前任务设置流程变量
     * 这里测试出差天数num流程变量,所以在启动流程实例的时候不用设置num,只设置任务负责人即可
     */
    @Test
    public void setGlobalVariableByTask() {
        //获取流程引起
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //当前任务id
        String taskId = "2509";
        //获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //设置流程变量
        Map<String, Object> map = new HashMap<>();
        map.put("num", 5);
        taskService.setVariables(taskId, map);

        Map<String, Object> variables = taskService.getVariables(taskId);
        variables.forEach((k, v) -> {
            System.out.println(k + ":" + v);
        });


    }

可以直接通过上面的数据进行测试,不用重新部署创建流程实例了。执行完成后,会发现变量表的num值更新成了5。

5.8 数据库表说明

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

//当前流程变量表
SELECT * FROM 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类型变量值

 #历史流程变量表
SELECT * FROM act_hi_varinst 

记录所有已创建的流程变量,包括 global和local变量

字段意义参考当前流程变量表。

6. 设置local流程变量
6.1 任务办理时设置

任务办理时设置local流程变量,当前运行的流程实例只能在该任务结束前使用,任务结束后无法在当前流程实例使用,可以通过历史任务查询。

    /**
     * 处理任务时设置local流程变量
     */
    @Test
    public void setLocalVariableByComplete() {
        //任务id
        String taskId = "7503";
        //获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //定义local流程变量
        Map<String, Object> map = new HashMap<>();
        map.put("num", 10);
        taskService.setVariablesLocal(taskId, map);
        taskService.complete(taskId);
    }
6.2 通过当前任务设置
    /**
     * 处理任务时设置local流程变量
     */
    @Test
    public void setLocalVariableByComplete() {
        //任务id
        String taskId = "7503";
        //获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //定义local流程变量
        Map<String, Object> map = new HashMap<>();
        map.put("num", 10);
        taskService.setVariablesLocal(taskId, map);
        //taskService.complete(taskId);
    }

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

Local变量在任务结束后无法在当前流程实例执行中使用,如果后续的流程执行需要用到此变量则会报错。

6.3 查询历史local流程变量
    /**
     * 查询历史local变量
     */
    @Test
    public void queryHistoricLocalVariable() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //查询local流程变量
        HistoryService historyService = processEngine.getHistoryService();
        List<HistoricTaskInstance> list = historyService
                .createHistoricTaskInstanceQuery()
                .includeTaskLocalVariables()
                .list();
        for (HistoricTaskInstance taskInstance : list) {
            System.out.println("任务id:" + taskInstance.getId());
            System.out.println("任务local变量:" + taskInstance.getTaskLocalVariables());
        }
    }

注意:查询历史流程变量,特别是查询pojo变量需要经过反序列化,不推荐使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值