Camunda介绍 Camunda是一种工作流引擎,是由Java开发的一个纯Java库。
通常集成在我们的服务中,作为其中一块功能。
官方-下载引导地址
docker pull camunda/camunda-bpm-platform:run-latest
docker run -d --name camunda -p 8080:8080 camunda/camunda-bpm-platform:run-latest
Camunda Platform 下载地址
我们下载好后,需要到这个路径下。这里是创建表的sql语句,选择自己的数据库运行语句,来创建对应的表。
修改default.yml 中数据源和JDBC 替换为自己使用的数据库的配置
然后把对应的JDBC放入标注上面的userlib之中即可。
Camunda Modeler 下载地址
我们在点击运行后可以直接使用。
我们创建在Camunda Modeler中创建一个流程,然后我们可以用Java或者JS,按照流程去执行它。
本篇使用Java处理。
首先,我们可以创建一个BPMN Diagram。
Business Process Modeling Notation,简称BPMN
它的事件包含
根据触发方式不同,可以分为
具体的使用方式请参考:参考-Executing automated steps 、Service tasks
我们准备一个简易的流程,如下图(与官方例子一致)。
这里可以直接下载官方的例子下载避免繁琐的配置操作
注意一下,最新版的是可集群的版本(版本8)
我们使用的是如下的版本(版本7)
换言之就是创建一个Java程序,用它以处理BPMN Diagram
这里是官方的写的依赖,依据自己的需要改动即可。
<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.0modelVersion>
<groupId>org.camunda.bpm.getstartedgroupId>
<artifactId>charge-card-workerartifactId>
<version>0.0.1-SNAPSHOTversion>
<properties>
<camunda.external-task-client.version>7.17.0camunda.external-task-client.version>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>org.camunda.bpmgroupId>
<artifactId>camunda-external-task-clientartifactId>
<version>${camunda.external-task-client.version}version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-simpleartifactId>
<version>1.6.1version>
dependency>
<dependency>
<groupId>javax.xml.bindgroupId>
<artifactId>jaxb-apiartifactId>
<version>2.3.1version>
dependency>
dependencies>
project>
笔者改为Spring Boot(Java11)
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.7.6version>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>javax.xml.bindgroupId>
<artifactId>jaxb-apiartifactId>
dependency>
<dependency>
<groupId>org.camunda.bpmgroupId>
<artifactId>camunda-external-task-clientartifactId>
<version>7.18.0version>
dependency>
dependencies>
该程序连接的是 Camunda Platform 系统注意端口和IP。
import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.client.ExternalTaskClient;
import java.awt.*;
import java.net.URI;
@Slf4j
public class ChargeCardWorker {
public static void main(String[] args) {
ExternalTaskClient client = ExternalTaskClient.create()
// 依据实际情况填写程序的IP和端口
.baseUrl("http://localhost:8080/engine-rest")
// 异步相应超时时间
.asyncResponseTimeout(10000) // long polling timeout
.build();
// subscribe to an external task topic as specified in the process
// 订阅流程中指定的外部任务主题,与活动ID对应
client.subscribe("charge-card")
// 默认锁的持续时间为20秒
.lockDuration(1000) // the default lock duration is 20 seconds, but you can override this
// 处理内容
// externalTask:任务,externalTaskService:处理服务
.handler((externalTask, externalTaskService) -> {
// Put your business logic here
// Get a process variable
String item = externalTask.getVariable("item");
Integer amount = externalTask.getVariable("amount");
log.info("Charging credit card with an amount of '{}'€ for the item '{}'...",amount,item);
try {
// 打开页面并挂起
Desktop.getDesktop().browse(new URI("https://docs.camunda.org/get-started/quick-start/complete"));
} catch (Exception e) {
e.printStackTrace();
}
// Complete the task
// 任务完成
externalTaskService.complete(externalTask);
})
.open();
}
}
这里的活动的Topic与我们的工作者一致。因而可以知道活动有对应的工作者去处理。
通过改变活动以及活动的顺序来改变流程,而活动自己被不同的工作者处理后继续流转因而不受影响,以此完成流程。
也就是将BPMN Diagram 与 Platform关联,然后让我们的工作者去处理它。
我们将流程部署过去
成功后,我们进入platform登陆后(默认账号密码均为demo),可以看到流程已经在这里了
http://localhost:8080/camunda/app/cockpit/default/#/processes
我们接下来可以使用postman
向这个地址发送Post请求
http://localhost:8080/engine-rest/process-definition/key/payment-retrieval/start
同时在body里面发送如下json参数
{
"variables": {
"amount": {
"value":555,
"type":"integer"
},
"item": {
"value": "item-xyz"
}
}
}
当我们在工作者的后台看到如下数据,并且成功打开了一个页面,就说明成功消费了
此处的key就是我们process的ID:payment-retrieval
当然这里只是最简单的使用。参考-Add a User Task to the Process
依据类似的操作,我们添加一个
我们把任务分配给demo用户
下面的候选组、人、到期日期请自行参考文档
我们接着在这个活动的Forms添加如下属性,来向流程中加一个表单
选择 File > New File > Form(版本7)创建如下表单
并把ID和我们payment-form设置为一样的,来关联起来。
我们接下来创建一个Amount项目,使用Number类型
再创建一个文本框,如下设置
再加一个是否同意
完成回到流程然后部署,记得加入我们的表单
来到这个页面,点击框住的按钮
http://localhost:8080/camunda/app/tasklist/
输入一个业务流程号后,我们可以找到我们的流程以及表格
同时可以看到流程位置
也就是类似if-else的方式,来确定流向。
我们先搭出如下内容
网关1
网关2
接下来我们部署该流程,按照1.3.5中流程开始一个流程,或者通过PostMan请求,可以看到流程流转到了不同地方。
我们查看,可以看到流程到了这里
启动我们的外部工作者,即可完成处理。
可以看到我们这里的流程到了1.3.5的部分,在tasklist中我们处理是否同意即可。
随后我们创建一个新的DMN流程(依然是版本7)。
我们这里直接把Decision1的ID(决策表)和我们业务规则输入的reference关联起来
创建如下内容
标题我们是Item大写,Expression我们是小写让变量与之后流程一致
制作如下表格
到现在为止,我们完成了决策表的制作。
关于决策表,可以参考Camunda DMN
我们接下来把它部署即可,名字可以取框住的
随后我们可以在决策里面找到
在重新部署我们的流程
我们用SpringBoot集成流程引擎。
可以参考-Camunda-Spring Boot 集成
相关的SpringBoot配置可以参考-流程引擎配置
<properties>
<maven.compiler.source>11maven.compiler.source>
<maven.compiler.target>11maven.compiler.target>
<camunda.spring-boot.version>7.18.0camunda.spring-boot.version>
<spring-boot.version>2.7.3spring-boot.version>
<xml-bind.version>2.3.6xml-bind.version>
<maven.compiler.target>11maven.compiler.target>
<mybatis-plus.version>3.5.1mybatis-plus.version>
properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>${spring-boot.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<dependencies>
<dependency>
<groupId>org.camunda.bpm.springbootgroupId>
<artifactId>camunda-bpm-spring-boot-starter-webappartifactId>
<version>${camunda.spring-boot.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.camunda.bpm.springbootgroupId>
<artifactId>camunda-bpm-spring-boot-starterartifactId>
<version>${camunda.spring-boot.version}version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>${mybatis-plus.version}version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-extensionartifactId>
<version>${mybatis-plus.version}version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
dependencies>
yml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://IP:Port/DataBase?useUnicode=true&NamePatternMatchesAll=true&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&useSSL=false
username: username
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
application:
name: applicationName
camunda:
bpm:
admin-user:
id: demo
password: demo
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
package camunda;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CamundaApplication {
public static void main(String[] args){
SpringApplication.run(CamundaApplication.class,args);
}
}
启动后我们访问
http://localhost:8080/camunda/app/welcome/default/#!/login
出现如下页面就说明成功了。
页面和地址的使用方式和我们之前的使用方式是一致的。
有页面是因为我们引入了,不需要页面的时候,我们可以不引入它即可。
<dependency>
<groupId>org.camunda.bpm.springbootgroupId>
<artifactId>camunda-bpm-spring-boot-starter-webappartifactId>
<version>${camunda.spring-boot.version}version>
dependency>
此外,我们可以配置yml,来修改路径以及是否重定向到默认的index.html.
camunda:
bpm:
webapp:
application-path: 路径
index-redirect-enabled: false
可以参考-Camunda BPM Javadocs 7.9.19-ee
我们可以引入如下依赖:
<dependency>
<groupId>org.camunda.bpm.springbootgroupId>
<artifactId>camunda-bpm-spring-boot-starter-restartifactId>
<version>${camunda.spring-boot.version}version>
dependency>
关于是否需要这个扩展包,new bing 给出的答复如下:
Camunda BPM Spring Boot Starter是一个Camunda BPM的Spring Boot Starter,它提供了REST API的支持,可以让您的Camunda BPM应用程序更容易地与其他应用程序集成。
- 使用camunda-bpm-spring-boot-starter-rest扩展,您可以使用Camunda BPM REST API与Camunda BPM引擎进行交互。这使得您可以使用Camunda BPM REST API执行各种操作,例如启动流程实例、查询任务、完成任务等。
- 如果您不使用camunda-bpm-spring-boot-starter-rest扩展,您仍然可以使用Camunda BPM REST API与Camunda BPM引擎进行交互。但是,您需要手动配置REST API,并且需要编写代码来与REST API进行交互。
也就是REST API 让我们可以用PostMan等方式,直接调用接口。不用的话,我们则可以自己写接口。
它的使用可参考-REST API Reference
默认API地址为
http://localhost:8080/engine-rest
Camunda使用的是jersey,因而一些配置需要jersey配置方式。
也可以通过修改spring boot的通用应用程序属性来改变API访问地址:
spring:
jersey:
application-path=地址
为了修改配置或注册额外的资源,可以提供一个集成自如下的配置类:
org.camunda.bpm.spring.boot.starter.rest.CamundaJerseyResourceConfig
@Component
@ApplicationPath("/engine-rest")
public class JerseyConfig extends CamundaJerseyResourceConfig {
@Override
protected void registerAdditionalResources() {
register(...);
}
}
中心起点是ProcessEngine(流程引擎),可以通过配置部分中描述的几种方式创建ProcessEngine。
从ProcessEngine中,可以获得包含 工作流/BPM 方法的各种服务。
ProcessEngine和服务对象是 线程安全 的。所以可以为整个服务器保留对其中一个的引用。
actiti.cfg.xml文件:
服务都是无状态的:
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
将在第一次调用流程引擎时初始化并构建流程引擎,之后总是返回相同的流程引擎.
可以使用ProcessEngines.init()和ProcessEngines.destroy()来正确地创建和关闭所有的流程引擎
RepositoryService repositoryService = processEngine.getRepositoryService();
RepositoryService可能是使用Camunda引擎时需要的第一个服务。此服务提供用于管理和操作部署和流程定义的操作。
部署 部署内容 意味着将其上传到引擎,在将所有进程存储到数据库之前,都将会对其进行检查和解析。
完成后,系统就知道部署了,之后就可以启动部署中包含的任何进程。
通过该服务,可以:
RuntimeService runtimeService = processEngine.getRuntimeService();
RuntimeService处理启动流程定义的新流程实例。
流程定义定义了流程中不同步骤的结构和行为,流程实例是此类流程定义的一次执行。对于每个流程定义,通常都有多个实例同时运行。
RuntimeService也是用于检索和存储流程变量的服务。这是特定于给定流程实例的数据,可以由流程中的各种构造使用(例如,独占网关通常使用流程变量来确定选择哪条路径来继续流程)。
RuntimeService还允许对流程实例和执行进行查询。基本上,执行就是指向流程实例当前位置的指针。
最后,当流程实例等待外部触发器且流程需要继续时,将使用RuntimeService。流程实例可以有各种等待状态,该服务包含各种“通知”实例接收到外部触发器并可以继续该流程实例的操作。
TaskService taskService = processEngine.getTaskService();
需要展示给实际用户执行的任务是流程引擎的核心。
围绕任务的所有内容都分组在TaskService中,例如
IdentityService identityService = processEngine.getIdentityService();
IdentityService允许对组和用户进行管理(创建、更新、删除、查询等)。
但是,核心引擎在运行时实际上不会对用户进行任何检查。
FormService formService = processEngine.getFormService();
FormService是一个可选服务。
此服务引入了启动表单和任务表单的概念。
该服务以一种易于使用的方式公开此数据。但同样,这是可选的,因为表单不需要嵌入到流程定义中。
HistoryService historyService = processEngine.getHistoryService();
HistoryService公开引擎收集的所有历史数据。
在执行流程时,引擎可以保存大量数据(这是可配置的),例如流程实例的开始时间、谁执行了哪些任务、完成任务所需的时间、每个流程实例遵循的路径等等。
该服务主要提供访问此数据的查询功能。
ManagementService managementService = processEngine.getManagementService();
在编写自定义应用程序时,通常不需要ManagementService。
它允许检索关于数据库表和表元数据的信息。此外,它还公开了作业的查询功能和管理操作。作业在引擎中用于各种用途,如计时器、异步延续、延迟挂起/激活等。
FilterService filterService = processEngine.getFilterService();
FilterService允许创建和管理过滤器。过滤器是像任务查询一样存储的查询。
例如,Tasklist使用过滤器来过滤用户任务。
camunda-Filters
ExternalTaskService externalTaskService = processEngine.getExternalTaskService();
ExternalTaskService提供对外部任务实例的访问。外部任务表示在外部独立于流程引擎处理的工作项。
CaseService caseService = processEngine.getCaseService();
CaseService类似于RuntimeService,但用于案例实例。它处理启动用例定义的新用例实例和管理用例执行的生命周期。该服务还用于检索和更新案例实例的流程变量。
DecisionService decisionService = processEngine.getDecisionService();
DecisionService允许评估部署到引擎的决策。它是在独立于流程定义的业务规则任务中评估决策的一种替代方法。
我们在启动类上添加@EnableProcessApplication注释,并将空的processes.xml文件放在src/main/resources/META-INF文件夹中。
@SpringBootApplication
@EnableProcessApplication
public class CamundaApplication {
public static void main(String[] args){
SpringApplication.run(CamundaApplication.class,args);
}
}
Camunda Engine的每个流程应用程序都需要该文件,此处我们始终将它保持为空(它会使用默认配置)
这里我们仍然从Modeler处创建一个流程。
然后保存在如下位置
启动后,我们可以看到已经成功部署
在流程定义中可以找到
此处也可以找到
如下就是部署与移除的流程,默认的配置下,即使删除bpmn,流程仍然存在于数据库中
我们可以创一个用于创建实例的类,这里的key就是我们流程的key,至此该监听器监听该流程。
可以完成部署后立即创建一个实例(重启也会)
@Service
@Slf4j
public class TestCamunda {
@Autowired
private RuntimeService runtimeService;
@EventListener
private void processPostDeploy(PostDeployEvent event) {
log.info("{}",event);
runtimeService.startProcessInstanceByKey("Process_028ntv2");
}
}
我们可以做一个接口,通过接受服务ID,然后用RuntimeService去创建。
消费服务我们之前就写给过了,这里就跳过。
默认情况下,camunda-spring-boot-starter 使用SpringProcessEngineConfiguration 配置自动部署功能。
从1.2.0开始,可以通过 SpringBootProcessApplication 配置。这将禁用SpringProcessEngineConfiguration 的自动部署功能。
自动部署功能,用如下路径作为资源扫描的目录。
META-INF/processes.xml
允许使用的所有 processes.xml 配置项在这里列出。
<process-application
xmlns="http://www.camunda.org/schema/1.0/ProcessApplication"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<process-archive>
<properties>
<property name="isDeleteUponUndeploy">falseproperty>
<property name="isScanForProcessDefinitions">trueproperty>
properties>
process-archive>
process-application>
官方给出的配置样例:
<process-application
xmlns="http://www.camunda.org/schema/1.0/ProcessApplication"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<process-archive name="loan-approval">
<process-engine>defaultprocess-engine>
<properties>
<property name="isDeleteUponUndeploy">trueproperty>
<property name="isScanForProcessDefinitions">trueproperty>
properties>
process-archive>
process-application>
我们在这里声明了一个单个部署(流程存档),流程存档的名称为loan-approval,并部署到名称为default的流程引擎。
isDeleteUponUndeploy:此属性控制流程应用程序的取消部署是否需要从数据库中删除流程引擎部署。
isScanForProcessDefinitions:如果此属性设置为true,则会自动扫描流程应用程序的类路径以查找可部署资源。
配置文件的基本设置,可参考-The processes.xml Deployment Descriptor
配置参数可查阅
只需要添加@EnableProcessApplication注解到SpringBootapplication类即可:
@SpringBootApplication
@EnableProcessApplication
public class CamundaApplication{
}
由于使用@EnableProcessApplication时,没有扩展ProcessApplication类,所以我们不能使用@PostDeploy和@PreUndeploy方法注释。
相反,这些回调是通过Spring事件发布机制提供的。所以可以使用以下事件监听器。
@SpringBootApplication
@EnableProcessApplication
public class CamundaApplication{
//...
}
@EventListener
public void onPostDeploy(PostDeployEvent event) {
//...
}
@EventListener
public void onPreUndeploy(PreUndeployEvent event) {
//...
}
camunda中文-官方文档
camunda内部构造
camunda英文-官方文档