[2023 latest Activiti7 is the most complete in the whole network] 4. Activiti7 advanced articles

1. Process instance

1.1 What is a process instance

Process instance (ProcessInstance) represents the execution instance of the process definition. A process instance includes all the running nodes. We can use this object to understand the progress of the current process instance and other information. For example: the content of the user or program installation process definition initiates a
  process , this is a process instance 

1.2 Business Management

  After the process definition is deployed in Activiti, we can manage the execution of the process through Activiti in the system, but if we want to associate our process instance with business data, then we need to use the BusinessKey reserved in Activiti (business identification ) to associate

 

 Implementation code:

    /**
     * 启动流程实例,添加businessKey
     */
    @Test
    public void test01(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RuntimeService对象
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 3.启动流程实例
        ProcessInstance instance = runtimeService
                .startProcessInstanceByKey("evection", "1001");
        // 4.输出processInstance相关属性
        System.out.println("businessKey = "+instance.getBusinessKey());
    }

1.3 Suspension and activation of process instances

  In actual scenarios, it may be necessary to suspend the currently running process instead of deleting it due to process changes. After the process is suspended, it cannot continue to execute.

1.3.1 All processes hang

The definition of an operation process is in a suspended state, and all process instances under the process definition are suspended.

The process definition is in a suspended state. This process definition will not allow new process instances to be started, and at the same time, all process instances under this process definition will be suspended and suspended.

    /**
     * 全部流程挂起实例与激活
     */
    @Test
    public void test02(){
       // 1.获取ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RepositoryService对象
        RepositoryService repositoryService = engine.getRepositoryService();
        // 3.查询流程定义的对象
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("evection")
                .singleResult();
        // 4.获取当前流程定义的状态
        boolean suspended = processDefinition.isSuspended();
        String id = processDefinition.getId();
        // 5.如果挂起就激活,如果激活就挂起
        if(suspended){
            // 表示当前定义的流程状态是 挂起的
            repositoryService.activateProcessDefinitionById(
                    id // 流程定义的id
            ,true // 是否激活
            ,null // 激活时间
            );
            System.out.println("流程定义:" + id + ",已激活");
        }else{
            // 非挂起状态,激活状态 那么需要挂起流程定义
            repositoryService.suspendProcessDefinitionById(
                    id // 流程id
                    ,true // 是否挂起
                    ,null // 挂起时间
            );
            System.out.println("流程定义:" + id + ",已挂起");
        }
    }

After suspending the process definition, the status in the instance object for will be changed to 2

 Then go to the process instance for the operation and throw an exception message

 We then turn the suspended process into an active state, and the state value for will be updated from 2 to 1

 Then the business process can be processed normally

1.3.2 Single instance hang 

Operate the process instance object, and execute the suspend operation for a single process. If a process instance is suspended, the process will not continue to execute, and other process instances defined by the current process will not be disturbed. Completing the current task of the process instance will throw an exception 

    /**
     * 单个流程实例挂起与激活
     */
    @Test
    public void test03(){
        // 1.获取ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RuntimeService
        RuntimeService runtimeService = engine.getRuntimeService();
        // 3.获取流程实例对象
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId("25001")
                .singleResult();
        // 4.获取相关的状态操作
        boolean suspended = processInstance.isSuspended();
        String id = processInstance.getId();
        if(suspended){
            // 挂起--》激活
            runtimeService.activateProcessInstanceById(id);
            System.out.println("流程定义:" + id + ",已激活");
        }else{
            // 激活--》挂起
            runtimeService.suspendProcessInstanceById(id);
            System.out.println("流程定义:" + id + ",已挂起");
        }

    }

 Then we can view the status update in the database

 2. Personal tasks

2.1 Assign task owners

2.1.1 Fixed Allocation

 Designate fixed task owners when modeling business processes:

 In the Properties view, fill in the Assignee item as the task leader

 2.1.2 Expression assignment

UEL expressions are supported in Activiti. UEL expressions are part of the Java EE6 specification. UEL (Unified Expression Language) is a unified expression voice. Activiti supports two UEL expressions: UEL-value and UEL-method 

UEL-value 

 Use process variable processing in assignee

 

 

 

Then we can operate

  First we need to deploy the defined process to the Activiti database

    /**
     * 先将新定义的流程部署到Activiti中数据库中
     */
    @Test
    public void test01(){
        // 1.获取ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RepositoryService进行部署操作
        RepositoryService service = engine.getRepositoryService();
        // 3.使用RepositoryService进行部署操作
        Deployment deploy = service.createDeployment()
                .addClasspathResource("bpmn/evection-uel.bpmn") // 添加bpmn资源
                .addClasspathResource("bpmn/evection-uel.png") // 添加png资源
                .name("出差申请流程-UEL")
                .deploy();// 部署流程
        // 4.输出流程部署的信息
        System.out.println("流程部署的id:" + deploy.getId());
        System.out.println("流程部署的名称:" + deploy.getName());
    }

After the deployment is successful, we need to start a new process instance, and then actually associate the UEL expression in the process instance created

    /**
     * 创建一个流程实例
     *    给流程定义中的 UEL表达式赋值
     */
    @Test
    public void test02(){
      // 获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取RuntimeService对象
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 设置 assignee 的取值,
        Map<String,Object> map = new HashMap<>();
        map.put("assignee0","张三");
        map.put("assignee1","李四");
        map.put("assignee2","王五");
        map.put("assignee3","赵财务");
        // 创建流程实例
        runtimeService.startProcessInstanceByKey("evection-uel",map);
    }

After the startup is successful, we can see the assignment information corresponding to the UEL expression in act_ru_variable

 UEL-method

 userBean is a bean in the spring container, which means calling the bean's getUserId() method.

Combination of UEL-method and UEL-value 

Another example:
${ldapService.findManagerForEmployee(emp)}
ldapService is a bean of the spring container, findManagerForEmployee is a method of the bean, emp is the activiti
process variable, and emp is passed as a parameter to the ldapService.findManagerForEmployee method.
other

Expressions support parsing basic types, beans, lists, arrays, and maps, and can also be used as conditional judgments.
  As follows:
  ${order.price > 100 && order.price < 250}

 2.1.3 Listener Assignment

Listeners can be used to complete many Activiti process business. We use the listener here to complete the designation of the person in charge, so we don't need to specify the assignee when designing the process 

Event options 

 create: Triggered after the task is created
assignment: Triggered after the task is assigned
Delete: Triggered after the task is completed
All: Triggered by all events

custom listener 

import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;

public class MyTaskListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        if("创建请假单".equals(delegateTask.getName())
        && "create".equals(delegateTask.getEventName())){
            // 指定任务的负责人
            delegateTask.setAssignee("张三-Listener");
        }

    }
}

test code

/**
 * 先将新定义的流程部署到Activiti中数据库中
 */
@Test
public void test01(){
    // 1.获取ProcessEngine对象
    ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
    // 2.获取RepositoryService进行部署操作
    RepositoryService service = engine.getRepositoryService();
    // 3.使用RepositoryService进行部署操作
    Deployment deploy = service.createDeployment()
            .addClasspathResource("bpmn/evection-listener.bpmn") // 添加bpmn资源
            .addClasspathResource("bpmn/evection-listener.png") // 添加png资源
            .name("出差申请流程-UEL")
            .deploy();// 部署流程
    // 4.输出流程部署的信息
    System.out.println("流程部署的id:" + deploy.getId());
    System.out.println("流程部署的名称:" + deploy.getName());
}

/**
 * 创建一个流程实例
 *    给流程定义中的 UEL表达式赋值
 */
@Test
public void test02(){
  // 获取流程引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 获取RuntimeService对象
    RuntimeService runtimeService = processEngine.getRuntimeService();

    // 创建流程实例
    runtimeService.startProcessInstanceByKey("evection-listener");
}

2.2 Query task 

Query the to-do tasks of the task owner

code show as below:

// 查询当前个人待执行的任务
@Test
public void findPersonalTaskList() {
    // 流程定义key
    String processDefinitionKey = "myEvection1";
    // 任务负责人
    String assignee = "张三";
    // 获取TaskService
    TaskService taskService = processEngine.getTaskService();
    List<Task> taskList = taskService.createTaskQuery()
    	.processDefinitionKey(processDefinitionKey)
    	.includeProcessVariables()
        .taskAssignee(assignee)
        .list();
    for (Task task : taskList) {
        System.out.println("----------------------------");
        System.out.println("流程实例id: " + task.getProcessInstanceId());
        System.out.println("任务id: " + task.getId());
        System.out.println("任务负责人: " + task.getAssignee());
        System.out.println("任务名称: " + task.getName());
    }
}

Associate businessKey

Requirements:
  In the actual application of activiti, querying to-do tasks may display some relevant information of the business system.

For example: To query the list of business trip tasks to be approved, it is necessary to display information such as the date of the business trip order and the number of days of business trip.

  Information such as the number of business trips exists in the business system, but not in the activiti database, so it is impossible to query information such as the number of business trips through the activiti API.
Realization:
  When querying to-do tasks, query the business trip form of the business system through the businessKey (business identifier), and query the number of business trip days and other information.
 

@Test
    public void findProcessInstance(){
//        获取processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        获取TaskService
        TaskService taskService = processEngine.getTaskService();
//        获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
//        查询流程定义的对象
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("myEvection1")
                .taskAssignee("张三")
                .singleResult();
//        使用task对象获取实例id
        String processInstanceId = task.getProcessInstanceId();
//          使用实例id,获取流程实例对象
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
//        使用processInstance,得到 businessKey
        String businessKey = processInstance.getBusinessKey();

        System.out.println("businessKey=="+businessKey);

    }

 2.3 Handling tasks

Note: In practical applications, it is necessary to verify whether the person in charge of the task has the authority to handle the task before completing the task.

/**
     * 完成任务,判断当前用户是否有权限
     */
    @Test
    public void completTask() {
        //任务id
        String taskId = "15005";
//        任务负责人
        String assingee = "张三";
        //获取processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 创建TaskService
        TaskService taskService = processEngine.getTaskService();
//        完成任务前,需要校验该负责人可以完成当前任务
//        校验方法:
//        根据任务id和任务负责人查询当前任务,如果查到该用户有权限,就完成
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskAssignee(assingee)
                .singleResult();
        if(task != null){
            taskService.complete(taskId);
            System.out.println("完成任务");
        }
    }

3. Process variables
3.1. What are process variables? Process
  variables play a very important role in activiti. Process operation sometimes requires process variables. When combining business systems and activiti, process variables are indispensable. Process variables are the basis for activiti to manage workflow. Variables set by management needs. For example: when the business trip application process flows, if the business trip days are more than 3 days, it will be reviewed by the general manager, otherwise it will be directly reviewed by the personnel, and the business trip days can be set as a process variable and used during the process flow.

Note: Although business data can be stored in process variables, you can query process variables through activiti's api to query business data, but it is not recommended to use this, because business data queries are responsible for business systems, and activiti sets process variables to create for process execution needs .

3.2. Process variable type
  If pojo is stored in a process variable, the serialization interface serializable must be implemented. In order to prevent deserialization due to new fields, serialVersionUID needs to be generated.

3.3. Process variable scope
  The scope of a process variable can be a process instance (processInstance), or a task (task), or an execution instance
(execution)

3.3.1. Globa variables
  The default scope of process variables is the process instance. When the scope of a process variable is the process instance, it can be called a global variable

Notice:

Such as: Global variables: userId (variable name), zhangsan (variable value)

  The variable name in the global variable is not allowed to be repeated. If you set a variable with the same name, the value set later will overwrite the variable value set before.

3.3.2. The local variable
  task and execution instance are only for one task and one execution instance range, and the scope is not as large as the process instance, which is called local variable. Because the scope of Local variables does not affect each other in different tasks or different execution instances, the variable names can be the same without any influence. The local variable name can also be the same as the global variable name, it has no effect.

3.4. How to use process variables
3.4.1. Use UEL expressions on attributes
  You can set UEL expressions at assignee, and the value of the expression is the person in charge of the task, for example: ${assignee}, assignee is a process variable name .

Activiti obtains the value of the UEL expression, that is, the value of the process variable assignee, and assigns the value of assignee as the person in charge of the task

3.4.2. Use UEL expression on the connection
  You can set the UEL expression on the connection to determine the flow direction. For example: ${price<10000}. price is a process variable name, and the result type of the uel expression is Boolean. If the UEL expression is true, it is necessary to determine the direction of process execution.

3.5 Use of process variables
3.5.1 Requirements
​ Employees create a business trip application form, which will be reviewed by the department manager. After the department manager’s application is approved, the financial department will directly apply for approval within 3 days. If it is more than 3 days, it will be approved by the general manager. Financial approval.

3.5.2 Process Definition

  First set the person in charge through UEL-value

 

Then set the condition on the branch line 

 Then you can also name it through object parameters, such as event.num:

 

 The other line corresponds to the setting

 

Then you can copy the relevant resource files into the project,

3.5.3 Using Global variables

  Next use the Global variable to control the process

3.5.3.1 POJO creation

  First create the POJO object

/**
 * 出差申请的POJO对象
 */
@Data
public class Evection {

    private long id;

    private String evectionName;


    /**
     * 出差的天数
     */
    private double num;

    private Date beginDate;

    private Date endDate;

    private String destination;

    private String reson;
}

 3.5.3.2 Process deployment

    /**
     * 部署流程
     */
    @Test
    public void test01(){
        // 1.获取ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RepositoryService进行部署操作
        RepositoryService service = engine.getRepositoryService();
        // 3.使用RepositoryService进行部署操作
        Deployment deploy = service.createDeployment()
                .addClasspathResource("bpmn/evection-variable.bpmn") // 添加bpmn资源
                .addClasspathResource("bpmn/evection-variable.png") // 添加png资源
                .name("出差申请流程-流程变量")
                .deploy();// 部署流程
        // 4.输出流程部署的信息
        System.out.println("流程部署的id:" + deploy.getId());
        System.out.println("流程部署的名称:" + deploy.getName());
    }

3.5.3.3 Setting Process Variables

a. Set process variables at startup

Set the process variable when starting the process, and the scope of the variable is the entire process instance. 

    /**
     * 启动流程实例,设置流程变量
     */
    @Test
    public void test02(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = engine.getRuntimeService();
        // 流程定义key
        String key = "evection-variable";
        // 创建变量集合
        Map<String,Object> variables = new HashMap<>();
        // 创建出差对象 POJO
        Evection evection = new Evection();
        // 设置出差天数
        evection.setNum(4d);
        // 定义流程变量到集合中
        variables.put("evection",evection);
        // 设置assignee的取值
        variables.put("assignee0","张三1");
        variables.put("assignee1","李四1");
        variables.put("assignee2","王五1");
        variables.put("assignee3","赵财务1");
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key, variables);
        // 输出信息
        System.out.println("获取流程实例名称:"+processInstance.getName());
        System.out.println("流程定义ID:" + processInstance.getProcessDefinitionId());
    }

mission accomplished

   /**
     * 完成任务
     */
    @Test
    public void test03(){
        String key = "evection-variable";
        String assignee = "李四1";
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        Task task = taskService.createTaskQuery()
                .processDefinitionKey(key)
                .taskAssignee(assignee)
                .singleResult();
        if(task != null){
            taskService.complete(task.getId());
            System.out.println("任务执行完成...");
        }
    }

The scope of the process variable set by the startProcessInstanceByKey method is a process instance. The process variable is stored in a Map. The key in the map of the same process instance is the same, and the latter will overwrite the former.

b. Set
  the process variable when the task is completed. The process variable can only be used by other nodes after the task is completed. Its scope is the entire process instance. If the key of the set process variable is in the process If the same name already exists in the instance, the variable set later will replace the variable set earlier.

  Here you need to set the process variable when the task of creating a business trip is completed
 

    /**
     * 启动流程实例,设置流程变量
     */
    @Test
    public void test02(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = engine.getRuntimeService();
        // 流程定义key
        String key = "evection-variable";
        // 创建变量集合
        Map<String,Object> variables = new HashMap<>();
        
        // 设置assignee的取值
        variables.put("assignee0","张三1");
        variables.put("assignee1","李四1");
        variables.put("assignee2","王五1");
        variables.put("assignee3","赵财务1");
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key, variables);
        // 输出信息
        System.out.println("获取流程实例名称:"+processInstance.getName());
        System.out.println("流程定义ID:" + processInstance.getProcessDefinitionId());
    }

    /**
     * 完成任务
     */
    @Test
    public void test03(){
        String key = "evection-variable";
        String assignee = "李四1";
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        Task task = taskService.createTaskQuery()
                .processDefinitionKey(key)
                .taskAssignee(assignee)
                .singleResult();

        Map<String,Object> variables = new HashMap<>();
        // 创建出差对象 POJO
        Evection evection = new Evection();
        // 设置出差天数
        evection.setNum(4d);
        // 定义流程变量到集合中
        variables.put("evection",evection);

        if(task != null){
            taskService.complete(task.getId(),variables);
            System.out.println("任务执行完成...");
        }
    }

Note:
To set the process variable through the current task, the current task id needs to be specified, and an exception will be thrown if the currently executing task id does not exist.
When processing tasks, process variables are also set through map<key,value>, and multiple variables can be set at a time.

c. Current process instance settings

  Set the global variable by the process instance id, the process instance must not be completed.

    @Test
    public void setGlobalVariableByExecutionId(){
//    当前流程实例执行 id,通常设置为当前执行的流程实例
        String executionId="2601";
//     获取processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
//        创建出差pojo对象
        Evection evection = new Evection();
//        设置天数
        evection.setNum(3d);
//      通过流程实例 id设置流程变量
        runtimeService.setVariable(executionId, "evection", evection);
//      一次设置多个值
//      runtimeService.setVariables(executionId, variables)
    }

Note:
  executionId must be the execution id of the current unfinished process instance, usually this id sets the id of the process instance. Process variables can also be obtained through runtimeService.getVariable().

d. Current task settings

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

 Note:
  The task id must be the current to-do task id, which exists in act_ru_task. If the task has ended, an error will be reported or the process variable can be obtained through taskService.getVariable().

3.5.4 Setting local process variables
3.5.4.1.
  Setting local process variables during task processing. When setting local process variables during task processing, the currently running process instance can only be used before the end of the task. After the task ends, this variable cannot be used in the current process instance. You can pass Query historical task query.
 

/*
*处理任务时设置local流程变量
*/
@Test
public void completTask() {
   //任务id
   String taskId = "1404";
//  获取processEngine
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    TaskService taskService = processEngine.getTaskService();
//  定义流程变量
   Map<String, Object> variables = new HashMap<String, Object>();
   Evection evection = new Evection ();
   evection.setNum(3d);
// 定义流程变量
   Map<String, Object> variables = new HashMap<String, Object>();
//  变量名是holiday,变量值是holiday对象
    variables.put("evection", evection);
//  设置local变量,作用域为该任务
    taskService.setVariablesLocal(taskId, variables);
//  完成任务
   taskService.complete(taskId);
}

Description:
  Set the local variable whose scope is the task, and each task can set a variable with the same name without affecting each other.

3.5.4.2, through the current task settings

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

Note:
  The task id must be the current to-do task id, which exists in act_ru_task.

3.5.4.3. Local variable test 1
  Is it feasible to change the setting of global variable to local variable in the above example? Why?
  Local variables cannot be used in the current process instance execution after the task ends, and an error will be reported if the variable is needed in subsequent process executions.

3.5.4.4, Local variable test 2
  Set up local variables during department manager review, general manager review, and financial review, and the value of process variables can also be queried when querying each historical task through historyService.

code show as below:
 

// 创建历史任务查询对象
      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());

}

Note: Querying historical process variables, especially querying pojo variables needs to be deserialized, which is not recommended.

4. Group tasks
4.1. Requirements

  In the process definition, the task leader is fixed in the assignee of the task node, and the participants are fixed in the .bpmn file when the process is defined. If the temporary task leader changes, the process definition needs to be modified. System scalability is poor.
  For this situation, multiple candidates can be set for the task, and participants can be selected from the candidates to complete the task.

4.2. Setting up task candidates
  Set candidate-users (candidates) in the configuration of task nodes in the flowchart, and separate multiple candidates with commas.

 view bpmn file

<userTask activiti:candidateUsers="lisi,wangwu" activiti:exclusive="true" id="_3" name="manager approval"/>

We can see that the reviewers of the department manager have been set to a group of candidates such as lisi and wangwu. You can use activiti:candiateUsers=”user 1, user 2, user 3” to set a group of candidates

4.3. Group task
4.3.1. Group task handling process

a. Query the designated candidate for the group task
  , and query the candidate's current pending tasks. Candidates cannot handle tasks immediately.

b. Pick up (claim) tasks
  All candidates for this group of tasks can be claimed. Turn the candidate's group task into a personal task. The original candidate becomes the person in charge of the task. If you don't want to handle the task after picking it up? It is necessary to return the personal tasks that have been picked up to the group, turning the personal tasks into group tasks.

c. Query personal tasks
  The query method is the same as the personal tasks part, and the personal tasks that the user is responsible for are queried according to the assignee.

d. Handle personal tasks
4.3.2. Query group tasks

   according to candidate query group tasks

    /**
     * 查询组任务
     */
    @Test
    public void test03(){
        String key = "evection1";
        String candidateUser = "lisi";
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey(key)
                .taskCandidateUser(candidateUser)
                .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());
        }
    }

4.3.3, pick up group tasks

   After the candidate picks up the group task, the task becomes his own personal task.

    /**
     * 候选人 拾取任务
     */
    @Test
    public void test04(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        String taskId = "72505";
        // 候选人
        String userId = "lisi";
        // 拾取任务
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskCandidateUser(userId) // 根据候选人查询
                .singleResult();
        if(task != null){
            // 可以拾取任务
            taskService.claim(taskId,userId);
            System.out.println("拾取成功");
        }
    }

4.3.4. Query personal to-do tasks

  The query method is the same as personal task query

    @Test
    public void test03(){
        String key = "evection1";
        String candidateUser = "lisi";
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey(key)
                //.taskCandidateUser(candidateUser)
                //.taskCandidateOrAssigned(candidateUser)
                .taskAssignee(candidateUser)
                .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());
        }
    }

4.3.5. Handle personal tasks

  with personal tasks

    /**
     * 完成个人任务
     */
    @Test
    public void test05(){
        String  taskId = "72505";
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        taskService.complete(taskId);
        System.out.println("完成任务:" + taskId);
    }

4.3.6. Return group tasks

   If an individual does not want to handle the group task, he can return the group task, after which the user is no longer the person in charge of the task

   /**
     * 归还任务
     */
    @Test
    public void test06(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        String taskId = "75002";
        String userId= "zhangsan";
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskAssignee(userId)
                .singleResult();
        if(task != null){
            // 如果设置为null,归还组任务,任务没有负责人
            taskService.setAssignee(taskId,null);
        }
    }

4,3,7 Task Handover

  Task owners hand off tasks to other owners

    /**
     * 任务交接
     */
    @Test
    public void test07(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        String taskId = "75002";
        String userId= "zhangsan";
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskAssignee(userId)
                .singleResult();
        if(task != null){
            // 设置该任务的新的负责人
            taskService.setAssignee(taskId,"赵六");
        }
    }

4.3.8, database table operation

  Query the current task execution table

SELECT * FROM act_ru_task 

 Task execution table, which records the currently executed task. Since the task is currently a group task, all assignees are empty. When the task is picked up, this field is the id of the picked user, and the task participant is queried

SELECT * FROM act_ru_identitylink

Task participant, record the current reference task user or group. If the current task has a candidate set, it will insert the candidate record into this table. If there are several candidates, insert several. Inserting a record also inserts a record into the history table. mission completed

5. Gateway
  The gateway is used to control the flow of the process

5.1 Exclusive Gateway ExclusiveGateway
5.1.1 What is an exclusive gateway:

  Exclusive gateways are used to implement decisions in the process. When the process is executed to this gateway, all branches will judge whether the condition is true, and if it is true, the branch will be executed.

Note: The exclusive gateway will only select a true branch for execution. If both branch conditions are true, the exclusive gateway will select the branch with the smaller id value to execute.

Why use an exclusive gateway?

  Branches can also be implemented without an exclusive gateway, such as: setting branch conditions on the condition conditions of the connection. Disadvantages of setting condition conditions on the connection: If the conditions are not met, the process ends (abnormally). If you use an exclusive gateway to determine the direction of the branch, as follows:

 If all the conditions of the line going out from the gateway are not met, the system throws an exception.

org.activiti.engine.ActivitiException: No outgoing sequence flow of the exclusive gateway 'exclusivegateway1' could be selected for continuing the process
   at org.activiti.engine.impl.bpmn.behavior.ExclusiveGatewayActivityBehavior.leave(ExclusiveGatewayActivityBehavior.java:85)

5.1.2 Process definition

  Exclusive gateway icon, inside the red box:
insert image description here

5.1.3 Testing

  After the review by the department manager, go to the exclusive gateway. There are two branches from the exclusive gateway. One is to judge whether the number of business trips is greater than 3 days, and the other is to judge whether the number of business trips is less than or equal to 3 days. When setting branch conditions, if all branch conditions are not true, an error will be reported:

org.activiti.engine.ActivitiException: No outgoing sequence flow of the exclusive gateway 'exclusivegateway1' could be selected for continuing the process

       at org.activiti.engine.impl.bpmn.behavior.ExclusiveGatewayActivityBehavior.leave(ExclusiveGatewayActivityBehavior.java:85)

5.2 Parallel Gateway ParallelGateway

5.2.1 What is a parallel gateway

Parallel gateways allow processes to be divided into multiple branches, and multiple branches can also be brought together. The function of parallel gateways is based on incoming and outgoing sequential flows:

l fork branch:

  All outgoing sequence flows in parallel, creating a concurrent branch for each sequence flow.

l join aggregation:

  All incoming branches that arrive at the parallel gateway and wait there until all incoming branches of the sequential flow have arrived, the flow passes through the convergent gateway.
Note that if the same parallel gateway has multiple incoming and multiple outgoing sequence flows, it has both branching and converging functions. At this time, the gateway will first aggregate all incoming sequence flows, and then split them into multiple parallel branches.
The main difference from other gateways is that parallel gateways do not parse conditions.  Even if a condition is defined in the sequence flow, it will be ignored.

 

 example:

illustrate:

  The technical manager and the project manager are two execution branches. There are two records in the act_ru_execution table, which are the technical manager and the project manager, and there is another record in act_ru_execution indicating the process instance. After the tasks of the technical manager and the project manager are all completed, they will converge at the convergence point and pass through the parallelGateway parallel gateway. Parallel gateways are often used in business applications for countersign tasks, which are tasks that are handled jointly by multiple participants.

5.2.2 Process definition
  parallel gateway icon, inside the red box:

insert image description here
5.2.3
  When the test is executed to the parallel gateway database, the tracking is as follows: current task table: SELECT * FROM act_ru_task

insert image description here
Above: There are two tasks currently executing. Query process instance execution table: SELECT * FROM act_ru_execution

insert image description here

 In the figure above, it shows that the current process instance has multiple branches (two) running.

Execution of parallel tasks:
the execution of parallel tasks is not divided into front and back, and the person in charge of the task can execute it.
After executing the technical manager task, query the current task table SELECT * FROM act_ru_task

insert image description here

The completed technical manager task in the current task table act_ru_task_ has been deleted.
In the execution table of the process instance: SELECT * FROM act_ru_execution has multiple branches and a sink node with parallel gateways.

insert image description here
Convergence node with parallel gateways: It means that a branch has arrived at the convergence, waiting for other branches to arrive.
When all branch tasks are completed and reach the aggregation node:
process instance execution table: SELECT * FROM act_ru_execution, the execution process instance has been approved by the general manager, indicating that the process execution has passed the parallel gateway

insert image description here

 Summary: All branches reach the sink node, and the execution of the parallel gateway is completed.

5.3 Inclusive Gateway InclusiveGateway

5.3.1 What is a containment gateway

Inclusive gateways can be seen as a combination of exclusive and parallel gateways. As with the exclusive gateway, you can define conditions on the outgoing sequence flow, and the containing gateway will resolve them. But the main difference is that containment gateways can select more than one sequence flow, just like parallel gateways.
  Functions that include gateways are based on incoming and outgoing sequence flows:

l branch:

  All outgoing sequence flow conditions are resolved, and sequence flows that evaluate to true continue execution in parallel, creating a branch for each sequence flow.

l Convergence:

  All parallel branches arriving at the containing gateway will enter a wait state until each branch containing a process token entering the sequence flow has arrived. This is the biggest difference from parallel gateways. In other words, the containing gateway will only wait for incoming sequence flows that are selected for execution. After convergence, the flow continues through the containing gateway.

5.3.2 Process definition:
  The business trip application must be approved by the project manager if it is longer than or equal to 3 days, and it must be approved by the technical manager if it is less than 3 days. The business trip application must be approved by the HR manager.
Contains the gateway icon, inside the red box:

insert image description here

 Define the process:

 Note: Set the condition condition on the connection of each branch containing the gateway.

5.3.3 Test
  if the process variable does not exist in the condition of the gateway setting, an error will be reported;
 

org.activiti.engine.ActivitiException: Unknown property used in expression: ${evection.num>=3}

 The process variable evection.num needs to be set when the process starts.

1) When the process reaches the first gateway, it will judge according to the conditions, which branches to go at present:

  Process instance execution table: SELECT * FROM act_ru_execution

insert image description here
First record: Contains the gateway branch.

 The last two records represent two branches to be executed:
ACT_ID = "_13" represents the project manager Shenpin
ACT_ID = "_5" represents the approval of the HR manager
Current task list: ACT_RU_TASK

insert image description here

 In the figure above, project manager approval and HR manager approval are current tasks and are being executed in parallel.
If there is a branch execution that goes to the branch of the converging node first, it must wait for other execution branches to go to the converging node.

2) Execute the approval of the project manager first, and then query the current task table: ACT_RU_TASK

insert image description here

 The current task still needs to be approved by the HR manager.
Process instance execution table: SELECT * FROM act_ru_execution

  It is found that the branch of the personnel manager still exists, and the branch of the project manager has reached the node of ACT_ID = _18. And ACT_ID=__18 is the second inclusion gateway. At this time, because there are 2 branches to be executed, the inclusion gateway will wait for all branches to converge before execution can be completed.

3) Execute the approval of the HR manager
and then query the current task table: ACT_RU_TASK

insert image description here
  The current task list is no longer approved by the HR manager, indicating that the HR manager's approval has been completed. Process instance execution table: SELECT * FROM act_ru_execution

insert image description here

After the execution of the containing gateway is completed, the branch and aggregation are deleted from act_ru_execution.

Summary: When branching, you need to judge the conditions. The branches that meet the conditions will be executed , and the branches that meet the conditions will finally be aggregated.
5.4 Event Gateway EventGateway

Event gateways allow flow to be determined based on events. Each outgoing sequence flow of the gateway is connected to an intermediate capture event. When a process reaches an event-based gateway, the gateway enters a wait state: execution is suspended. At the same time, relative event subscriptions are created for each outgoing sequence flow.

  The outbound sequence flow of the event gateway is different from the normal sequence flow. These sequence flows will not really "execute". Instead, they let the process engine decide which events need to be subscribed to by the process executing to the event gateway. The following conditions are to be considered:

The event gateway must have two or more outgoing sequence flows;
after the event gateway, only the intermediateCatchEvent type can be used (activiti does not support receivingTask based on the event gateway). The
intermediate capture event connected to the event gateway must have only one entry sequence flow.
5.4.1 Process definition

Event gateway icon, inside the red frame 

insert image description here

 intermediateCatchEvent:

 Event types supported by intermediateCatchEvent:
Message Event: Message Event
Signal Event: Signal Event
Timer Event: Timing Event

Define a process using an event gateway: 

The content of the advanced chapter will be introduced here. 

Guess you like

Origin blog.csdn.net/wufaqidong1/article/details/129596381