相关文章推荐
玩篮球的菠萝  ·  Can't ping docker ...·  11 月前    · 
耍酷的抽屉  ·  EmmyLua Attach ...·  1 年前    · 
知识渊博的饺子  ·  Microchip dsPIC33F ...·  1 年前    · 
气势凌人的伤疤  ·  pytorch ...·  1 年前    · 
Camunda SpringBoot与进阶内容

Camunda SpringBoot与进阶内容

在开始之前,首先确保你已经完成了 快速入门部分 http://shaochenfeng.com/blog/camunda-快速入门/

本章我们将继续完成 Camunda 官网上的其他入门部分,你将学到:

Spring Boot部分:

  1. 创建 Camunda Spring Boot 项目
  2. 配置项目
  3. 使用“自动部署”功能部署流程
  4. 自定义HTML表格
  5. 在流程中调用 JAVA Class

DMN部分:

  1. 在JAVA端调用DMN决策
  2. 从DMN决策表与DRG决策图

本教程对应官方教程中 Spring Boot 、DMN 、 JAVA Process Application 三章的内容,用一个例子串联起来,让我们开始吧!

创建 Camunda Spring Boot 项目

首先打开你喜欢的 IDE,新建一个空的Maven项目,本次的案例是“贷款审批”,所以项目名命名为 loan-approval-spring-boot ,groupId为 org.example

也可以使用命令行创建

mvn archetype:generate -DgroupId=org.example -DartifactId=loan-approval-spring-boot -Dversion=1.0-SNAPSHOT -DarchetypeArtifactId=maven-archetype-quickstart -DinactiveMode=false

配置Maven依赖

接下来添加 Maven 依赖,Maven依赖需要添加到项目根目录下的 pom.xml 文件中。我们需要将 Spring Boot 依赖添加到 “dependency management” 中,然后将 Camunda Spring Boot Starter 添加为依赖,这将提供 Camunda 流程引擎和自带的 WebApp ;为简单起见,数据库使用嵌入式H2数据库;最后添加 spring-boot-maven-plugin ,它会将Spring Boot项目打包在一起。最终完成后效果如下:

<?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.15.0</camunda.spring-boot.version>
        <spring-boot.version>2.4.4</spring-boot.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </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-webapp</artifactId>
            <version>${camunda.spring-boot.version}</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.2.3</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>

为项目添加主类

接下来,我们将为应用添加可以运行的主类,在 src/main/java 下新建一个类,类名为 WebappExampleProcessApplication ,包名为 org.example.loanapproval

如果使用命名行创建项目,会存在一个自带的 App.java 主类 ,这个不需要,删除即可

Spring Boot的主类需要添加 @SpringBootApplication 注解,最后完成的效果如下:

package org.example.loanapproval;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class WebappExampleProcessApplication {
    public static void main(String... args) {
        SpringApplication.run(WebappExampleProcessApplication.class, args);
}
到此第一部分结束,如果想直接获取到现在为止的进度,可以下载 zip包 ,或者使用如下命令
sh git clone https://gitee.com/zoollcar/camunda-get-started-spring-boot-and-dmn.git git checkout -f Step-1

配置项目

Camunda Spring Boot 自带了最佳实践配置,这些配置会在启动时自动启用,如果要覆盖部分配置,可以在 resources 中新增 application.yaml application.properties ,默认配置的具体内容可以查看 docs.camunda.org/manual

自定义管理员账户

让我们在 src/main/resources 下创建 application.yaml 文件,输入如下内容:

camunda.bpm:
  admin-user:
    id: demo
    password: demo
    firstName: Demo
  filter:
    create: All tasks

以上配置将使用 demo 作为管理员用户名密码,在 Tasklist 中添加 All tasks 过滤器

编译运行

IDE通常有工具可以直接编译运行,使用工具运行即可

也可以使用命令行运行:

mvn package
java -jar target/loan-approval-spring-boot-1.0-SNAPSHOT.jar

运行后打开浏览器访问: localhost:8080/ ,会自动打开登录界面,可以使用 demo/demo 登录,然后打开 Tasklist,可以看到 “All tasks”也被创建出来了。



到此第二部分结束,如果想直接获取到现在为止的进度,可以下载 zip包 ,或者使用如下命令
sh git clone https://gitee.com/zoollcar/camunda-get-started-spring-boot-and-dmn.git git checkout -f Step-2

部署BPMN2.0流程

在本章中,我们将要为刚才的Spring Boot项目部署流程,并使用监听器,在流程部署时发起流程

编辑流程

下载并打开 Camunda Modeler,编辑只包含一个人工节点的简单流程



点击空白处,编辑流程id为 loan-approval ,Name 为 Loan approval

如果你对流程编辑不熟悉,可以阅读快速入门中的 编辑流程部分

流程编辑完成后,保存流程模型到项目的 src/main/resources 文件夹中,命名为 loan-approval.bpmn ,然后重新编译运行项目。

浏览器中打开 localhost:8080/ ,点击 cockpit 可以看到流程已经部署到流程引擎中了



如果遇到报错:
src-resolve: 无法将名称 'XXXX' 解析为 'element declaration' 组件。
请检查项目路径是否有中文,这里要求路径不能包含中文。

为项目启用流程支持

现在我们在 Camunda Spring Boot 项目中添加 @EnableProcessApplication 注解,这会提供更多可配置项,以及启用更多流程相关注解。

package org.example.loanapproval;
import org.camunda.bpm.spring.boot.starter.annotation.EnableProcessApplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableProcessApplication // 新增
public class WebappExampleProcessApplication {
    public static void main(String... args) {
        SpringApplication.run(WebappExampleProcessApplication.class, args);
}

添加完注解后,需要新建 Camunda 配置文件—— src/main/resources/META-INF/processes.xml META-INF 文件夹可能不存在,需要新建后,在其中增加 processes.xml ,这个文件暂时留空,但对于 Camunda 来说却是必要的。



流程部署时发起流程测试

下一步是一项测试,我们希望在流程部署完成后发起一次流程,需要用到事件监听注解 @EventListener ,监听的类型为 PostDeployEvent (流程部署),修改后的 WebappExampleProcessApplication 如下:

@SpringBootApplication
@EnableProcessApplication
public class WebappExampleProcessApplication {
    public static void main(String... args) {
        SpringApplication.run(WebappExampleProcessApplication.class, args);
    // >>新增
    @Autowired
    private RuntimeService runtimeService;
    @EventListener
    private void processPostDeploy(PostDeployEvent event) {
        runtimeService.startProcessInstanceByKey("loanApproval");
}

修改后,我们再次重启项目,浏览器中打开 localhost:8080/ ,点击 Tasklist 进入,可以看到新创建的流程实例人工任务



到此第三部分结束,如果想直接获取到现在为止的进度,可以下载 zip包 ,或者使用如下命令
sh git clone https://gitee.com/zoollcar/camunda-get-started-spring-boot-and-dmn.git git checkout -f Step-3

添加自定义表单

快速入门 中,我们通过form选项卡添加过表单,通过变量名和变量类型简单的生成了自带表单,本章我们将使用自定义html嵌入的方式,让表单具有更大的灵活性。

添加申请表单

我们需要将自定义表单放入Spring Boot静态资源文件夹,在 resources 中新建目录 static/forms ,然后新建申请表单,内容如下,命名为 loan-approval.html ,保存到 resources/static/forms 目录

<form name="loanApproval">
    <div class="form-group">
        <label for="lenderId">贷款人</label>
        <input class="form-control"
               cam-variable-type="String"
               cam-variable-name="lenderId"
               name="lenderId" />
    </div>
    <div class="form-group">
        <label for="amount">金额</label>
        <input class="form-control"
               cam-variable-type="Double"
               cam-variable-name="amount"
               name="amount" />
    </div>
</form>

打开 Camunda Modeler ,点击 “发起贷款申请” 节点,在右侧属性菜单选择Forms,写入 embedded:app:forms/loan-approval.html 这意味着表单将以嵌入式的方式添加进 Tasklist 中

添加“检查申请单”节点表单

同样的,我们新建 loan-auth.html resources/static/forms 目录,内容如下:

<form name="loanAuth">
    <div class="form-group">
        <label for="lenderId">贷款人</label>
        <input class="form-control"
               cam-variable-type="String"
               cam-variable-name="lenderId"
               name="lenderId"
               readonly="true" />
    </div>
    <div class="form-group">
        <label for="amount">金额</label>
        <input class="form-control"
               cam-variable-type="Double"
               cam-variable-name="amount"
               name="amount" />
    </div>
</form>

打开 Camunda Modeler ,点击 “检查申请单” 节点,在右侧属性菜单选择Forms,写入 embedded:app:forms/loan-auth.html

测试一下

重新编译并运行项目,浏览器中打开 localhost:8080/ ,点击 Tasklist 进入,点击右上角 Start Process ,可以看到表单已经嵌入到 Tasklist 中了,发起流程后,任务列表中可以看到审核界面的表单





到此第四部分结束,如果想直接获取到现在为止的进度,可以下载 zip包 ,或者使用如下命令
sh git clone https://gitee.com/zoollcar/camunda-get-started-spring-boot-and-dmn.git git checkout -f Step-4

在流程中调用 JAVA Class

在本章中我们将学到如何使用流程的 Service task(服务任务) 中调用JAVA类。

将 Service Task 添加到流程中

打开 Camunda Modeler ,在左侧工具架中选择 Task(矩形),拖动到“检查申请单”后面,双击命名为“发放贷款”



点击新创建的节点,点击右侧弹出的扳手按钮,将类型修改为 Service Task。



实现 JavaDelegate 类

现在我们需要添加 Service Task 可以调用的实现类,将类添加到 org.example.loanapproval 包下,命名为 OfferLoan ,这里我们希望打印贷款人信息到日志,具体代码如下:

package org.example.loanapproval;
import java.util.logging.Logger;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
public class OfferLoan implements JavaDelegate {
    private final static Logger LOGGER = Logger.getLogger("LOAN-REQUESTS");
    @Override
    public void execute(DelegateExecution execution) {
        LOGGER.info("offer " + execution.getVariable("lenderId") + " loans");
}

配置 Service Task

回到 Camunda Modeler ,选择“发放贷款”节点,在右侧的属性面板中,选择 Implementation Java Class ,Java Class 为我们刚才创建的类 org.example.loanapproval.OfferLoan



保存流程

测试一下

重新编译并运行项目,浏览器中打开 localhost:8080/ ,点击 Tasklist 进入,点击右上角 Start Process ,启动一个新流程



刷新页面,完成人工任务



检查 Spring Boot 程序控制台输出,可以看到贷款人信息已经被打印出来了

INFO 3156 --- [nio-8080-exec-6] LOAN-REQUESTS    : offer 张三 loans
到此第五部分结束,如果想直接获取到现在为止的进度,可以下载 zip包 ,或者使用如下命令
sh git clone https://gitee.com/zoollcar/camunda-get-started-spring-boot-and-dmn.git git checkout -f Step-5

在 JAVA 中调用 DMN 决策

在本章中,我们将会学到创建一个DMN决策并部署到流程引擎中,以及在JAVA里调用测试我们的DMN。

我们使用BMI健康状况作为案例,BMI是身高体重的比值,通常用于判断人的胖瘦程度。

创建新的 DMN

启动 Camunda Modeler,点击工具栏最左侧的新建按钮,新建一个 DMN



配置DMN决策

点击画布上默认的DMN决策表,修改在右侧的属性面板中的 id bmi-classification Name BMI Classification



下一步,点击左上角的表格按钮,进入决策编辑界面



双击 input 区域, input 修改为 BMI Expression 修改为 bmi Type 选择 douoble

同样的,双击output区域, output 修改为 result Output Name 修改为 result Type 选择 string



点击表格左侧的蓝色加号,添加BMI分类规则,最终效果如下:



确保顶部 Hit Policy(命中策略) 为“UNIQUE(唯一)”,在“唯一”模式下,只有所有规则都是互斥的,一个输入只能匹配一种规则。



默认的规则就是“唯一”,这条规则可以自动匹配,不需要更改。

保存决策表

编辑完成后,点击工具栏“save”按钮,将流程保存到项目的 src/main/resources 目录下。

到此第六部分结束,如果想直接获取到现在为止的进度,可以下载 zip包 ,或者使用如下命令
sh git clone https://gitee.com/zoollcar/camunda-get-started-spring-boot-and-dmn.git git checkout -f Step-6

在JAVA中调用DMN决策表

我们将在决策表部署完成后调用测试,因此如下修改主类:

package org.example.loanapproval;
//import ...
import java.util.logging.Level;
import java.util.logging.Logger;
@SpringBootApplication
@EnableProcessApplication
public class WebappExampleProcessApplication {
    // 增加logger用于打印决策后的结果
    protected final static Logger LOGGER = Logger.getLogger(WebappExampleProcessApplication.class.getName());
    public static void main(String... args) {
        SpringApplication.run(WebappExampleProcessApplication.class, args);
    @Autowired
    private RuntimeService runtimeService;
    @EventListener
    private void processPostDeploy(PostDeployEvent event) {
        runtimeService.startProcessInstanceByKey("loan-approval");
        // >>>> 新增
        DecisionService decisionService = event.getProcessEngine().getDecisionService();
        // 输入参数
        VariableMap variables = Variables.createVariables()
                .putValue("bmi", 20.0);
        // 调用决策
        DmnDecisionTableResult dmnDecisionTableResult = decisionService
                .evaluateDecisionTableByKey("bpm-classification", variables);
        String result = dmnDecisionTableResult.getSingleEntry();
        // 打印结果
        LOGGER.log(Level.INFO, "\n\nBMI Classification result is : {0}\n\n", result);
}
到此第七部分结束,如果想直接获取到现在为止的进度,可以下载 zip包 ,或者使用如下命令
sh git clone https://gitee.com/zoollcar/camunda-get-started-spring-boot-and-dmn.git git checkout -f Step-7

测试一下

编译项目并重新运行,查看 Spring Boot 输出,如果看到:

BMI Classification result is : 正常

表示执行成功了

用浏览器打开 localhost:8080/camunda/ 使用 demo/demo 登录,打开 Decision Definitions,可以找到刚才的流程实例,可以看到判定结果



从DMN决策表与DRG决策图

这一章,我们将创建新的DMN决策表,并将两个DMN决策表组成一张DRG决策图,最后通过JAVA调用,获得两个决策表协同得到的结果。

DMN与DRG:
DMN本质上就是一组输入输出的对应关系,体现的是一个简单决策,不应该过于复杂,对于需要多次决策才能得到答案的复杂决策,可以将多个简单的DMN连接起来,组成DRG决策图。
DRG与DRD
DRD是使用可视化的方式显示和编辑DRG的方式,因为Camunda Modeler是可视化的,所以在Camunda Modeler中显示未DRD

配置DRD决策图

点击左上角的 Edit DRD 切换到 DRD编辑界面



就像编辑流程一样,点击空白处,修改DRD的id为 bmi-health ,Name为 BMI Health

创建新的DMN决策到DRD

现在可以创建一个新的决策了,我们希望在评估完BMI类型后给出建议,则拖动左侧正方形到画布,双击修改名称为 BMI Suggestion ,切换类型为 Decision Table,最后修改id为 bmi-suggestion



点击 “BMI Classification” 节点,选择弹出的连线,连接到新的“BMI Suggestion”节点,这表示,新节点 依赖于 “BMI Classification”



编辑“BMI Suggestion”决策

点击 “BMI Suggestion” 节点左上角的表格按钮,进入编辑界面,输入内容如下:

“Input”为 result ,“Expression”为 result

“Output”为 suggestion ,“Expression”为 suggestion



在JAVA中执行

执行DRG决策图的方法就是执行它的最后一个节点,因为DRG的节点之间具有依赖关系,在执行最后一个节点前会执行它所以来的决策

所以新增的代码与执行DMN一样,修改后的主类如下:

// ...
@SpringBootApplication
@EnableProcessApplication
public class WebappExampleProcessApplication {
    protected final static Logger LOGGER = Logger.getLogger(WebappExampleProcessApplication.class.getName());
    public static void main(String... args) {
        SpringApplication.run(WebappExampleProcessApplication.class, args);
    @Autowired
    private RuntimeService runtimeService;
    @EventListener
    private void processPostDeploy(PostDeployEvent event) {
        runtimeService.startProcessInstanceByKey("loan-approval");
        DecisionService decisionService = event.getProcessEngine().getDecisionService();
        VariableMap variables = Variables.createVariables()
                .putValue("bmi", 20.0);
        DmnDecisionTableResult dmnDecisionTableResult = decisionService
                .evaluateDecisionTableByKey("bmi-classification", variables);
        String result = dmnDecisionTableResult.getSingleEntry();
        LOGGER.log(Level.INFO, "\n\nBMI Classification result is : {0}\n\n", result);
        // >>>> 新增
        DmnDecisionTableResult suggestionResult = decisionService
                .evaluateDecisionTableByKey("bmi-suggestion", variables);