[Workflow engine] Use of Activiti 02

The use of Activiti is mainly divided into three steps:

1, Define process

Define a process according to the bpmn specification,
template file

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns: xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg. org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg. org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace ="http://www.activiti.org/test">
  <process id="myProcess" name="My process" isExecutable="true">
    <startEvent id="startevent1" name="Start"></startEvent>
    <userTask id="usertask1" name="Create leave request"></userTask>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
    <userTask id="usertask2" name="Department Manager Review"></userTask>
    <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>
    <userTask id="usertask3" name="Personnel Review"></userTask>
    <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow4" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_myProcess">
    <bpmndi:BPMNPlane bpmnElement="myProcess" id="BPMNPlane_myProcess">
      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="130.0" y="160.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
        <omgdc:Bounds height="55.0" width="105.0" x="210.0" y="150.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
        <omgdc:Bounds height="55.0" width="105.0" x="360.0" y="150.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">
        <omgdc:Bounds height="55.0" width="105.0" x="510.0" y="150.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="660.0" y="160.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="165.0" y="177.0"></omgdi:waypoint>
        <omgdi:waypoint x="210.0" y="177.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
        <omgdi:waypoint x="315.0" y="177.0"></omgdi:waypoint>
        <omgdi:waypoint x="360.0" y="177.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
        <omgdi:waypoint x="465.0" y="177.0"></omgdi:waypoint>
        <omgdi:waypoint x="510.0" y="177.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
        <omgdi:waypoint x="615.0" y="177.0"></omgdi:waypoint>
        <omgdi:waypoint x="660.0" y="177.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

Process symbols in BPMN specification

1. Event

  • start
  • middle
  • Finish

2.Activity

  • User tasks
  • Service tasks
  • Task sub-process

An activity can be a task or a word processing process of the current process. The activity can also specify different types.

3.GateWay
The gateway is used to handle decisions

  • exclusive gateway

Only one path will be selected. When the process is executed to the gateway, it will be executed one by one according to the output order. When the condition is true, the current gateway will continue to be executed.

If there are multiple paths, the first line with a value of true will be executed. If all are true, an exception will be reported.

The exclusive gateway needs to be used in conjunction with the conditional sequence flow. The default attribute specifies the default sequence flow. When all conditions are not met, the sequence flow specified by default will be used.

  • Parallel gateway

All paths will be selected simultaneously

Split—–Execute all output streams in parallel, creating a parallel execution line for each sequence six

Merge—-All lines split and executed by parallel gateways are waiting here, and execution will not continue until all lines are completed.

  • inclusive gateway

Multiple lines can be executed at the same time, or conditions can be set on the gateway
Split—-calculate the expression on the line, if the result is true, create a parallel line for execution

Merge—-All lines split and executed by parallel gateways are waiting here, and execution will not continue until all lines are completed.

  • Integrated gateway

  • event gateway

It is used to capture event settings, allowing multiple output streams to execute multiple different intermediate capture events. When the process is executed to the event gateway, the process is in a waiting state and needs to wait until an event is thrown to convert the waiting state to the active state.

Create process file

Download the actiBPM plug-in in idea. The plug-in may not be found in the plug-in library.
actiBPMN plug-in download

Create a process file **.bmpn file in the resource folder, and then use the plug-in to draw the business process


Add each process-related person (applicant, approver…) to the process


Then we look at the event.bpmn file

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http: //www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http: //www.omg.org/spec/DD/20100524/DI" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3. org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id ="m1696900343930" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
  <process activiti:candidateStarterGroups="employee" activiti:candidateStarterUsers="Gavin" id="MyEvection" isClosed="false" isExecutable="true" name="Travel Application" processType ="None">
    <startEvent id="_2" name="StartEvent"/>
    <userTask activiti:assignee="zhangsan" activiti:exclusive="true" id="_3" name="Travel Application"/>
    <userTask activiti:assignee="jerry" activiti:exclusive="true" id="_4" name="Department Manager Approval"/>
    <userTask activiti:assignee="tom" activiti:exclusive="true" id="_5" name="General Manager Approval"/>
    <userTask activiti:assignee="gavin" activiti:exclusive="true" id="_6" name="Financial Approval"/>
    <sequenceFlow id="_7" sourceRef="_2" targetRef="_3"/>
    <sequenceFlow id="_8" sourceRef="_3" targetRef="_4"/>
    <sequenceFlow id="_9" sourceRef="_4" targetRef="_5"/>
    <sequenceFlow id="_10" sourceRef="_5" targetRef="_6"/>
    <endEvent id="_11" name="EndEvent"/>
    <sequenceFlow id="_12" sourceRef="_6" targetRef="_11"/>
  </process>
  <bpmndi:BPMNDiagram documentation="background=#FFFFFF;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
    <bpmndi:BPMNPlane bpmnElement="MyEvection">
      <bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
        <omgdc:Bounds height="32.0" width="32.0" x="165.0" y="25.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
        <omgdc:Bounds height="55.0" width="85.0" x="150.0" y="135.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4">
        <omgdc:Bounds height="55.0" width="100.0" x="155.0" y="255.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="100.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5">
        <omgdc:Bounds height="55.0" width="85.0" x="160.0" y="355.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_6" id="Shape-_6">
        <omgdc:Bounds height="55.0" width="85.0" x="160.0" y="450.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_11" id="Shape-_11">
        <omgdc:Bounds height="32.0" width="32.0" x="190.0" y="585.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="_12" id="BPMNEdge__12" sourceElement="_6" targetElement="_11">
        <omgdi:waypoint x="206.0" y="505.0"/>
        <omgdi:waypoint x="206.0" y="585.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_7" id="BPMNEdge__7" sourceElement="_2" targetElement="_3">
        <omgdi:waypoint x="181.0" y="57.0"/>
        <omgdi:waypoint x="181.0" y="135.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_8" id="BPMNEdge__8" sourceElement="_3" targetElement="_4">
        <omgdi:waypoint x="195.0" y="190.0"/>
        <omgdi:waypoint x="195.0" y="255.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_9" id="BPMNEdge__9" sourceElement="_4" targetElement="_5">
        <omgdi:waypoint x="202.5" y="310.0"/>
        <omgdi:waypoint x="202.5" y="355.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_10" id="BPMNEdge__10" sourceElement="_5" targetElement="_6">
        <omgdi:waypoint x="202.5" y="410.0"/>
        <omgdi:waypoint x="202.5" y="450.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

We can see that the .bpmn file is actually a file in xml format. Let’s try changing the suffix to .xml

Since the .xml file suffix is used instead of the native .bpmn file, how to generate a flow chart?
Right-click the file->>

After that, a picture will be generated: This picture is more beautiful and can be used to show to customers (it is not necessary for internal use)

Of course, you can also take screenshots. Anyway, there are many ways, so don’t worry too much;

If the process name is in Chinese, garbled characters may occur. Don’t worry.

If the code is still garbled, you need to modify the following two files:

Refer to this article-Three steps to solve the Chinese garbled problem of the .bpmn file of the IDEA actiBPM plug-in

Chinese version process

2, Deployment process

Load the process definition file into the database

 @Test
    public void Test02() {<!-- -->
        //1, create processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2, Get the deployed service RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //3, use the RepositoryService instance to deploy the process, define a process name and then deploy it to the database
        DeploymentBuilder deployment = repositoryService.createDeployment();
        //4, load deployment information into the database table
        Deployment deploy = deployment.name("Business trip application process").disableSchemaValidation().addClasspathResource("bpmn/evection.bpmn").addClasspathResource("bpmn/evection.png").deploy();

        System.out.println("Process deployment id" + deploy.getId());
        System.out.println("Process deployment name" + deploy.getName());
        System.out.println("Process Deployment Catalog" + deploy.getCategory());
        System.out.println("Process Deployment" + deploy.getTenantId());
        System.out.println("Process Deployment" + deploy.getKey());
        System.out.println("Process deployment time" + deploy.getDeploymentTime());

    }

After the deployment is completed, we can see that there is data in the re table


The tables operated during deployment are:

  • ACT_RE_DEPLOYMENT
    Store deployment process information (name, deployment time, etc.)
DeploymentEntity[id=1, name=Business trip application process]
2023-10-10 11:45:14,089 2510 [main] DEBUG entEntityImpl.insertDeployment - ==> Preparing: insert into ACT_RE_DEPLOYMENT(ID_, NAME_, CATEGORY_, KEY_, TENANT_ID_, DEPLOY_TIME_, ENGINE_VERSION_) values(?, ?, ?, ?, ?, ?, ?)
2023-10-10 11:45:14,100 2521 [main] DEBUG entEntityImpl.insertDeployment - ==> Parameters: 1(String), Business trip application process (String), null, null, (String), 2023-10-10 11 :45:14.01(Timestamp), null
2023-10-10 11:45:14,102 2523 [main] DEBUG entEntityImpl.insertDeployment - <== Updates: 1

  • ACT_GE_BYTEARRAY
    Store deployment file information
Preparing: INSERT INTO ACT_GE_BYTEARRAY(ID_, REV_, NAME_, BYTES_, DEPLOYMENT_ID_, GENERATED_) VALUES (?, 1, ?, ?, ?, ?) , (?, 1, ?, ?, ?, ?)
2023-10-10 11:45:14,121 2542 [main] DEBUG eEntityImpl.bulkInsertResource - ==> Parameters: 2(String), bpmn/evection.png(String), java.io.ByteArrayInputStream@7a11c4c7(ByteArrayInputStream), 1 (String), false(Boolean), 3(String), bpmn/evection.bpmn(String), java.io.ByteArrayInputStream@4cc547a(ByteArrayInputStream), 1(String), false(Boolean)
2023-10-10 11:45:14,132 2553 [main] DEBUG eEntityImpl.bulkInsertResource - <== Updates: 2

ACT_RE_PROCDEF
process definition table

ACT_GE_PROPERTY

3, Start the process

The startup process requires the use of runtimeService,

 @Test
    public void Test03() {<!-- -->
        //process engine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //Get runtime service
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //Open an instance through key
        ProcessInstance myEvection = runtimeService.startProcessInstanceByKey("MyEvection");
        System.out.println(myEvection.getProcessDefinitionId());
        System.out.println(myEvection.getId());
        System.out.println(myEvection.getActivityId());
    }

At startup, an instance is started based on the key in the act_re_procdef table;

Tables used/operated when creating process instances
Mainly the following tables

Recorded process history table

Record the current process

Recorded the process time of the operation (start time and end time)

The entire process code for completing the task is as follows:

package gavin.test;

import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;

import java.util.List;

public class ActTest {


    //Create data table
    @Test
    public void Test01() {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        System.out.println(engine);
    }

    /**
     * Deployment process
     * 1, create processEngine
     * 2. Get the deployed service RepositoryService
     * 3. Use the RepositoryService instance to deploy the process, define a process name and then deploy it to the database.
     * 4. Input the deployment information (.bpmn file and .png file) into the database table and output the deployment information
     */
    @Test
    public void Test02() {<!-- -->
        //1, create processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2, Get the deployed service RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //3, use the RepositoryService instance to deploy the process, define a process name and then deploy it to the database
        DeploymentBuilder deployment = repositoryService.createDeployment();
        //4, load deployment information into the database table
        Deployment deploy = deployment.name("Business trip application process").disableSchemaValidation().addClasspathResource("bpmn/evection.bpmn").addClasspathResource("bpmn/evection.png").deploy();

        System.out.println("Process deployment id" + deploy.getId());
        System.out.println("Process deployment name" + deploy.getName());
        System.out.println("Process Deployment Catalog" + deploy.getCategory());
        System.out.println("Process Deployment" + deploy.getTenantId());
        System.out.println("Process Deployment" + deploy.getKey());
        System.out.println("Process deployment time" + deploy.getDeploymentTime());

    }

    /**
     * hi_actinst process instance execution history
     * hi_identitylink process participation user history
     * hi_procinst process instance historical information
     * hi_taskinst process task history
     * ru_execution process execution information
     * ru_identitylink route participating user information
     * ru_task process task
     */
    @Test
    public void Test03() {<!-- -->
        //process engine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //Get runtime service
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //Open an instance through key
        ProcessInstance myEvection = runtimeService.startProcessInstanceByKey("MyEvection");
        System.out.println(myEvection.getProcessDefinitionId());
        System.out.println(myEvection.getId());
        System.out.println(myEvection.getActivityId());
    }

    /**
     * Query the tasks performed by individuals
     */
    @Test
    public void Test04() {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List list = taskService.createTaskQuery().processDefinitionKey("MyEvection").taskAssignee("zhangsan").list();

        for (Task task:
                list) {
            System.out.println(task.getProcessInstanceId());
            System.out.println(task.getId());
            System.out.println(task.getAssignee());
            System.out.println(task.getName());
        }
    }

    /**
     *Complete task id
     */
    @Test
    public void Test05() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = defaultProcessEngine.getTaskService();
        taskService.complete("10005");
    }


    /**
     * Query the tasks performed by individuals
     */
    @Test
    public void Test06() {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List list = taskService.createTaskQuery().processDefinitionKey("MyEvection").taskAssignee("jerry").list();

        for (Task task:
                list) {
            System.out.println(task.getProcessInstanceId());
            System.out.println(task.getId());
            System.out.println(task.getAssignee());
            System.out.println(task.getName());
        }
    }
    /**
     *Complete task id
     */
    @Test
    public void Test07() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = defaultProcessEngine.getTaskService();
        taskService.complete("17502");
    }
    /**
     * Query the tasks performed by individuals
     */
    @Test
    public void Test08() {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List list = taskService.createTaskQuery().processDefinitionKey("MyEvection").taskAssignee("tom").list();

        for (Task task:
                list) {
            System.out.println(task.getProcessInstanceId());
            System.out.println(task.getId());
            System.out.println(task.getAssignee());
            System.out.println(task.getName());
        }
    }
    /**
     *Complete task id
     */
    @Test
    public void Test09() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = defaultProcessEngine.getTaskService();
        taskService.complete("20002");
    }
        /**
     *Complete task id
     */
    @Test
    public void Test10() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = defaultProcessEngine.getTaskService();
        taskService.complete("22502");
    }

}

summary:
1. Get processengine-to generate data table

2. Deploy the corresponding workflow
Obtain the deployment service (deployment file *.bpmn and flow chart) repositoryService through processengine

3. Start the process instance
Get runtime after getting runtimeservice

4. Processing workflow
Obtain the taskservice completion process instance to proceed to the next step.

Packaging and deployment

 @Test
    public void deployProcessZip() {<!-- -->
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
        //Get stream---read resources
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("bpmn/evection.zip");
        //Flow into the constructor
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        Deployment deploy = repositoryService.createDeployment().disableSchemaValidation().addZipInputStream(zipInputStream).deploy();
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }