Camunda大杂烩(一:搭建)
环境
自己瞎折腾,抽空整的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 mvc: 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: bpm: 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:向下流转的条件(这边没设值,会导致必须串行人员全部审批完才能继续走下去)
基础方法
这边列举几个会经常用到的service
RuntimeService
进行时操作(流程实例):开启流程/删除流程/流程挂起、激活/获取流程内变量等操作
TaskService
任务相关操作:任务完成/任务挂起/任务查询/任务删除/任务内变量等操作
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); } }