自己瞎折腾,抽空整的Spring Cloud Alibaba 2.2.7 + Camunda 7.17.0大杂烩版本,想啥都加点进去,这边就记录一下Camunda的部分,后续有空再加上其他部分吧(不需要的可以忽略spring cloud alibaba的部分)
父POM文件
<?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>com.grey.demo</groupId>
<artifactId>demo</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>demo_user_service</module>
<module>demo_gateway</module>
<module>demo_business_service</module>
<module>demo_commons</module>
</modules>
<properties>
<spring.cloud-version>2021.0.0</spring.cloud-version>
<spring.boot-version>2.6.2</spring.boot-version>
<spring.cloud.alibaba-version>2.2.7.RELEASE</spring.cloud.alibaba-version>
<lombok-version>1.16.20</lombok-version>
</properties>
<dependencyManagement>
<dependencies>
<!--springcloud-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
子POM文件
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>demo</artifactId>
<groupId>com.grey.demo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>camunda</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>camunda</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.camunda.bpm</groupId>
<artifactId>camunda-bom</artifactId>
<version>7.17.0</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.camunda.bpm.springboot</groupId>
<artifactId>camunda-bpm-spring-boot-starter-rest</artifactId>
</dependency>
<dependency>
<groupId>org.camunda.bpm.springboot</groupId>
<artifactId>camunda-bpm-spring-boot-starter-webapp</artifactId>
</dependency>
<dependency>
<groupId>org.camunda.bpm</groupId>
<artifactId>camunda-engine-plugin-spin</artifactId>
</dependency>
<dependency>
<groupId>org.camunda.spin</groupId>
<artifactId>camunda-spin-dataformat-all</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
yml文件
server:
port: 9077
spring:
application:
name: demo-camunda-service
pathmatch:
matching-strategy: ant_path_matcher # spring boot版本问题
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #Nacos服务注册中心地址
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://####/camunda
username: ####
password: ####
camunda:
admin-user:
id: demo
password: demo
filter:
create: All tasks
database:
schema-update: true
processes.xml
需要在以下路径新建这样一个文件
<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>default</process-engine>
<properties>
<property name="isDeleteUponUndeploy">false</property>
<property name="isScanForProcessDefinitions">true</property>
</properties>
</process-archive>
</process-application>
绘图这边使用官方工具,camunda-modeler,流程图如下,由于是大杂烩,所以一个流程里包括了
1、普通流程(三级领导审批)
2、串行流程(二级领导审批)
3、并行流程(一级领导审批)
这边尤其强调一下串行变量
Collection:指集合名称(所有需要审批人的标识列表)
Element Variable:集合内的元素变量(当处于某个审批人时,该变量里存的会是当前审批人的标识)
Completion Condition:向下流转的条件(这边没设值,会导致必须串行人员全部审批完才能继续走下去)
任务相关操作:任务完成/任务挂起/任务查询/任务删除/任务内变量等操作
RepositoryService
拓扑图部署/删除、流程相关查询等等(与上面的区别是,上面是流程实例,此处为部署的流程)
获取当前部署的全部bpm
由于camunda会记录历史版本,所以你对流程结构进行了修改了一次,就会发现有两个结果
package com.grey.demo.camunda.service.impl;
import com.grey.demo.camunda.controller.response.ProcessDefinitionResponseDTO;
import com.grey.demo.camunda.service.IDeploymentService;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
* 流程引擎部署相关服务
* @author 话离小小灰
* @since 2022/5/11
@Service
public class DeploymentServiceImpl implements IDeploymentService {
* camunda定义服务类
@Resource
private RepositoryService repositoryService;
@Override
public List<ProcessDefinitionResponseDTO> queryProcessDefinitionPages(int firstResult, int maxResults) {
// 构建返回值
List<ProcessDefinitionResponseDTO> processDefinitionResponseDTOS = new ArrayList<>();
// 查询全部已部署的流程
List<ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery().listPage(firstResult, maxResults);
processDefinitions.forEach(processDefinition -> {
ProcessDefinitionResponseDTO processDefinitionResponseDTO = new ProcessDefinitionResponseDTO();
BeanUtils.copyProperties(processDefinition, processDefinitionResponseDTO);
processDefinitionResponseDTOS.add(processDefinitionResponseDTO);
return processDefinitionResponseDTOS;
示例结果(同一张bpm,但是存在两个版本):
一些基础操作
对于流程开启、任务查询、任务完成的基础操作
package com.grey.demo.camunda.service.impl;
import com.grey.demo.camunda.service.ICamundaService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.task.Task;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
* 流程引擎实现类
* @author 话离小小灰
* @since 2022/5/7
@Service
public class CamundaServiceImpl implements ICamundaService {
* 运行实例的业务类
@Resource
private RuntimeService runtimeService;
* 任务相关的业务类
@Resource
private TaskService taskService;
* 开启流程
* @param processDefinitionKey 流程定义key
* @return 流程
public ProcessInstance startProcess(String processDefinitionKey) {
ProcessInstance instance = runtimeService.startProcessInstanceByKey(processDefinitionKey);
if (instance == null) {
throw new RuntimeException("开启流程失败");
return instance;
* 开启流程
* @param processDefinitionKey 流程定义key
* @param map 参数
* @return 流程
public ProcessInstance startProcess(String processDefinitionKey, Map<String, Object> map) {
ProcessInstance instance = runtimeService.startProcessInstanceByKey(processDefinitionKey, map);
if (instance == null) {
throw new RuntimeException("开启流程失败");
return instance;
* 根据组获取task
* @param group 组
* @return 任务列表
public List<Task> getTasksListByGroup(String group) {
return taskService.createTaskQuery().taskCandidateGroup(group).list();
* 根据组获取tasks
* @param groups 组
* @return 任务列表
public List<Task> getTaskCandidateGroupIn(List<String> groups) {
return taskService.createTaskQuery().taskCandidateGroupIn(groups).list();
* 根据用户获取任务列表
* @param userId 用户ID
* @return 任务列表
public List<Task> getTasksListByUser(String userId) {
return taskService.createTaskQuery().taskCandidateUser(userId).list();
* 根据用户名获取任务列表
* @param userName 用户名称
* @return 任务列表
public List<Task> getTaskListByTaskAssignee(String userName) {
return taskService.createTaskQuery().taskAssignee(userName).list();
* 根据任务名称获取任务列表
* @param taskName 任务名称
* @return 任务列表
public List<Task> getTaskListByTaskName(String taskName) {
return taskService.createTaskQuery().taskName(taskName).list();
* 根据流程号获取任务列表
* @param flowId 流程号
* @return 任务列表
public List<Task> getTaskListByFlowId(String flowId) {
return taskService.createTaskQuery().processInstanceId(flowId).list();
* 根据任务名称和组获取任务列表
* @param taskName 任务名称
* @param group 组
* @return 任务列表
public List<Task> getTaskListByTaskNameAndGroup(String taskName, String group) {
return taskService.createTaskQuery().taskName(taskName).taskCandidateGroup(group).list();
* 根据任务ID
* @param taskId 任务ID
* @return 任务列表
public List<Task> getTaskListByTaskId(String taskId) {
return taskService.createTaskQuery().taskId(taskId).list();
* 任务完成
* @param taskId 任务ID
* @return 是否成功
public boolean taskComplete(String taskId) {
taskService.complete(taskId);
return true;
* 任务完成(带参数)
* @param taskId 任务ID
* @param map 参数
* @return 是否成功
public boolean taskComplete(String taskId, Map<String, Object> map) {
taskService.complete(taskId, map);
return true;
Controller
package com.grey.demo.camunda.controller;
import com.grey.demo.camunda.controller.response.ProcessDefinitionResponseDTO;
import com.grey.demo.camunda.service.ICamundaService;
import com.grey.demo.camunda.service.IDeploymentService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.camunda.bpm.engine.task.Task;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
* Camunda测试controller
* @author 话离小小灰
* @since 2022/5/11
@RestController
@RequestMapping("/camunda")
@Api(tags = "Camunda测试API")
public class CamundaDemoController {
* 部署的流程服务类
@Resource
IDeploymentService deploymentService;
* 流程服务类
@Resource
ICamundaService camundaService;
* 获取当前部署的全部流程(包括历史版本)TODO 先懒得分页了
* @param firstResult 开始的游标
* @param maxResults 结束的游标
* @return 分页后的数据
@GetMapping(value = "/listPage")
@ApiOperation("获取当前部署的全部流程")
public List<ProcessDefinitionResponseDTO> listPage(int firstResult, int maxResults) {
return deploymentService.queryProcessDefinitionPages(firstResult, maxResults);
* 开始一个流程
* @param processDefinitionKey 流程key
* @return 流程内容
@PostMapping(value = "/start")
@ApiOperation("开始一个流程")
public String start(String processDefinitionKey) {
return camundaService.startProcess(processDefinitionKey).getId();
* 下一步操作
* @param taskId 任务ID
* @param map 参数
* @return 是否成功
@PostMapping(value = "/next")
@ApiOperation("下一步")
public Boolean next(String taskId, Map<String, Object> map) {
return camundaService.taskComplete(taskId, map);
* 根据流程号获取任务列表 TODO 直接返回会报错,Task可能需要转换
* @param flowId 流程ID
* @return 任务列表
@GetMapping(value = "/getTasks")
@ApiOperation("获取任务列表")
public List<Task> getTasks(String flowId) {
return camundaService.getTaskListByFlowId(flowId);