Camunda SpringBoot与进阶内容
在开始之前,首先确保你已经完成了 快速入门部分 ( http://shaochenfeng.com/blog/camunda-快速入门/ )
本章我们将继续完成 Camunda 官网上的其他入门部分,你将学到:
Spring Boot部分:
- 创建 Camunda Spring Boot 项目
- 配置项目
- 使用“自动部署”功能部署流程
- 自定义HTML表格
- 在流程中调用 JAVA Class
DMN部分:
- 在JAVA端调用DMN决策
- 从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
,默认配置的具体内容可以查看
https://
docs.camunda.org/manual
/latest/user-guide/spring-boot-integration/configuration/#camunda-engine-properties
自定义管理员账户
让我们在
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
运行后打开浏览器访问: http:// 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
,然后重新编译运行项目。
浏览器中打开 http:// 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");
}
修改后,我们再次重启项目,浏览器中打开 http:// 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
测试一下
重新编译并运行项目,浏览器中打开
http://
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
保存流程
测试一下
重新编译并运行项目,浏览器中打开
http://
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 : 正常
表示执行成功了
用浏览器打开 http:// localhost:8080/camunda/ app/cockpit/ 使用 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);