Activiti7工作流学习笔记三 流程变量

流程变量

流程变量在 activiti 中是一个非常重要的角色,流程运转有时需要靠流程变量,业务系统和 activiti结合时少不了流程变量,流程变量就是 activiti在管理工作流时根据管理需要而设置的变量。

比如在请假流程流转时如果请假天数大于 3 天则由总经理审核,否则由人事直接审核,请假天数就可以设置为流程变量,在流程流转时使用。

注意:虽然流程变量中可以存储业务数据可以通过 activitiapi查询流程变量从而实现查询业务数据,但是不建议这样使用,因为业务数据查询由业务系统负责,activiti 设置流程变量是为了流程执行需要而创建。

流程变量类型

在这里插入图片描述
注意:如果将pojo存储到流程变量中,必须实现序列化接口 serializable,为了防止由于新增字段无
法反序列化,需要生成 serialVersionUID

流程变量作用域

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

  • 流程实例的范围最大,可以称为global 变量
    • global 变量中变量名不允许重复
    • 设置相同名称的变量,后设置的值会覆盖前设置的变量值。
  • 任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大,称为local 变量
    • Local 变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响。
    • Local 变量名也可以和 global 变量名相同,没有影响。

流程变量的使用方法

  1. 第一步:设置流程变量
  2. 第二步:通过 UEL 表达式使用流程变量
    1. 可以在 assignee处设置UEL 表达式,表达式的值为任务的负责人
      比如:${assignee}assignee 就是一个流程变量名称
      在这里插入图片描述

    2. 可以在连线上设置 UEL 表达式,决定流程走向
      比如:${price>=10000}${price<10000}: price 就是一个流程变量名称,uel表达式结果类型为布尔类型
      如果 UEL 表达式true,要决定 流程执行走向
      在这里插入图片描述

使用 Global变量控制流程

需求:
员工创建请假申请单,由部门经理审核,部门经理审核通过后请假 3 天及以下由人事经理直接审核,3 天以上先由总经理审核,总经理审核通过再由人事经理存档。
在这里插入图片描述

流程定义

请假天数大于等于 3 连线条件:
在这里插入图片描述
请假天数小于 3 连线条件:
在这里插入图片描述
Condition也可以设置为${holiday.num}

设置 global流程变量

在部门经理审核前设置流程变量,变量值为请假单信息(包括请假天数),部门经理审核后可以根据流程变量的值决定流程走向。

启动流程时设置

在启动流程时设置流程变量,变量的作用域是整个流程实例。
通过 map<key,value>设置流程变量,map 中可以设置多个变量,这个key就是流程变量的名字。

// 启动流程时设置流程变量
@Test
public void startProcessInstance() {
	// 流程定义key
	String processDefinitionKey = "";
	Holiday holiday = new Holiday();
	holiday.setNum(3);
	// 定义流程变量
	Map<String, Object> variables = new HashMap<String, Object>();
	//变量名是num,变量值是holiday.getNum(),变量名也可以是一个对象
	variables.put("num", holiday.getNum());
	RuntimeService runtimeService = processEngine.getRuntimeService();
	ProcessInstance processInstance = runtimeService
	.startProcessInstanceByKey(processDefinitionKey, variables);
	System.out.println(" 流 程 实 例 id:" + 
	processInstance.getProcessInstanceId());
}

说明:
startProcessInstanceByKey(processDefinitionKey, variables)流程变量作用域是一个流程实例,流程变量使用 Map 存储,同一个流程实例设置变量 mapkey相同,后者覆盖前者。

任务办理时设置

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

这里需要在创建请假单任务完成时设置流程变量

// 办理任务时设置流程变量
@Test
public void completTask() {
	//任务id
	String taskId = "";
	TaskService taskService = processEngine.getTaskService();
	Holiday holiday = new Holiday();
	holiday.setNum(4);
	// 定义流程变量
	Map<String, Object> variables = new HashMap<String, Object>();
	//变量名是holiday,变量值是holiday对象
	variables.put("holiday", holiday);
	taskService.complete(taskId, variables);
}

说明:
通过当前任务设置流程变量,需要指定当前任务id,如果当前执行的任务 id不存在则抛出异常。
任务办理时也是通过map<key,value>设置流程变量,一次可以设置多个变量。

通过当前流程实例设置

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

public void setGlobalVariableByExecutionId(){
	//当前流程实例执行 id,通常设置为当前执行的流程实例
	String executionId="2601";
	RuntimeService runtimeService = processEngine.getRuntimeService();
	Holiday holiday = new Holiday();
	holiday.setNum(3);
	//通过流程实例 id设置流程变量
	runtimeService.setVariable(executionId, "holiday", holiday);
	//一次设置多个值
	//runtimeService.setVariables(executionId, variables)
}

注意:
executionId必须当前未结束 流程实例的执行 id,通常此id设置流程实例 的 id
也可以通过 runtimeService.getVariable()获取流程变量

通过当前任务设置

public void setGlobalVariableByTaskId(){
	//当前待办任务id
	String taskId="1404";
	TaskService taskService = processEngine.getTaskService();
	Holiday holiday = new Holiday();
	holiday.setNum(3);
	//通过任务设置流程变量
	taskService.setVariable(taskId, "holiday", holiday);
	//一次设置多个值
	//taskService.setVariables(taskId, variables)
}

注意:
任务id必须是当前待办任务idact_ru_task中存在。如果该任务已结束,报错:
在这里插入图片描述
也可以通过 taskService.getVariable()获取流程变量。

测试

正常测试:

  • 设置流程变量的值大于等于 3 天
  • 设计流程变量的值小于 3 天

异常测试:

  • 流程变量不存在
  • 流程变量的值为空 NULLprice 属性为空
  • UEL 表达式都不符合条件
  • 不设置连线的条件

注意事项

  1. 如果 UEL表达式中流程变量名不存在则报错。
  2. 如果 UEL表达式中流程变量值为空NULL,流程不按 UEL 表达式去执行,而流程结束 。
  3. 如果UEL表达式都不符合条件,流程结束
  4. 如果连线不设置条件,会走 flow序号小的那条线

操作数据库表

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

当前流程变量表

SELECT * FROM act_ru_variable
记录当前运行流程实例可使用的流程变量,包括 globallocal 变量

字段 说明
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
记录所有已创建的流程变量,包括globallocal 变量
字段意义参考当前流程变量表。

代码

启动时设置流程变量
/**
 * com.lxf.activiti.processInstance
 * 请假实体类:
 *    注意POJO类型,一定要实现Serializable接口,否则在存储这个pojo时就会报异常
 * @author lxf
 * @version 1.0
 * @date 2020/4/27 7:09
 */
public class Holiday implements Serializable {
  private Integer id;
  private String holidayName;//申请人的名字
  private Date beginDate;//开始时间
  private Date endDate;//结束日期
  private Float num;//请假天数
  private String reason;//事由
  private String type;//请假类型

  public Integer getId() {
    return id;
  }

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

  public String getHolidayName() {
    return holidayName;
  }

  public void setHolidayName(String holidayName) {
    this.holidayName = holidayName;
  }

  public Date getBeginDate() {
    return beginDate;
  }

  public void setBeginDate(Date beginDate) {
    this.beginDate = beginDate;
  }

  public Date getEndDate() {
    return endDate;
  }

  public void setEndDate(Date endDate) {
    this.endDate = endDate;
  }

  public Float getNum() {
    return num;
  }

  public void setNum(Float num) {
    this.num = num;
  }

  public String getReason() {
    return reason;
  }

  public void setReason(String reason) {
    this.reason = reason;
  }

  public String getType() {
    return type;
  }

  public void setType(String type) {
    this.type = type;
  }
}

测试

/**
 * com.lxf.activiti.processInstance
 * 流程变量的测试
 * @author lxf
 * @version 1.0
 * @date 2020/4/27 7:10
 */
public class VariableTest {

  public static void main(String[] args) {
    VariableTest variableTest = new VariableTest();
    variableTest.processDeploy();
  }

  /**
   * 1. 新的请假流程定义的部署
   */
  public void processDeploy(){
    //1.得到ProcessEngine
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

    //2.得到RepositoryService对象
    RepositoryService repositoryService = processEngine.getRepositoryService();

    //3.部署
    Deployment deploy = repositoryService.createDeployment()
        .addClasspathResource("diagram/holiday4.bpmn")
        .addClasspathResource("diagram/holiday4.png")
        .name("请假流程-流程变量")
        .deploy();

    System.out.println(deploy.getId());
    System.out.println(deploy.getName());

  }

  /**
   * 2. 启动流程实例,同时还要设置流程变量的值
   *  act_ge_bytearray
   *  act_ru_variable
   */
  public void startProcessInstance(){
    //1.得到ProcessEngine
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

    //2.得到RuntimeService
    RuntimeService runtimeService =  processEngine.getRuntimeService();

    //3.流程定义的key问题   myProcess_1
    String key = "myProcess_1";
    Map<String ,Object> map = new HashMap<>();

    Holiday holiday = new Holiday();
    holiday.setNum(5F);
    map.put("holiday",holiday);

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

    //5.输出实例信息
    System.out.println(processInstance.getName());
    System.out.println(processInstance.getProcessDefinitionId());
    //6.通过实例id,来设置流程变量
    //第一个参数:流程实例的id
    //第二个参数:流程变量名
    //第三个变量:流程变量名,所对应的值
//    runtimeService.setVariable(processInstance.getId(),"holiday",map);
  }

  /**
   * 完成任务  zhangsan  -----lishi----判断流程变量的请假天数,1天----分支:人事经理存档(zhaoliu)
   */
  public void complete(){
    //1.得到ProcessEngine
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

    //2.得到TaskService
    TaskService taskService = processEngine.getTaskService();

    //3.查询当前用户是否有任务
    String key = "myProcess_1";
    Task task = taskService.createTaskQuery().processDefinitionKey(key)
        .taskAssignee("zhaoliu").singleResult();

    //4.判断task!=null,说明当前用户有任务
    if(task!=null){
      taskService.complete(task.getId());
//      可以设置流程变量的值
//      taskService.complete(task.getId(),map);
      System.out.println("任务执行完毕");
    }
  }
}

设置 local流程变量

任务办理时设置

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

// 办理任务时设置local流程变量
@Test
public void completTask() {
	//任务id
	String taskId = "";
	TaskService taskService = processEngine.getTaskService();
	// 定义流程变量
	Map<String, Object> variables = new HashMap<String, Object>();
	Holiday holiday = new Holiday ();
	holiday.setNum(3);
	// 定义流程变量
	Map<String, Object> variables = new HashMap<String, Object>();
	//变量名是holiday,变量值是holiday对象
	variables.put("holiday", holiday);
	// 设置local变量,作用域为该任务
	taskService.setVariablesLocal(tasked, variables);
	taskService.complete(taskId);
}

说明:
设置作用域为任务的 local 变量,每个任务可以设置同名的变量,互不影响。
与全局变量的区别为setVariablesLocal,全局变量为setVariables

通过当前任务设置

@Test
public void setLocalVariableByTaskId(){
	//当前待办任务id
	String taskId="1404";
	TaskService taskService = processEngine.getTaskService();
	Holiday holiday = new Holiday ();
	holiday.setNum(3);
	//通过任务设置流程变量
	taskService.setVariableLocal(taskId, "holiday", holiday);
	//一次设置多个值
	//taskService.setVariablesLocal(taskId, variables)
}

注意:
任务 id必须是当前待办任务idact_ru_task 中存在。

Local变量测试

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

在部门经理审核、总经理审核、人事经理审核时设置 local变量,可通过 historyService 查询每个历史任务时将流程变量的值也查询出来。

// 创建历史任务查询对象
HistoricTaskInstanceQuery historicTaskInstanceQuery = 
historyService
.createHistoricTaskInstanceQuery();
// 查询结果包括 local变量
historicTaskInstanceQuery.includeTaskLocalVariables();
for (HistoricTaskInstance historicTaskInstance : list) {
System.out.println("==============================");
System.out.println(" 任 务 id : " + 
historicTaskInstance.getId());
System.out.println(" 任 务 名 称 : " + 
historicTaskInstance.getName());
System.out.println(" 任 务 负 责 人 : " + 
historicTaskInstance.getAssignee());
System.out.println(" 任 务 local 变 量 : "+ 
historicTaskInstance.getTaskLocalVariables());
}

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章