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
4.2 RestAPI request path
http://localhost:8080/engine-rest/ interface path
For example: http://localhost:8080/engine-rest/engine
3. Construction and use of camunda modeler
3.1. Installation
Open the download address https://camunda.com/download/modeler/
Download the version corresponding to the system and unzip it to any location
Execute camunda-modeler.exe
(Windows), camunda-modeler.app
(Mac), or camunda-modeler.sh
(Linux) to start Camunda Modeler
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
Edit a simple process
- Double-click the Start node to edit the tab and enter "Payment Request"
Labels can wrap, need to use Shift + Enter
- 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"
- 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)
- Add an end node and name it "Payment Received"
Configure the "Pay by Card" node
Service types have many methods to execute, this time we use the "external" task pattern
- Click the "Get Credit Card" node, and in the right panel, modify the Implementation to
External
and the Topic tocharge-card
Configure process parameters
- 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.
- 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
If you receive a success prompt, the deployment is successful
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',
});
})
5.3. Task initiation processing
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)
})
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。