Camunda

曹化金發表於2024-04-19

Camunda

簡介

Camunda是一個工作流引擎,執行Bpmn2.0標準。與它同型別的流程引擎有jbpm、activiti、flowable,但與Camunda相比,Camunda效能和穩定性都表現較好,更輕量級。

Camunda包括:流程設計器(Modeler)、流程引擎(Engine)、API介面(REST/Java API)、任務列表(TaskList)、流程管理控制檯(Cockpit)、系統管理工具(Admin)。

詳細介紹參考部落格:https://blog.csdn.net/qq_41468822/article/details/135343266

示例demo下載: https://github.com/caohuajin/spring-boot-camunda.git

架構圖

camunda整體架構如下圖所示,主要包括兩部分:流程建模工具(modeler)和流程引擎(Engine)。業務分析與開發人員(Business Analyst/Developer)透過modeler設計業務流程,將結果存入repository中,業務分析與開發人員一般不需要懂開發。流程引擎則負責流程例項的建立、執行、維護和管理,並透過REST/Java API向使用者提供服務,基於這些API,流程使用者(End User)透過Tasklist工具參與流程的執行,運維人員(operator)透過Cockpit工具檢視、管理和維護流程的狀態,管理人員(administrator)透過Admin工具進行使用者的許可權管理。當然,我們也可以基於REST/Java API開發自己的相應工具。透過下面的例項展示可知,camunda提供的tasklist、cockpit、admin工具非常有可能不是很符合你們團隊的需求,需要自己開發部分功能。

BPMN概念

BPMN(Business Process Model and Notation)是一種用於描述業務流程的圖形化標準。它提供了一種統一的方法來表示業務過程,使得業務分析師、業務使用者和技術人員之間可以更好地溝通和理解業務流程。

以下是 BPMN 中的一些主要概念:

  1. 流程(Process):流程是指業務中的一系列活動或任務,以實現特定的業務目標。在 BPMN 中,流程可以被建模成各種形式,包括業務流程、子流程和協作流程等。
  2. 活動(Activity):活動是流程中的基本單元,代表執行的任務或操作。活動可以是一個簡單的任務,也可以是一個複雜的子流程。
  3. 事件(Event):事件是流程中的狀態變化,可以觸發或影響流程的執行。例如,開始事件表示流程的開始,結束事件表示流程的結束,中間事件表示在流程執行過程中發生的中間狀態。
  4. 閘道器(Gateway):閘道器用於控制流程的分支、合併和路由。根據條件,閘道器可以決定流程的執行路徑。
  5. 序列流(Sequence Flow):序列流表示流程中活動之間的順序關係,指示流程執行的方向。
  6. 資料物件(Data Object):資料物件表示流程中使用的資料或資訊。它可以是輸入、輸出或中間資料,用於支援流程的執行。
  7. 泳道(Swimlane):泳道用於組織流程中的活動,可以按角色、部門或其他組織方式進行劃分。泳道提供了對流程執行者的視覺化描述。

BPMN 的這些概念可以幫助使用者以圖形化的方式清晰地描述業務流程,從而更好地進行流程分析、最佳化和執行。

Camunda Modeler

用於建立、編輯和管理流程模型的軟體工具。下載地址:https://camunda.com/download/modeler/

整合Spring boot

配置環境:

  • jdk 17
  • mysql latest
  • camunda-bpm-spring-boot-starter 7.20.0
  • spring-boot-starter-parent 3.2.3

application.yaml

spring:
  application:
    name: camunda-demo
  jersey:
    application-path: /engine-rest
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/camunda_demo?allowPublicKeyRetrieval=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useOldAliasMetadataBehavior=true
    username: root
    password: root
camunda.bpm:
  generic-properties:
    properties:
      enforceHistoryTimeToLive: false
  admin-user:
    id: demo
    password: demo
    firstName: Demo
  filter:
    create: All tasks
  database:
    type: mysql
server:
  port: 8080
  tomcat:
    uri-encoding: UTF-8

maven的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>guru.springframework</groupId>
    <artifactId>spring-boot-camunda</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <name>spring-boot-camunda</name>
    <description>Demo project for Spring Boot and Camunda</description>

    <properties>
        <camunda.spring-boot.version>7.20.0</camunda.spring-boot.version>
        <maven.compiler.release>17</maven.compiler.release>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </dependency>
        <dependency>
            <groupId>org.camunda.bpm.springboot</groupId>
            <artifactId>camunda-bpm-spring-boot-starter</artifactId>
            <version>${camunda.spring-boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.camunda.bpm.springboot</groupId>
            <artifactId>camunda-bpm-spring-boot-starter-webapp</artifactId>
            <version>${camunda.spring-boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.camunda.bpm.springboot</groupId>
            <artifactId>camunda-bpm-spring-boot-starter-rest</artifactId>
            <version>${camunda.spring-boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.camunda.bpm.extension.swagger</groupId>
            <artifactId>camunda-bpm-swagger-json</artifactId>
            <version>7.8.0</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>swagger-ui</artifactId>
            <version>3.1.4</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
    </dependencies>
</project>

常用web地址

  • Swagger UI:http://localhost:8080/webjars/swagger-ui/3.1.4/index.html?docExpansion=none&url=/swagger.json#/

  • REST API: http://localhost:8080/engine-rest/
  • Camunda web:http://localhost:8080/camunda/app/welcome/default/#!/welcome

使用示例

基於JavaDelegate配置Camunda 的自動化服務節點

示例程式碼:

package guru.springframework.services.process;

import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;

public class TestDelegate implements JavaDelegate {
    @Override
    public void execute(DelegateExecution delegateExecution) throws Exception {
        System.out.println("TestDelegate: " + delegateExecution.getProcessInstanceId());
    }
}

Modeler配置:

基於ExecutionListener監聽整個流程執行過程中的事件

import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.ExecutionListener;

public class AmountApprovalDecisionListener implements ExecutionListener {
    
    @Override
    public void notify(DelegateExecution execution) throws Exception {
        double amount = (double) execution.getVariable("amount");
        execution.setVariable("amount", amount);
    }
}