Activiti workflow from entry to entry: complete Hello World Competition (Activiti workflow API with examples)

Time:2019-9-20

Article source hosting: https://github.com/OUYANGSIHA…
Welcome to star!!!

Originally I wanted to be idle. I just used the Workflow Activiti framework to write blogs in my previous project. However, things are always miscellaneous. It has been delayed till now. This section originally wanted to write about Activiti.APIBut, thinking about too many such blogs, and it seems too rigid, difficult to understand, so, theseAPIIt’s explained in the actual demo.

I. Establishment of Flow Chart

Before we start to do workflow, we should first show the specific business in the workflow deployment flow chart, and all the tests are passed, which is equivalent to half the success, and the development of specific business is relatively easy.

First, let’s look at what controls are in idea and what controls are commonly labeled.

Let’s talk about the process of establishing a flow chart.

First, we need to pull in one.Start nodereachbpmnIn the file, this is the graphical interface, just need to pull in.

Then, we pull in one from the controlUserTaskUser Task Node tobpmnIn the document.

In this way, there are two approval nodes. If we need some other business requirements, we can add some more.gatewayIt’s not added here for the time being.

Finally, we only need an end nodeEndEventThe deployment diagram of the workflow is completed.

Let’s conclude with a complete example.

It seems that the whole flow chart has been drawn, but the drawback is that we haven’t set it up yet.Supervisor approvalandCounselor approvalWho is going to approve it, so we still need to see how to set it up.Approver

First of all, we needSelect an Approval NodeFor example, select a mentor to approve the node.

Second, we can clearly see a name on the left side of the idea editor calledBPMN editorThe property box of theAll properties that a user task node can set

Be careful:Candidate users, candidate groups, task listeners, these three attributes are not mentioned here for the time being, and will be supplemented later.

Since, at this stage, we need to set up approvers, so we need toAssigneeThis property sets our approver.

As shown above, settings are set hereSupervisor approvalThe approver of this node is human-madesihai。 In addition to setting the examiner directly, there are two ways to set it up, which are supplemented later.

Another approval node can also be set up in this way to complete the setup of the approver.

Very good, which basically completes the creation of a flow chart. Next, we will explain it in detail through examples.Explanation of API for Activiti

2. Explaining API with examples

In the creation of the above flowchart, we have not yet generated png images, so if you do not know how to generate, you can refer to the previous article: Activiti workflow from entry to entry: integration spring.

Since we are explaining API, we should first look at the main APIs, so as to have a comprehensive grasp.

How to use these APIs? Let’s talk about them one by one.

2.1 Process Definition

Since it is a process definition, how to deploy the process definition is absolutely indispensable.

2.1.1 Deployment process definition method 1
@Autowired
    private ProcessEngine processEngine;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private HistoryService historyService;

    /**
     * Deployment process definition (from classpath)
     */
    @Test
    public void deploymentProcessDefinition_classpath(){
        Deployment deployment = processEngine. getRepositoryService ()// Service related to process definition and deployment objects
                CreateDeployment ()// Create a deployment object
                .name ("process definition")// Add the name of the deployment
                AddClasspath Resource ("bpmn/hello.bpmn")// loaded from classpath resources, only one file can be loaded at a time
                AddClasspath Resource ("bpmn/hello.png")// loaded from classpath resources, only one file can be loaded at a time
                Deploy (); // complete deployment
        System.out.println ("Deployment ID:"+deployment.getId()));
        System. out. println ("Deployment name:"+deployment. getName ()));
    }

Note: This is the JUnit test environment after the integration of spring. How to integrate spring? See this article: Activiti workflow from entry to entry: integration of spring.

Output results:

In this way, we deploy the process. So how to operate it, let’s look at the whole process.

  • Get the process engine object: This is integrated with spring.
  • Get a Repository Service object (warehouse object) through the process engine
  • A deployment object configuration object is generated by the service object of the warehouse to encapsulate the configuration of the deployment operation.
  • This is a chain programming, which sets the display name in the deployment configuration object and uploads the process definition rule file.
  • Store process-defined rule information in database tables.

Actually, three tables in Activiti database are used in this step: act_re_deployment (deployment object table), act_re_procdef (process definition table), act_ge_bytearray (resource file table).

Let’s look at the changes in these three tables.
1)act_re_deployment

As you can see, the deployment ID and the deployment name exist in this table.

2)act_re_procdef

This table contains the ID of the deployment process of Deployment_ID, the name of the BPMN resource file, and the name of the PNG image.

3)act_ge_bytearray

Storage process defines relevant deployment information. That is, the place where the process defines the document to be stored. For each deployment, two records are added, one is about the BPMN rule file and the other is a picture (if only one BPMN file is specified at deployment time, activiti parses the content of the BPMN file and automatically generates the flow chart at deployment time). The two files are not very large, they are stored in the database in binary form.

2.1.2 Deployment process definition method 2
/**
     * Deployment process definition (from zip)
     */
    @Test
    public void deploymentProcessDefinition_zip(){
        InputStream in = this.getClass().getClassLoader().getResourceAsStream("bpmn/hello.zip");
        ZipInputStream zipInputStream = new ZipInputStream(in);
        Deployment deployment = processEngine. getRepositoryService ()// Service related to process definition and deployment objects
                CreateDeployment ()// Create a deployment object
                .name ("process definition")// Add the name of the deployment
                AdZipInputStream (zipInputStream)//Files in ZIP format are deployed
                Deploy (); // complete deployment
        System.out.println ("Deployment ID:"+deployment.getId()));//
        System. out. println ("Deployment name:"+deployment. getName ();)//
    }

The project structure is as follows:

Output results:

In this way, there is no problem. The only difference is that the zip file is compressed into ZIP format. The input stream of zip is used as the definition of deployment process, and there is no difference in other uses.

After deploying the process definition, we should want to look at some information about the process definition.

2.1.3 View process definition
/**
     * Query process definition
     */
    @Test
    public void findProcessDefinition(){
        List < Process Definition > List = processEngine. getRepository Service ()// Service related to process definition and deployment objects
                CreateProcessDefinitionQuery ()// Create a process-defined query
                / ** Specify query criteria, where criteria*/
//. DeploymentId (deploymentId)// Query using deployment object ID
// Process Definition Id (process Definition Id)// Use Process Definition ID Queries
// Process Definition Key // Query using process defined key
// Process Definition NameLike // Fuzzy Query with Process Definition NameLike // Name Definition

                * * * sort *
                OrderByProcess Definition Version (). ASC ()/// in ascending order of versions
// orderByProcess Definition Name (). desc ()/// in descending order by the name of the process definition

                / ** Return result set*/
                List (); // Returns a list of collections, encapsulating process definitions
// singleResult ();// Returns a unique result set
// count ();// Number of Result Sets Returned
// ListPage (first Result, maxResults);//Paging query
        if(list!=null && list.size()>0){
            for(ProcessDefinition pd:list){
                System.out.println ("Process Definition ID:"+pd.getId()); //Key+Version of Process Definition + Random Generation Number
                System.out.println ("name of process definition:"+pd.getName ();//corresponding to name attribute value in hello.bpmn file)
                System.out.println ("key:" +pd.getKey ()); //corresponds to the ID attribute value in the hello.bpmn file
                System.out.println ("Process Defined Version:"+pd.getVersion ();//When the key value of process definition is the same, version upgrade, default 1
                System. out. println ("resource name BPMN file:" +pd. getResourceName ()));
                System.out.println ("resource name png file:"+pd.getDiagram ResourceName ()));
                System. out. println ("Deployment Object ID:" +pd. getDeploymentId ()));
                System.out.println("*********************************************");
            }
        }
    }

Output results:

Summary of Query Process Definition:

  • Service related to process definition and deployment objects areRepositoryServiceAs you’ll see later, all about process definitions areRepositoryService
  • Through thiscreateProcessDefinitionQuery()Method to set some query parameters, such as through conditions, descending and ascending order.
2.1.4 Delete process definitions

By deleting the information with deployment ID 251.

/**
     * Delete process definition
     */
    @Test
    public void deleteProcessDefinition(){
        // Use deployment ID, complete deletion, specify deployment object ID 251 deletion
        String deploymentId = "2501";
        /**
         * Delete without cascade
         * Only processes that are not started can be deleted, and if the process is started, an exception will be thrown.
         */
//        processEngine.getRepositoryService()//
//                        .deleteDeployment(deploymentId);

        /**
         * Cascade deletion
         * Whether or not the process is started, it can be deleted
         */
        processEngine.getRepositoryService()//
                .deleteDeployment(deploymentId, true);
        System.out.println ("Delete successfully! "";
    }

Output results:

Go to the database and find outact_re_deploymentThe data in the file no longer exists.

  • Here or throughgetRepositoryService()Method gets the deployment definition object, and then specifies the ID to delete the information.
2.1.5 Getting Resources for Process Definition Documents

The main function here is to query pictures, which can be used for process display in the future. Let’s see how to look at it.

/**
     * View flow chart
     *
     * @throws IOException
     */
    @Test
    public void viewPic() throws IOException {
        / ** Put the generated image under the folder*/
        String deploymentId = "5001";
        // Get the name of the image resource
        List<String> list = processEngine.getRepositoryService()//
                .getDeploymentResourceNames(deploymentId);
        // Define the name of the image resource
        String resourceName = "";
        if (list != null && list.size() > 0) {
            for (String name : list) {
                if (name.indexOf(".png") >= 0) {
                    resourceName = name;
                }
            }
        }

        // Get the input stream of the picture
        InputStream in = processEngine.getRepositoryService()//
                .getResourceAsStream(deploymentId, resourceName);

        // Generate pictures into the directory of disk F
        File file = new File("F:/" + resourceName);

        // Write pictures of the input stream to disk
        FileUtils.copyInputStreamToFile(in, file);
    }

Under the F disk, you can find pictures.

2.1.6 Query the latest version of the process definition
/**
     * Query the latest version of the process definition
     */
    @Test
    public void findLastVersionProcessDefinition() {
        List<ProcessDefinition> list = processEngine.getRepositoryService()//
                .createProcessDefinitionQuery()//
                OrderByProcess Definition Version (). ASC ()// Use the version ascending sequence defined by the process
                .list();
        /**
         Characteristic of map set: When the key value of map set is the same, the value of the latter one will replace the value of the former one.
         */
        Map<String, ProcessDefinition> map = new LinkedHashMap<String, ProcessDefinition>();
        if (list != null && list.size() > 0) {
            for (ProcessDefinition pd : list) {
                map.put(pd.getKey(), pd);
            }
        }
        List<ProcessDefinition> pdList = new ArrayList<ProcessDefinition>(map.values());
        if (pdList != null && pdList.size() > 0) {
            for (ProcessDefinition pd : pdList) {
                System.out.println ("Process Definition ID:" +pd.getId ()); //Key+Version of Process Definition + Random Generation Number
                System.out.println ("name of process definition:" +pd.getName ();//corresponding to name attribute value in hello.bpmn file)
                System. out. println ("key:" + pd. getKey ();// corresponds to the ID attribute value in the hello. BPMN file)
                System.out.println ("Process Defined Version:" +pd.getVersion ()); //When the key value of process definition is the same, version upgrade, default 1
                System. out. println ("resource name BPMN file:" + pd. getResourceName ()));
                System.out.println ("resource name png file:" + pd.getDiagram ResourceName ()));
                System. out. println ("Deployment Object ID:" + pd. getDeploymentId ()));
                System.out.println("*********************************************************************************");
            }
        }
    }

Output results:

2.1.7 Summary of Process Definition

1. The deployment process definition uses the following tables of Activiti.

  • Act_re_deployment: Deployment object table
  • Act_re_procdef: Process Definition Table
  • Act_ge_bytearray: Resource file table
  • Act_ge_property: Primary key generation policy table

2. We find that the operations defined by the deployment process are all in theRepositoryServiceFor operations under this class, we only need to pass throughgetRepositoryService()With the object, all operations defined by the deployment process can be performed through the chain rules.

2.2 The Use of Complete Example of Workflow

This section, through a complete example, summarizes some of the basic knowledge mentioned earlier, so that we can better learn the knowledge points before and after, which is also a transitional chapter.

Go back toSection 1 Establishment of Flow ChartWe have already established the basic BPMN diagram, but we need to do a complete example, we still need to add some content, so that we can do a good job of such an example, let’s take the first section of the BPMN diagram.

First, we need to be clear:So far, we have only simply drawn out the process. For example, when we need to audit, we need to specific to a specific person to audit, so we need to set up specific personnel for each node to audit.

Be careful:The auditors who set up the nodes will be described in detail later. This is just a simple example. So, just need to be able to understand and do a good job here.

Setting up Auditor Steps

First, we need to select a node, such as the Tutor Approval node in the figure below.

Next, in the left toolbar, we will see many options, one for Assignee, in which we need to set the approver that our node needs to set.

Assignee formatting:You can use either English or Chinese directly. For example,sihaiMore complex settings will be discussed later.

The node settings below are exactly the same as those above.

The examining and approving staff of counselors are Ouyang Sihai.

Perfect, so that the task of the flow chart is completed, we can proceed to the test phase of this example.

1) Deployment process definition
Deployment process definition, as mentioned in the previous chapter, is handled in two ways, one is to load the BPMN file and PNG file, the other is to compress the two files into ZIP format compression file, and then load. Here we use the first approach.

/**
     * Deployment process definition (from classpath)
     */
    @Test
    public void deploymentProcessDefinition_classpath() {
        Deployment deployment = processEngine. getRepositoryService ()// Service related to process definition and deployment objects
                CreateDeployment ()// Create a deployment object
                Name ("hello")// Add the name of the deployment
                AddClasspath Resource ("bpmn/hello.bpmn")// loaded from classpath resources, only one file can be loaded at a time
                AddClasspath Resource ("bpmn/hello.png")// loaded from classpath resources, only one file can be loaded at a time
                Deploy (); // complete deployment
        Log. info ("Deployment ID:" + deployment. getId ()));
        Log. info ("Deployment name:"+ deployment. getName ()));
    }

Now that the process definition is in place, we need to start the process instance.

What has been done about this step can be seen in the previous section.

2) Start-up process example

/**
     * Start process instance
     */
    @Test
    public void startProcessInstance(){
        // 1. Process defined key, through which process instances are started
        String processDefinitionKey = "hello";
        // 2. Service related to executing process instances and executing objects
        // The startProcessInstanceByKey method can also set other parameters, such as process variables.
        ProcessInstance pi = processEngine.getRuntimeService()
                StartProcessInstanceByKey; // Start the process instance with the key defined by the process, which corresponds to the attribute value of the ID in the helloworld. BPMN file and starts with the key value, default is to start according to the latest version of the process definition.
        Log.info ("process instance ID:"+pi.getId();//process instance ID)
        Log.info ("process definition ID:" + PI. Getprocessdefinitionid()); // process definition ID
    }


Be careful:ProceDefinitionKey is the name of the BPMN file.

step
Get the runtimeService instance.
2 Start the process instance by the name of the BPMN file, process Definition Key.
3 After the process is started, the task of the process comes.Supervisor approvalNode.

Here is the query of personal tasks, we can query the task of the tutor approval node.

3) Query Personal Tasks

/**
     * Query the current person's personal tasks
     */
    @Test
    public void findPersonalTask(){
        String assignee = "sihai";
        List < Task > List = processEngine. getTaskService ()// Service related to task management being performed
                CreateTaskQuery ()// Create TaskQuery Objects
                / ** Query conditions (where part)*/
                TaskAssignee (assignee)//Assignee Personal Task Query, Assignee
//. TaskCandidate User (candidate User)// Transactor Query for Group Tasks
// Process Definition Id (process Definition Id)// Use Process Definition ID Queries
// Processing Instance Id (Processing Instance Id)// Query with Process Instance ID
//. ExecutionId (executionId)// Query using execution object ID
                * * * sort *
                OrderByTaskCreateTime (). ASC ()// Ascending order using creation time
                / ** Returns the result set*/
// singleResult ()// Returns a unique result set
// count ()// Number of result sets returned
// ListPage (first Result, maxResults);//Paging query
                List (); // Return List
        if(list!=null && list.size()>0){
            for(Task task:list){
                Log. info ("Task ID:"+task. getId ()));
                Log. info ("Task Name:"+task. getName ()));
                Log. info ("Task creation time:"+task. getCreateTime ()));
                Log. info ("task handler:"+task. getAssignee ()));
                Log. info ("process instance ID:"+task. getProcessInstanceId ()));
                Log. info ("Execution Object ID:"+task. getExecution Id ()));
                Log.info ("process definition ID:" + task. Getprocessdefinitionid());
                log.info("********************************************");
            }
        }
    }

adoptsihaiThis approver has inquired about the following information.

Analysis steps
First, the TaskService object is obtained by getTaskService method.
2 Create query object by createTaskQuery method.
Setting up auditors through taskAssignee method.
4 For the return of results, we can set sorting and other information by orderByTaskCreateTime (). ASC ().

Here we need to note that one of the important information queried is task ID. Next, we need to use this task ID to complete the task.

4) Personal tasks

/**
     * Complete my task
     */
    @Test
    public void completePersonalTask() {
        // Task ID, obtained from the previous query.
        String taskId = "7504";
        ProcessEngine. getTaskService ()// Service related to task management being performed
                .complete(taskId);
        Log. info ("Complete tasks: Task ID:" + taskId);
    }

Through the task ID of the previous step: 7504, complete the task.

step
First, get the TaskService object through the getTaskService method.
2 Call the complete method to complete the task given the specific task ID.

5) Query process status (determine which node the process goes to)
This interface is still very necessary. When we need to determine the state of our process in a specific business, or which node our process has reached, this interface saves us a lot of things to implement business.

/**
     * Query process status (determine which node the process goes to)
     */
    @Test
    public void isProcessActive() {
        String processInstanceId = "7501";
        ProcessInstance pi = processEngine. getRuntimeService ()// Represents the process instance and execution object being executed
                CreateProcessInstanceQuery ()// Create process instance queries
                Processing Instance Id (Processing Instance Id)// Query with Process Instance ID
                .singleResult();
        if (pi == null) {
            Log. info ("The process is over");
        } else {
            Log. info ("The process is not over");
            // Getting Task Status
            Log. info ("node id:" + pi. getActivityId ()));
        }
    }

Steps:
1 Gets the process instance ProcessInstance object.
2 Get instance Id (node id) by getActivityId method.

So I got it.Node IdWhat’s the effect?
In fact, with this ID, we can determine where the process is going. For example, the node ID of the output above is_4This _4 corresponds.ID of counselor approval nodeTherefore, we can interpret that the process has come to this node, and later need to play a role when the page shows the process status.

6) Query the history of process execution
By looking at the official API interface of activiti 5, the following query interface is found for viewing historical information.

Next, we test the following methods one by one through the examples above.

Historical Activity Instance Query Interface

/**
     * Historical Activity Query Interface
     */
    @Test
    public void findHistoryActivity() {
        String processInstanceId = "7501";
        List<HistoricActivityInstance> hais = processEngine.getHistoryService()//
                .createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .list();
        for (HistoricActivityInstance hai : hais) {
            Log. info ("activity id:" + hai. getActivityId ()
                    + "Approver:" + hai. getAssignee ()
                    + "Task id:" + hai. getTaskId ();"
            log.info("************************************");
        }
    }

Through this interface, we can not only find these information, but also other ways to get more information about them.Historical activitiesOther information.

Historical Process Instance Query Interface

/**
     * Examples of query history process
     */
    @Test
    public void findHistoryProcessInstance() {
        String processInstanceId = "7501";
        Historic Process Instance HPI = processEngine. getHistoryService ()// Service related to historical data (historical table)
                CreateHistoricProcessInstanceQuery ()// Create historical process instance queries
                Processing Instance Id (Processing Instance Id)// Query with Process Instance ID
                .orderByProcessInstanceStartTime().asc().singleResult();
        log.info(hpi.getId() + "    " + hpi.getProcessDefinitionId() + "    " + hpi.getStartTime() + "    "
                + hpi.getEndTime() + "     " + hpi.getDurationInMillis());
    }

This interface can query aboutExamples of historical processesAll information.

Historical Task Instance Query Interface

/**
     * Query History Task
     */
    @Test
    public void findHistoryTask() {
        String processInstanceId = "7501";
        List < Historic Task Instance > List = processEngine. getHistoryService ()// Service related to historical data (historical table)
                CreateHistoricTaskInstanceQuery ()// Create historical task instance queries
                .processInstanceId(processInstanceId)//
                .orderByHistoricTaskInstanceStartTime().asc().list();
        if (list != null && list.size() > 0) {
            for (HistoricTaskInstance hti : list) {
                Log. info (" n Task Id:" + hti. getId ()+ "Task Name:" + hti. getName ()+ "Process Instance Id:" + hti. getProcessInstanceId ()+"\ n Start Time:"
                        + hti. getStartTime ()+ "End Time:" + hti. getEndTime ()+ "Duration:" + hti. getDuration InMillis ();"
            }
        }
    }

This query interface can be queried toHistorical Task Information

Historical Process Variable Query Interface

/**
     * Query history process variables
     */
    @Test
    public void findHistoryProcessVariables() {
        String processInstanceId = "7501";
        List<HistoricVariableInstance> list = processEngine.getHistoryService()//
                CreateHistoricVariableInstanceQuery ()// Create a historical process variable query object
                .processInstanceId(processInstanceId)//
                .list();
        if (list != null && list.size() > 0) {
            for (HistoricVariableInstance hvi : list) {
                log.info("\n" + hvi.getId() + "   " + hvi.getProcessInstanceId() + "\n" + hvi.getVariableName()
                        + "   " + hvi.getVariableTypeName() + "    " + hvi.getValue());
            }
        }
    }

There are no process variables set in this instance, so no historical information can be queried here.

This interface is mainly aboutHistorical process variablesSome information about the settings.

History Local Interface Query Interface

/**
     * query historical data by executing sql, because the bottom level of activiti is database tables.
     */
    @Test
    public void findHistoryByNative() {
        HistoricProcessInstance hpi = processEngine.getHistoryService()
                .createNativeHistoricProcessInstanceQuery()
                SQL ("sql statements to query underlying database tables")
                .singleResult();
        log.info("\n" + hpi.getId() + "    " + hpi.getProcessDefinitionId() + "    " + hpi.getStartTime()
                + "\n" + hpi.getEndTime() + "     " + hpi.getDurationInMillis());
    }

This interface provides direct accessSQL statementTo query historical information, we just need tosql()The method can query data by writing native SQL statements.

Writing here, I think we should introduce the APIs of Activiti workflow through such a complete example, and this section will say goodbye to you. Looking back at the API interface at the beginning of this article, this is a summary of this section.

There are some mistakes in this article. You are welcome to correct them. If you like Wechat reading, you can also pay attention to me.Wechat Public NumberLearn Java wellAccess to high-quality learning resources.

Recommended Today

Install SQL Server tutorial under Ubuntu

Microsoft has just announced a public preview of the next generation of SQL Server, and Canonical has officially announced that this preview version is available for Ubuntu. Whether deployed in-house or in the cloud, SQL Server on Ubuntu offers developers and organizations more freedom of choice. The development languages and data types allowed by SQL […]