This article focuses on the advanced content of Activiti, such as process instances, individual tasks, process variables, group tasks, and gateways.

The most detailed Activiti series of articles, strongly recommended to collect and pay attention to oh!

Activiti advanced

1. Process instance

1.1 What is a Process Instance

A ProcessInstance represents an execution instance of a process definition. A ProcessInstance contains all the running nodes. We can use this object to learn about the progress of the current ProcessInstance

1.2 Service Management

Once the process definition is deployed in Activiti, we can manage the execution of the process in the system through Activiti, but if we want to associate our process instances with business data, we need to use the BusinessKey(business identity) reserved in Activiti to do soImplementation code:

    /** * Start the process instance and add businessKey */
    @Test
    public void test01(a){
        // 1. Get the ProcessEngine object
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2. Get the RuntimeService object
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 3. Start the process instance
        ProcessInstance instance = runtimeService
                .startProcessInstanceByKey("evection"."1001");
        // 4. Output processInstance attributes
        System.out.println("businessKey = "+instance.getBusinessKey());
    }
Copy the code

1.3 Suspending and activating process instances

In the actual scenario, the current running process may be suspended rather than deleted due to process changes. After the process is suspended, the execution of the process cannot continue.

1.3.1 All processes are suspended

The operation process is defined as suspended, and all process instances below the process definition are suspended.

The process definition is in the suspended state, and the process definition will not allow new process instances to be started, and all process instances under the process definition will be suspended and suspended.

    /** * All processes suspend instances and activate */
    @Test
    public void test02(a){
       // 1. Get the ProcessEngine object
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2. Obtain RepositoryService
        RepositoryService repositoryService = engine.getRepositoryService();
        // 3. Query the objects defined by the process
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("evection")
                .singleResult();
        // 4. Get the state of the current process definition
        boolean suspended = processDefinition.isSuspended();
        String id = processDefinition.getId();
        // 5. Activate if suspended, and suspend if activated
        if(suspended){
            // indicates that the currently defined process state is suspended
            repositoryService.activateProcessDefinitionById(
                    id // Id of the process definition
            ,true // Whether to activate
            ,null // Activation time
            );
            System.out.println("Process definition:" + id + ", activated");
        }else{
            // If the process definition is not suspended, the process definition needs to be suspended
            repositoryService.suspendProcessDefinitionById(
                    id / / process id
                    ,true // Whether to suspend
                    ,null // Hang time
            );
            System.out.println("Process definition:" + id + ", hung"); }}Copy the code

After the process definition is suspended, the state in the instance object for is changed to 2

Then the operation will throw exception information for the process instance ofWe then change the pending process to the active state, updating the status value for 2 to 1

Then the business process can be processed normally

1.3.2 Single instance is suspended

The operation process instance object performs a suspend operation on a single process. When a process instance is suspended, the process does not continue, and other process instances defined by the current process are undisturbed. Completing the current task of the process instance throws an exception

    /** * Single process instance suspended and activated */
    @Test
    public void test03(a){
        // 1. Get the ProcessEngine object
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2. Obtain the RuntimeService
        RuntimeService runtimeService = engine.getRuntimeService();
        // 3. Obtain the process instance object
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId("25001")
                .singleResult();
        // 4. Obtain related state operations
        boolean suspended = processInstance.isSuspended();
        String id = processInstance.getId();
        if(suspended){
            // Hang -- is activated
            runtimeService.activateProcessInstanceById(id);
            System.out.println("Process definition:" + id + ", activated");
        }else{
            // Activate -- hangs
            runtimeService.suspendProcessInstanceById(id);
            System.out.println("Process definition:" + id + ", hung"); }}Copy the code

We can then view the status update in the database

2. Personal tasks

2.1 Assign task responsibility persons

2.1.1 Fixed allocation

Assign a fixed task leader when modeling a business process:In the Properties view, fill in the Assiginee item as the task leader

2.1.2 Expression allocation

Activiti supports UEL expressions. UEL expressions are part of the Java EE6 specification. The Unified Expression Language (UEL) supports two types of UEL expressions: UEL – value and UEL – method

UEL-value

Process variable processing is used in Assignee

And then we can do it

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

    /** * First deploy the newly defined process to the database in Activiti */
    @Test
    public void test01(a){
        // 1. Get the ProcessEngine object
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2. Obtain RepositoryService to deploy
        RepositoryService service = engine.getRepositoryService();
        // 3. Use RepositoryService to deploy
        Deployment deploy = service.createDeployment()
                .addClasspathResource("bpmn/evection-uel.bpmn") // Add BPMN resources
                .addClasspathResource("bpmn/evection-uel.png") // Add PNG resources
                .name("Travel Application Process -UEL")
                .deploy();// Deployment process
        // 4. Output the process deployment information
        System.out.println(Id of process deployment: + deploy.getId());
        System.out.println("Name of process deployment:" + deploy.getName());
    }
Copy the code

After successful deployment we need to start a new process instance and associate UEL expressions with the process instance created

    /** * Create a process instance * assign a value to the UEL expression in the process definition */
    @Test
    public void test02(a){
      // Get the process engine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // Get the RuntimeService object
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // Set the value of assignee,
        Map<String,Object> map = new HashMap<>();
        map.put("assignee0"."Zhang");
        map.put("assignee1"."Bill");
        map.put("assignee2"."Fifty");
        map.put("assignee3"."Zhao Finance");
        // Create a process instance
        runtimeService.startProcessInstanceByKey("evection-uel",map);
    }
Copy the code

After the UEL is started, you can view the assignment information of the UEL expression in the act_ru_variable

UEL – method

A userBean is a bean in the Spring container that calls the bean’s getUserId() method.

Uel-method is combined with uel-value

Such as: ${ldapService. FindManagerForEmployee (emp)} ldapService is a bean, spring container findManagerForEmployee is one of the bean method, Emp is activiti process variables, an emp as a parameter to ldapService. FindManagerForEmployee method.

other

Expressions support parsing of base types, beans, lists, arrays, and maps, and can also be used as conditions. ${order.price > 100 && order.price < 250}

2.1.3 Listener allocation

Listeners can be used to accomplish much of Activiti’s process business. We use the listener here to complete the designation of the responsible person, so we do not need to specify assignee Event option in process design

Assignment: Triggers the task assignment. Delete: Triggers the task completion. All: All events are triggeredCopy the code

Custom listeners

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

public class MyTaskListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        if("Create a leave form".equals(delegateTask.getName())
        && "create".equals(delegateTask.getEventName())){
            // Assign the person responsible for the task
            delegateTask.setAssignee("Zhang SAN - the Listener"); }}}Copy the code

The test code

/** * First deploy the newly defined process to the database in Activiti */
@Test
public void test01(a){
    // 1. Get the ProcessEngine object
    ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
    // 2. Obtain RepositoryService to deploy
    RepositoryService service = engine.getRepositoryService();
    // 3. Use RepositoryService to deploy
    Deployment deploy = service.createDeployment()
            .addClasspathResource("bpmn/evection-listener.bpmn") // Add BPMN resources
            .addClasspathResource("bpmn/evection-listener.png") // Add PNG resources
            .name("Travel Application Process -UEL")
            .deploy();// Deployment process
    // 4. Output the process deployment information
    System.out.println(Id of process deployment: + deploy.getId());
    System.out.println("Name of process deployment:" + deploy.getName());
}

/** * Create a process instance * assign a value to the UEL expression in the process definition */
@Test
public void test02(a){
  // Get the process engine
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // Get the RuntimeService object
    RuntimeService runtimeService = processEngine.getRuntimeService();

    // Create a process instance
    runtimeService.startProcessInstanceByKey("evection-listener");
}
Copy the code

2.2 Query Task

Queries the task owner’s to-do list

The code is as follows:

// Query the personal tasks to be performed
@Test
public void findPersonalTaskList(a) {
    // Process definition key
    String processDefinitionKey = "myEvection1";
    // Task leader
    String assignee = "Zhang";
    / / get the 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("Process instance ID:" + task.getProcessInstanceId());
        System.out.println("Task ID:" + task.getId());
        System.out.println("Mission Leader:" + task.getAssignee());
        System.out.println("Task name:"+ task.getName()); }}Copy the code

Associated businessKey

Requirements: When activiti is used, querying to-do tasks may display some information about the business system.

For example, when querying the travel task list to be approved, you need to display information such as the travel travel date and days.

Information such as travel days exists in the service system, but not in the Activiti database. Therefore, information such as travel days cannot be queried through the API of Activiti. Implementation: When you query to-do tasks, you can use the businessKey (service ID) to associate query the business trip list table of the service system to query information such as the business trip days.

@Test
    public void findProcessInstance(a){
/ / get processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        获取TaskService
        TaskService taskService = processEngine.getTaskService();
/ / get RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
// Query the objects defined by the process
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("myEvection1")
                .taskAssignee("Zhang")
                .singleResult();
// Use the task object to get the instance ID
        String processInstanceId = task.getProcessInstanceId();
// Use the instance id to get the process instance object
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
// Use processInstance to get the businessKey
        String businessKey = processInstance.getBusinessKey();

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

    }
Copy the code

2.3 Handling tasks

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

/** * Complete the task to determine whether the current user has permission */
    @Test
    public void completTask(a) {
        / / task id
        String taskId = "15005";
// Task leader
        String assingee = "Zhang";
        / / get processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        / / create the TaskService
        TaskService taskService = processEngine.getTaskService();
// Before completing the task, verify that the person in charge can complete the current task
// Check method:
// Query the current task according to the task ID and task owner. If the user is found to have permission, the task is completed
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskAssignee(assingee)
                .singleResult();
        if(task ! =null){
            taskService.complete(taskId);
            System.out.println("Finish the job."); }}Copy the code

3. Process variables

3.1. What are process variables

Process variables in Activiti is a very important role, process operation sometimes need to rely on process variables, business system and Activiti combination of process variables, process variables are activiti in the management of workflow according to the management needs to set variables. For example, in the process of business trip application flow, if the number of days of business trip is more than 3 days, it will be reviewed by the general manager; otherwise, it will be reviewed directly by personnel. The number of days of business trip can be set as a process variable and used in the process flow.

Note: Although it is possible to store business data in the process variables and query the business data through Activiti’s API to query the process variables, this is not recommended because the business system is responsible for querying the business data and Activiti sets the process variables to be created for process execution.

3.2 process variable types

If a POJO is stored in a process variable, the serializable interface must be implemented, and the serialVersionUID needs to be generated in case it cannot be deserialized due to the new field.

3.3. Process variable scope

A process variable can be scoped as a processInstance, a task, or an execution instance

3.3.1 globa variable

The default scope for a process variable is the process instance. When a process variable is scoped to a process instance, it can be called a global variable

Note:

For example: Global variable: userId (variable name), zhangsan (variable value)

The global variable name cannot be repeated. If a variable with the same name is set, the later value will overwrite the previous one.

3.3.2. Local variable

Task and execution instance are only for one task and one execution instance scope. The scope is not as large as the process instance and is called the local variable. Since the scope of the Local variable is not affected by different tasks or different execution instances, the name of the Local variable can be the same without any impact. The name of the Local variable can also be the same as the name of the global variable.

3.4 Use of process variables

3.4.1 Using UEL Expressions on Properties

A UEL expression can be set at assignee, and the value of the expression is the responsible person of the task, such as ${assignee}, where assignee is a process variable name.

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

3.4.2 Using UEL Expressions on a Wire

You can set UEL expressions on the wire to determine the flow direction. For example: ${price<10000}. Price is the name of a process variable. The result type of a UEL expression is a Boolean type. If the UEL expression is true, the process execution direction is determined.

3.5 Use of process variables

3.5.1 track of demand

Employees create business trip application form, which shall be reviewed by the department manager. The finance department shall directly apply for approval within 3 days after the application is approved by the department manager, and the general manager shall first approve the application within 3 days after the application is approved by the general manager, and then the finance department shall approve the application after the approval of the general manager.

3.5.2 Process Definition

Uel-value is used to set the responsible personThen set the condition on the branch line

You can also name it with an object argument, such as evection. Num:

The other line corresponds to the setting

You can then copy the relevant resource files into the project,

3.5.3 Using the Global variable

Next, control the process using the Global variable

3.5.3.1 POJO created

Start by creating POJO objects

/** * POJO object for business trip application */
@Data
public class Evection {

    private long id;

    private String evectionName;


    /** * Number of business trips */
    private double num;

    private Date beginDate;

    private Date endDate;

    private String destination;

    private String reson;
}

Copy the code
3.5.3.2 Process Deployment
    /** * Deployment process */
    @Test
    public void test01(a){
        // 1. Get the ProcessEngine object
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2. Obtain RepositoryService to deploy
        RepositoryService service = engine.getRepositoryService();
        // 3. Use RepositoryService to deploy
        Deployment deploy = service.createDeployment()
                .addClasspathResource("bpmn/evection-variable.bpmn") // Add BPMN resources
                .addClasspathResource("bpmn/evection-variable.png") // Add PNG resources
                .name("Travel Application Process - Process Variables")
                .deploy();// Deployment process
        // 4. Output the process deployment information
        System.out.println(Id of process deployment: + deploy.getId());
        System.out.println("Name of process deployment:" + deploy.getName());
    }
Copy the code
3.5.3.3 Setting process Variables
A. Set process variables during startup

The process variables are set when the process is started, and the scope of the variables is the entire process instance.

    /** * Start the process instance and set the process variables */
    @Test
    public void test02(a){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = engine.getRuntimeService();
        // Process definition key
        String key = "evection-variable";
        // Create a variable collection
        Map<String,Object> variables = new HashMap<>();
        // Create a POJO on the move
        Evection evection = new Evection();
        // Set the travel days
        evection.setNum(4d);
        // Define the process variables into the collection
        variables.put("evection",evection);
        // Set the value of assignee
        variables.put("assignee0"."Zhang SAN 1");
        variables.put("assignee1"."Li si 1");
        variables.put("assignee2"."Fifty and 1");
        variables.put("assignee3"."Zhao Finance 1");
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key, variables);
        // Output information
        System.out.println(Get the process instance name:+processInstance.getName());
        System.out.println("Process definition ID:" + processInstance.getProcessDefinitionId());
    }
Copy the code

To complete the task

   /** * Complete the task */
    @Test
    public void test03(a){
        String key = "evection-variable";
        String assignee = "Li si 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("Mission accomplished..."); }}Copy the code

Through setting the process variables startProcessInstanceByKey method is a process instance, the scope of the process variables using the Map storage, the same process instance Map the same key, the latter will overwrite the former

B. Set during task processing

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 already has the same name in the process instance, the variable set later will replace the variable set earlier.

Here you need to set the process variables when the task of creating a travel order is complete

    /** * Start the process instance and set the process variables */
    @Test
    public void test02(a){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = engine.getRuntimeService();
        // Process definition key
        String key = "evection-variable";
        // Create a variable collection
        Map<String,Object> variables = new HashMap<>();
        
        // Set the value of assignee
        variables.put("assignee0"."Zhang SAN 1");
        variables.put("assignee1"."Li si 1");
        variables.put("assignee2"."Fifty and 1");
        variables.put("assignee3"."Zhao Finance 1");
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key, variables);
        // Output information
        System.out.println(Get the process instance name:+processInstance.getName());
        System.out.println("Process definition ID:" + processInstance.getProcessDefinitionId());
    }

    /** * Complete the task */
    @Test
    public void test03(a){
        String key = "evection-variable";
        String assignee = "Li si 1";
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        Task task = taskService.createTaskQuery()
                .processDefinitionKey(key)
                .taskAssignee(assignee)
                .singleResult();

        Map<String,Object> variables = new HashMap<>();
        // Create a POJO on the move
        Evection evection = new Evection();
        // Set the travel days
        evection.setNum(4d);
        // Define the process variables into the collection
        variables.put("evection",evection);

        if(task ! =null){
            taskService.complete(task.getId(),variables);
            System.out.println("Mission accomplished..."); }}Copy the code

Note: To set the process variable through the current task, you need to specify the id of the current task. If the id of the current task does not exist, an exception is thrown. Map <key,value> is also used to set process variables during task processing. Multiple variables can be set at a time.

C. Set the current process instance

The global variable is set by the process instance ID, which must not be completed.

    @Test
    public void setGlobalVariableByExecutionId(a){
// Current process instance execution ID, usually set to the currently executing process instance
        String executionId="2601";
/ / get processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
/ / get RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
// Create a travel POJO object
        Evection evection = new Evection();
// Set the number of days
        evection.setNum(3d);
// Set the process variable by the process instance ID
        runtimeService.setVariable(executionId, "evection", evection);
// Set multiple values at once
// runtimeService.setVariables(executionId, variables)
    }
Copy the code

Note: executionId must be the executionId of the current pending process instance, usually this id sets the id of the process instance. Also can pass runtimeService. GetVariable () to obtain the process variables.

D. Set the current task
@Test
	public void setGlobalVariableByTaskId(a){
		
		// Id of the current to-do task
		String taskId="1404";
/ / get processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
		TaskService taskService = processEngine.getTaskService();
		Evection evection = new Evection();
		evection.setNum(3);
		// Set the process variables by task
		taskService.setVariable(taskId, "evection", evection);
		// Set multiple values at once
		//taskService.setVariables(taskId, variables)
	}
Copy the code

Note: The task ID must be the current to-do task ID, which exists in act_ru_task. If the task is finished, an error will be reported. You can also get the process variables from taskService.getVariable().

3.5.4 Setting Local Process Variables

3.5.4.1 Setting during task handling

The local process variable is set when the task is processed. The current running process instance can only be used before the task ends. When the task ends, the variable cannot be used in the current process instance.

/* * Set the local process variable */ when processing the task
@Test
public void completTask(a) {
   / / task id
   String taskId = "1404";
/ / get processEngine
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    TaskService taskService = processEngine.getTaskService();
// Define process variables
   Map<String, Object> variables = new HashMap<String, Object>();
   Evection evection = new Evection ();
   evection.setNum(3d);
// Define process variables
   Map<String, Object> variables = new HashMap<String, Object>();
// The name of the variable is holiday and the value of the variable is a holiday object
    variables.put("evection", evection);
// Set the local variable to scope the task
    taskService.setVariablesLocal(taskId, variables);
// Finish the task
   taskService.complete(taskId);
}
Copy the code

Note: Set the scope to the local variable of the task, each task can set the same variable, do not affect each other.

3.5.4.2 Setting through the current task
@Test
public void setLocalVariableByTaskId(a){
// Id of the current to-do task
    String taskId="1404";
/ / get processEngine
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    TaskService taskService = processEngine.getTaskService();
    Evection evection = new Evection ();
    evection.setNum(3d);
// Set the process variables by task
    taskService.setVariableLocal(taskId, "evection", evection);
// Set multiple values at once
    //taskService.setVariablesLocal(taskId, variables)
}
Copy the code

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 possible to set the local variable instead of the global variable in the example above? Why is that? The Local variable cannot be used in the current process instance execution after the task has finished, and an error will be reported if the variable is required in subsequent process executions.

3.5.4.4 Testing the Local variable 2

Set the local variable when the department manager audit, general manager audit, and financial audit, and the value of the process variable can be queried through historyService when querying each historical task.

The code is as follows:

// Create the historical task query object
      HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery();
      // The query result includes the local variable
      historicTaskInstanceQuery.includeTaskLocalVariables();
for (HistoricTaskInstance historicTaskInstance : list) {
         System.out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
         System.out.println("Task ID:" + historicTaskInstance.getId());
         System.out.println("Task name:" + historicTaskInstance.getName());
         System.out.println("Mission Leader:" + historicTaskInstance.getAssignee());
     System.out.println("Task local variable:"+ historicTaskInstance.getTaskLocalVariables());

}
Copy the code

Note: Querying historical process variables, especially POJO variables, requires deserialization and is not recommended.

4. The set of tasks

4.1, requirements,

Assignee at the task node in the process definition is fixed as the task leader, and the participant is fixed in the. BPMN file during the process definition. If the temporary task leader changes, the process definition needs to be modified, resulting in poor system scalability. In this case, multiple candidates can be set for the task, and participants can be selected from the candidates to complete the task.

4.2. Set task candidates

Set candidate-users in the configuration of the task node in the flowchart, with multiple candidates separated by commas.

View the BPMN file

<userTask activiti:candidateUsers="lisi,wangwu" activiti:exclusive="true" id="_3" name="Manager approval"/>
Copy the code

We can see that the department manager’s moderators have been set to lisi, Wangwu and a set of candidates. You can use activiti:candiateUsers= “user 1, User 2, user 3” to set up a set of candidates

4.3 Group Tasks

4.3.1 Group task handling process

A. Query group tasks

Specify a candidate to query the candidate’s current to-do tasks. The candidate could not handle the task immediately.

B. Claim task

All candidates for this group of tasks can pick them up. Turn the candidate’s group tasks into individual tasks. The candidate becomes the person in charge of the task. If you don’t want to handle this task after picking it up? You need to return the individual tasks you have picked up to the group, turning the individual tasks into group tasks.

C. Query personal tasks

The query method is the same as that of the individual task section, and the individual task responsible for by the user is queried according to Assignee.

D. Handle personal tasks

4.3.2 Querying Group Tasks

Query group tasks by candidate

    /** * Query group task */
    @Test
    public void test03(a){
        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("Process instance Id:" + task.getProcessInstanceId());
            System.out.println("Task ID:" + task.getId());
            System.out.println("Person in charge :" + task.getAssignee());
            System.out.println("Task name:"+ task.getName()); }}Copy the code

4.3.3 Pick up group tasks

The candidate picks up the group task and it becomes his or her personal task.

    /** * Candidate pick quest */
    @Test
    public void test04(a){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        String taskId = "72505";
        / / the candidate
        String userId = "lisi";
        // Pick up the task
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskCandidateUser(userId) // Search by candidate
                .singleResult();
        if(task ! =null) {// You can pick up tasks
            taskService.claim(taskId,userId);
            System.out.println("Successful pickup"); }}Copy the code

4.3.4 Querying personal To-do tasks

The query method is the same as the personal task query

    @Test
    public void test03(a){
        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("Process instance Id:" + task.getProcessInstanceId());
            System.out.println("Task ID:" + task.getId());
            System.out.println("Person in charge :" + task.getAssignee());
            System.out.println("Task name:"+ task.getName()); }}Copy the code

4.3.5 Handling personal tasks

Handle the same personal tasks

    /** * Complete personal missions */
    @Test
    public void test05(a){
        String  taskId = "72505";
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        taskService.complete(taskId);
        System.out.println("Mission accomplished:" + taskId);
    }
Copy the code

4.3.6 Return group tasks

If the individual does not want to handle the group task, the user can return the group task and the user is no longer in charge of the task

   /** * Return the task */
    @Test
    public void test06(a){
        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) {// If set to NULL, the group task is returned with no responsible person
            taskService.setAssignee(taskId,null); }}Copy the code

4,3,7 handover

The task leader assigns the task to another person in charge

    /** * Task handover */
    @Test
    public void test07(a){
        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) {// Set a new person for the task
            taskService.setAssignee(taskId,"Daisy"); }}Copy the code

4.3.8 Database table operations

Example Query the current task execution table

SELECT * FROM act_ru_task 
Copy the code

The task execution table records the task currently executed. Since the task is a group task, all assignee is empty; when the task is picked, this field is the ID of the user picked to query the task participants

SELECT * FROM act_ru_identitylink
Copy the code

Task participant, which records the current reference task user or group. If the current task has a candidate set, it inserts the candidate records into this table. If there are several candidates, it inserts the number of candidates corresponding to act_ru_identitylink and a history table act_hi_identitylink, Inserting a record into act_RU_IDENTItylink also inserts a record into the history table. Task to complete

5. The gateway

The gateway is used to control the flow of the process

5.1 ExclusiveGateway

5.1.1 What is an exclusive gateway:

An exclusive gateway used to implement decisions in the process. When the process reaches the gateway, all branches determine if the condition is true, and if true, execute the branch.

Note: Exclusive gateways will only select a branch that is true for execution. If both branch conditions are true, the exclusive gateway will select the branch with the smaller ID.

Why use exclusive gateways?

It is possible to branch without an exclusive gateway, for example, by setting a branching condition on a wired condition. The disadvantage of setting the condition on the line is that if none of the conditions are met, the process ends (an exception ends). If the exclusive gateway is used to determine the direction of the branch, it is as follows:

The system throws an exception if none of the conditions for the line from the gateway is met.

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)

Copy the code

5.1.2 Process definition

Exclusive gateway icon in the red box:

5.1.3 test

After the review by the department manager, the department travels to the exclusive gateway. There are two branches from the exclusive gateway. One is to determine whether the travel days are more than three days, and the other is to determine whether the travel days are less than or equal to three days. Error setting branch condition if none of the branch conditions is true:

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)

Copy the code

5.2 ParallelGateway

5.2.1 What is the Parallel Gateway

The parallel gateway allows the process to be divided into multiple branches or to be aggregated into multiple branches. The function of the parallel gateway is based on the incoming and outgoing sequential flows:

L fork:

For all outgoing sequential flows after parallelization, a concurrent branch is created for each sequential flow.

L Join:

All incoming branches that arrive at the parallel gateway and wait there until all branches that enter the sequential flow arrive, the process will pass through the aggregation gateway. Note that if the same parallel gateway has multiple incoming and outgoing sequential flows, it has both branching and converging capabilities. In this case, the gateway will first aggregate all incoming sequential streams and then cut into multiple parallel branches.

The main difference with other gateways is that parallel gateways do not resolve conditions. Conditions are ignored even if they are defined in the sequential flow.

Example:Description:

Technical Manager and Project Manager are two execution branches. There are two entries in the ACT_RU_EXECUTION table for technical manager and project Manager, and one entry in the ACT_RU_EXECUTION table for the process instance. After all tasks of the technical manager and project manager are completed, the technical manager and project manager are aggregated at the aggregation point and parallelGateway is used. In service applications, parallel gateways are often used for countersign tasks, which are performed by multiple participants.

5.2.2 Process definition

Parallel gateway icon, in the red box:

5.2.3 requires testing

When executed to the parallel gateway database trace is as follows: Current task table: SELECT * FROM act_ru_task

Above: There are two tasks currently executing. SELECT * FROM act_ru_executionIn the figure above, the current process instance has multiple branches (two) running.

The execution of parallel tasks: the execution of parallel tasks is not before and after, and the person in charge of the task can execute it. After the technical manager task is executed, query the current task table. SELECT * FROM act_ru_task

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

Convergence with parallel gateways: indicates that a branch has reached the convergence and is waiting for other branches to arrive. When all branch tasks have been completed and reached the sink node: process instance execution table: SELECT * FROM act_ru_execution, the process instance execution has been changed to general manager approval, indicating that the process execution has passed the parallel gatewayConclusion: All branches reach the aggregation node, and the parallel gateway execution is completed.

5.3 Including the Gateway InclusiveGateway

5.3.1 What is an included Gateway

An inclusive gateway can be seen as a combination of an exclusive gateway and a parallel gateway. As with exclusive gateways, you can define conditions on outgoing sequential flows, and the inclusive gateway resolves them. But the main difference is that a containing gateway can choose more than one sequential flow, just like a parallel gateway. The functionality that contains the gateway is based on incoming and outgoing sequential flows:

L branches:

All conditions for outgoing sequential flows are resolved, and sequential flows that result in true continue to execute in parallel, creating a branch for each sequential flow.

L together:

All parallel branches arriving at the containing gateway enter a wait state until each branch entering the sequential flow containing the process token arrives. This is the biggest difference with parallel gateways. In other words, the containment gateway will only wait for the selected and executed to enter the sequential flow. After the aggregation, the process continues through the containment gateway.

5.3.2 Process Definition:

The application for business trip for more than 3 days should be approved by the project manager, and the application for business trip for less than 3 days should be approved by the technical manager. The application for business trip must be approved by the personnel manager. Contains the gateway icon, in the red box:Define the process:Note: Condition is set on the line through each branch that contains the gateway.

5.3.3 test

If the process variable does not exist in the condition containing the gateway setting, an error is reported.

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

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

1) When the process is executed to the first including gateway, it will judge which branches to go according to the conditions:

SELECT * FROM act_ru_execution

First record: contains the gateway branch.

The last two records represent the two branches to execute: ACT_ID = “_13” for the project manager. ACT_ID = “_5” for the personnel manager to approve the current task list: ACT_RU_TASK

In the figure above, project manager approval and personnel manager approval are both current tasks, being executed in parallel. If a branch execution goes to the sink node first, wait for the other branches to go to the sink.

2), first execute the project manager approval, and then query the current task list: ACT_RU_TASKThe current task still has the personnel manager approval to deal with. SELECT * FROM act_ru_executionIt is found that the personnel manager branch still exists, while the project manager branch has gone to the node ACT_ID = _18. ACT_ID=__18 is the second containing gateway. In this case, since there are two branches to execute, the containing gateway will not complete until all branches have reached the aggregation.

3), execute the personnel manager approval and query the current task list: ACT_RU_TASK

The current task list is not approved by the personnel manager, indicating that the approval of the personnel manager has been completed. SELECT * FROM act_ru_execution

Branch and aggregation are removed from the act_ru_execution after inclusion gateway execution.

Summary: When branching, we need to judge the conditions, the branches that meet the conditions will be executed, and the branches that meet the conditions will be aggregated finally.

5.4 EventGateway

The event gateway allows you to determine the flow direction based on events. Each outbound sequential flow of the gateway is connected to an intermediate capture event. When the process reaches an event-based gateway, the gateway enters a wait state: execution is suspended. At the same time, a relative event subscription is created for each outbound sequential flow.

The outgoing order flows of the event gateway are different from normal order flows in that they do not actually “execute”, instead they let the process engine decide which events the process executing to the event gateway needs to subscribe to. Consider the following conditions:

  1. The event gateway must have two or more outgoing sequential flows;
  2. After the event gateway, only the intermediateCatchEvent type can be used (Activiti does not support connecting ReceiveTask based on the event gateway)
  3. Intermediate capture events connected to the event gateway must have only one entry sequence flow.

5.4.1 Process Definition

Event gateway icon, in the red box

IntermediateCatchEvent:

IntermediateCatchEvent Indicates the Event types supported by the following intermediateCatchEvent: Message Event: Message Event Singal Event: signal Event Timer Event: timing Event

Define the process using the event gateway:

~ advanced content will introduce to you here, if you feel helpful welcome to like attention plus collection oh V_V