Project introduction workflow engine scheme description

1. Workflow engine selection

1. Flowable

Flowable is based on the version derived from activiti6. The latest version of flowable is v6.6.0. The development team was split from activiti, fixed a number of activiti6 bugs, and developed DMN support, BPEL support, etc. on its basis. Compared with the open source version, its commercial version will be more powerful. Taking the flowable6.4.1 version as a watershed, vigorously develop its commercial version products, * the open source version is not maintained in time, and some functions are no longer released in the open source version, such as form generator (form engine), historical data synchronization to other data sources, ES, etc. * . Flowable is a lightweight business process engine written in Java and open sourced using the Apache V2 license. In October 2016, the main developer of the Activiti workflow engine left Alfresco and started the Flowable open source project based on the Activiti fork. The first Flowable release based on Activiti v6 beta4 is 6.0. The Flowable project includes modules such as BPMN (Business Process Model and Notation) engine, CMMN (Case Management Model and Notation) engine, DMN (Decision Model and Notation) engine, and Form Engine (Form Engine). Official website: https://flowable.com/open-source/

2. Camunda

Camunda is based on activiti5, so it retains PVM. The latest version, Camunda7.15, maintains the rhythm of releasing 2 small versions every year. The development team is also split from activiti. The development trajectory is similar to flowable, and a commercial version is also provided, but For general enterprise applications, the open source version is also sufficient. For details, see: https://blog.csdn.net/wxz258/article/details/10904373 . Official website: https://docs.camunda.org/manual/7.15/ . The author strongly recommends the camunda process engine, and uses camunda in the cloud process low-code platform, with stable functions and performance.
Reasons to choose camunda:
(1) Verify that the Camunda BPMN engine has better performance and stability through stress testing. For details, see: https://blog.csdn.net/wxz258/article/details/109030329
(2) The functions are relatively complete. In addition to BPMN, Camunda also supports CMMN (case management) and DMN (decision automation) in enterprise and community versions. Camunda not only comes with an engine, but also very powerful tools for modeling, task management, operations monitoring and user management, all of which are open source. For details, see: https://blog.csdn.net/wxz258/article/details/109121092

3. Osworkflow

Osworkflow is a lightweight process engine, based on the state machine mechanism, with few database tables. The workflow components provided by Osworkflow are: steps, conditions, loops, splits, merge ( joins), etc. *but does not support counter-signing, jumping, returning, adding signatures and other operations* , you need to expand and develop by yourself, which is difficult. If the process is relatively simple, osworkflow is a very good choice. The author gave a large-scale The OA system developed by the state-owned enterprise group is based on Osworkflow, which is still running stably and has high performance. Official website: http://www.opensymphony.com/osworkflow/

4. JBPM

JBPM is developed by JBoss, the current highest version is JPBM7, but since JBPM5 is not the same product as before, the code base of JBPM5 is not JBPM4, but starts from Drools Flow, *based on Drools Flow technology in the domestic market Very few, all versions after jBPM5 are not recommended* . jBPM4 was born relatively early. Later, after JBPM4 creator Tom Baeyens left JBoss, he joined Alfresco and soon launched a new jBPM4 -based open source workflow system Activiti. Hibernate as a data persistence ORM is no longer a mainstream technology* . When the author developed the BPM platform of a group in 2012, he chose JBPM 4.4, which is also the last version of the 4 series. After a lot of expansion and development, the process requirements with Chinese characteristics were realized. Now the time node chooses the process engine, JBPM is not the best choice. Official website: https://www.jbpm.org/

5. Activiti

Activiti is developed by Alfresco software, and the current highest version is activiti 7. The version of activiti is more complicated. There are several mainstream versions of activiti5, activiti6, and activiti7. When selecting models, it is confusing. It is necessary to understand the development history of these versions of activiti. The core leader of activiti5 and activiti6 is Tijs Rademakers. Due to internal differences in the team, Tijs Rademakers left the team in 2017 and created the later *flowable* , activiti6 and activiti5 code has been handed over to Salaboy team, *activiti6 and activiti5 code official Maintenance has been suspended * , * The Salaboy team is currently developing the activiti7 framework, and the activiti7 kernel still uses activiti6. It does not inject more new features into the engine, but only encapsulates some applications in the upper layer outside activiti. The conclusion is that activiti chooses * carefully . Official website: https://www.activiti.org/

2. Construction of camunda workflow platform

Springboot2.5.4+jdk1.8+camunda7.16.0+mysql5.7

1. Create a springboot project and modify the pom.xml file

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>loan-approval-spring-boot</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <camunda.spring-boot.version>7.16.0</camunda.spring-boot.version>
        <spring-boot.version>2.5.4</spring-boot.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <mysql.version>8.0.19</mysql.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- 流程引擎 -->
<!--        <dependency>-->
<!--            <groupId>org.camunda.bpm.springboot</groupId>-->
<!--            <artifactId>camunda-bpm-spring-boot-starter</artifactId>-->
<!--            <version>${camunda.spring-boot.version}</version>-->
<!--        </dependency>-->
        <!-- Rest服务接口,会自动加载camunda-bpm-spring-boot-starter,所以上面的引入可以不要 -->
        <dependency>
            <groupId>org.camunda.bpm.springboot</groupId>
            <artifactId>camunda-bpm-spring-boot-starter-rest</artifactId>
            <version>${camunda.spring-boot.version}</version>
        </dependency>
        <!-- web界面模块,会自动加载camunda-bpm-spring-boot-starter,所以上面的引入可以不要 -->
        <!-- web界面模块不必需,如果只是提供引擎服务可以不引入 -->
        <dependency>
            <groupId>org.camunda.bpm.springboot</groupId>
            <artifactId>camunda-bpm-spring-boot-starter-webapp</artifactId>
            <version>${camunda.spring-boot.version}</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.5</version>
        </dependency>

        <dependency>
            <groupId>org.camunda.bpm</groupId>
            <artifactId>camunda-engine-plugin-spin</artifactId>
            <version>${camunda.spring-boot.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.camunda.spin/camunda-spin-dataformat-all -->
        <dependency>
            <groupId>org.camunda.spin</groupId>
            <artifactId>camunda-spin-dataformat-all</artifactId>
            <version>1.13.0</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <layout>ZIP</layout>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

2. Create or modify the application.yaml file

 server:
  port: 8080

camunda:
  bpm:
    database:
      type: mysql
    admin-user:
      id: admin
      password: admin
      first-name: zhou
      last-name: lei
    filter:
      create: All tasks
    #禁止自动部署resources下面的bpmn文件
    auto-deployment-enabled: false
    #禁止index跳转到Camunda自带的管理界面,默认true
#    webapp:
#      ndex-redirect-enabled: false

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/camunda?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
    username: root
    password: root

3. Create a project startup class

 package com.sxvbd;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author ZL
 * @version 1.0
 * @date 2022/1/18 16:59
 */
@SpringBootApplication
public class WebappExampleProcessApplication {
    public static void main(String... args) {
        SpringApplication.run(WebappExampleProcessApplication.class, args);
    }
}

4. Project access path

4.1 web module access path

http://localhost:8080

image-20220120171611854

4.2 RestAPI request path

http://localhost:8080/engine-rest/ interface path

For example: http://localhost:8080/engine-rest/engine

image-20220120171949371

3. Construction and use of camunda modeler

3.1. Installation

Open the download address https://camunda.com/download/modeler/

img

Download the version corresponding to the system and unzip it to any location

img

Execute camunda-modeler.exe (Windows), camunda-modeler.app (Mac), or camunda-modeler.sh (Linux) to start Camunda Modeler

img

3.2 Sinicization

1. First, the installation directory of Camunda Modeler, camunda-modeler-4.12.0-win-x64\resources\plugins

2. git clone https://gitee.com/skay463/camunda-modeler-i18n-plugin.git

3. npm install

4. npm run build

5. Select Simplified Chinese on the right side of the toolbar, restart Camunda Modeler to take effect

3.3 Editing Process

Create a new BPMN process

Click File > New File > BPMN Diagram to create a new process design file

img

Edit a simple process

img

  1. Double-click the Start node to edit the tab and enter "Payment Request"
Labels can wrap, need to use Shift + Enter
  1. Click on the box shown on the right to add a new activity

You can see a new activity appear on the canvas, double click and name it "Swipe to Pay"

  1. Click the wrench to the right of the credit card node to modify the activity type, here we modify it to Service Task (service type)

img

  1. Add an end node and name it "Payment Received"

img

Configure the "Pay by Card" node

Service types have many methods to execute, this time we use the "external" task pattern

  1. Click the "Get Credit Card" node, and in the right panel, modify the Implementation to External and the Topic to charge-card

img

Configure process parameters

  1. Click on the blank space of the canvas, the panel on the right will display the parameters of the current process itself

Here we modify the id to payment-retrieval , and the id is the identifier that distinguishes the process

Then modify the Name to "Payment Process"

Finally, make sure that Executable is checked, and the process can only be executed if Executable is checked.

img

  1. Click File > Save File As.. or directly click the Save button in the toolbar to save the process to a location you like, named payment.bpmn
This is the end of the first part. If you want to directly get the progress so far, you can use the following command
git checkout -f Step-1

Deploy a process using Camunda Modeler

Click the deploy button in the toolbar to deploy the current process to the process engine, click the deploy button, enter Deployment Name as "Payment", enter the REST Endpoint as http://localhost:8080/engine-rest (camunda platform path), then click Deploy in the lower right corner

img

If you receive a success prompt, the deployment is successful

img

4. Process deployment and task initiation

step:

1. Make a process file according to the editing process steps in Chapter 3, and transfer the generated bpmn file to the camunda platform

2. Create a process instance and start the process

3. The transaction handler handles the task of the current node.

4. Process progress query

5. Historical information query

Five, camunda-rest API description

Response Codes
Code Media type Description
200 application/json Request successful.
400 application/json In case one of the bpmn resources cannot be parsed. See the Introduction for the error response format.
5.1. Deployment
5.1.1 Deploy the bpmn file

Method: POST /deployment/create

parameter:

parameter type illustrate
upload File bpmn process file

Response result:

Name Type Description
links List Link to the newly created deployment with method , href and rel .
id String The id of the deployment.
name String The name of the deployment.
source String The source of the deployment.
tenantId String The tenant id of the deployment.
deploymentTime String The time when the deployment was created.
deployedProcessDefinitions Object A JSON Object containing a property for each of the process definitions, which are successfully deployed with that deployment. The key is the process definition id, the value is a JSON Object corresponding to the process definition, which is defined in the Process Definition resource .
deployedCaseDefinitions Object A JSON Object containing a property for each of the case definitions, which are successfully deployed with that deployment. The key is the case definition id, the value is a JSON Object corresponding to the case definition, which is defined in the Case Definition resource .
deployedDecisionDefinitions Object A JSON Object containing a property for each of the decision definitions, which are successfully deployed with that deployment. The key is the decision definition id, the value is a JSON Object corresponding to the decision definition, which is defined in the Decision Definition resource .
deployedDecisionRequirementsDefinitions Object A JSON Object containing a property for each of the decision requirements definitions, which are successfully deployed with that deployment. The key is the decision requirements definition id, the value is a JSON Object corresponding to the decision requirements definition, which is defined in the Decision Requirements Definition resource .

Test case: POST /deployment/create

success

 {
    "links": [
        {
            "method": "GET",
            "href": "http://localhost:38080/rest-test/deployment/aDeploymentId",
            "rel": "self"
        }
    ],
    "id": "aDeploymentId",
    "name": "aName",
    "source": "process application",
    "deploymentTime": "2013-01-23T13:59:43.000+0200",
    "tenantId": null,
    "deployedProcessDefinitions": {
        "aProcDefId": {
            "id": "aProcDefId",
            "key": "aKey",
            "category": "aCategory",
            "description": "aDescription",
            "name": "aName",
            "version": 42,
            "resource": "aResourceName",
            "deploymentId": "aDeploymentId",
            "diagram": "aResourceName.png",
            "suspended": true,
            "tenantId": null,
            "versionTag": null
        }
    },
    "deployedCaseDefinitions": null,
    "deployedDecisionDefinitions": null,
    "deployedDecisionRequirementsDefinitions": null
}

fail

 {
    "type": "ParseException",
    "message": "ENGINE-09005 Could not parse BPMN process. Errors: Exclusive Gateway 'ExclusiveGateway_1' has outgoing sequence flow 'SequenceFlow_0' without condition which is not the default flow.",
    "details": {
        "invoice.bpmn": {
            "errors": [
                {
                    "message": "Exclusive Gateway 'ExclusiveGateway_1' has outgoing sequence flow 'SequenceFlow_0' without condition which is not the default flow.",
                    "line": 77,
                    "column": 15,
                    "mainBpmnElementId": "ExclusiveGateway_1",
                    "bpmnElementIds": [
                        "ExclusiveGateway_1",
                        "SequenceFlow_0"
                    ]
                }
            ],
            "warnings": [
                {
                    "message": "It is not recommended to use a cancelling boundary timer event with a time cycle.",
                    "line": 87,
                    "column": 20,
                    "mainBpmnElementId": "BoundaryEvent_1",
                    "bpmnElementIds": [
                        "BoundaryEvent_1"
                    ]
                }
            ]
        }
    }
5.1.2 Deployment Information List Query

Method: GET /deployment

parameter:

Name Description
id Filter by deployment id.
name Filter by the deployment name. Exact match.
nameLike Filter by the deployment name that the parameter is a substring of. The parameter can include the wildcard % to express like-strategy such as: starts with ( % name), ends with ( name % ) or contains ( % name % ).
source Filter by the deployment source.
withoutSource Filter by the deployment source whereby source is equal to null .
tenantIdIn Filter by a comma-separated list of tenant ids. A deployment must have one of the given tenant ids.
withoutTenantId Only include deployments which belong to no tenant. Value may only be true , as false is the default behavior.
includeDeploymentsWithoutTenantId Include deployments which belong to no tenant. Can be used in combination with tenantIdIn . Value may only be true , as false is the default behavior
after Restricts to all deployments after the given date. By default*, the date must have the format yyyy-MM-dd'T'HH:mm:ss.SSSZ , eg, 2013-01-23T14:42:45.000+0200 .
before Restricts to all deployments before the given date. By default*, the date must have the format yyyy-MM-dd'T'HH:mm:ss.SSSZ , eg, 2013-01-23T14:42:45.000+0200 .
sortBy Results A at The lexicographically by the Sort GIVEN Criterion.! Valid values are id , name , deploymentTime and tenantId . Must BE Used in conjunction with the sortOrder parameter.
sortOrder Sort the results in a given order. Values may be asc for ascending order or desc for descending order. Must be used in conjunction with the sortBy parameter
firstResult Pagination of results. Specifies the index of the first result to return.
maxResults Pagination of results. Specifies the maximum number of results to return. Will return less results if there are no more results left.

Response result:

ame Type Description
id String The id of the deployment.
name String The name of the deployment.
source String The source of the deployment.
tenantId String The tenant id of the deployment.
deploymentTime Date The date and time of the deployment.

Test case: GET /deployment?name=deploymentName

success

 [
  {
    "id": "someId",
    "name": "deploymentName",
    "source": "process application",
    "tenantId": null,
    "deploymentTime": "2013-04-23T13:42:43.000+0200"
  }
]
5.1.3 Deployment Information List Count Query

Method: GET /deployment

parameter:

Name Description
id Filter by deployment id.
name Filter by the deployment name. Exact match.
nameLike Filter by the deployment name that the parameter is a substring of. The parameter can include the wildcard % to express like-strategy such as: starts with ( % name), ends with ( name % ) or contains ( % name % ).
source Filter by the deployment source.
withoutSource Filter by the deployment source whereby source is equal to null .
tenantIdIn Filter by a comma-separated list of tenant ids. A deployment must have one of the given tenant ids.
withoutTenantId Only include deployments which belong to no tenant. Value may only be true , as false is the default behavior.
includeDeploymentsWithoutTenantId Include deployments which belong to no tenant. Can be used in combination with tenantIdIn . Value may only be true , as false is the default behavior.
after Restricts to all deployments after the given date. By default*, the date must have the format yyyy-MM-dd'T'HH:mm:ss.SSSZ , eg, 2013-01-23T14:42:45.000+0200 .
before Restricts to all deployments before the given date. By default*, the date must have the format yyyy-MM-dd'T'HH:mm:ss.SSSZ , eg, 2013-01-23T14:42:45.000+0200 .
sortBy Results A at The lexicographically by the Sort GIVEN Criterion.! Valid values are id , name , deploymentTime and tenantId . Must BE Used in conjunction with the sortOrder parameter.
sortOrder Sort the results in a given order. Values may be asc for ascending order or desc for descending order. Must be used in conjunction with the sortBy parameter
firstResult Pagination of results. Specifies the index of the first result to return.
maxResults Pagination of results. Specifies the maximum number of results to return. Will return less results if there are no more results left.

Response result:

ame Type Description
id String The id of the deployment.
name String The name of the deployment.
source String The source of the deployment.
tenantId String The tenant id of the deployment.
deploymentTime Date The date and time of the deployment.

Test case: GET /deployment?name=deploymentName

success

 [
  {
    "id": "someId",
    "name": "deploymentName",
    "source": "process application",
    "tenantId": null,
    "deploymentTime": "2013-04-23T13:42:43.000+0200"
  }
]
5.1.4 Delete deployment information
5.1.5 Redeploy redeploy
5.1.6 Query deployment information based on ID
5.1.7 Querying the Deployment Information Resource List
5.1.8 Query deployment resource information based on ID
5.1.9 Query deployment resource information based on ID (binary)
5.2. Process design
 const modeling = this.bpmnModeler.get('modeling');
          const elementRegistry = this.bpmnModeler.get('elementRegistry');
          let todo = data.filter(item => item.state == 1) // 已完成
          let notStart = data.filter(item => item.state == 0) // 未开始
          todo.forEach(item =>{
            let node = elementRegistry.filter(item_ => item_.id == item.key)
            modeling.setColor(node[0], {
              stroke: 'green',
            });
          })
          notStart.forEach(item =>{
            let node = elementRegistry.filter(item_ => item_.id == item.key)
            modeling.setColor(node[0], {
              stroke: 'red',
            });
          })

image.png

5.3. Task initiation processing

image.png

5.6. Custom events
 entryNode.appendChild(html)
        // TODO JASON
        if (entryNode.querySelector('input')) {
          if (entry.id === 'formKey') {
            entryNode.querySelector('input').addEventListener('click', function() {
              console.log(entry)
              //回显
              let val={};val[entry.id] = "";
              self.applyChanges(entry, val, entryNode)
              // self._modeling.updateProperties(self._current.element,{'flowable:candidateUsers': 'userId_123'})
              // console.log(entry)
              v.$dialogFormKey.show(self)
            })
          }

          // if (entry.id === 'candidateUsers' || entry.id === 'candidateStarterUsers') {
            if (entry.id === 'camunda:Approving' || entry.id === 'candidateStarterUsers') {
            entryNode.querySelector('input').addEventListener('click', function() {
              //回显
              let val={};val[entry.id] = "";
              self.applyChanges(entry, val, entryNode)
              // self._modeling.updateProperties(self._current.element,{'flowable:candidateUsers': 'userId_123'})
              // console.log(entry)
              v.$dialog.show(self)
            })
          }
        }
5.5. Permission docking
5.6. Historical process tracking
5.7. Third-party docking

西安小哥
1.3k 声望88 粉丝

thinking、doing、do better、do much better than today。exchange 、sharing、improve as quickly as possible。