关于javascript:常见的工作流方案对比

10次阅读

共计 15613 个字符,预计需要花费 40 分钟才能阅读完成。

我的项目引入工作流引擎计划阐明

一、工作流引擎选型

1、flowable

flowable 基于 activiti6 衍生进去的版本,flowable 目前最新版本是 v6.6.0,开发团队是从 activiti 中决裂进去的,修复了一众 activiti6 的 bug,并在其根底上研发了 DMN 反对,BPEL 反对等等,绝对开源版,其商业版的性能会更弱小。以 flowable6.4.1 版本为分水岭,大力发展其商业版产品,* 开源版本保护不及时,局部性能曾经不再开源版公布,比方表单生成器(表单引擎)、历史数据同步至其余数据源、ES 等 *。Flowable 是一个应用 Java 编写的轻量级业务流程引擎,应用 Apache V2 license 协定开源。2016 年 10 月,Activiti 工作流引擎的次要开发者来到 Alfresco 公司并在 Activiti 分支根底上开启了 Flowable 开源我的项目。基于 Activiti v6 beta4 公布的第一个 Flowable release 版本为 6.0。Flowable 我的项目中包含 BPMN(Business Process Model and Notation)引擎、CMMN(Case Management Model and Notation)引擎、DMN(Decision Model and Notation)引擎、表单引擎(Form Engine)等模块。官方网站:https://flowable.com/open-sou…

2、Camunda

Camunda 基于 activiti5,所以其保留了 PVM,最新版本 Camunda7.15,放弃每年公布 2 个小版本的节奏,开发团队也是从 activiti 中决裂进去的,倒退轨迹与 flowable 类似,同时也提供了商业版,不过对于个别企业应用,开源版本也足够了,具体见:https://blog.csdn.net/wxz258/…。官方网站:https://docs.camunda.org/manu…。笔者强烈推荐 camunda 流程引擎,并在云程低代码平台中应用了 camunda, 性能和性能体现稳固。
抉择 camunda 的理由:
(1)通过压力测试验证 Camunda BPMN 引擎性能和稳定性更好。具体见:https://blog.csdn.net/wxz258/…
(2)性能比较完善,除了 BPMN,Camunda 还反对企业和社区版本中的 CMMN(案例治理)和 DMN(决策自动化)。Camunda 不仅带有引擎,还带有十分弱小的工具,用于建模,工作治理,操作监控和用户治理,所有这些都是开源的。具体见:https://blog.csdn.net/wxz258/…

3、Osworkflow

Osworkflow 是一个轻量化的流程引擎,基于状态机机制,数据库表很少,Osworkflow 提供的工作流形成元素有:步骤(step)、条件(conditions)、循环(loops)、分支(spilts)、合并(joins)等,* 但不反对会签、跳转、退回、加签等这些操作 *,须要本人扩大开发,有肯定难度,如果流程比较简单,osworkflow 是很号的抉择,笔者在 2008 年给某大型国企团体开发 OA 零碎,就是基于 Osworkflow,至今仍稳固运行,性能也很高。官方网站:http://www.opensymphony.com/o…

4、JBPM

JBPM 由 JBoss 公司开发,目前最高版本 JPBM7,不过从 JBPM5 开始曾经跟之前不是同一个产品了,JBPM5 的代码根底不是 JBPM4,而是从 Drools Flow 从新开始,* 基于 Drools Flow 技术在国内市场上用的很少,所有不倡议抉择 jBPM5 当前版本 *,jBPM4 诞生的比拟早,起初 JBPM4 创建者 Tom Baeyens 来到 JBoss 后,退出 Alfresco 后很快推出了新的基于 jBPM4 的开源工作流零碎 Activiti, * 另外 JBPM 以 hibernate 作为数据长久化 ORM 也已不是支流技术 *。笔者在 2012 年开发某团体 BPM 平台时,抉择的就是 JBPM4.4 版本,也是 4 系列的最初一个版本,进行了大量的扩大开发,才实现中国特色的流程需要。当初工夫节点抉择流程引擎,JBPM 不是最佳抉择。官方网站:https://www.jbpm.org/

5、Activiti

activiti 由 Alfresco 软件开发,目前最高版本 activiti 7。activiti 的版本比较复杂,有 activiti5、activiti6、activiti7 几个支流版本,选型时让人昏头昏脑,有必要先理解一下 activiti 这几个版本的倒退历史。activiti5 和 activiti6 的外围 leader 是 Tijs Rademakers,因为团队外部一致,在 2017 年时 Tijs Rademakers 来到团队,创立了起初的*flowable*, activiti6 以及 activiti5 代码曾经交接给了 Salaboy 团队, *activiti6 以及 activiti5 的代码官网曾经暂停保护了 *, *Salaboy 团队目前在开发 activiti7 框架,activiti7 内核应用的还是 activiti6,并没有为引擎注入更多的新个性,只是在 activiti 之外的下层封装了一些利用。论断是 activiti 审慎抉择 *。官方网站:https://www.activiti.org/

二、camunda 工作流平台搭建

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

1、创立 springboot 我的项目,批改 pom.xml 文件

<?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、创立或批改 application.yaml 文件

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、创立我的项目启动类

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、我的项目拜访门路

4.1 web 模块拜访门路

http://localhost:8080

4.2 RestAPI 申请门路

http://localhost:8080/engine-… 接口门路

例如:http://localhost:8080/engine-…

三、camunda modeler 搭建及应用

3.1、装置

关上下载地址 https://camunda.com/download/modeler/

下载对应零碎的版本,并解压到任意地位

执行 camunda-modeler.exe (Windows), camunda-modeler.app (Mac), or camunda-modeler.sh(Linux),即可启动Camunda Modeler

3.2 汉化

1、首先 Camunda Modeler 的装置目录,camunda-modeler-4.12.0-win-x64\resources\plugins

2、git clone https://gitee.com/skay463/cam…

3、npm install

4、npm run build

5、在工具栏右侧抉择简体中文,重启 Camunda Modeler 失效

3.3 编辑流程

新建 BPMN 流程

点击 File > New File > BPMN Diagram,创立一个新的流程设计文件

编辑一个简略的流程

  1. 双击 开始 节点编辑标签,输出“付款申请”

标签能够换行,须要应用 Shift + 回车

  1. 点击右面显示的方框,增加一个新的流动

能够看到一个新的流动显示到画布上,双击将它命名为“刷卡付款”

  1. 点击 取信用卡 节点右面的扳手能够批改流动类型,这里咱们批改为Service Task(服务类型)

  1. 新增一个 完结 节点,并命名为“收到付款”

配置“刷卡付款”节点

服务类型有很多执行的办法,这次咱们应用“external(内部)”工作模式

  1. 点击“取信用卡”节点,在右侧的面板中批改 Implementation(实现)为 External,批改 Topic 为 charge-card

配置流程参数

  1. 点击画布的空白处,右侧的面板会显示以后流程自身的参数

这里咱们批改 id 为payment-retrieval,id 是辨别流程的标识

而后批改 Name 为“付款流程”

最初确保 Executable 是勾选的,只有 Executable 被勾选,流程能力执行

  1. 点击 File > Save File As.. 或者间接点击工具栏中的保留按钮,将流程保留到你喜爱的地位,命名为 payment.bpmn

到此第一局部完结,如果想间接获取到当初为止的进度,能够应用如下命令
git checkout -f Step-1

应用 Camunda Modeler 部署流程

点击工具栏中的部署按钮能够将以后流程部署到流程引擎,点击部署按钮,输出Deployment Name 为“Payment”,输出下方REST Endpointhttp://localhost:8080/engine-rest (camunda 平台门路),而后点击右下角 Deploy 部署

如果收到胜利提醒,示意部署胜利

四、流程部署及工作启动

步骤:

1、按第三章编辑流程步骤制作流程文件,将生成的 bpmn 文件到 camunda 平台

2、创立流程实例并启动流程

3、事务处理人解决以后节点工作。

4、流程进度查问

5、历史信息查问

五、camunda-rest API 阐明

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、部署
5.1.1 部署 bpmn 文件

办法:POST /deployment/create

参数:

参数 类型 阐明
upload File bpmn 流程文件

响应后果:

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.

测试用例:POST /deployment/create

胜利

{
    "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
}

失败

{
    "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 部署信息 List 查问

办法:GET /deployment

参数:

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, e.g., 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, e.g., 2013-01-23T14:42:45.000+0200.
sortBy Sort the results lexicographically by a given criterion. Valid values are id, name, deploymentTime and tenantId. Must be used in conjunction with the sortOrderparameter.
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.

响应后果:

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.

测试用例:GET /deployment?name=deploymentName

胜利

[
  {
    "id": "someId",
    "name": "deploymentName",
    "source": "process application",
    "tenantId": null,
    "deploymentTime": "2013-04-23T13:42:43.000+0200"
  }
]
5.1.3 部署信息 List count 查问

办法:GET /deployment

参数:

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, e.g., 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, e.g., 2013-01-23T14:42:45.000+0200.
sortBy Sort the results lexicographically by a given criterion. Valid values are id, name, deploymentTime and tenantId. Must be used in conjunction with the sortOrderparameter.
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.

响应后果:

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.

测试用例:GET /deployment?name=deploymentName

胜利

[
  {
    "id": "someId",
    "name": "deploymentName",
    "source": "process application",
    "tenantId": null,
    "deploymentTime": "2013-04-23T13:42:43.000+0200"
  }
]
5.1.4 删除部署信息
5.1.5 重新部署 redeploy
5.1.6 依据 ID 查问部署信息
5.1.7 部署信息资源列表查问
5.1.8 依据 ID 查问部署资源信息
5.1.9 依据 ID 查问部署资源信息(binary)
5.2、流程设计
     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、工作发动解决

5.6、自定义事件
    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、权限对接
5.6、历史流程跟踪
5.7、第三方对接
正文完
 0