Spring Boot 项目集成camunda流程引擎
Spring Boot 项目集成camunda流程引擎
camunda地址
camunda中文地址
使用camunda开源工作流引擎有:通过docker运行、使用springboot集成、部署camunda发行包、基于源代码编译运行等多种方式。
文本重点介绍如何在Spring Boot应用程序中如何集成Camunda Platform开源流程平台,这也是项目中最为常见的一种使用方式。
在本教程中,我们假设您熟悉 Java Web 应用程序开发和 Spring Boot 的基础知识。前提条件是您已经安装了 Eclipse/IDEA等Java开发工具和 Camunda Modeler流程设计器。
1.新建Spring Boot 项目集成camunda
首先,让我们在您选择的 IDE 中设置您的第一个流程应用程序项目。
该项目需要 Java jdk8以上版本。我本地使用的JDK版本为8,使用的开发工具IDEA2024。
1.1. 添加 Camunda 平台和 Spring Boot 依赖项
下一步包括为新项目设置 Maven 依赖项。需要将 Maven 依赖添加到项目的文件中。由于本示例要使用camunda流程引擎、web界面、Rest服务接口,所以需要导入camunda-bpm-spring-boot-starter-rest、camunda-bpm-spring-boot-starter-webapp依赖包。我们在“依赖管理”部分添加了 Spring Boot BOM和camunda相关依赖,这将自动将 camunda 引擎、rest服务接口和 Web 应用程序包含在应用程序中。
我们使用camunda7.19.0版本,该版本支持jdk8和springboot2。camunda和springboot版本的依赖对应关系,查看官方文档说明:Spring Boot Version Compatibility | docs.camunda.org
<?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><artifactId>camunda-demo</artifactId><name>camunda-demo</name><groupId>com.liuhm</groupId><version>1.0</version><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version><spring-boot.version>2.7.5</spring-boot.version><camunda.spring-boot.version>7.19.0</camunda.spring-boot.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-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.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><dependency><groupId>com.sun.xml.bind</groupId><artifactId>jaxb-impl</artifactId><version>2.3.6</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version></dependency></dependencies><build><finalName>${project.artifactId}</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version></plugin><!--指定JDK编译版本 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin></plugins></build></project>
1.2. 配置 Spring Boot 项目
在项目中src/main/resources新建application.yml
让我们在文件夹中创建一个包含以下内容的文件:application.yml
默认在mysql数据库中创建了camundatest
spring:datasource:url: jdbc:mysql://192.168.0.154:3306/camundatest?characterEncoding=UTF-8&useUnicode=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghaiusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Drivercamunda:bpm:database:type: mysqlschema-update: true # 是否自动建表,但我测试为true时,创建表会出现,因此还是改成false由手工建表。auto-deployment-enabled: false # 自动部署 resources 下的 bpmn文件admin-user:id: adminpassword: 123456
server:port: 8080
此配置将导致以下结果:
- 将创建具有提供的密码和名字的管理员用户 admin/123456。
- 认使用mysql数据库,启动时自动创建数据库。
1.3. 编写Spring Boot启动类
接下来,我们添加一个带有 main 方法的应用程序类,该方法将成为启动 Spring Boot 应用程序的入口点。该类上有@SpringBootApplication注解,它隐含地添加了几个方便的功能(自动配置、组件扫描等 - 参见 Spring Boot 文档)
package com.liuhm;import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@Slf4j
public class CamundaApplication {public static void main(String[] args) {try {SpringApplication.run(CamundaApplication.class, args);}catch (Exception e){log.error(ExceptionUtils.getStackTrace(e));}}
}
1.4. 启动Spring Boot工程
在IDEA的maven操作窗口,执行mvn clean install命令,下载相关的第三方Jar包。
1.4.1. 启动
我们的第一个 Camunda Spring Boot 应用程序现已准备就绪,此程序是一个 Spring Boot 应用程序,它作为 Web 容器、Camunda 引擎和 Camunda Web 应用程序资源嵌入到 Tomcat 中,并使用了mysql 数据库。您可以通过右键单击该类并选择CamundaApplication来运行应用程序。
1.4.2. 访问
现在,在浏览器中打开 http://localhost:8080/ 时,您可以使用我们之前配置的登录名和密码“admin/123456”来访问 Camunda Web 应用程序。
能正常登录访问这个界面,表示基于springboot集成camunda成功了。
1.4.3. 数据库表
数据库也创建了表
执行完成后,通过工具打开数据库控制台查看,一共有49张表。
执行的sql脚本,找到camunda-bpm-platform-7.19.0\engine\src\main\resources\org\camunda\bpm\engine\db\create文件夹下的数据库脚本,选择mysql脚本依次执行即可。
2.设计并部署一个BPMN流程
我们将学习如何使用camunda流程设计器设计一个BPMN2的业务流程,并部署流程。
2.1.下载安装流程设计器
官网下载:Camunda Modeler官网下载(https://camunda.com/download/modeler/)
直接下载地址:https://downloads.camunda.cloud/release/camunda-modeler/5.29.0/camunda-modeler-5.29.0-win-x64.zip
下载 流程设计器后camunda-modeler后,只需将下载内容解压缩到您选择的文件夹中即可。
成功解压缩后,对于 Windows 用户运行Camunda Modeler.exe,对于 Mac 用户或 Linux 用户运行.sh文件,启动流程建模器。
2.2. 设计BPMN流程
首先使用 Camunda Modeler 对可执行流程进行建模。设置两个人工任务节点,配置流程处理人为admin用户。
流程模型bpmn内容:
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0p1akz6" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.29.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.22.0"><bpmn:process id="test1" isExecutable="true"><bpmn:startEvent id="StartEvent_1"><bpmn:outgoing>Flow_1747ke5</bpmn:outgoing></bpmn:startEvent><bpmn:sequenceFlow id="Flow_1747ke5" sourceRef="StartEvent_1" targetRef="Activity_14mnow7" /><bpmn:userTask id="Activity_14mnow7" name="申请" camunda:assignee="admin"><bpmn:incoming>Flow_1747ke5</bpmn:incoming><bpmn:outgoing>Flow_0t3binq</bpmn:outgoing></bpmn:userTask><bpmn:sequenceFlow id="Flow_0t3binq" sourceRef="Activity_14mnow7" targetRef="Activity_1ezp043" /><bpmn:userTask id="Activity_1ezp043" name="审批" camunda:assignee="admin"><bpmn:incoming>Flow_0t3binq</bpmn:incoming><bpmn:outgoing>Flow_0ug1mkb</bpmn:outgoing></bpmn:userTask><bpmn:endEvent id="Event_110i53j"><bpmn:incoming>Flow_0ug1mkb</bpmn:incoming></bpmn:endEvent><bpmn:sequenceFlow id="Flow_0ug1mkb" sourceRef="Activity_1ezp043" targetRef="Event_110i53j" /></bpmn:process><bpmndi:BPMNDiagram id="BPMNDiagram_1"><bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="test1"><bpmndi:BPMNShape id="StartEvent_1_di" bpmnElement="StartEvent_1"><dc:Bounds x="192" y="82" width="36" height="36" /></bpmndi:BPMNShape><bpmndi:BPMNShape id="Activity_106g3s5_di" bpmnElement="Activity_14mnow7"><dc:Bounds x="160" y="170" width="100" height="80" /><bpmndi:BPMNLabel /></bpmndi:BPMNShape><bpmndi:BPMNShape id="Activity_1afp88w_di" bpmnElement="Activity_1ezp043"><dc:Bounds x="160" y="280" width="100" height="80" /></bpmndi:BPMNShape><bpmndi:BPMNShape id="Event_110i53j_di" bpmnElement="Event_110i53j"><dc:Bounds x="192" y="412" width="36" height="36" /></bpmndi:BPMNShape><bpmndi:BPMNEdge id="Flow_1747ke5_di" bpmnElement="Flow_1747ke5"><di:waypoint x="210" y="118" /><di:waypoint x="210" y="170" /></bpmndi:BPMNEdge><bpmndi:BPMNEdge id="Flow_0t3binq_di" bpmnElement="Flow_0t3binq"><di:waypoint x="210" y="250" /><di:waypoint x="210" y="280" /></bpmndi:BPMNEdge><bpmndi:BPMNEdge id="Flow_0ug1mkb_di" bpmnElement="Flow_0ug1mkb"><di:waypoint x="210" y="360" /><di:waypoint x="210" y="412" /></bpmndi:BPMNEdge></bpmndi:BPMNPlane></bpmndi:BPMNDiagram>
</bpmn:definitions>
2.3. 发布BPMN流程
点击流程设计器左下方的发布流程按钮:
3. 验证camunda流程引擎
3.1. 通过camunda web控制台测试
现在,当您在浏览器中打开 http://localhost:8080/camunda/app/tasklist/ 时,您可以使用我们之前配置的登录名和密码“admin/123456”来访问 Camunda Web 应用程序。
选择刚刚设计的的流程“test1”,发起一个流程实例。点击左侧“Add a simple filter”添加一个默认待办任务过滤器,就可以查看到刚刚提交的流程待办任务了。
此时,我看打开mysql数据库表,查看camunda数据库表里的数据:
3.1.1. ACT_RE_DEPLOYMENT
打开流程定义发布表ACT_RE_DEPLOYMENT,看到我们刚刚发布的这个流动定义模型。
3.1.2. ACT_HI_PROCINST
打开流程实例历史表ACT_HI_PROCINST,看到我们刚刚发起的这个流程实例数据。
3.1.3. ACT_RU_TASK
打开流程待办任务表ACT_RU_TASK,多了一条demo用户待处理的任务。
3.2. 通过camunda rest接口测试
以上我们通过camunda的web界面进行了发起流程测试验证,下面我们通过Camunda REST API的方式进行测试验证。
Camunda Platform REST API官方说明文档:Camunda Platform REST API
3.2.1.查询流程定义
查看流程定义rest接口:http://{host}:{port}/{contextPath}/process-definition
详细接口描述见官方文档:Camunda Platform REST API
用Postman测试验证:http://localhost:8080/engine-rest/process-definition
返回json:
[{"id": "test1:1:7d603a61-abc5-11ef-9172-0a0027000009","key": "test1","category": "http://bpmn.io/schema/bpmn","description": null,"name": null,"version": 1,"resource": "diagram_1.bpmn","deploymentId": "7d4e600f-abc5-11ef-9172-0a0027000009","diagram": null,"suspended": false,"tenantId": null,"versionTag": null,"historyTimeToLive": null,"startableInTasklist": true}
]
3.2.2. 发起流程实例
流程发起的rest接口为:http://{host}:{port}/{contextPath}/process-definition/key/{key}/start
详细接口描述见官方文档:Camunda Platform REST API
打开postman工具进行测试验证:http://localhost:8080/engine-rest/process-definition/key/test1/start
输入json
{"variables": {"variable1": {"value": "hello","type": "String"},"variable2": {"value": true,"type": "Boolean"}},"businessKey": "第二次发起请求"
}
返回json
{"links": [{"method": "GET","href": "http://localhost:8080/engine-rest/process-instance/2f8a9efb-abc7-11ef-9172-0a0027000009","rel": "self"}],"id": "2f8a9efb-abc7-11ef-9172-0a0027000009","definitionId": "test1:1:7d603a61-abc5-11ef-9172-0a0027000009","businessKey": "第二次发起请求","caseInstanceId": null,"ended": false,"suspended": false,"tenantId": null
}
3.2.3. 查询待办任务
通过上面接口得知,流程当前流转到了人工节点上,那么需要查询待办任务:
查询待办任务的rest接口:http://{host}:{port}/{contextPath}/task
详细接口描述见官方文档:Camunda Platform REST API
用Postman测试:http://localhost:8080/engine-rest/task
返回json
[{"id": "2f8bfe92-abc7-11ef-9172-0a0027000009","name": "申请","assignee": "admin","created": "2024-11-26T15:22:26.000+0800","due": null,"followUp": null,"lastUpdated": null,"delegationState": null,"description": null,"executionId": "2f8a9efb-abc7-11ef-9172-0a0027000009","owner": null,"parentTaskId": null,"priority": 50,"processDefinitionId": "test1:1:7d603a61-abc5-11ef-9172-0a0027000009","processInstanceId": "2f8a9efb-abc7-11ef-9172-0a0027000009","taskDefinitionKey": "Activity_14mnow7","caseExecutionId": null,"caseInstanceId": null,"caseDefinitionId": null,"suspended": false,"formKey": null,"camundaFormRef": null,"tenantId": null}
]
3.2.4. 完成待办提交流程
完成待办任务,提交流程往下走,提交流程的rest服务接口为:
流程发起的rest接口为:http://{host}:{port}/{contextPath}/task/{id}/complete
详细接口描述见官方文档:Camunda Platform REST API
用Postman测试:http://localhost:8080/engine-rest/task/2f8bfe92-abc7-11ef-9172-0a0027000009/complete
输入json:
{"variables": {"variable": {"value": "china"},"variable2": {"value": false}},"withVariablesInReturn": true
}
返回json:
{"variable1": {"type": "String","value": "hello","valueInfo": {}},"variable2": {"type": "Boolean","value": false,"valueInfo": {}},"variable": {"type": "String","value": "china","valueInfo": {}}
}
3.3. 通过Java API接口测试
上面介绍了通过Camunda Web控制台界面和Camunda提供的rest接口两种方式,来调用流程引擎服务。以下介绍第三种方式,即Java编码方式,直接调用Camunda提供的Service接口。
我们自己开发一个RestController服务类,类里注入RuntimeService和TaskService的SpringBean,然后调用这两个类的API接口,实现发起流程和查询待办的逻辑。
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.impl.persistence.entity.TaskEntity;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.task.Task;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import java.util.List;@RestController
@RequestMapping
public class TestController {@Resourceprivate RuntimeService runtimeService;@Resourceprivate TaskService taskService;/*** 通过流程定义key,发起一个流程实例* @param processKey 流程定义key* @return 流程实例ID*/@GetMapping(value = "/startProcessInstanceByKey/{processKey}")public String startProcessInstanceByKey(@PathVariable("processKey") String processKey) {ProcessInstance instance = runtimeService.startProcessInstanceByKey(processKey);return instance.getRootProcessInstanceId();}/*** 查询某个用户的待办任务* @param assignee 用户ID* @return 待办任务列表*/@GetMapping(value = "/getTaskByAssignee/{assignee}")public String getTaskByAssignee(@PathVariable("assignee") String assignee) {List<TaskEntity> taskList = (List)taskService.createTaskQuery().taskAssignee(assignee).list();StringBuffer sb = new StringBuffer();for (Task task : taskList) {String taskTitle = "待办任务ID="+task.getId()+",流程实例ID="+task.getProcessInstanceId()+"\n";System.out.println(taskTitle);sb.append(taskTitle);}return sb.toString();}
}
重启启动Springboot程序,调用刚刚开发的流程接口进行测试。
发起一个流程实例:http://localhost:8080/startProcessInstanceByKey/test1
执行成功,返回了流程实例ID,接着查询用户admin的待办任务:
http://localhost:8080/getTaskByAssignee/admin
4. 绘制流程图介绍
4.1. 绘制
新建一个
我这边稍微画了一个,具体怎么画,就不在细说了,最后效果如下,模拟了个OA的流程
4.2. 任务分类
只介绍最常用的两种
- 用户任务 (User Task)
具体来说就是需要手动执行的任务,即需要我们这变写完业务代码后,调用代码
taskService.complete(taskId, variables);
才会完成的任务
- 系统任务(Service Task)
系统会自动帮我们完成的任务
4.3. 网关
分为这么几类,会根据我们传入的流程变量及设定的条件走
- 排他网关(exclusive gateway)
这个网关只会走一个,我们走到这个网关时,会从上到下找第一个符合条件的任务往下走
- 并行网关(Parallel Gateway)
这个网关不需要设置条件,会走所有的任务
- 包含网关(Inclusive Gateway)
这个网关会走一个或者多个符合条件的任务
示例
如上图包含网关,需要在网关的连线初设置表达式 condition,
参数来自于流程变量
两个参数:
switch2d 、 switch3d
如果 都为true,则走任务1,3
如果 switch2d 为true switch3d为false,则只走任务1
如果 switch3d 为true switch2d为false,则只走任务3
如果都为false,则直接走网关,然后结束
5. 任务相关API介绍
基于service的查询类,都可先构建一个 query,然后在附上查询条件,实例几个
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
List<Task> list = taskService.createTaskQuery().taskAssignee("zhangsan").list();
List<ProcessInstance> instances = runtimeService.createProcessInstanceQuery().listPage(1, 10);
5.1. 查询历史任务
List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().list();
5.2. 查询当前任务/分页
List<Task> list = taskService.createTaskQuery().orderByTaskCreateTime().desc().list();
5.3. 任务回退
大体思路是拿到当前的任务,及当前任务的上一个历史任务,然后重启
代码示例
Task activeTask = taskService.createTaskQuery().taskId(taskId).active().singleResult();
List<HistoricTaskInstance> historicTaskInstance = historyService.createHistoricTaskInstanceQuery().processInstanceId(instanceId).orderByHistoricActivityInstanceStartTime().desc().list();List<HistoricTaskInstance> historicTaskInstances = historicTaskInstance.stream().filter(v -> !v.getTaskDefinitionKey().equals(activeTask.getTaskDefinitionKey())).toList();Assert.notEmpty(historicTaskInstances, "当前已是初始任务!");
HistoricTaskInstance curr = historicTaskInstances.get(0);runtimeService.createProcessInstanceModification(instanceId).cancelAllForActivity(activeTask.getTaskDefinitionKey()).setAnnotation("重新执行").startBeforeActivity(curr.getTaskDefinitionKey()).execute();
5.4. 流程变量
包括流程中产生的变量信息,包括控制流程流转的变量,网关、业务表单中填写的流程需要用到的变量等。很多地方都要用到
流程变量变量传递
变量最终会存在 act_ru_variable
这个表里面
在绘制流程图的时候,如果是用户任务(userService
) 可以设置变量,比如执行人,
写法有这么几种方式
- 写死,就比如 zhangsan
- 表达式,比如上面写的 ${user},这种需要传入参数,其实就是启动参数的时候传入,传入参数,可选值为一个
Map<String, Object>
,之后的流程可查看次参数,上面写的是 user, 所以map里面的key需要带着user,不然会报错。
关于扩展变量,可在流程图绘制这么设定,传递方式还是一样,流程图里面在下面写:
代码:
ProcessInstance instance = runtimeService.startProcessInstanceByKey(key, new HashMap<>());
变量设置
runtimeService.setVariable(instance.getId(), Constants.PATIENT_ID, relatedId);
变量查询
Object variable = runtimeService.getVariable(instance.getId(), Constants.GENERAL_ID);
历史变量查询
HistoricVariableInstance variableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(bo.getId().toString()).variableName(Constants.PATIENT_ID).singleResult();
//变量值
variableInstance.getValue();
//变量名称
variableInstance.getName();
5.5. 针对后端来说任务类型主要有两种。
用户任务-userTask
即需要用户参与的任务,因为工作流执行过程中需要涉及到审批、过审之类的需要用户参与的任务,这个时候需要用户参与,然后调用接口完成任务。
服务任务-serviceTask
即自动执行的任务,比如用户提交后,系统自动存储、修改状态等自动完成的任务。
Type
任务类型是关键,可根据配型配置实现调用 java的方法,spring 的bean方法,等等有这么几种类型
**Delegate Expression **推荐使用 –
在系统任务中,因为是自动执行,所以实际应用中需要嵌入各种业务逻辑,可以在流程图设计中,按照下面方式调用java代码执行,在spring中配置同名的bean
配置表达式,可以实现JavaDelegate接口使用类名配置,快捷写法如下,比较推荐下面这种,此种可灵活配置bean和spring结合使用,注入service等业务方法
@Bean("t17")
JavaDelegate t17() {return execution -> {Map<String, Object> variables = execution.getVariables();Task task = taskService.createTaskQuery().processInstanceId(execution.getProcessInstanceId()).singleResult();//业务逻辑task.setOwner(String.valueOf(dentistId));};
}
Java Class :
配置java类名,需要实现JavaDelegate接口,注意是全路径名,不可以使用Spring的bean配置!!!
@Component
public class T17Delegate implements JavaDelegate {@Overridepublic void execute(DelegateExecution execution) throws Exception {String taskId = execution.getId();String instanceId = execution.getProcessInstanceId();Map<String, Object> variables = execution.getVariables();}
}
下面两种可使用spring的配置
Expression:
EL表达式,调用java类的方法 ,规范:
expression="#{monitorExecution.execution(execution)}"
@Component("monitorExecution")
public class MonitorExecution {public void execution(DelegateExecution execution){String processInstanceId = execution.getProcessInstanceId();}
}
5.6.监听器
任务监听器 - Task Listener
任务监听器用于在某个与任务相关的事件发生时执行自定义Java逻辑或表达式。它只能作为用户任务的子元素添加到流程定义中。请注意,这也必须作为BPMN 2.0扩展元素的子级和Camunda命名空间中发生,因为任务侦听器是专门为Camunda引擎构建的。
适用场景:
@Bean
TaskListener t21() {return delegateTask -> {String taskId = delegateTask.getId();String instanceId = delegateTask.getProcessInstanceId();Map<String, Object> variables = delegateTask.getVariables();// TODO: 20log/3/22delegateTask.setVariable("", "");};
}
执行监听器 - Execution Listener
执行侦听器在流程执行过程中发生某些事件时执行外部Java代码或计算表达式。可以用在任何任务中,可以捕获的事件有:
- 流程实例的开始和结束。
- 进行过渡。
- 活动的开始和结束。
- 网关的开始和结束。
- 中间事件的开始和结束。
- 结束开始事件或开始结束事件
适用场景:每个任务结束时设置任务进度
public class ExampleExecutionListenerOne implements ExecutionListener {public void notify(DelegateExecution execution) throws Exception {execution.setVariable("variableSetInExecutionListener", "firstValue");execution.setVariable("eventReceived", execution.getEventName());}
}
5.7. 扩展属性- Extension properties
扩展属性适用于很多自定义的业务属性,比如设置业务流程进度
5.8. 流程权限及创建人设置
IdentityService
为鉴权相关服务,但是我们实际开发中,一般会用到我们自己的鉴权系统,所以可以使用camunda提供的api来设置,具体可以看IdentityServiceImpl
这个类,其中也是使用了ThreadLocal来保存鉴权信息 ,代码在下面
private ThreadLocal<Authentication> currentAuthentication = new ThreadLocal<Authentication>();
用户信息设置:
// Userutil是我们自己封装的用户工具类
identityService.setAuthenticatedUserId(UserUtil.getUserId().toString());//获取
Authentication authentication = identityService.getCurrentAuthentication();
他内置很多比如开启流程时候,会默认找当前登录的人,这个类DefaultHistoryEventProducer
// set super process instance id
ExecutionEntity superExecution = executionEntity.getSuperExecution();
if (superExecution != null) {evt.setSuperProcessInstanceId(superExecution.getProcessInstanceId());
}//state
evt.setState(HistoricProcessInstance.STATE_ACTIVE);// set start user Id
evt.setStartUserId(Context.getCommandContext().getAuthenticatedUserId());
5.9.任务执行人及发起人设置
//根据任务id设置执行人
taskService.setAssignee(task.getId(), UserUtil.getUserId().toString());
博客地址
代码下载
下面的camunda-demo
相关文章:

Spring Boot 项目集成camunda流程引擎
Spring Boot 项目集成camunda流程引擎 camunda地址 camunda中文地址 使用camunda开源工作流引擎有:通过docker运行、使用springboot集成、部署camunda发行包、基于源代码编译运行等多种方式。 文本重点介绍如何在Spring Boot应用程序中如何集成Camunda Platform开…...
2024.12.2工作复盘
1.今天学了什么? 简单的写了一篇博客,是关于参数校验的问题,参数校验,一个是前后端校验到底一不一致,一个是绕过前端校验,看后台的逻辑到底能不能校验住。 2.今天解决了什么问题? 3.今天完成…...

Hot100 - 二叉树的中序遍历
Hot100 - 二叉树的中序遍历 最佳思路: 中序遍历的顺序是:左子树 -> 根节点 -> 右子树。为了实现这个顺序,我们可以利用栈来模拟递归过程,从而避免栈溢出的问题。在遍历过程中,始终向左子树深入,直到…...
docker build ubuntu ssh
dockerfile 构建镜像 为了使用Dockerfile构建Docker镜像,请遵循以下步骤: 创建一个名为Dockerfile的文件,并在其中定义镜像的构建指令。 FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/ubuntu:24.04# 安装openssh-server和pas…...

三维路径规划|基于黑翅鸢BKA优化算法的三维路径规划Matlab程序
三维路径规划|基于黑翅鸢BKA优化算法的三维路径规划Matlab程序 文章目录 前言三维路径规划|基于黑翅鸢BKA优化算法的三维路径规划Matlab程序基于黑翅鸢BKA优化算法的三维路径规划一、研究基本原理二、黑翅鸢BKA优化算法的基本步骤:三、详细流程四、总结 二、实验结果…...

day01(Linux底层)基础知识
目录 导学 基础知识 1、Bootloader是什么 2、Bootloader的基本作用 3、入式中常见的Bootloader有哪些 4、Linux系统移植为什么要使用bootloader 5、uboot和Bootloader之间的关系 6.Uboot的获取 7、uboot版本命名 8、uboot版本选择 9、uboot的特点 10.Uboot使用 导学…...
flink学习(13)—— 重试机制和维表join
重试机制 当任务出现异常的时候,会直接停止任务——解决方式,重试机制 1、设置checkpoint后,会给任务一个重启策略——无限重启 2、可以手动设置任务的重启策略 代码设置 //开启checkpoint后,默认是无限重启,可以…...
第三方Cookie的消亡与Google服务器端标记的崛起
随着互联网用户对隐私保护的关注日益增强,各大浏览器正在逐步淘汰第三方Cookie。这一变革深刻影响了广告商和数字营销人员的用户跟踪和数据分析方式。然而,Google推出的服务器端标记技术为这一挑战提供了新的解决方案。 什么是第三方Cookie? …...

微信小程序——文档下载功能分享(含代码)
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...
Burp Suite 全面解析:开启你的 Web 安全测试之旅
声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&a…...
Oracle DataGuard 主备正常切换 (Switchover)
前言 众所周知,DataGuard 的切换分为两种情况: 系统正常情况下的切换:这种方式称为 switchover,是无损切换,不会丢失数据。灾难情况下的切换:这种情况下一般主库已经启动不起来了,称为 failov…...
为什么编程语言会设计不可变的对象?字符串不可变?NSString *s = @“hello“变量s是不可变的吗?Rust内部可变性的意义?
为什么编程语言会设计不可变的对象? Java和C#中String是不可变的,StringBuilder是可变的。Obj-C中NSArray是不可变数组,NSMutableArray是可变数组。编程语言设计不可变的对象其实是为了优化(更高性能和节省存储空间)、安全(包括线程安全)。 字符串不可变…...

安装 RabbitMQ 服务
安装 RabbitMQ 服务 一. RabbitMQ 需要依赖 Erlang/OTP 环境 (1) 先去 RabbitMQ 官网,查看 RabbitMQ 需要的 Erlang 支持:https://www.rabbitmq.com/ 进入官网,在 Docs -> Install and Upgrade -> Erlang Version Requirements (2) …...
爬虫—Scrapy 整合 ChromeDriver 实现动态网页拉取
在进行爬虫开发时,使用 Scrapy 配合 ChromeDriver 来模拟真实浏览器加载 JavaScript 渲染内容是一种常见且高效的方法。Scrapy 本身是一个非常强大的爬虫框架,然而它默认使用的是 requests 库来抓取静态网页内容。对于需要通过 JavaScript 渲染的动态网页…...
Linux 进程管理详解
Linux 进程管理详解 引言 在现代操作系统中,进程是执行程序的基本单位。Linux作为一个强大的多任务操作系统,提供了丰富且灵活的机制来管理和控制进程。本文将详细介绍Linux进程管理的基本概念、核心机制以及常用的管理工具,帮助读者深入了…...
MySQL更新JSON字段key:value形式
MySQL更新JSON字段key:value形式 1. 介绍 MySQL的JSON数据类型是MySQL 5.7及以上版本中引入的一种数据类型,用于存储JSON格式的数据。使用JSON数据类型可以自动校验文档是否满足JSON格式的要求,优化存储格式,并允许快速访问文档中的特定…...

vue.js学习(day 18)
实例:面经基础版...
WINDOWS 单链表SLIST_ENTRY使用
1.初始化链表头 //初始化链表头qq1490900437 void InitialGloubleVar() {while (1){G_Handle.SaveProcessThreadHandle (PSLIST_HEADER)_aligned_malloc(sizeof(SLIST_HEADER), MEMORY_ALLOCATION_ALIGNMENT);if (G_Handle.SaveProcessThreadHandle ! NULL){break;}}Initiali…...

【Linux 篇】Docker 容器星河与镜像灯塔:Linux 系统下解锁应用部署奇幻征程
文章目录 【Linux 篇】Docker 容器星河与镜像灯塔:Linux 系统下解锁应用部署奇幻征程前言一 、docker上部署mysql1. 拉取mysql镜像2. 创建容器3. 远程登录mysql 二 、docker上部署nginx1. 拉取nginx镜像2. 在dockerTar目录下 上传nginx.tar rz命令3. 创建nginx容器4…...

不同云计算网络安全等级
导读云计算的本质是服务,如果不能将计算资源规模化/大范围的进行共享,如果不能真正以服务的形式提供,就根本算不上云计算。 等级保护定级流程 定级是开展网络安全等级保护工作的 “基本出发点”,虚拟化技术使得传统的网络边界变…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...

遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

热烈祝贺埃文科技正式加入可信数据空间发展联盟
2025年4月29日,在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上,可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞,强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...

软件工程 期末复习
瀑布模型:计划 螺旋模型:风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合:模块内部功能紧密 模块之间依赖程度小 高内聚:指的是一个模块内部的功能应该紧密相关。换句话说,一个模块应当只实现单一的功能…...