简单的camunda流程处理开发记录
1. 需求
公司使用的是老版本的activiti5xx开发的流程系统,并且微服务中也有workflow模块,但是需要使用webService调用老的流程服务,我自己简单修改了下workflow模块webService调用部分,修改为本地调用,并且流程引擎修改为camunda,基本实现了流程的代办,发起,结束,跳岗,高亮,公司项目没有使用到camunda的外部任务等特性,里面还可以设置租户信息,进行不同租户流程信息隔离,这里简单记录一下开发代码。
2. 主要实现过程
2.1 pom引用
其中camunda标记部分为流程使用需要的包,其余为业务功能使用包
<?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">
<parent>
<artifactId>credit-camunda</artifactId>
<groupId>cn.git</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>camunda-server</artifactId>
<description>camunda流程引擎模块</description>
<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>cn.git</groupId>
<artifactId>business-common</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
<exclusion>
<groupId>cn.git</groupId>
<artifactId>database-synchronize-client</artifactId>
</exclusion>
<exclusion>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.git</groupId>
<artifactId>camunda-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.git</groupId>
<artifactId>credit-swagger-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.git</groupId>
<artifactId>credit-log-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.git</groupId>
<artifactId>cache-manage-client</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.git</groupId>
<artifactId>credit-discovery-starter</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>cn.git</groupId>
<artifactId>credit-monitor-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-log4j-2.x</artifactId>
<version>8.6.0</version>
</dependency>
<!-- camunda 引擎使用jar包引入 -->
<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.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.21</version>
</dependency>
<!--groovy发送Http请求,底层是对HTTPClient封装 HttpBuilder-->
<dependency>
<groupId>org.codehaus.groovy.modules.http-builder</groupId>
<artifactId>http-builder</artifactId>
<version>0.7.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- compiler -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<!-- package -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.2 调用入口实现
调用入口主要包含controller以及Feign接口两部分,主要实现了基本的流程操作功能,功能如下
- 代办未分类列表信息count查询
- 代办分类列表信息查询
- 获取下一岗位信息
- 获取跟踪列表信息
- 获取跟踪列表操作员列表信息
- 获取流程定义信息列表
- 获取流程任务节点列表信息
- 流程跳岗信息部署方法
- 流程参数信息操作
- 流程图xml获取
- 流程部署
- 部署流程列表
- 等等等
2.2.1 controller实现
package cn.git.camunda.controller;
import cn.git.camunda.dto.*;
import cn.git.camunda.entity.*;
import cn.git.camunda.mapstruct.CamundaConverter;
import cn.git.camunda.page.CamundaFlowPage;
import cn.git.camunda.service.CamundaCommonService;
import cn.git.camunda.util.CamundaTenantEnum;
import cn.git.camunda.vo.*;
import cn.git.common.result.Result;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* @description: camunda通用流程方法类
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2023-09-12 08:46:20
*/
@RestController
@RequestMapping("/flow")
public class CamundaCommonController {
@Autowired
private CamundaConverter camundaConverter;
@Autowired
private CamundaCommonService camundaCommonService;
/**
* 代办未分类列表信息count查询
*
* @param userCd 柜员号
* @param orgCd 机构号
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "代办未分类列表信息count查询", notes = "代办未分类列表信息count查询")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@GetMapping(value = "/listUndoWorkInfoInit")
public Result<CamundaFlowPage<List<CamundaUndoCount>>> listUndoWorkInfoInit(
@ApiParam(name = "userCd", value = "柜员号", required = true)
@RequestParam("userCd") String userCd,
@ApiParam(name = "camundaTenantEnum", value = "租户组信息", required = true)
@RequestParam("camundaTenantEnum") CamundaTenantEnum camundaTenantEnum,
@ApiParam(name = "orgCd", value = "机构号", required = true)
@RequestParam("orgCd") String orgCd) {
// 设置查询参数信息
CamundaUndoCountDTO camundaUndoCountDTO = new CamundaUndoCountDTO();
camundaUndoCountDTO.setOrgCd(orgCd);
camundaUndoCountDTO.setUserCd(userCd);
camundaUndoCountDTO.setCamundaTenantEnum(camundaTenantEnum);
CamundaFlowPage<List<CamundaUndoCount>> camundaFlowPage = camundaCommonService.getUndoCountList(camundaUndoCountDTO);
return Result.ok(camundaFlowPage);
}
/**
* 代办分类列表信息查询
*
* @param undoTaskListInVO 参数inVO
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "代办分类列表信息查询", notes = "代办分类列表信息查询")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/listUndoTaskList")
public Result<CamundaUndoTaskListOutVO> listUndoTaskList(
@Valid @RequestBody CamundaUndoTaskListInVO undoTaskListInVO) {
// 设置查询参数信息
CamundaUndoTaskDTO camundaUndoTaskDTO = camundaConverter.undoListInVOtoDTO(undoTaskListInVO);
CamundaFlowPage<CamundaUndoTask> camundaFlowPage = camundaCommonService.getUndoTaskList(camundaUndoTaskDTO);
CamundaUndoTaskListOutVO undoTaskListOutVO = new CamundaUndoTaskListOutVO();
undoTaskListOutVO.setCamundaFlowPage(camundaFlowPage);
return Result.ok(undoTaskListOutVO);
}
/**
* 结束任务
*
* @param endTaskDTO 结束任务DTO
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "结束任务", notes = "结束任务")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/end")
public Result endTask(@Valid @RequestBody CamundaEndTaskDTO endTaskDTO) {
camundaCommonService.endProcess(endTaskDTO);
return Result.ok();
}
/**
* 发起流程
* @param camundaStartProcessDTO 撤销inVO
*/
@ApiOperation(value = "新发起一个流程", notes = "新发起一个流程")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/start")
public Result<CamundaStartRspDTO> startProcess(@Valid @RequestBody CamundaStartProcessDTO camundaStartProcessDTO) {
CamundaStartRspDTO camundaStartRspDTO = camundaCommonService.startProcess(camundaStartProcessDTO);
return Result.ok(camundaStartRspDTO);
}
/**
* 正常提交流程
* @param submitTaskDTO 提交流程dto
*/
@ApiOperation(value = "正常提交流程", notes = "正常提交流程")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/submit")
public Result<CamundaSubmitTaskRspDTO> submitNormalTask(@Valid @RequestBody CamundaSubmitTaskDTO submitTaskDTO) {
CamundaSubmitTaskRspDTO camundaSubmitTaskRspDTO = camundaCommonService.submitNormalTask(submitTaskDTO);
return Result.ok(camundaSubmitTaskRspDTO);
}
/**
* 流程撤销
* @param camundaCancelInVO 撤销inVO
*/
@ApiOperation(value = "流程撤销", notes = "流程撤销")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/cancel")
public Result cancelProcess(@Valid @RequestBody CamundaCancelInVO camundaCancelInVO) {
// 封装参数
CamundaCancelDTO camundaCancelDTO = new CamundaCancelDTO();
camundaCancelDTO.setProcessId(camundaCancelInVO.getProcessId());
camundaCancelDTO.setCancelReason(camundaCancelInVO.getCancelReason());
camundaCancelDTO.setCamundaTenantEnum(camundaCancelInVO.getCamundaTenantEnum());
camundaCommonService.cancelProcess(camundaCancelDTO);
return Result.ok();
}
/**
* 驳回任务到上一岗或者发起岗
* @param rejectTaskDTO 驳回DTO
*/
@ApiOperation(value = "驳回任务到上一岗或者发起岗", notes = "驳回任务到上一岗或者发起岗")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/reject")
public Result rejectTaskToStartNode(@Valid @RequestBody CamundaRejectTaskDTO rejectTaskDTO) {
// 封装参数
camundaCommonService.rejectTaskToStartNode(rejectTaskDTO);
return Result.ok();
}
/**
* 流程跳跃节点
* @param camundaGotoDTO 跳跃节点DTO
*/
@ApiOperation(value = "流程撤销", notes = "流程撤销")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/gotoTask")
public Result gotoTask(@Valid @RequestBody CamundaGotoDTO camundaGotoDTO) {
// 封装参数
camundaCommonService.gotoDestinationTask(camundaGotoDTO);
return Result.ok();
}
/**
* 获取下一岗位信息
*
* @param nextPositionInVO 参数inVO
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "获取下一岗位信息", notes = "获取下一岗位信息")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/getNextPositionInfo")
public Result<CamundaNextPositionRspDTO> getNextPositionInfo(@Valid @RequestBody CamundaNextPositionInVO nextPositionInVO) {
// 设置查询参数信息
CamundaNextPositionDTO camundaNextPositionDTO = camundaConverter.nextPositionInVOtoDTO(nextPositionInVO);
CamundaNextPositionRspDTO rspDTO = camundaCommonService.getNextPositionList(camundaNextPositionDTO);
return Result.ok(rspDTO);
}
/**
* 获取流程参数信息
*
* @param camundaVariableInVO 流程参数信息获取InVO
*/
@ApiOperation(value = "获取流程参数信息", notes = "获取流程参数信息")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/task/variables")
public Result<CamundaVariableOutVO> getTaskVariables(@Valid @RequestBody CamundaVariableInVO camundaVariableInVO) {
// 封装参数
CamundaVariablesDTO variablesDTO = new CamundaVariablesDTO();
variablesDTO.setTaskId(camundaVariableInVO.getTaskId());
variablesDTO.setVariableKeyList(camundaVariableInVO.getVariableKeyList());
variablesDTO.setCamundaTenantEnum(camundaVariableInVO.getCamundaTenantEnum());
Map<String, Object> taskVariableMap = camundaCommonService.getTaskVariables(variablesDTO);
// 设置响应参数信息
CamundaVariableOutVO camundaVariableOutVO = new CamundaVariableOutVO();
camundaVariableOutVO.setVariableMap(taskVariableMap);
return Result.ok(camundaVariableOutVO);
}
/**
* 删除参数key值
*
* @param taskId 参数id
* @param removeKey 参数key
*/
@ApiOperation(value = "删除参数key值", notes = "删除参数key值")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@GetMapping(value = "/remove/variable")
public Result removeParamByKey(
@ApiParam(name = "removeKey", value = "删除参数的key", required = true)
@NotBlank(message = "删除参数的key不能为空!")
@RequestParam("removeKey") String removeKey,
@ApiParam(name = "camundaTenantEnum", value = "删除参数的key", required = true)
@NotBlank(message = "租户枚举信息不能为空!")
@RequestParam("camundaTenantEnum") CamundaTenantEnum camundaTenantEnum,
@ApiParam(name = "taskId", value = "任务id", required = true)
@NotBlank(message = "删除参数对应taskId不能为空!")
@RequestParam("taskId") String taskId) {
// 进行删除操作
camundaCommonService.removeVariable(taskId, removeKey, camundaTenantEnum);
return Result.ok();
}
/**
* 新增或者修改参数
* @param addOrUpdateVariableInVO 参数inVO
*/
@ApiOperation(value = "新增或者修改参数,原来没有此参数则新增,否则修改", notes = "新增或者修改参数,原来没有此参数则新增,否则修改")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/add/update/variable")
public Result addOrUpdateVariableByKey(@Valid @RequestBody CamundaAddOrUpdateVariableInVO addOrUpdateVariableInVO) {
// 进行删除操作
CamundaAddOrUpdateVariableDTO addOrUpdateVariableDTO = camundaConverter.addOrUpdateVariableInVOtoDTO(addOrUpdateVariableInVO);
camundaCommonService.addOrUpdateVariable(addOrUpdateVariableDTO);
return Result.ok();
}
/**
* 获取跟踪列表信息
*
* @param camundaTraceHistoryDTO 参数dto
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "获取跟踪列表信息", notes = "获取跟踪列表信息")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/getTraceInfo")
public Result<CamundaFlowPage<List<CamundaTraceHistory>>> getTraceInfo(
@Valid @RequestBody CamundaTraceHistoryDTO camundaTraceHistoryDTO) {
// 进行查询
CamundaFlowPage<List<CamundaTraceHistory>> camundaFlowPage = camundaCommonService
.getCamundaTracePage(camundaTraceHistoryDTO);
return Result.ok(camundaFlowPage);
}
/**
* 获取跟踪列表操作员列表信息
*
* @param camundaTraceApproveHistoryDTO 参数dto
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "获取跟踪列表操作员列表信息", notes = "获取跟踪列表操作员列表信息")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/getTraceApproveList")
public Result<CamundaFlowPage<CamundaTraceApproveHistory>> getTraceApproveList(
@Valid @RequestBody CamundaTraceApproveHistoryDTO camundaTraceApproveHistoryDTO) {
// 进行查询
CamundaFlowPage<CamundaTraceApproveHistory> camundaFlowPage = camundaCommonService
.getCamundaTraceApprovePage(camundaTraceApproveHistoryDTO);
return Result.ok(camundaFlowPage);
}
/**
* 获取流程已经部署信息
*
* @param camundaLoadTemplateInVO
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "获取流程已经部署信息", notes = "获取流程已经部署信息")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/load/template/page")
public Result<CamundaLoadTemplateOutVO> getLoadTemplatePage(
@Valid @RequestBody CamundaLoadTemplateInVO camundaLoadTemplateInVO) {
// 参数赋值操作
CamundaLoadTemplateDTO templateDTO = new CamundaLoadTemplateDTO();
templateDTO.setTemplateKey(camundaLoadTemplateInVO.getTemplateKey());
templateDTO.setTemplateName(camundaLoadTemplateInVO.getTemplateName());
templateDTO.setVersion(camundaLoadTemplateInVO.getVersion());
templateDTO.setCamundaTenantEnum(camundaLoadTemplateInVO.getCamundaTenantEnum());
// 进行查询
CamundaFlowPage<CamundaLoadTemplate> camundaFlowPage = camundaCommonService
.getLoadTemplatePage(templateDTO);
CamundaLoadTemplateOutVO outVO = new CamundaLoadTemplateOutVO();
outVO.setPageBean(camundaFlowPage);
return Result.ok(outVO);
}
/**
* 获取流程定义信息列表
*
* @param camundaDeployDTO 参数dto
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "获取流程定义信息列表", notes = "获取流程定义信息列表")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/getProcessDeployInfoPage")
public Result<CamundaFlowPage<ActReProcdef>> getProcessDeployInfoPage(
@Valid @RequestBody CamundaDeployDTO camundaDeployDTO) {
// 进行查询
CamundaFlowPage<ActReProcdef> camundaCommonServiceReProcessDeployPage = camundaCommonService
.getReProcessDeployPage(camundaDeployDTO);
return Result.ok(camundaCommonServiceReProcessDeployPage);
}
/**
* 获取流程任务节点列表信息
*
* @param camundaJumpPointPageDTO 参数dto
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "获取流程任务节点列表信息", notes = "获取流程任务节点列表信息")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/getJumpPointPage")
public Result<CamundaFlowPage<CamundaJumpPoint>> getJumpPointPage(
@Valid @RequestBody CamundaJumpPointPageDTO camundaJumpPointPageDTO) {
// 进行查询
CamundaFlowPage<CamundaJumpPoint> camundaCommonServiceJumpPointPage = camundaCommonService
.getJumpPointPage(camundaJumpPointPageDTO);
return Result.ok(camundaCommonServiceJumpPointPage);
}
/**
* 流程跳岗信息部署方法
*
* @param processDefinitionId 流程定义id
* @param orgCd 机构cd
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "流程跳岗信息部署方法", notes = "流程跳岗信息部署方法")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@GetMapping(value = "/loadProcessDefinition/{processDefinitionId}/{orgCd}")
public Result loadProcessDefinition(@PathVariable(value = "processDefinitionId") String processDefinitionId,
@PathVariable(value = "orgCd") String orgCd) {
// 进行查询
camundaCommonService.loadProcessDefinition(processDefinitionId, orgCd);
return Result.ok();
}
/**
* 通过版本号,流程定义processDefinitionId获取流程定义xml信息
*
* @param processDefinitionKey 流程定义key
* @param version 版本编号
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "通过版本号,流程定义processDefinitionKey获取流程定义xml信息", notes = "通过版本号,流程定义processDefinitionKey获取流程定义xml信息")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@GetMapping(value = "/definition/xml/{processDefinitionKey}/{version}")
public Result<String> getDefinitionXMLByKeyAndVersion(
@PathVariable(value = "processDefinitionKey") String processDefinitionKey,
@PathVariable(value = "version") Integer version,
@ApiParam(name = "camundaTenantEnum", value = "租户信息", required = true)
@RequestParam("camundaTenantEnum") CamundaTenantEnum camundaTenantEnum) throws IOException {
// 进行查询
String definitionXMLStr = camundaCommonService.getDefinitionXMLByKeyAndVersion(processDefinitionKey,
version,
camundaTenantEnum);
return Result.ok(definitionXMLStr);
}
/**
* 通过processId下载获取流程xml
* @param processId
* @return
*/
@ApiOperation(value = "通过processId获取流程xml", notes = "通过processId获取流程xml")
@PostMapping(value = "/definition/xml/{processId}")
public void downloadFile(
@ApiParam(name = "processId", value = "流程实例Id", required = true)
@PathVariable(value = "processId") String processId,
@ApiParam(name = "camundaTenantEnum", value = "租户枚举信息", required = true)
@RequestParam("camundaTenantEnum") CamundaTenantEnum camundaTenantEnum) throws IOException {
// 获取文件
camundaCommonService.getDefinitionXMLByProcessId(processId, camundaTenantEnum);
}
/**
* 通过processId获取流程图XML字符串
* @param processId
* @return
*/
@ApiOperation(value = "通过processId获取流程图XML字符串", notes = "通过processId获取流程图XML字符串")
@PostMapping(value = "/definition/str/xml/{processId}")
public Result<String> getDefinitionXMLStr(
@ApiParam(name = "processId", value = "流程实例Id", required = true)
@PathVariable(value = "processId") String processId,
@ApiParam(name = "camundaTenantEnum", value = "租户枚举信息", required = true)
@RequestParam(value = "camundaTenantEnum") CamundaTenantEnum camundaTenantEnum) throws IOException {
// 获取文件
String xmlStr = camundaCommonService.getDefinitionXMLStrByProcessId(processId, camundaTenantEnum);
return Result.ok(xmlStr);
}
/**
* 获取流程高亮线等,高亮任务等
*
* @param taskId taskId
* @param orgCd 机构cd
* @param userCd 柜员编号
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "流程跳岗信息部署方法", notes = "流程跳岗信息部署方法")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@GetMapping(value = "/highlight/lines/{taskId}/{userCd}/{orgCd}")
public Result<CamundaTaskImageNodeRspDTO> loadProcessDefinition(
@ApiParam(name = "taskId", value = "任务id", required = true)
@PathVariable(value = "taskId") String taskId,
@ApiParam(name = "userCd", value = "柜员cd", required = true)
@PathVariable(value = "userCd") String userCd,
@ApiParam(name = "orgCd", value = "机构cd", required = true)
@PathVariable(value = "orgCd") String orgCd) {
// 封装参数
CamundaTaskImageDTO camundaTaskImageDTO = new CamundaTaskImageDTO();
camundaTaskImageDTO.setTaskId(taskId);
camundaTaskImageDTO.setUserCd(userCd);
camundaTaskImageDTO.setOrgCd(orgCd);
CamundaTaskImageNodeRspDTO rspDTO = camundaCommonService.getCamundaTaskImage(camundaTaskImageDTO);
return Result.ok(rspDTO);
}
/**
* 通过文件部署流程图, 文件格式为xml
* @return
*/
@ApiOperation(value = "直接通过文件部署新流程图", notes = "部署新流程图,返回流程部署成功的流程定义id[processDefinitionId]")
@PostMapping(value = "/deploy/process")
public Result<String> uploadProcessDefinition(
@ApiParam(name = "tenantEnum", value = "租户id", required = true)
@RequestParam(value = "tenantEnum") CamundaTenantEnum tenantEnum,
@RequestParam MultipartFile file) throws IOException {
// 获取文件进行部署
String processDefinitionId = camundaCommonService.deployProcess(file, tenantEnum);
return Result.ok(processDefinitionId);
}
}
2.2.2 feign接口实现
feign接口定义类
package cn.git.camunda.api;
import cn.git.camunda.dto.*;
import cn.git.camunda.entity.CamundaTraceApproveHistory;
import cn.git.camunda.entity.CamundaTraceHistory;
import cn.git.camunda.page.CamundaFlowPage;
import cn.git.camunda.util.CamundaTenantEnum;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.List;
/**
* @description: camunda服务feign调用api
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2024-05-11
*/
@RequestMapping("/flow/feign/api")
public interface CamundaApi {
/**
* 发起流程
* @param startProcessDTO 参数dto
* @return rspDTO
*/
@PostMapping("/start")
CamundaStartRspDTO startProcess(@RequestBody CamundaStartProcessDTO startProcessDTO);
/**
* 撤销任务
* @param camundaCancelDTO 参数dto
*/
@PostMapping("/cancel")
void cancelProcess(@RequestBody CamundaCancelDTO camundaCancelDTO);
/**
* 任务驳回到发起岗或者上一岗位
* @param camundaRejectTaskDTO
* @return
*/
@PostMapping("/reject")
Boolean rejectTaskToStartNode(@RequestBody CamundaRejectTaskDTO camundaRejectTaskDTO);
/**
* 提交普通任务
* @param camundaSubmitTaskDTO 参数dto
* @return
*/
@PostMapping("/submit")
CamundaSubmitTaskRspDTO submitNormalTask(@RequestBody CamundaSubmitTaskDTO camundaSubmitTaskDTO);
/**
* 结束任务
* @param endTaskDTO 参数dto
*/
@PostMapping("/end")
void endProcess(@RequestBody CamundaEndTaskDTO endTaskDTO);
/**
* 获取下一处理岗位信息
* @param camundaNextPositionDTO
* @return
*/
@PostMapping("/position")
CamundaNextPositionRspDTO getNextPositionList(@RequestBody CamundaNextPositionDTO camundaNextPositionDTO);
/**
* 跳转到目标节点
* @param camundaGotoDTO
* @return
*/
@PostMapping("/goto")
Boolean gotoDestinationTask(@RequestBody CamundaGotoDTO camundaGotoDTO);
/**
* 获取流程图XML字符串
* @param processId 流程实例id
*/
@GetMapping("/xml")
String getDefinitionXMLStrByProcessId(@RequestParam("processId") String processId,
@RequestParam("camundaTenantEnum") CamundaTenantEnum camundaTenantEnum)
throws IOException;
/**
* 获取跟踪列表信息
* @param camundaTraceHistoryDTO 参数dto
* @return
*/
@PostMapping("/trace")
CamundaFlowPage<List<CamundaTraceHistory>> getCamundaTracePage(@RequestBody CamundaTraceHistoryDTO camundaTraceHistoryDTO);
/**
* 跟踪列表处理人列表信息
* @param camundaTraceApproveHistoryDTO 参数dto
* @return
*/
@PostMapping("/trace/approve")
CamundaFlowPage<CamundaTraceApproveHistory> getCamundaTraceApprovePage(@RequestBody CamundaTraceApproveHistoryDTO camundaTraceApproveHistoryDTO);
}
feign接口实现类
package cn.git.camunda.manage;
import cn.git.camunda.api.CamundaApi;
import cn.git.camunda.dto.*;
import cn.git.camunda.entity.CamundaTraceApproveHistory;
import cn.git.camunda.entity.CamundaTraceHistory;
import cn.git.camunda.page.CamundaFlowPage;
import cn.git.camunda.service.CamundaCommonService;
import cn.git.camunda.util.CamundaTenantEnum;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.util.List;
/**
* @description: camundaApi外围feign接口实现类
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2024-05-11
*/
@Api(value = "camundaApi外围feign接口实现类", tags = "camundaApi外围feign接口实现类")
@RestController
public class CamundaApiImpl implements CamundaApi {
private CamundaCommonService commonService;
/**
* 发起流程
*
* @param startProcessDTO 参数dto
* @return rspDTO
*/
@Override
public CamundaStartRspDTO startProcess(CamundaStartProcessDTO startProcessDTO) {
return commonService.startProcess(startProcessDTO);
}
/**
* 撤销任务
*
* @param camundaCancelDTO 参数dto
*/
@Override
public void cancelProcess(CamundaCancelDTO camundaCancelDTO) {
commonService.cancelProcess(camundaCancelDTO);
}
/**
* 任务驳回到发起岗或者上一岗位
*
* @param camundaRejectTaskDTO
* @return
*/
@Override
public Boolean rejectTaskToStartNode(CamundaRejectTaskDTO camundaRejectTaskDTO) {
return commonService.rejectTaskToStartNode(camundaRejectTaskDTO);
}
/**
* 提交普通任务
*
* @param camundaSubmitTaskDTO 参数dto
* @return
*/
@Override
public CamundaSubmitTaskRspDTO submitNormalTask(CamundaSubmitTaskDTO camundaSubmitTaskDTO) {
return commonService.submitNormalTask(camundaSubmitTaskDTO);
}
/**
* 结束任务
*
* @param endTaskDTO 参数dto
*/
@Override
public void endProcess(CamundaEndTaskDTO endTaskDTO) {
commonService.endProcess(endTaskDTO);
}
/**
* 获取下一处理岗位信息
*
* @param camundaNextPositionDTO
* @return
*/
@Override
public CamundaNextPositionRspDTO getNextPositionList(CamundaNextPositionDTO camundaNextPositionDTO) {
return commonService.getNextPositionList(camundaNextPositionDTO);
}
/**
* 跳转到目标节点
*
* @param camundaGotoDTO
* @return
*/
@Override
public Boolean gotoDestinationTask(CamundaGotoDTO camundaGotoDTO) {
return commonService.gotoDestinationTask(camundaGotoDTO);
}
/**
* 获取流程图XML字符串
*
* @param processId 流程实例id
*/
@Override
public String getDefinitionXMLStrByProcessId(String processId, CamundaTenantEnum camundaTenantEnum) throws IOException {
return commonService.getDefinitionXMLStrByProcessId(processId, camundaTenantEnum);
}
/**
* 获取跟踪列表信息
*
* @param camundaTraceHistoryDTO 参数dto
* @return
*/
@Override
public CamundaFlowPage<List<CamundaTraceHistory>> getCamundaTracePage(CamundaTraceHistoryDTO camundaTraceHistoryDTO) {
return commonService.getCamundaTracePage(camundaTraceHistoryDTO);
}
/**
* 跟踪列表处理人列表信息
*
* @param camundaTraceApproveHistoryDTO 参数dto
* @return
*/
@Override
public CamundaFlowPage<CamundaTraceApproveHistory> getCamundaTraceApprovePage(CamundaTraceApproveHistoryDTO camundaTraceApproveHistoryDTO) {
return commonService.getCamundaTraceApprovePage(camundaTraceApproveHistoryDTO);
}
}
2.3 service接口
package cn.git.camunda.service;
import cn.git.camunda.dto.*;
import cn.git.camunda.entity.*;
import cn.git.camunda.page.CamundaFlowPage;
import cn.git.camunda.util.CamundaTenantEnum;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* @description: camunda通用方法service
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2023-09-12 08:58:58
*/
public interface CamundaCommonService {
/**
* 发起流程
* @param startProcessDTO 参数dto
* @return rspDTO
*/
CamundaStartRspDTO startProcess(CamundaStartProcessDTO startProcessDTO);
/**
* 查询未分类代办列表信息
* @param camundaUndoCountDTO 参数dto
* @return
*/
CamundaFlowPage<List<CamundaUndoCount>> getUndoCountList(CamundaUndoCountDTO camundaUndoCountDTO);
/**
* 查询代办分类后单一业务列表信息
* @param camundaUndoTaskDTO 参数dto
* @return
*/
CamundaFlowPage<CamundaUndoTask> getUndoTaskList(CamundaUndoTaskDTO camundaUndoTaskDTO);
/**
* 结束任务
* @param endTaskDTO 参数dto
*/
void endProcess(CamundaEndTaskDTO endTaskDTO);
/**
* 撤销任务
* @param camundaCancelDTO 参数dto
*/
void cancelProcess(CamundaCancelDTO camundaCancelDTO);
/**
* 提交普通任务
* @param camundaSubmitTaskDTO 参数dto
* @return
*/
CamundaSubmitTaskRspDTO submitNormalTask(CamundaSubmitTaskDTO camundaSubmitTaskDTO);
/**
* 获取下一处理岗位信息
* @param camundaNextPositionDTO
* @return
*/
CamundaNextPositionRspDTO getNextPositionList(CamundaNextPositionDTO camundaNextPositionDTO);
/**
* 获取任务变量信息
* @param camundaVariablesDTO 参数DTO
* @return
*/
Map<String, Object> getTaskVariables(CamundaVariablesDTO camundaVariablesDTO);
/**
* 删除参数key值
* @param taskId 参数id
* @param removeKey 参数key
* @param camundaTenantEnum 租户枚举
* @return
*/
void removeVariable(String taskId, String removeKey, CamundaTenantEnum camundaTenantEnum);
/**
* 新增或者修改参数
* @param addOrUpdateVariableDTO 参数DTO
* @return
*/
void addOrUpdateVariable(CamundaAddOrUpdateVariableDTO addOrUpdateVariableDTO);
/**
* 部署流程定义信息到本地库表中
* @param processDefinitionId 流程定义id
* @param orgCd 机构cd
*/
void loadProcessDefinition(String processDefinitionId, String orgCd);
/**
* 操作跳跃节点信息
* @param camundaJumpPointSetDTO 参数dto
*/
void optionJumpPoint(CamundaJumpPointSetDTO camundaJumpPointSetDTO);
/**
* 获取全部流程定义列表信息
* @param camundaDeployDTO 参数dto
* @return
*/
CamundaFlowPage<ActReProcdef> getReProcessDeployPage(CamundaDeployDTO camundaDeployDTO);
/**
* 获取任务节点信息
* @param jumpPointPageDTO 参数dto
* @return
*/
CamundaFlowPage<CamundaJumpPoint> getJumpPointPage(CamundaJumpPointPageDTO jumpPointPageDTO);
/**
* 获取跟踪列表信息
* @param camundaTraceHistoryDTO 参数dto
* @return
*/
CamundaFlowPage<List<CamundaTraceHistory>> getCamundaTracePage(CamundaTraceHistoryDTO camundaTraceHistoryDTO);
/**
* 跟踪列表处理人列表信息
* @param camundaTraceApproveHistoryDTO 参数dto
* @return
*/
CamundaFlowPage<CamundaTraceApproveHistory> getCamundaTraceApprovePage(CamundaTraceApproveHistoryDTO camundaTraceApproveHistoryDTO);
/**
* 获取已经部署流程模板列表信息
* @param camundaLoadTemplateDTO 参数dto
* @return
*/
CamundaFlowPage<CamundaLoadTemplate> getLoadTemplatePage(CamundaLoadTemplateDTO camundaLoadTemplateDTO);
/**
* 任务驳回到发起岗或者上一岗位
* @param camundaRejectTaskDTO
* @return
*/
Boolean rejectTaskToStartNode(CamundaRejectTaskDTO camundaRejectTaskDTO);
/**
* 跳转到目标节点
* @param camundaGotoDTO
* @return
*/
Boolean gotoDestinationTask(CamundaGotoDTO camundaGotoDTO);
/**
* 获取当前任务完成节点,连线,未完成节点信息
* @param camundaTaskImageDTO 参数dto
* @return
*/
CamundaTaskImageNodeRspDTO getCamundaTaskImage(CamundaTaskImageDTO camundaTaskImageDTO);
/**
* 通过版本号,流程定义processDefinitionId获取流程定义xml信息
*
* @param processDefinitionId 流程定义id
* @param camundaTenantEnum 租户枚举
* @param version 版本编号
*/
String getDefinitionXMLByKeyAndVersion(String processDefinitionId, Integer version, CamundaTenantEnum camundaTenantEnum) throws IOException;
/**
* 获取流程图
* @param processId 流程实例id
* @param camundaTenantEnum 租户枚举
*/
void getDefinitionXMLByProcessId(String processId, CamundaTenantEnum camundaTenantEnum) throws IOException;
/**
* 获取流程图XML字符串
* @param processId 流程实例id
*/
String getDefinitionXMLStrByProcessId(String processId, CamundaTenantEnum camundaTenantEnum) throws IOException;
/**
* 部署流程
* @param file 文件
* @param tenantEnum 租户
*/
String deployProcess(MultipartFile file, CamundaTenantEnum tenantEnum) throws IOException;
}
2.4 service接口实现类
这里面主要是流程具体操作的实现类,我这边处理,流程主要跟业务需求关联比较大,所以会有很多业务相关参数,判定条件出现在流程中,主要用于网关参数流向判定
package cn.git.camunda.service.impl;
import cn.git.camunda.consts.CamundaConst;
import cn.git.camunda.dto.*;
import cn.git.camunda.entity.*;
import cn.git.camunda.mapper.ActReProcdefMapper;
import cn.git.camunda.mapper.CamundaJumpPointMapper;
import cn.git.camunda.mapper.CamundaUnfinishedFlowMapper;
import cn.git.camunda.page.CamundaFlowPage;
import cn.git.camunda.page.PageUtil;
import cn.git.camunda.service.CamundaCommonService;
import cn.git.camunda.util.CamundaFlowTypeEnum;
import cn.git.camunda.util.CamundaSysEnum;
import cn.git.camunda.util.CamundaTenantEnum;
import cn.git.camunda.util.CamundaUtil;
import cn.git.common.exception.ServiceException;
import cn.git.common.page.PaginationContext;
import cn.git.common.util.LogUtil;
import cn.git.common.util.WebUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.camunda.bpm.engine.*;
import org.camunda.bpm.engine.history.*;
import org.camunda.bpm.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.camunda.bpm.engine.impl.pvm.PvmActivity;
import org.camunda.bpm.engine.impl.pvm.PvmTransition;
import org.camunda.bpm.engine.impl.pvm.process.ActivityImpl;
import org.camunda.bpm.engine.repository.Deployment;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.repository.ProcessDefinitionQuery;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.runtime.ProcessInstanceModificationInstantiationBuilder;
import org.camunda.bpm.engine.runtime.ProcessInstantiationBuilder;
import org.camunda.bpm.engine.task.Comment;
import org.camunda.bpm.engine.task.Task;
import org.camunda.bpm.engine.task.TaskQuery;
import org.camunda.bpm.engine.variable.VariableMap;
import org.camunda.bpm.engine.variable.Variables;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.camunda.bpm.model.bpmn.impl.instance.ProcessImpl;
import org.camunda.bpm.model.bpmn.impl.instance.UserTaskImpl;
import org.camunda.bpm.model.bpmn.instance.FlowNode;
import org.camunda.bpm.model.bpmn.instance.Process;
import org.camunda.bpm.model.bpmn.instance.SequenceFlow;
import org.camunda.bpm.model.bpmn.instance.UserTask;
import org.camunda.bpm.model.xml.instance.ModelElementInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @description: camunda通用方法service
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2023-09-12 09:12:05
*/
@Slf4j
@Service
public class CamundaCommonServiceImpl implements CamundaCommonService {
@Autowired
private TaskService taskService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private IdentityService identityService;
@Autowired
private RepositoryService repositoryService;
@Autowired
private HistoryService historyService;
@Autowired
private ProcessEngine processEngine;
@Autowired
private CamundaUnfinishedFlowMapper camundaUnfinishedFlowMapper;
@Autowired
private ActReProcdefMapper actReProcdefMapper;
@Autowired
private CamundaJumpPointMapper camundaJumpPointMapper;
@Autowired
private FormService formService;
@Autowired
private PageUtil pageUtil;
@Autowired
private CamundaUtil camundaUtil;
@Autowired
private HttpServletResponse response;
@Autowired
private WebUtil webUtil;
/**
* 发起流程
*
* @param startProcessDTO 参数dto
* @return rspDTO
*/
@Override
@Transactional(rollbackFor = Exception.class)
public CamundaStartRspDTO startProcess(CamundaStartProcessDTO startProcessDTO) {
// 发起流程key
String businessKey = startProcessDTO.getBusinessKey();
log.info("businessKey[{}]准备发起流程,入参startProcessDTO为[{}]",
businessKey,
JSONObject.toJSONString(startProcessDTO));
// 设置发起流程操作员标识,以及认证信息(group组信息,tenantId租户信息)
String creator = startProcessDTO.getUserCd().concat(StrUtil.COLON).concat(startProcessDTO.getOrgCd());
identityService.setAuthentication(creator,
Arrays.asList(startProcessDTO.getCamundaTenantEnum().getGroup()),
Arrays.asList(startProcessDTO.getCamundaTenantEnum().getTenantId()));
log.info("businessKey[{}]发起流程设置操作员信息成功", businessKey);
// 设置传递参数信息
VariableMap variableMap = Variables.createVariables();
// 流程发起用户id
variableMap.put(CamundaConst.USER_ID_FLAG, creator);
// 流程模板id
variableMap.put(CamundaConst.PROCESS_TEMPLATE_KEY, startProcessDTO.getCamundaFlowTypeEnum().getProcessTemplateKey());
// 流程业务id
variableMap.put(CamundaConst.BUSINESS_KEY_FLAG, startProcessDTO.getBusinessKey());
// 流程业务类型
variableMap.put(CamundaConst.PROCESS_BIZ_TYPE, startProcessDTO.getCamundaFlowTypeEnum().getBizType());
// 流程业务名称
variableMap.put(CamundaConst.PROCESS_BIZ_NAME, startProcessDTO.getCamundaFlowTypeEnum().getBizName());
// 流程发起人
variableMap.put(CamundaConst.PROCESS_CREATOR, creator);
// 设置机构信息
variableMap.put(CamundaConst.ORG_NAME_FLAG, webUtil.getCurrentOrgName());
// 客户名称
variableMap.put(CamundaConst.CUSTOMER_NAME_FLAG, startProcessDTO.getCustomerName());
// 客户编号
variableMap.put(CamundaConst.CUSTOMER_NUM_FLAG, startProcessDTO.getCustomerNum());
// 发起系统来源
variableMap.put(CamundaConst.SYSTEM, startProcessDTO.getCamundaSysEnum().getSystemFlag());
// 设置自定义参数信息
if (ObjectUtil.isNotEmpty(startProcessDTO.getVariableMap())) {
variableMap.putAll(startProcessDTO.getVariableMap());
log.info("businessKey[{}]发起流程设置操作参数信息成功,参数为[{}]", businessKey, JSONObject.toJSONString(variableMap));
}
// 发起流程
log.info("businessKey[{}]装备发起流程!", businessKey);
String templateKey = startProcessDTO.getCamundaFlowTypeEnum().getProcessTemplateKey();
ProcessInstantiationBuilder builder = runtimeService.createProcessInstanceByKey(templateKey)
.processDefinitionTenantId(startProcessDTO.getCamundaTenantEnum().getTenantId())
.businessKey(startProcessDTO.getBusinessKey())
.setVariables(variableMap);
ProcessInstance processInstance = builder.execute();
// 设置响应信息
CamundaStartRspDTO camundaStartRspDTO = null;
if (ObjectUtil.isNotNull(processInstance)) {
camundaStartRspDTO = new CamundaStartRspDTO();
// 流程processId
String processInstanceId = processInstance.getProcessInstanceId();
// 通过 processId,获取task信息进行返回
Task task = taskService.createTaskQuery()
.tenantIdIn(startProcessDTO.getCamundaTenantEnum().getTenantId())
.processInstanceId(processInstanceId).singleResult();
if (ObjectUtil.isNotNull(task)) {
camundaStartRspDTO.setProcessId(processInstanceId);
camundaStartRspDTO.setTaskId(task.getId());
camundaStartRspDTO.setTaskName(task.getName());
// 当前流程任务定义key
camundaStartRspDTO.setTaskDefinitionKey(task.getTaskDefinitionKey());
log.info("businessKey[{}],发起流程后,获取任务信息为[{}]",
businessKey,
JSONObject.toJSONString(camundaStartRspDTO));
// 新增业务插入到在途业务表中,自定义代办任务记录表,业务系统方便查询。
CamundaUnfinishedFlow camundaUnfinishedFlow = new CamundaUnfinishedFlow();
camundaUnfinishedFlow.setId(IdUtil.simpleUUID());
camundaUnfinishedFlow.setOptionOrgCd(startProcessDTO.getUserCd());
camundaUnfinishedFlow.setOptionOrgCd(startProcessDTO.getOrgCd());
camundaUnfinishedFlow.setCustomerNum(startProcessDTO.getCustomerNum());
camundaUnfinishedFlow.setCustomerName(startProcessDTO.getCustomerName());
camundaUnfinishedFlow.setBusinessKey(startProcessDTO.getBusinessKey());
camundaUnfinishedFlow.setProcessId(processInstanceId);
camundaUnfinishedFlow.setBizName(startProcessDTO.getCamundaFlowTypeEnum().getBizName());
camundaUnfinishedFlow.setProcessTemplateKey(startProcessDTO.getCamundaFlowTypeEnum().getProcessTemplateKey());
if (ObjectUtil.isNotNull(startProcessDTO.getCamundaSysEnum())) {
camundaUnfinishedFlow.setSystemFlag(startProcessDTO.getCamundaSysEnum().getSystemFlag());
} else {
camundaUnfinishedFlow.setSystemFlag(CamundaSysEnum.DICS.getSystemFlag());
}
camundaUnfinishedFlowMapper.insert(camundaUnfinishedFlow);
}
}
return camundaStartRspDTO;
}
/**
* 通过柜员编号和机构编号获取代办未分类列表信息
*
* @param camundaUndoCountDTO 参数dto
* @return
*/
@Override
public CamundaFlowPage<List<CamundaUndoCount>> getUndoCountList(CamundaUndoCountDTO camundaUndoCountDTO) {
// 创建一个查询接口,进行传入操作标识人员代办任务查询
String userId = camundaUndoCountDTO.getUserCd().concat(StrUtil.COLON).concat(camundaUndoCountDTO.getOrgCd());
TaskQuery taskQuery = taskService.createTaskQuery()
// 具体操作人员标识
.taskAssignee(userId)
// 未被挂起任务
.active()
// 租户信息
.tenantIdIn(camundaUndoCountDTO.getCamundaTenantEnum().getTenantId())
// 获取参数信息
.matchVariableNamesIgnoreCase();
// 设定查询模板类型
if (StrUtil.isNotBlank(camundaUndoCountDTO.getProcessTemplateKey())) {
taskQuery.processDefinitionKey(camundaUndoCountDTO.getProcessTemplateKey());
}
// 查询带如下参数的流程信息
Map<String, Object> paramMap = camundaUndoCountDTO.getParamMap();
if (ObjectUtil.isNotEmpty(paramMap)) {
for (String key : camundaUndoCountDTO.getParamMap().keySet()) {
taskQuery.processVariableValueEquals(key, paramMap.get(key));
}
}
// 计算从哪条开始取,如何取出数据
List<Task> taskList = taskQuery.list();
// 对代办数据进行分类求count处理
List<CamundaUndoCount> camundaUndoCountList = new ArrayList<>();
if (ObjectUtil.isNotEmpty(taskList)) {
// 获取所有任务代办任务类型数据
List<String> processIdList = taskList.stream().map(Task::getProcessInstanceId).collect(Collectors.toList());
QueryWrapper<CamundaUnfinishedFlow> unfinishedFlowQueryWrapper = new QueryWrapper<>();
unfinishedFlowQueryWrapper.lambda().in(CamundaUnfinishedFlow::getProcessId, processIdList);
List<CamundaUnfinishedFlow> unfinishedFlowList = camundaUnfinishedFlowMapper
.selectList(unfinishedFlowQueryWrapper);
// 将查询数据转换为map信息
Map<String, CamundaUnfinishedFlow> unfinishedFlowMap = unfinishedFlowList.stream().collect(
Collectors.toMap(
CamundaUnfinishedFlow::getProcessId, Function.identity(), (k1, k2) -> k1
)
);
Map<String, CamundaUndoCount> undoCountMap = new HashMap<>(CamundaConst.INT_16);
taskList.forEach(task -> {
// 对任务进行分类计算count信息
CamundaUnfinishedFlow unfinishedFlow = unfinishedFlowMap.get(task.getProcessInstanceId());
if (ObjectUtil.isNotNull(unfinishedFlow)) {
// 获取流程模板id以及流程模板枚举类型
String processTemplateKey = unfinishedFlow.getProcessTemplateKey();
CamundaFlowTypeEnum flowTypeEnum = camundaUtil.getCamundaEnumByTemplateKey(processTemplateKey);
if (ObjectUtil.isNotNull(flowTypeEnum)) {
// 如果此类型有值,则count数进行加一
if (ObjectUtil.isNotNull(undoCountMap.get(processTemplateKey))) {
CamundaUndoCount currentUndoCount = undoCountMap.get(processTemplateKey);
currentUndoCount.setBizCount(currentUndoCount.getBizCount() + 1);
undoCountMap.put(processTemplateKey, currentUndoCount);
} else {
// 首次添加
CamundaUndoCount camundaUndoCount = new CamundaUndoCount();
camundaUndoCount.setBizCount(CamundaConst.INT_1);
camundaUndoCount.setBizTypeName(flowTypeEnum.getBizName());
camundaUndoCount.setBizType(flowTypeEnum.getBizType());
undoCountMap.put(processTemplateKey, camundaUndoCount);
}
}
}
});
// 封装返回信息list
if (ObjectUtil.isNotEmpty(undoCountMap)) {
undoCountMap.forEach((key, value) -> {
camundaUndoCountList.add(value);
});
}
}
return pageUtil.setFlowListPage(camundaUndoCountList, PaginationContext.getPageNum(), PaginationContext.getPageSize());
}
/**
* 查询代办分类后单一业务列表信息
*
* @param camundaUndoTaskDTO 参数dto
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public CamundaFlowPage<CamundaUndoTask> getUndoTaskList(CamundaUndoTaskDTO camundaUndoTaskDTO) {
// 创建一个查询接口,进行传入操作标识人员代办任务查询
String userId = camundaUndoTaskDTO.getUserCd().concat(StrUtil.COLON).concat(camundaUndoTaskDTO.getOrgCd());
TaskQuery taskQuery = taskService.createTaskQuery()
// 具体操作人员标识
.taskAssignee(userId)
// 未被挂起任务
.active()
// 租户信息
.tenantIdIn(camundaUndoTaskDTO.getCamundaTenantEnum().getTenantId())
// 获取参数信息
.matchVariableNamesIgnoreCase()
.orderByTaskCreateTime()
.desc();
// 设定查询模板类型
String processTemplateKey = camundaUndoTaskDTO.getProcessTemplateKey();
if (StrUtil.isNotBlank(processTemplateKey)) {
taskQuery.processDefinitionKey(processTemplateKey);
} else {
throw new ServiceException("单一业务模板查询必填!");
}
// 查询总条数信息
int totalCount = (int) taskQuery.count();
// 分页查询
int firstResultNum = pageUtil.getStartSizeNum(PaginationContext.getPageNum(), PaginationContext.getPageSize());
List<Task> taskList = taskQuery.listPage(firstResultNum, PaginationContext.getPageSize());
// 查询获取列表信息,封装最终返回信息
List<CamundaUndoTask> camundaUndoTaskList = new ArrayList<>();
if (ObjectUtil.isNotEmpty(taskList)) {
taskList.forEach(task -> {
// 获取参数信息以及业务枚举类型
Map<String, Object> variableMap = runtimeService.getVariables(task.getExecutionId());
CamundaFlowTypeEnum camundaFlowTypeEnum = camundaUtil.getCamundaEnumByTemplateKey(processTemplateKey);
// 封装返回类型信息
CamundaUndoTask camundaUndoTask = new CamundaUndoTask();
camundaUndoTask.setTaskId(task.getId());
camundaUndoTask.setOrgCd(StrUtil.toString(variableMap.get(CamundaConst.PROCESS_CREATOR)));
camundaUndoTask.setOrgName(StrUtil.toString(variableMap.get(CamundaConst.ORG_NAME_FLAG)));
camundaUndoTask.setProcessId(task.getProcessInstanceId());
camundaUndoTask.setBizType(camundaFlowTypeEnum.getBizType());
camundaUndoTask.setBizName(camundaFlowTypeEnum.getBizName());
camundaUndoTask.setProcessTemplateKey(camundaFlowTypeEnum.getProcessTemplateKey());
camundaUndoTask.setBusinessKey(StrUtil.toString(variableMap.get(CamundaConst.BUSINESS_KEY_FLAG)));
camundaUndoTask.setActivityId(task.getTaskDefinitionKey());
camundaUndoTask.setCreator(StrUtil.toString(variableMap.get(CamundaConst.PROCESS_CREATOR)));
camundaUndoTask.setProcessCreateDate(task.getCreateTime());
camundaUndoTask.setCustomerName(StrUtil.toString(variableMap.get(CamundaConst.CUSTOMER_NAME_FLAG)));
camundaUndoTask.setCustomerNum(StrUtil.toString(variableMap.get(CamundaConst.CUSTOMER_NAME_FLAG)));
camundaUndoTaskList.add(camundaUndoTask);
});
}
CamundaFlowPage<CamundaUndoTask> camundaFlowPage = new CamundaFlowPage<>();
camundaFlowPage.setPageSize(PaginationContext.getPageSize());
camundaFlowPage.setPageNum(PaginationContext.getPageNum());
// 返回分页信息
return pageUtil.setCountFlowListPage(camundaUndoTaskList,
PaginationContext.getPageNum(),
PaginationContext.getPageSize(),
totalCount);
}
/**
* 结束任务
*
* @param endTaskDTO 参数dto
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void endProcess(CamundaEndTaskDTO endTaskDTO) {
// 获取任务信息以及流程实例信息
Task task = taskService.createTaskQuery()
// 租户id
.tenantIdIn(endTaskDTO.getCamundaTenantEnum().getTenantId())
// 任务id
.taskId(endTaskDTO.getTaskId())
.singleResult();
if (ObjectUtil.isNull(task)) {
throw new ServiceException(StrUtil.format("通过taskId[{}]以及租户id[{}]获取任务信息为空!"));
}
// 获取流程实例信息
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
// 流程实例id
.processInstanceId(task.getProcessInstanceId())
// 租户信息
.tenantIdIn(endTaskDTO.getCamundaTenantEnum().getTenantId())
.singleResult();
// 空值校验
if (ObjectUtil.isNull(processInstance)) {
throw new ServiceException(StrUtil.format("通过taskId[{}]以及租户id[{}]获取流程实例信息为空,请确认!",
task.getProcessInstanceId(),
endTaskDTO.getCamundaTenantEnum().getTenantId()));
}
// 流程定义id
String processId = processInstance.getProcessInstanceId();
// 获取流程定义信息,获取结束任务对应节点,如果强制结束则直接获取流程中end结束节点进行结束任务
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService
.getProcessDefinition(processInstance.getProcessDefinitionId());
List<ActivityImpl> activityList = processDefinition.getActivities();
// 强制结束分支,如果一个节点没有 OutgoingTransitions 则为结束节点
ActivityImpl activityEndPoint = activityList.stream().filter(filterAct ->
ObjectUtil.isEmpty(filterAct.getOutgoingTransitions())
).findFirst().orElse(null);
// 设置评论信息
if (StrUtil.isNotBlank(endTaskDTO.getOpinion())) {
taskService.createComment(task.getId(), task.getProcessInstanceId(), endTaskDTO.getOpinion());
}
// 获取当前节点
ActivityImpl currentActivity = processDefinition.findActivity(task.getTaskDefinitionKey());
// 进行任务结束处理,判定当前节点是否为end节点
if (currentActivity.getActivityId().equals(activityEndPoint.getActivityId())) {
// 非强制结束,当前节点为end节点,调用complete方法即可
if (ObjectUtil.isNotEmpty(endTaskDTO.getParamsMap())) {
taskService.complete(task.getId(), endTaskDTO.getParamsMap());
} else {
taskService.complete(task.getId());
}
} else {
// 非end节点,进行强制结束,不是在结束任务,需要任务流转(跳节点),判断流转节点是否为空
if (ObjectUtil.isNotEmpty(endTaskDTO.getParamsMap())) {
// 带参数结束任务
runtimeService.createProcessInstanceModification(processInstance.getProcessInstanceId())
// 取消当前节点所有活动中的Task任务
.cancelAllForActivity(currentActivity.getActivityId())
// 目标节点Id,在流程图中看
.startBeforeActivity(activityEndPoint.getActivityId())
// 参数信息
.setVariables(endTaskDTO.getParamsMap())
// 意见信息
.setAnnotation(endTaskDTO.getOpinion())
.execute();
} else {
// 不带参数结束任务
runtimeService.createProcessInstanceModification(processInstance.getProcessInstanceId())
// 取消当前节点所有活动中的Task任务
.cancelAllForActivity(currentActivity.getActivityId())
// 目标节点Id,在流程图中看
.startBeforeActivity(activityEndPoint.getActivityId())
// 意见信息
.setAnnotation(endTaskDTO.getOpinion())
.execute();
}
// 未完成任务列表信息设置为删除状态
QueryWrapper<CamundaUnfinishedFlow> unfinishedFlowQueryWrapper = new QueryWrapper<>();
unfinishedFlowQueryWrapper.lambda().eq(CamundaUnfinishedFlow::getProcessId, processId);
camundaUnfinishedFlowMapper.delete(unfinishedFlowQueryWrapper);
}
}
/**
* 撤销任务
*
* @param camundaCancelDTO
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void cancelProcess(CamundaCancelDTO camundaCancelDTO) {
// 获取流程实例
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.tenantIdIn(camundaCancelDTO.getCamundaTenantEnum().getTenantId())
.processInstanceId(camundaCancelDTO.getProcessId())
.singleResult();
if (ObjectUtil.isNull(processInstance)) {
throw new ServiceException(StrUtil.format("通过流程实例id[{}]以及租户id[{}]获取流程实例为空,撤销失败!",
camundaCancelDTO.getProcessId(),
camundaCancelDTO.getCamundaTenantEnum().getTenantId()));
}
// 进行撤销操作
runtimeService.deleteProcessInstance(camundaCancelDTO.getProcessId(), camundaCancelDTO.getCancelReason());
// 未完成任务列表信息设置为删除状态
QueryWrapper<CamundaUnfinishedFlow> unfinishedFlowQueryWrapper = new QueryWrapper<>();
unfinishedFlowQueryWrapper.lambda().eq(CamundaUnfinishedFlow::getProcessId, camundaCancelDTO.getProcessId());
camundaUnfinishedFlowMapper.delete(unfinishedFlowQueryWrapper);
}
/**
* 提交普通任务
*
* @param camundaSubmitTaskDTO 参数dto
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public CamundaSubmitTaskRspDTO submitNormalTask(CamundaSubmitTaskDTO camundaSubmitTaskDTO) {
// 获取task任务信息
Task task = taskService.createTaskQuery()
// 租户id
.tenantIdIn(camundaSubmitTaskDTO.getCamundaTenantEnum().getTenantId())
// 任务id
.taskId(camundaSubmitTaskDTO.getTaskId()).singleResult();
if (ObjectUtil.isNull(task)) {
throw new ServiceException("提交普通任务,获取task信息为空!");
}
// 获取流程实例信息
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
// 租户id
.tenantIdIn(camundaSubmitTaskDTO.getCamundaTenantEnum().getTenantId())
// 流程实例id
.processInstanceId(task.getProcessInstanceId())
.singleResult();
if (ObjectUtil.isNull(processInstance)) {
throw new ServiceException("提交普通任务,获取流程实例为空!");
}
// 设置评论信息
String approver = camundaSubmitTaskDTO.getNextUserCd().concat(StrUtil.COLON).concat(camundaSubmitTaskDTO.getNextOrgCd());
// 设置认证身份信息
identityService.setAuthentication(approver,
Arrays.asList(camundaSubmitTaskDTO.getCamundaTenantEnum().getGroup()),
Arrays.asList(camundaSubmitTaskDTO.getCamundaTenantEnum().getTenantId()));
// 将处理人填入
runtimeService.setVariable(task.getExecutionId(), "approver", approver);
// 设置评论信息
taskService.createComment(camundaSubmitTaskDTO.getTaskId(), processInstance.getProcessInstanceId(), camundaSubmitTaskDTO.getOpinion());
// 正常提交任务信息
if (ObjectUtil.isNotEmpty(camundaSubmitTaskDTO.getVariableMap())) {
taskService.complete(camundaSubmitTaskDTO.getTaskId(), camundaSubmitTaskDTO.getVariableMap());
} else {
taskService.complete(camundaSubmitTaskDTO.getTaskId());
}
// 获取提交之后的task信息
List<Task> taskList = taskService.createTaskQuery()
// 租戶信息
.tenantIdIn(camundaSubmitTaskDTO.getCamundaTenantEnum().getTenantId())
// 流程实例id
.processInstanceId(processInstance.getProcessInstanceId())
.orderByFollowUpDate()
.desc()
.list();
CamundaSubmitTaskRspDTO camundaSubmitTaskRspDTO = null;
if (ObjectUtil.isNotEmpty(taskList)) {
// 设定任务执行人信息
Task currentTask = taskList.get(CamundaConst.INT_0);
if (ObjectUtil.isNotNull(currentTask) && StrUtil.isBlank(task.getAssignee())) {
// 类似于setAssignee,设定执行人信息
taskService.claim(currentTask.getId(), approver);
}
// 设置下一处理task任务信息
camundaSubmitTaskRspDTO = new CamundaSubmitTaskRspDTO();
camundaSubmitTaskRspDTO.setNextTaskId(currentTask.getId());
camundaSubmitTaskRspDTO.setNextTaskName(currentTask.getName());
camundaSubmitTaskRspDTO.setTaskDefKey(currentTask.getTaskDefinitionKey());
}
return camundaSubmitTaskRspDTO;
}
/**
* 获取下一处理岗位信息
*
* @param camundaNextPositionDTO
* @return
*/
@Override
public CamundaNextPositionRspDTO getNextPositionList(CamundaNextPositionDTO camundaNextPositionDTO) {
// 最终响应参数信息
CamundaNextPositionRspDTO positionRspDTO = new CamundaNextPositionRspDTO();
// 通过taskId获取task实例信息
Task task = taskService.createTaskQuery()
// 租户id
.tenantIdIn(camundaNextPositionDTO.getCamundaTenantEnum().getTenantId())
// 任务id
.taskId(camundaNextPositionDTO.getTaskId())
.singleResult();
// 空值校验
if (ObjectUtil.isNull(task)) {
throw new ServiceException(StrUtil.format("通过taskId[{}]以及租户id[{}]获取下一处理岗位获取task实例信息为空!",
camundaNextPositionDTO.getTaskId(),
camundaNextPositionDTO.getCamundaTenantEnum().getTenantId()));
}
positionRspDTO.setCurrentPositionDefinitionKey(task.getTaskDefinitionKey());
// 获取流程实信息
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
// 租户id
.tenantIdIn(camundaNextPositionDTO.getCamundaTenantEnum().getTenantId())
// 流程实例id
.processInstanceId(task.getProcessInstanceId())
.singleResult();
// 空值校验
if (ObjectUtil.isNull(processInstance)) {
throw new ServiceException(StrUtil.format("通过流程实例id[{}]以及租户id[{}]获取流程定义信息获取为空!",
task.getProcessInstanceId(),
camundaNextPositionDTO.getCamundaTenantEnum().getTenantId()));
}
// 获取整体流程定义信息
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService
.getProcessDefinition(processInstance.getProcessDefinitionId());
// 获取当前节点定义信息
ActivityImpl currentActivity = processDefinition.findActivity(task.getTaskDefinitionKey());
// 获取当前节点传入参数信息
Map<String, Object> variablesMap = runtimeService.getVariables(task.getExecutionId());
// 最终获取全部下一处理岗位定义节点
List<PvmActivity> finalActivityList = new ArrayList<>();
// 获取当前节点对外指向,并且对指向进行分析
List<PvmTransition> transitionList = currentActivity.getOutgoingTransitions();
if (ObjectUtil.isNotEmpty(transitionList)) {
for (PvmTransition transition : transitionList) {
// 获取目标节点
PvmActivity destinationActivity = transition.getDestination();
String activityNodeType = StrUtil.toString(destinationActivity.getProperty(CamundaConst.CAMUNDA_NODE_TYPE));
// 目标节点不同类型进行不同处理,
if (CamundaConst.EXCLUSIVE_GATEWAY.equals(activityNodeType) || CamundaConst.INCLUSIVE_GATEWAY.equals(activityNodeType)) {
// 注意此处为 节点->排他网关/包含网关->节点 形式,更复杂形式需要针对业务进行调整
List<PvmActivity> exclusiveGateActivityList = getNextPositionByExclusiveGateway(destinationActivity, variablesMap);
finalActivityList.addAll(exclusiveGateActivityList);
} else if (CamundaConst.PARALLEL_GATEWAY.equals(activityNodeType)) {
// 并行网关 节点->并行网关->节点
List<PvmActivity> parallelGateActivityList = getNextPositionByParallelGateway(destinationActivity);
finalActivityList.addAll(parallelGateActivityList);
} else if (CamundaConst.USER_TASK.equals(activityNodeType)) {
// 普通用户任务 节点->节点
finalActivityList.add(destinationActivity);
} else {
throw new ServiceException(StrUtil.format("当前获取下一岗位信息暂时activityNodeType[{}]暂时不支持!", activityNodeType));
}
}
// 返回信息进行封装
List<CamundaNextPositionRspDTO.NextPosition> nextPositionList = new ArrayList<>();
if (ObjectUtil.isNotEmpty(finalActivityList)) {
nextPositionList = finalActivityList.stream().map(pvmActivity -> {
ActivityImpl activity = (ActivityImpl)pvmActivity;
CamundaNextPositionRspDTO.NextPosition nextPosition = new CamundaNextPositionRspDTO.NextPosition();
nextPosition.setNextPositionName(activity.getName());
nextPosition.setNextPositionDefinitionKey(activity.getActivityId());
return nextPosition;
}).collect(Collectors.toList());
}
// 查看是否有跳岗信息
String processDefinitionId = task.getProcessDefinitionId();
ActReProcdef actReProcdef = actReProcdefMapper.selectById(processDefinitionId);
if (ObjectUtil.isNull(actReProcdef)) {
throw new ServiceException(StrUtil.format("通过流程定义id[{}]获取流程实例定义信息为空!",
processDefinitionId));
}
// 获取版本,机构,模板key,机构以及task定义id查询跳岗信息
QueryWrapper<CamundaJumpPoint> jumpPointQueryWrapper = new QueryWrapper<>();
jumpPointQueryWrapper.lambda().eq(CamundaJumpPoint::getProcessTemplateKey, actReProcdef.getKey())
.eq(CamundaJumpPoint::getTemplateVersion, actReProcdef.getVersion())
.eq(CamundaJumpPoint::getActivityId, task.getTaskDefinitionKey())
.eq(CamundaJumpPoint::getOwnOrg, camundaNextPositionDTO.getOrgCd());
CamundaJumpPoint camundaJumpPoint = camundaJumpPointMapper.selectOne(jumpPointQueryWrapper);
// 如果当前没有获取到配置的机构,则向上获取上级机构配置,直到最顶级配置机构0001,如果没有配置,则认为当前你岗位不能跳岗,整体跳岗原则为就近原则
if (ObjectUtil.isNotNull(camundaJumpPoint) && StrUtil.isNotBlank(camundaJumpPoint.getJumpActivityIds())) {
// 获取跳岗信息字符串,多个岗位使用逗号分隔
List<String> activityIdList = Arrays.asList(camundaJumpPoint.getJumpActivityIds().split(StrUtil.COMMA).clone());
jumpPointQueryWrapper = new QueryWrapper<>();
jumpPointQueryWrapper.lambda().in(CamundaJumpPoint::getProcessTemplateKey, actReProcdef.getKey())
.eq(CamundaJumpPoint::getTemplateVersion, actReProcdef.getVersion())
.in(CamundaJumpPoint::getActivityId, activityIdList)
.eq(CamundaJumpPoint::getOwnOrg, camundaNextPositionDTO.getOrgCd());
List<CamundaJumpPoint> camundaJumpPointList = camundaJumpPointMapper.selectList(jumpPointQueryWrapper);
if (ObjectUtil.isNotEmpty(camundaJumpPointList)) {
// 封装跳岗信息
List<CamundaNextPositionRspDTO.NextPosition> jumpPositionList = camundaJumpPointList.stream().map(jumpPoint -> {
CamundaNextPositionRspDTO.NextPosition nextPosition = new CamundaNextPositionRspDTO.NextPosition();
nextPosition.setNextPositionName(jumpPoint.getActivityName());
nextPosition.setNextPositionDefinitionKey(jumpPoint.getActivityId());
return nextPosition;
}).collect(Collectors.toList());
// 添加跳岗信息
nextPositionList.addAll(jumpPositionList);
}
}
positionRspDTO.setNextPositionList(nextPositionList);
}
return positionRspDTO;
}
/**
* 获取任务变量信息
*
* @param camundaVariablesDTO 参数DTO
* @return
*/
@Override
public Map<String, Object> getTaskVariables(CamundaVariablesDTO camundaVariablesDTO) {
// 通过taskId获取task实例信息
Task task = taskService.createTaskQuery()
// 租户信息
.tenantIdIn(camundaVariablesDTO.getCamundaTenantEnum().getTenantId())
// 任务id
.taskId(camundaVariablesDTO.getTaskId())
.singleResult();
if (ObjectUtil.isNull(task)) {
throw new ServiceException(StrUtil.format("通过taskId[{}]以及租户id[{}]获取任务实例失败,请确认taskId传入正确!",
camundaVariablesDTO.getTaskId(),
camundaVariablesDTO.getCamundaTenantEnum().getTenantId()));
}
// 获取参数信息
Map<String, Object> variablesMap = taskService.getVariables(camundaVariablesDTO.getTaskId());
if (ObjectUtil.isNotEmpty(variablesMap) && ObjectUtil.isNotEmpty(camundaVariablesDTO.getVariableKeyList())) {
// 进行值过滤,过滤非筛选值
Map<String, Object> innerMap = variablesMap.entrySet().stream().filter(entry ->
camundaVariablesDTO.getVariableKeyList().contains(entry.getKey())
).collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue)
);
return innerMap;
}
return variablesMap;
}
/**
* 删除参数key值
*
* @param taskId 任务id
* @param removeKey 参数key
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void removeVariable(String taskId, String removeKey, CamundaTenantEnum tenantEnum) {
// 获取task实例信息
Task task = taskService.createTaskQuery()
// 租户信息
.tenantIdIn(tenantEnum.getTenantId())
// 任务id
.taskId(taskId).singleResult();
if (ObjectUtil.isNull(task)) {
throw new ServiceException(StrUtil.format("删除参数通过taskId[{}]以及租户id[{}]查询task实例信息为空!",
taskId,
tenantEnum.getTenantId()));
}
taskService.removeVariable(taskId, removeKey);
}
/**
* 新增或者修改参数
*
* @param addOrUpdateVariableDTO 参数dto
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void addOrUpdateVariable(CamundaAddOrUpdateVariableDTO addOrUpdateVariableDTO) {
// 获取taskId以及租户信息
String taskId = addOrUpdateVariableDTO.getTaskId();
String tenantId = addOrUpdateVariableDTO.getCamundaTenantEnum().getTenantId();
// 获取任务实例信息,空值判定
Task task = taskService.createTaskQuery()
.tenantIdIn(tenantId)
.taskId(taskId)
.singleResult();
if (ObjectUtil.isNull(task)) {
throw new ServiceException(StrUtil.format("修改参数通过taskId[{}]以及租户id[{}]查询task实例信息为空!",
taskId,
tenantId));
}
// 修改参数
taskService.setVariable(taskId, addOrUpdateVariableDTO.getParamKey(), addOrUpdateVariableDTO.getParamValue());
}
/**
* 部署流程定义信息到本地库表中
*
* @param processDefinitionId 流程实例key
* @param orgCd 配置属于哪个机构
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void loadProcessDefinition(String processDefinitionId, String orgCd) {
// 流程定义信息
BpmnModelInstance bpmnModelInstance = repositoryService.getBpmnModelInstance(processDefinitionId);
if(ObjectUtil.isNull(bpmnModelInstance)){
throw new ServiceException(StrUtil.format("通过processDefinitionId[{}]查询流程定义实例信息为空", processDefinitionId));
}
// 获取process定义信息,服务名称
String processDefinitionName = null;
String processDefinitionKey = null;
Collection<Process> processCollection = bpmnModelInstance.getModelElementsByType(Process.class);
if (ObjectUtil.isNotNull(processCollection)) {
Optional<Process> optionalProcess = processCollection.stream().findFirst();
ProcessImpl processImpl = (ProcessImpl) optionalProcess.get();
// 获取流程定义名称 eg: camunda流程测试请假
processDefinitionName = processImpl.getName();
// 获取流程定义key eg: getRestDays
processDefinitionKey = processImpl.getId();
}
// 获取流程定义信息
ActReProcdef actReProcdef = actReProcdefMapper.selectById(processDefinitionId);
if (ObjectUtil.isNull(actReProcdef)) {
throw new ServiceException(StrUtil.format("通过processDefinitionId[{}]查询流程定义实例信息为空", processDefinitionId));
}
// 删除原有信息
QueryWrapper<CamundaJumpPoint> jumpPointQueryWrapper = new QueryWrapper<>();
jumpPointQueryWrapper.lambda().eq(CamundaJumpPoint::getProcessTemplateKey, processDefinitionKey)
.eq(CamundaJumpPoint::getOwnOrg, orgCd)
.eq(CamundaJumpPoint::getTemplateVersion, actReProcdef.getVersion());
camundaJumpPointMapper.delete(jumpPointQueryWrapper);
// 获取所有userTask任务节点信息
Collection<UserTask> userTaskCollection = bpmnModelInstance.getModelElementsByType(UserTask.class);
// 整合任务节点信息
List<UserTaskImpl> userTaskImplList = null;
if (ObjectUtil.isNotEmpty(userTaskCollection)) {
userTaskImplList = userTaskCollection.stream().map(userTask -> {
UserTaskImpl userTaskImpl = (UserTaskImpl) userTask;
return userTaskImpl;
}).collect(Collectors.toList());
}
// 开始进行落数
String finalProcessDefinitionKey = processDefinitionKey;
String finalProcessDefinitionName = processDefinitionName;
userTaskImplList.forEach(userTask -> {
// 获取流程task任务定义id以及定义name
String activityId = userTask.getId();
String activityName = userTask.getName();
// 封装跳转参数信息
CamundaJumpPoint camundaJumpPoint = new CamundaJumpPoint();
camundaJumpPoint.setId(IdUtil.simpleUUID());
// 所属机构
camundaJumpPoint.setOwnOrg(orgCd);
// 流程任务节点定义id
camundaJumpPoint.setActivityId(activityId);
// 任务节点定义名称
camundaJumpPoint.setActivityName(activityName);
// 模板key
camundaJumpPoint.setProcessTemplateKey(finalProcessDefinitionKey);
// 模板名称
camundaJumpPoint.setProcessTemplateName(finalProcessDefinitionName);
// 是否禁止跳岗标识
camundaJumpPoint.setNoJumpFlag(CamundaConst.STR_0);
// 版本信息
camundaJumpPoint.setTemplateVersion(actReProcdef.getVersion().toString());
// 插入信息
camundaJumpPointMapper.insert(camundaJumpPoint);
});
}
/**
* 操作跳跃节点信息
*
* @param camundaJumpPointSetDTO 参数dto
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void optionJumpPoint(CamundaJumpPointSetDTO camundaJumpPointSetDTO) {
// 跳跃节点不能包含当前节点信息
if (ObjectUtil.isNotEmpty(camundaJumpPointSetDTO.getJumpPoints())
&& camundaJumpPointSetDTO.getJumpPoints().contains(camundaJumpPointSetDTO.getCurrentActivityId())) {
throw new ServiceException("跳跃节点不能包含当前节点信息");
}
// 通过流程定义id获取流程定义信息
String processDefinitionId = camundaJumpPointSetDTO.getProcessDefinitionId();
ActReProcdef actReProcdef = actReProcdefMapper.selectById(processDefinitionId);
if (ObjectUtil.isNull(actReProcdef)) {
throw new ServiceException(StrUtil.format("通过processDefinitionId[{}]查询流程定义实例信息为空", processDefinitionId));
}
// 获取流程名称以及定义key以及version信息
String processTemplateName = actReProcdef.getName();
String processTemplateKey = actReProcdef.getKey();
String version = actReProcdef.getVersion().toString();
// 查询预设置跳岗信息
QueryWrapper<CamundaJumpPoint> camundaJumpPointQueryWrapper = new QueryWrapper<>();
camundaJumpPointQueryWrapper.lambda().eq(CamundaJumpPoint::getActivityId, camundaJumpPointSetDTO.getCurrentActivityId())
.eq(CamundaJumpPoint::getProcessTemplateKey, processTemplateKey)
.eq(CamundaJumpPoint::getProcessTemplateName, processTemplateName)
.eq(CamundaJumpPoint::getTemplateVersion, version)
.eq(CamundaJumpPoint::getOwnOrg, camundaJumpPointSetDTO.getOrgCd());
CamundaJumpPoint camundaJumpPoint = camundaJumpPointMapper.selectOne(camundaJumpPointQueryWrapper);
if (ObjectUtil.isNull(camundaJumpPoint)) {
throw new ServiceException(StrUtil.format("获取设置跳岗节点信息为空!"));
}
// 开始设置节点信息
if (StrUtil.isNotBlank(camundaJumpPointSetDTO.getJumpPoints())) {
camundaJumpPoint.setJumpActivityIds(camundaJumpPointSetDTO.getJumpPoints());
camundaJumpPointMapper.updateById(camundaJumpPoint);
} else {
// 跳转节点为空,则设置不能跳转
camundaJumpPointMapper.deleteJumpPointsById(camundaJumpPoint.getId());
}
}
/**
* 获取全部流程定义列表信息
*
* @param camundaDeployDTO 参数dto
* @return
*/
@Override
public CamundaFlowPage<ActReProcdef> getReProcessDeployPage(CamundaDeployDTO camundaDeployDTO) {
// 进行信息查询
QueryWrapper<ActReProcdef> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(StrUtil.isNotBlank(camundaDeployDTO.getProcessTemplateKey()), "KEY_", camundaDeployDTO.getProcessTemplateKey())
.like(StrUtil.isNotBlank(camundaDeployDTO.getProcessTemplateName()), "NAME_", camundaDeployDTO.getProcessTemplateName())
.eq(StrUtil.isNotBlank(camundaDeployDTO.getVersion()), "VERSION_", camundaDeployDTO.getVersion());
List<ActReProcdef> actReProcdefList = actReProcdefMapper.selectList(queryWrapper);
return pageUtil.setFlowListPage(actReProcdefList, PaginationContext.getPageNum(), PaginationContext.getPageSize());
}
/**
* 获取任务节点信息
*
* @param camundaJumpPointPageDTO 参数dto
* @return
*/
@Override
public CamundaFlowPage<CamundaJumpPoint> getJumpPointPage(CamundaJumpPointPageDTO camundaJumpPointPageDTO) {
// 获取流程定义信息
ActReProcdef actReProcdef = actReProcdefMapper.selectById(camundaJumpPointPageDTO.getProcessDefinitionId());
if (ObjectUtil.isNull(actReProcdef)) {
throw new ServiceException(StrUtil.format("通过processDefinitionId[{}]查询流程定义实例信息为空", camundaJumpPointPageDTO.getProcessDefinitionId()));
}
// 获取流程名称以及定义key以及version信息
String processTemplateName = actReProcdef.getName();
String processTemplateKey = actReProcdef.getKey();
String version = actReProcdef.getVersion().toString();
// 查询预设置跳岗信息
List<String> unExpectActivityIdList = camundaJumpPointPageDTO.getUnExpectActivityIdList();
QueryWrapper<CamundaJumpPoint> camundaJumpPointQueryWrapper = new QueryWrapper<>();
camundaJumpPointQueryWrapper.lambda()
.eq(CamundaJumpPoint::getProcessTemplateKey, processTemplateKey)
.eq(CamundaJumpPoint::getProcessTemplateName, processTemplateName)
.eq(CamundaJumpPoint::getTemplateVersion, version)
// 跳跃节点设置权限失效标识 0 生效, 1 失效
.eq(CamundaJumpPoint::getIsDel, CamundaConst.STR_0)
.eq(CamundaJumpPoint::getOwnOrg, camundaJumpPointPageDTO.getOrgCd())
// 排除自定义无用节点
.notIn(ObjectUtil.isNotEmpty(unExpectActivityIdList), CamundaJumpPoint::getActivityId, unExpectActivityIdList);
List<CamundaJumpPoint> camundaJumpPointList = camundaJumpPointMapper.selectList(camundaJumpPointQueryWrapper);
return pageUtil.setFlowListPage(camundaJumpPointList, PaginationContext.getPageNum(), PaginationContext.getPageSize());
}
/**
* 获取跟踪列表信息
* 以任务角度出发,可能会出现一个businessKey对应多个task任务,因为此人在流程中多次审批,以不同岗位
*
* @param camundaTraceHistoryDTO 参数dto
* @return
*/
@Override
public CamundaFlowPage<List<CamundaTraceHistory>> getCamundaTracePage(CamundaTraceHistoryDTO camundaTraceHistoryDTO) {
// 封装列表参数信息
List<CamundaTraceHistory> camundaTraceHistoryList = new ArrayList<>();
// 封装查询参数信息 userCd:orgCd
String handleUser = camundaTraceHistoryDTO.getUserCd()
.concat(StrUtil.COLON)
.concat(camundaTraceHistoryDTO.getOrgCd());
// 封装查询参数信息
HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
.tenantIdIn(camundaTraceHistoryDTO.getCamundaTenantEnum().getTenantId())
.taskInvolvedUser(handleUser)
.orderByProcessInstanceId()
.desc()
.matchVariableNamesIgnoreCase();
// 条件参数确认,任务模板查询
if (StrUtil.isNotBlank(camundaTraceHistoryDTO.getProcessTemplateKey())) {
historicTaskInstanceQuery.processVariableValueEquals(CamundaConst.PROCESS_TEMPLATE_KEY, camundaTraceHistoryDTO.getProcessTemplateKey());
}
// 客户名称查询
if (StrUtil.isNotBlank(camundaTraceHistoryDTO.getCustomerName())) {
historicTaskInstanceQuery.processVariableValueEquals(CamundaConst.CUSTOMER_NAME_FLAG, camundaTraceHistoryDTO.getCustomerName());
}
// 发起业务系统
if (StrUtil.isNotBlank(camundaTraceHistoryDTO.getSystem())) {
historicTaskInstanceQuery.processVariableValueEquals(CamundaConst.SYSTEM, camundaTraceHistoryDTO.getSystem());
}
// 流程在途结束判定
if (CamundaConst.RUNNING.equals(camundaTraceHistoryDTO.getStatus())) {
// 在途任务查询
historicTaskInstanceQuery.processUnfinished();
} else if (CamundaConst.FINISHED.equals(camundaTraceHistoryDTO.getStatus())) {
// 已经结束任务查询参数封装
historicTaskInstanceQuery.processFinished();
} else {
throw new ServiceException("查询跟踪列信息,是否在途参数获取为空!");
}
// 获取所有任务列表信息
List<HistoricTaskInstance> historicTaskInstanceList = historicTaskInstanceQuery.list();
// 进行数据封装
int totalCount = 0;
if (ObjectUtil.isNotEmpty(historicTaskInstanceList)) {
// 查询历史记录参数信息为map信息
Map<String, Map<String, Object>> historyVariablesMap = new HashMap<>(CamundaConst.INT_16);
Set<String> processIdList = historicTaskInstanceList.stream().
map(HistoricTaskInstance::getProcessInstanceId)
.collect(Collectors.toSet());
// 获取processInstance实例列表信息
int firstResultNum = pageUtil.getStartSizeNum(PaginationContext.getPageNum(), PaginationContext.getPageSize());
HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery()
.processInstanceIds(processIdList)
.orderByProcessInstanceStartTime()
.desc()
.matchVariableValuesIgnoreCase();
// 流程实例历史信息进行分页查询
totalCount = (int)processInstanceQuery.count();
List<HistoricProcessInstance> historicProcessInstanceList = processInstanceQuery
.listPage(firstResultNum, PaginationContext.getPageSize());
// 组装查询variables 参数信息idArray
String[] processIdArray = processIdList.toArray(new String[processIdList.size()]);
List<HistoricVariableInstance> variableInstanceList = historyService.createHistoricVariableInstanceQuery()
// 租户信息
.tenantIdIn(camundaTraceHistoryDTO.getCamundaTenantEnum().getTenantId())
// 流程实例id列表
.processInstanceIdIn(processIdArray)
.list();
// 开始封装参数map key 为processInstanceId,value为当前processInstanceId下个属性map信息
if (ObjectUtil.isNotEmpty(variableInstanceList)) {
variableInstanceList.forEach(variableInstance-> {
String processInstanceId = variableInstance.getProcessInstanceId();
// 当前那processInstanceId加入过map
Map<String, Object> currentMap;
if (ObjectUtil.isNotEmpty(historyVariablesMap.get(processInstanceId))) {
currentMap = historyVariablesMap.get(processInstanceId);
} else {
// 首次加入map信息
currentMap = new HashMap<>(CamundaConst.INT_16);
}
currentMap.put(variableInstance.getName(), variableInstance.getValue());
historyVariablesMap.put(processInstanceId, currentMap);
});
}
historicProcessInstanceList.forEach(processInstance -> {
// 获取参数信息
Map<String, Object> variablesMap = historyVariablesMap.get(processInstance.getId());
CamundaTraceHistory camundaTraceHistory = new CamundaTraceHistory();
camundaTraceHistory.setBizType(StrUtil.toString(variablesMap.get(CamundaConst.PROCESS_BIZ_TYPE)));
camundaTraceHistory.setBusinessKey(StrUtil.toString(variablesMap.get(CamundaConst.BUSINESS_KEY_FLAG)));
camundaTraceHistory.setCreator(StrUtil.toString(variablesMap.get(CamundaConst.PROCESS_CREATOR)));
camundaTraceHistory.setOrgCd(StrUtil.toString(variablesMap.get(CamundaConst.PROCESS_CREATOR)));
camundaTraceHistory.setCustomerName(StrUtil.toString(variablesMap.get(CamundaConst.CUSTOMER_NAME_FLAG)));
camundaTraceHistory.setCustomerNum(StrUtil.toString(variablesMap.get(CamundaConst.CUSTOMER_NAME_FLAG)));
camundaTraceHistory.setProcessId(processInstance.getId());
camundaTraceHistory.setCreateDate(processInstance.getStartTime());
if (CamundaConst.FINISHED.equals(camundaTraceHistoryDTO.getStatus())) {
camundaTraceHistory.setStatus(CamundaConst.FINISHED);
} else {
camundaTraceHistory.setStatus(CamundaConst.RUNNING);
}
camundaTraceHistoryList.add(camundaTraceHistory);
});
}
// 返回分页信息
return pageUtil.setCountFlowListPage(camundaTraceHistoryList,
PaginationContext.getPageNum(),
PaginationContext.getPageSize(),
totalCount);
}
/**
* 跟踪列表处理人列表信息
*
* @param camundaTraceApproveHistoryDTO 参数dto
* @return
*/
@Override
public CamundaFlowPage<CamundaTraceApproveHistory> getCamundaTraceApprovePage(CamundaTraceApproveHistoryDTO camundaTraceApproveHistoryDTO) {
// 获取流程实例id
String processInstanceId = camundaTraceApproveHistoryDTO.getProcessId();
// 获取历史任务查询类
HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
// 租户信息
.tenantIdIn(camundaTraceApproveHistoryDTO.getCamundaTenantEnum().getTenantId())
// 流程实例id
.processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceStartTime()
.desc()
.matchVariableNamesIgnoreCase();
// 分页查询
int totalCount = (int) historicTaskInstanceQuery.count();
int firstResultNum = pageUtil.getStartSizeNum(PaginationContext.getPageNum(), PaginationContext.getPageSize());
List<HistoricTaskInstance> historicTaskInstanceList = historicTaskInstanceQuery.listPage(firstResultNum, PaginationContext.getPageSize());
// 最终返回分页信息
List<CamundaTraceApproveHistory> camundaTraceApproveHistoryList = new ArrayList<>();
// 进行数据封装
if (ObjectUtil.isNotEmpty(historicTaskInstanceList)) {
// 查询历史记录参数信息为map信息
Map<String, Object> historyVariablesMap = new HashMap<>(CamundaConst.INT_16);
// 组装查询variables
List<HistoricVariableInstance> variableInstanceList = historyService.createHistoricVariableInstanceQuery()
// 租户信息
.tenantIdIn(camundaTraceApproveHistoryDTO.getCamundaTenantEnum().getTenantId())
// 流程实例id
.processInstanceIdIn(processInstanceId)
.list();
// 开始封装参数map key 为processInstanceId,value为当前 processInstanceId 下个属性map信息
if (ObjectUtil.isNotEmpty(variableInstanceList)) {
variableInstanceList.forEach(variableInstance -> {
historyVariablesMap.put(variableInstance.getName(), variableInstance.getValue());
});
}
historicTaskInstanceList.forEach(historicTaskInstance -> {
// 获取参数信息
CamundaTraceApproveHistory camundaTraceApproveHistory = new CamundaTraceApproveHistory();
// 业务编号
camundaTraceApproveHistory.setBusinessKey(StrUtil.toString(historyVariablesMap.get(CamundaConst.BUSINESS_KEY_FLAG)));
// 流程实例id
camundaTraceApproveHistory.setProcessId(historicTaskInstance.getProcessInstanceId());
// 创建时间
camundaTraceApproveHistory.setCreateDate(historicTaskInstance.getStartTime());
// 结束时间
camundaTraceApproveHistory.setEndDate(historicTaskInstance.getEndTime());
// 操作岗位名称
camundaTraceApproveHistory.setPositionName(historicTaskInstance.getName());
// 机构信息 assign 截取
camundaTraceApproveHistory.setOrgCd(historicTaskInstance.getAssignee());
// 柜员信息 assign 截取
camundaTraceApproveHistory.setUserCd(historicTaskInstance.getAssignee());
// 获取评论信息
String commentMessage = null;
String taskId = historicTaskInstance.getId();
List<Comment> commentList = taskService.getTaskComments(taskId);
if (ObjectUtil.isNotEmpty(commentList)) {
commentMessage = commentList.get(CamundaConst.INT_0).getFullMessage();
}
camundaTraceApproveHistory.setOpinion(commentMessage);
camundaTraceApproveHistoryList.add(camundaTraceApproveHistory);
});
}
return pageUtil.setCountFlowListPage(camundaTraceApproveHistoryList,
PaginationContext.getPageNum(),
PaginationContext.getPageSize(),
totalCount);
}
/**
* 获取已经部署流程模板列表信息
*
* @param camundaLoadTemplateDTO 参数dto
* @return
*/
@Override
public CamundaFlowPage<CamundaLoadTemplate> getLoadTemplatePage(CamundaLoadTemplateDTO camundaLoadTemplateDTO) {
// 定义查询类
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
// 设置爱租户信息
processDefinitionQuery.tenantIdIn(camundaLoadTemplateDTO.getCamundaTenantEnum().getTenantId());
// 流程定义条件查询,分别是定义key,以及流程定义名称还有版本号
if (StrUtil.isNotBlank(camundaLoadTemplateDTO.getTemplateKey())) {
processDefinitionQuery.processDefinitionKeyLike(camundaLoadTemplateDTO.getTemplateKey());
}
// 版本编号如果为空,则默认设置为最终版本
if (ObjectUtil.isNotNull(camundaLoadTemplateDTO.getVersion())) {
processDefinitionQuery.processDefinitionVersion(camundaLoadTemplateDTO.getVersion());
} else {
processDefinitionQuery.latestVersion();
}
// 开始查询列表信息
List<ProcessDefinition> definitionList = processDefinitionQuery
.orderByProcessDefinitionKey()
.asc()
.list();
// 封装返回分页信息
List<CamundaLoadTemplate> camundaLoadTemplateList = new ArrayList<>();
if (ObjectUtil.isNotEmpty(definitionList)) {
camundaLoadTemplateList = definitionList.stream().filter(definition -> {
if (StrUtil.isBlank(camundaLoadTemplateDTO.getTemplateName())) {
return true;
} else if (ObjectUtil.isNull(definition) || StrUtil.isBlank(definition.getName())) {
return false;
} else {
return definition.getName().contains(camundaLoadTemplateDTO.getTemplateName());
}
}).map(definition -> {
CamundaLoadTemplate camundaLoadTemplate = new CamundaLoadTemplate();
camundaLoadTemplate.setId(definition.getDeploymentId());
camundaLoadTemplate.setTemplateKey(definition.getKey());
camundaLoadTemplate.setTemplateName(definition.getName());
camundaLoadTemplate.setVersion(definition.getVersion());
// 通过deploymentId获取deployment部署时间信息
String deploymentId = definition.getDeploymentId();
Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId)
.singleResult();
if (ObjectUtil.isNotNull(deployment)) {
camundaLoadTemplate.setCreateTime(DateUtil.format(deployment.getDeploymentTime(), DatePattern.NORM_DATETIME_PATTERN));
}
return camundaLoadTemplate;
}).collect(Collectors.toList());
}
return pageUtil.setCountFlowListPage(camundaLoadTemplateList,
PaginationContext.getPageNum(),
PaginationContext.getPageSize(),
definitionList.size());
}
/**
* 任务驳回到发起岗或者上一岗位
*
* @param camundaRejectTaskDTO 驳回参数DTO
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean rejectTaskToStartNode(CamundaRejectTaskDTO camundaRejectTaskDTO) {
// 获取当前任务信息
Task currentTask = taskService.createTaskQuery()
// 租户信息
.tenantIdIn(camundaRejectTaskDTO.getCamundaTenantEnum().getTenantId())
.taskId(camundaRejectTaskDTO.getTaskId())
.singleResult();
if (ObjectUtil.isNull(currentTask)) {
throw new ServiceException(StrUtil.format("通过taskId[{}]获取当前任务信息为空!", camundaRejectTaskDTO.getTaskId()));
}
// 通过task任务信息获取流程实例信息
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
// 租户信息
.tenantIdIn(camundaRejectTaskDTO.getCamundaTenantEnum().getTenantId())
// 流程实例id
.processInstanceId(currentTask.getProcessInstanceId())
.singleResult();
if (ObjectUtil.isNull(processInstance)) {
throw new ServiceException(StrUtil.format("通过processId[{}]获取流程实例信息为空!", processInstance.getProcessInstanceId()));
}
// 获取已经结束的历史节点信息
List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery()
// 租户信息
.tenantIdIn(camundaRejectTaskDTO.getCamundaTenantEnum().getTenantId())
// 流程实例id
.processInstanceId(processInstance.getProcessInstanceId())
// 节点类型
.activityType(CamundaConst.USER_TASK)
// 已经结束的
.finished()
// 按照结束时间进行升序排序
.orderByHistoricActivityInstanceEndTime()
.asc()
.list();
// 空值校验
if (ObjectUtil.isEmpty(activityInstanceList)) {
throw new ServiceException("获取历史userTask任务信息为空!");
}
// 首个任务节点
HistoricActivityInstance startInstance = activityInstanceList.get(CamundaConst.INT_0);
// 设置退回操作员信息以及退回节点activityId信息
String activityId = null;
String assignee = null;
// 强制退回到发起节点判定
if (camundaRejectTaskDTO.getIfRejectToStartNode()) {
// 如果历史userTask节点没有或者只有一个,则不能进行驳回操作
if (activityInstanceList.size() < CamundaConst.INT_1) {
throw new ServiceException("首个用户操作节点无法驳回!");
}
// 获取跳转节点信息,目标节点id以及节点操作员信息
activityId = startInstance.getActivityId();
assignee = startInstance.getAssignee();
} else {
// 退回到上一节点判定,当前节点为首个节点,无法退回
if (currentTask.getTaskDefinitionKey().equals(startInstance.getActivityId())) {
throw new ServiceException("首个用户操作节点无法驳回!");
}
// 判断当前任务是否已经退回过
List<HistoricActivityInstance> equalCurrentActivityList = activityInstanceList.stream().filter(instance -> {
if (instance.getActivityId().equals(currentTask.getTaskDefinitionKey())) {
return true;
}
return false;
}).collect(Collectors.toList());
// 首次退回
if (ObjectUtil.isEmpty(equalCurrentActivityList)) {
// 倒数第一个为上一岗位信息
HistoricActivityInstance historicActivityInstance = activityInstanceList.get(activityInstanceList.size() - 1);
activityId = historicActivityInstance.getActivityId();
assignee = historicActivityInstance.getAssignee();
} else {
// 经过退回操作,eg: 1 2 3 4,4个节点当前节点信息如果在3,则表示该节点是从4退回来的,如果再退回则需要退回到2,再到1
for (int index = 0; index < activityInstanceList.size(); index ++) {
// 获取循环对象
HistoricActivityInstance loopActivityInstance = activityInstanceList.get(index);
// 如果当前循环activity信息不是第一节点,并且循环节点等于当前任务节点,则上一节点就为应退回节点
if (index > CamundaConst.INT_0
&& loopActivityInstance.getActivityId().equals(currentTask.getTaskDefinitionKey())) {
HistoricActivityInstance backActivityInstance = activityInstanceList.get(index - CamundaConst.INT_1);
activityId = backActivityInstance.getActivityId();
assignee = backActivityInstance.getAssignee();
}
}
}
}
// 设置参数以及拒绝任务的原因参数信息
Map<String, Object> variablesMap = new HashMap<>();
variablesMap.put(CamundaConst.APPROVE, assignee);
taskService.createComment(currentTask.getId(), processInstance.getProcessInstanceId(), camundaRejectTaskDTO.getRejectReason());
// 获取流程定义信息,获取结束任务对应节点,如果强制结束则直接获取流程中end结束节点进行结束任务
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService
.getProcessDefinition(processInstance.getProcessDefinitionId());
// 获取当前节点
ActivityImpl currentActivity = processDefinition.findActivity(currentTask.getTaskDefinitionKey());
runtimeService.createProcessInstanceModification(processInstance.getProcessInstanceId())
// 驳回原因
.setAnnotation(camundaRejectTaskDTO.getRejectReason())
// 取消当前活动的所有任务
.cancelAllForActivity(currentActivity.getActivityId())
// 目标节点Id,在流程图中看
.startBeforeActivity(activityId)
// 参数信息
.setVariables(variablesMap)
.execute();
return true;
}
/**
* 跳转到目标节点
*
* @param camundaGotoDTO
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean gotoDestinationTask(CamundaGotoDTO camundaGotoDTO) {
// 获取当前节点task任务信息
Task currentTask = taskService.createTaskQuery()
// 租户信息
.tenantIdIn(camundaGotoDTO.getCamundaTenantEnum().getTenantId())
// 任务节点信息
.taskId(camundaGotoDTO.getCurrentTaskId()).singleResult();
if (ObjectUtil.isNull(currentTask)) {
throw new ServiceException(StrUtil.format("通过taskId[{}]获取task信息为空!", camundaGotoDTO.getCurrentTaskId()));
}
// 校验节点是否可以跳跃,获取流程定义id,当前节点activityId以及机构信息
String processDefinitionId = currentTask.getProcessDefinitionId();
String currentActivityId = currentTask.getTaskDefinitionKey();
String ownOrgCd = camundaGotoDTO.getOrgCd();
// 查询当前节点是否配置可跳跃节点信息
ActReProcdef actReProcdef = actReProcdefMapper.selectById(processDefinitionId);
if (ObjectUtil.isNull(actReProcdef)) {
throw new ServiceException(StrUtil.format("通过流程定义id[{}],获取流程定义信息为空!", processDefinitionId));
}
// 获取当前节点配置信息
QueryWrapper<CamundaJumpPoint> jumpPointQueryWrapper = new QueryWrapper<>();
jumpPointQueryWrapper.lambda().eq(CamundaJumpPoint::getActivityId, currentActivityId)
.eq(CamundaJumpPoint::getTemplateVersion, actReProcdef.getVersion())
.eq(CamundaJumpPoint::getOwnOrg, ownOrgCd)
.eq(CamundaJumpPoint::getProcessTemplateKey, actReProcdef.getKey());
CamundaJumpPoint camundaJumpPoint = camundaJumpPointMapper.selectOne(jumpPointQueryWrapper);
if (ObjectUtil.isNull(camundaJumpPoint)) {
throw new ServiceException(StrUtil.format("当前模板[{}]对应机构[{}]对应岗位未配置跳岗信息,请确认!",
actReProcdef.getKey(),
ownOrgCd));
}
// 岗位配置正确性校验,可跳跃节点不好含当前跳跃节点,则直接返回异常信息
if (StrUtil.isNotBlank(camundaJumpPoint.getJumpActivityIds())
&& !camundaJumpPoint.getJumpActivityIds().contains(camundaGotoDTO.getDestActivityId())) {
throw new ServiceException("当前岗位不能跳转到选定岗位,请配置后再试!");
}
// 设置意见信息
taskService.createComment(currentTask.getId(), currentTask.getProcessInstanceId(), camundaGotoDTO.getOpinion());
// 进行跳岗信息
ProcessInstanceModificationInstantiationBuilder instantiationBuilder = runtimeService
.createProcessInstanceModification(currentTask.getProcessInstanceId())
// 取消当前活动的所有任务
.cancelAllForActivity(currentActivityId)
// 跳转原因
.setAnnotation(camundaGotoDTO.getOpinion())
// 目标节点Id,在流程图中看
.startBeforeActivity(camundaGotoDTO.getDestActivityId());
// 参数信息
if (ObjectUtil.isNotEmpty(camundaGotoDTO.getVariablesMap())) {
instantiationBuilder.setVariables(camundaGotoDTO.getVariablesMap());
}
// 执行节点跳跃
instantiationBuilder.execute();
return true;
}
/**
* 获取当前任务完成节点,连线,未完成节点信息
* todo: 后续可以加入自定义的完成节点,退回操作记录表,更准确展示当前节点任务高亮信息
*
* @param camundaTaskImageDTO 参数dto
* @return
*/
@Override
public CamundaTaskImageNodeRspDTO getCamundaTaskImage(CamundaTaskImageDTO camundaTaskImageDTO) {
// 最终返回参数信息
CamundaTaskImageNodeRspDTO camundaTaskImageNodeRspDTO = new CamundaTaskImageNodeRspDTO();
// 根据taskId获取任务信息
String taskId = camundaTaskImageDTO.getTaskId();
Task currentTask = taskService.createTaskQuery()
.tenantIdIn(camundaTaskImageDTO.getCamundaTenantEnum().getTenantId())
.taskId(taskId)
.singleResult();
if (ObjectUtil.isNull(currentTask)) {
throw new ServiceException(StrUtil.format("通过taskId[{}]以及租户id[{}]获取task信息为空!",
taskId,
camundaTaskImageDTO.getCamundaTenantEnum().getTenantId()));
}
// 获取processInstance信息
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
// 租户id
.tenantIdIn(camundaTaskImageDTO.getCamundaTenantEnum().getTenantId())
// 流程实例id
.processInstanceId(currentTask.getProcessInstanceId())
.singleResult();
if (ObjectUtil.isNull(processInstance)) {
throw new ServiceException(StrUtil.format("通过processId[{}]获取流程实例信息为空!", currentTask.getProcessInstanceId()));
}
// 流程实例id
String processInstanceId = processInstance.getProcessInstanceId();
// 获取已经完成的任务节点
List<HistoricActivityInstance> finishedActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
.tenantIdIn(camundaTaskImageDTO.getCamundaTenantEnum().getTenantId())
.processInstanceId(processInstanceId)
.finished()
.orderByHistoricActivityInstanceStartTime()
.asc()
.list();
if (ObjectUtil.isNotEmpty(finishedActivityInstanceList)) {
List<String> finishedActivityIdList = finishedActivityInstanceList
.stream()
.map(HistoricActivityInstance::getActivityId)
.collect(Collectors.toList());
camundaTaskImageNodeRspDTO.setFinishedActivityIdList(finishedActivityIdList);
}
// 未完成节点信息
List<HistoricActivityInstance> unfinishedActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
.tenantIdIn(camundaTaskImageDTO.getCamundaTenantEnum().getTenantId())
.processInstanceId(processInstanceId)
.unfinished()
.list();
if (ObjectUtil.isNotEmpty(unfinishedActivityInstanceList)) {
List<String> unfinishedActivityIdList = unfinishedActivityInstanceList
.stream()
.map(HistoricActivityInstance::getActivityId)
.collect(Collectors.toList());
camundaTaskImageNodeRspDTO.setUnfinishedActivityIdList(unfinishedActivityIdList);
}
// 自己办理任务获取
String optionUser = camundaTaskImageDTO.getUserCd().concat(StrUtil.COLON).concat(camundaTaskImageDTO.getOrgCd());
List<HistoricTaskInstance> selfOptionTaskInstanceList = historyService.createHistoricTaskInstanceQuery()
.tenantIdIn(camundaTaskImageDTO.getCamundaTenantEnum().getTenantId())
.taskAssignee(optionUser)
.finished()
.processInstanceId(processInstanceId)
.list();
if (ObjectUtil.isNotEmpty(selfOptionTaskInstanceList)) {
List<String> selfOptionIdList = selfOptionTaskInstanceList
.stream()
.map(HistoricTaskInstance::getTaskDefinitionKey)
.collect(Collectors.toList());
camundaTaskImageNodeRspDTO.setSelfOptionActivityIdList(selfOptionIdList);
}
// 获取流程中的高亮线,获取流程定义的bpmn模型
List<String> highLineList = new ArrayList<>();
BpmnModelInstance bpmnModelInstance = repositoryService.getBpmnModelInstance(processInstance.getProcessDefinitionId());
for (HistoricActivityInstance finishedActivity : finishedActivityInstanceList) {
// 获取 bpmn 元素
ModelElementInstance modelElementInstance = bpmnModelInstance.getModelElementById(finishedActivity.getActivityId());
// 将节点转换为 flowNode 流程节点,获取输入输出线
FlowNode flowNode = (FlowNode)modelElementInstance;
// 获取outgoing线信息
Collection<SequenceFlow> outgoingCollection = flowNode.getOutgoing();
if (ObjectUtil.isEmpty(outgoingCollection)) {
continue;
}
// 循环outgoing信息
outgoingCollection.forEach(outgoing -> {
// 线段目标节点信息
String targetId = outgoing.getTarget().getId();
// 完成任务,多次循环,所有完成任务对应outgoing线全部高亮
for (HistoricActivityInstance innerFinished : finishedActivityInstanceList) {
String optionActivityId = innerFinished.getActivityId();
// 循环任务为target目标节点,并且 则高亮
if(targetId.equals(optionActivityId)){
if(finishedActivity.getEndTime().equals(innerFinished.getStartTime())){
highLineList.add(outgoing.getId());
}
}
}
// 待完成任务高亮节点
for (HistoricActivityInstance unfinishedActivityInstance : unfinishedActivityInstanceList) {
String optionActivityId = unfinishedActivityInstance.getActivityId();
if(targetId.equals(optionActivityId)){
if(finishedActivity.getEndTime().equals(unfinishedActivityInstance.getStartTime())){
highLineList.add(outgoing.getId());
}
}
}
});
camundaTaskImageNodeRspDTO.setHighLineList(highLineList);
}
return camundaTaskImageNodeRspDTO;
}
/**
* 通过版本号,流程定义processDefinitionKey获取流程定义xml信息
*
* @param processDefinitionKey
* @param version 版本编号
* @param tenantEnum 租户枚举信息
*/
@Override
public String getDefinitionXMLByKeyAndVersion(String processDefinitionKey, Integer version, CamundaTenantEnum tenantEnum) throws IOException {
// 获取流程定义信息
List<ProcessDefinition> processDefinitionList = repositoryService.createProcessDefinitionQuery()
// 租户id
.tenantIdIn(tenantEnum.getTenantId())
.processDefinitionKey(processDefinitionKey)
.list();
// 空值判定
if (ObjectUtil.isEmpty(processDefinitionList)) {
throw new ServiceException(StrUtil.format("通过processDefinitionKey[{}]获取流程定义信息为空!",
processDefinitionKey));
}
// 获取对应版本的信息
ProcessDefinition processDefinition = processDefinitionList.stream().filter(definition ->
version.equals(definition.getVersion())
).findFirst().orElse(null);
// 空值判定
if (ObjectUtil.isNull(processDefinition)) {
throw new ServiceException(StrUtil.format("通过processDefinitionKey[{}]获取版本号[{}]的流程定义信息为空,未找到对应版本定义信息!",
processDefinitionKey,
version));
}
// 获取文件输入流信息
InputStream xmlStream = repositoryService.getProcessModel(processDefinition.getId());
// 通过 inputStream 获取xml字符串信息
String xmlStr = IOUtils.toString(xmlStream, StandardCharsets.UTF_8);
return xmlStr;
}
/**
* 获取流程图
*
* @param processId 流程实例id
*/
@Override
public void getDefinitionXMLByProcessId(String processId, CamundaTenantEnum camundaTenantEnum) throws IOException {
// 通过runtimeService获取processDefinitionId
String processDefinitionId = runtimeService.createProcessInstanceQuery()
// 租户信息
.tenantIdIn(camundaTenantEnum.getTenantId())
.processInstanceId(processId)
.singleResult()
.getProcessDefinitionId();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
// 租户信息
.tenantIdIn(camundaTenantEnum.getTenantId())
.processDefinitionId(processDefinitionId)
.singleResult();
InputStream xmlStream = repositoryService.getProcessModel(processDefinition.getId());
// 设置响应头信息,比如Content-Type和Content-Disposition
response.setContentType("application/xml");
// 根据实际文件类型设置MIME类型,这里是XML文件
response.setHeader("Content-Disposition", "attachment;filename=\"" + processDefinition.getKey() + "\"");
try (OutputStream out = response.getOutputStream()) {
byte[] buffer = new byte[1024]; // 缓冲区大小,可以根据实际情况调整
int bytesRead;
// 从xmlStream读取数据并写入到responseOutputStream
while ((bytesRead = xmlStream.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
// 处理IO异常
String errorMessage = LogUtil.getStackTraceInfo(e);
throw new ServiceException(StrUtil.format("下载文件异常,异常信息为[{}]", errorMessage));
} finally {
response.flushBuffer();
}
}
/**
* 获取流程图XML字符串
*
* @param processId 流程实例id
* @param camundaTenantEnum 租户枚举信息
*/
@Override
public String getDefinitionXMLStrByProcessId(String processId, CamundaTenantEnum camundaTenantEnum) throws IOException {
// 通过runtimeService获取processDefinitionId
String processDefinitionId = runtimeService.createProcessInstanceQuery()
// 租户信息
.tenantIdIn(camundaTenantEnum.getTenantId())
.processInstanceId(processId)
.singleResult()
.getProcessDefinitionId();
// 空值判定
if (StrUtil.isBlank(processDefinitionId)) {
throw new ServiceException("通过processId获取流程定义processDefinitionId为空!");
}
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.tenantIdIn(camundaTenantEnum.getTenantId())
.processDefinitionId(processDefinitionId)
.singleResult();
// 空值判定
if (ObjectUtil.isNull(processDefinition)) {
throw new ServiceException(StrUtil.format("通过processDefinitionId[{}]获取流程定义信息为空!",
processDefinitionId));
}
InputStream xmlStream = repositoryService.getProcessModel(processDefinition.getId());
// 通过 inputStream 获取xml字符串信息
String xmlStr = IOUtils.toString(xmlStream, StandardCharsets.UTF_8);
return xmlStr;
}
/**
* 部署流程
*
* @param file 文件
* @param tenantEnum 租户枚举
*/
@Override
@Transactional(rollbackFor = Exception.class)
public String deployProcess(MultipartFile file, CamundaTenantEnum tenantEnum) throws IOException {
// 文件校验
if (file.isEmpty()) {
throw new ServiceException("部署新流程,流程文件为空!");
}
// 开始部署流程
Deployment deployment = repositoryService.createDeployment()
.addInputStream(file.getOriginalFilename(), file.getInputStream())
.tenantId(tenantEnum.getTenantId())
.name(file.getOriginalFilename())
.deploy();
// 通过deploymentId获取流程定义集合信息(首次部署,只有一个流程定义信息)
String deploymentId = deployment.getId();
List<ProcessDefinition> definitionList = repositoryService.createProcessDefinitionQuery()
// 租户id
.tenantIdIn(tenantEnum.getTenantId())
.deploymentId(deploymentId)
.list();
// 通过流程定义信息获取流程定义key
if (ObjectUtil.isNotEmpty(definitionList)) {
// 首次部署,取第一个定义信息即可
ProcessDefinition processDefinition = definitionList.get(0);
return processDefinition.getKey();
} else {
throw new ServiceException(StrUtil.format("流程已经部署,通过部署deploymentId[{}]获取流程定义信息为空!",
deploymentId));
}
}
/**
* 获取排他网关正确的下一节点信息
* @param currentActivity 当前节点信息
* @param currentVariablesMap 当前节点处参数信息
* @return
*/
public List<PvmActivity> getNextPositionByExclusiveGateway(PvmActivity currentActivity, Map<String, Object> currentVariablesMap) {
// 返回结果信息
List<PvmActivity> activityList = new ArrayList<>();
// 获取当前节点对外连接信息,并且计算最终选择哪条路线
List<PvmTransition> transitionList = currentActivity.getOutgoingTransitions();
for (PvmTransition transition : transitionList) {
// 获取当前任务判定条件,注意此处不是节点,为对外条件flowSequence
Object condition = transition.getProperty(CamundaConst.CONDITION_TEXT);
// 节点条件判定是否满足
if (ObjectUtil.isNotNull(condition) && camundaUtil.camundaEvalExpress(condition, currentVariablesMap)) {
// 此处为对外指向flowSequence指向满足条件的节点
activityList.add(transition.getDestination());
}
}
return activityList;
}
/**
* 获取并行网关正确的下一节点信息
* @param currentActivity 当前节点信息
* @return
*/
public List<PvmActivity> getNextPositionByParallelGateway(PvmActivity currentActivity) {
// 返回结果信息
List<PvmActivity> activityList = new ArrayList<>();
// 获取当前并行网关节点对外连接信息 transitionList 为并行网关对外的 -> 连线
List<PvmTransition> transitionList = currentActivity.getOutgoingTransitions();
for (PvmTransition transition : transitionList) {
// 获取当前任务判定条件,注意此处不是节点,为对外条件 flowSequence,获取destination则为 -> 对应后面的节点
PvmActivity destinationActivity = transition.getDestination();
String activityNodeType = StrUtil.toString(destinationActivity.getProperty(CamundaConst.CAMUNDA_NODE_TYPE));
// 如果目标节点为userTask节点,则直接加入执行节点
if (CamundaConst.USER_TASK.equals(activityNodeType)) {
activityList.add(transition.getDestination());
}
}
return activityList;
}
}
2.5 实体类实现
2.5.1 流程获取定义信息实体
package cn.git.camunda.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @description: 流程获取定义信息实体
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2023-09-18 05:08:05
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("ACT_RE_PROCDEF")
public class ActReProcdef implements Serializable {
private static final long serialVersionUID=1L;
@TableId(value = "ID_", type = IdType.ASSIGN_ID)
private String id;
@TableField("REV_")
private BigDecimal rev;
@TableField("CATEGORY_")
private String category;
@TableField("NAME_")
private String name;
@TableField("KEY_")
private String key;
@TableField("VERSION_")
private BigDecimal version;
@TableField("DEPLOYMENT_ID_")
private String deploymentId;
@TableField("RESOURCE_NAME_")
private String resourceName;
@TableField("DGRM_RESOURCE_NAME_")
private String dgrmResourceName;
@TableField("HAS_START_FORM_KEY_")
private Integer hasStartFormKey;
@TableField("SUSPENSION_STATE_")
private BigDecimal suspensionState;
@TableField("TENANT_ID_")
private String tenantId;
@TableField("VERSION_TAG_")
private String versionTag;
@TableField("HISTORY_TTL_")
private BigDecimal historyTtl;
@TableField("STARTABLE_")
private Integer startable;
}
2.5.2 岗位信息跳转配置表
package cn.git.camunda.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* @author lixuchun
* @title: 岗位信息跳转配置表
* @projectName bank-credit-sy
* @description: 岗位信息跳转配置表-entity
* @date 2023-09-19
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("CAMUNDA_JUMP_POINT")
public class CamundaJumpPoint implements Serializable {
private static final long serialVersionUID=1L;
/**
* 主键
*/
@TableId(value = "ID", type = IdType.ASSIGN_ID)
private String id;
/**
* 模板名称
*/
@TableField("PROCESS_TEMPLATE_NAME")
private String processTemplateName;
/**
* 模板key
*/
@TableField("PROCESS_TEMPLATE_KEY")
private String processTemplateKey;
/**
* 任务定义id
*/
@TableField("ACTIVITY_ID")
private String activityId;
/**
* 任务定义名称
*/
@TableField("ACTIVITY_NAME")
private String activityName;
/**
* 当前任务可跳岗位id 多个用逗号分隔
*/
@TableField("JUMP_ACTIVITY_IDS")
private String jumpActivityIds;
/**
* 流程模板版本
*/
@TableField("TEMPLATE_VERSION")
private String templateVersion;
/**
* 所属机构
*/
@TableField("OWN_ORG")
private String ownOrg;
/**
* 当前任务是否允许跳岗 0 允许 1 不允许
*/
@TableField("NO_JUMP_FLAG")
private String noJumpFlag;
/**
* 创建时间
*/
@TableField("CREATE_TIME")
private Date createTime;
/**
* 修改时间
*/
@TableField("UPDATE_TIME")
private Date updateTime;
/**
* 删除标识 0 否 1 是
*/
@TableField("IS_DEL")
private String isDel;
}
2.5.3 未完成任务信息
package cn.git.camunda.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
* @description: camunda 未完成任务信息
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2023-09-13 10:06:11
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CamundaUndoTask {
/**
* 业务编号
*/
public String businessKey;
/**
* 客户名称
*/
public String customerName;
/**
* 客户编号
*/
public String customerNum;
/**
* bizType 业务种类
*/
public String bizType;
/**
* bizName业务种类名称
*/
public String bizName;
/**
* 模板key
*/
public String processTemplateKey;
/**
* 业务发起人
*/
public String creator;
/**
* 发起机构号
*/
public String orgCd;
/**
* 发起机构名称
*/
public String orgName;
/**
* 业务发起时间
*/
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
public Date processCreateDate;
/**
* ActivityId
*/
public String activityId;
/**
* taskId 任务id
*/
public String taskId;
/**
* executionId
*/
public String processId;
}
2.5.4 流程发起代办任务留痕表
package cn.git.camunda.entity;
import cn.git.oracle.constant.DbConstant;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* @description: 流程发起代办任务留痕表
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2023-09-12 04:08:49
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("CAMUNDA_UNFINISHED_FLOW")
public class CamundaUnfinishedFlow implements Serializable {
private static final long serialVersionUID = -2523276919607556911L;
/**
* 主键id
*/
@TableId(value = "ID", type = IdType.ASSIGN_ID)
private String id;
/**
* 操作柜员cd
*/
@TableField("OPTION_USER_CD")
private String optionUserCd;
/**
* 操作机构cd
*/
@TableField("OPTION_ORG_CD")
private String optionOrgCd;
/**
* 客户号
*/
@TableField("CUSTOMER_NUM")
private String customerNum;
/**
* 客户名称
*/
@TableField("CUSTOMER_NAME")
private String customerName;
/**
* 流程processId
*/
@TableField("PROCESS_ID")
private String processId;
/**
* 业务编号
*/
@TableField("BUSINESS_KEY")
private String businessKey;
/**
* 业务名称
*/
@TableField("BIZ_NAME")
private String bizName;
/**
* 流程模板key
*/
@TableField("PROCESS_TEMPLATE_KEY")
private String processTemplateKey;
/**
* 发起系统标识
*/
@TableField("SYSTEM_FLAG")
private String systemFlag;
/**
* 创建日期
*/
@TableField(value = "CTIME", fill = FieldFill.INSERT)
private Date ctime;
/**
* 更新日期
*/
@TableField(value = "MTIME", fill = FieldFill.UPDATE)
private Date mtime;
/**
* 删除标记(0:未删除,1:已删除)
* 逻辑删除
*/
@TableLogic(value = DbConstant.DEFAULT_VALUE, delval = DbConstant.DELETE_VALUE)
@TableField("IS_DEL")
private String isDel;
}
2.6 mapper以及对应xml
2.6.1 流程获取定义信息mapper
package cn.git.camunda.mapper;
import cn.git.camunda.entity.ActReProcdef;
import cn.git.oracle.mapper.BaseMybatisPlusMapper;
/**
* @description: 流程获取定义信息mapper
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2023-09-12 04:19:32
*/
public interface ActReProcdefMapper extends BaseMybatisPlusMapper<ActReProcdef> {
}
2.6.2 岗位信息跳转配置表 Mapper 接口
package cn.git.camunda.mapper;
import cn.git.camunda.entity.CamundaJumpPoint;
import cn.git.oracle.mapper.BaseMybatisPlusMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
/**
* @author lixuchun
* @title: 岗位信息跳转配置表 Mapper 接口
* @projectName bank-credit-sy
* @description: 岗位信息跳转配置表-entity
* @date 2023-09-19
*/
public interface CamundaJumpPointMapper extends BaseMybatisPlusMapper<CamundaJumpPoint> {
/**
* 通过id删除跳岗信息
* @param id 主键
*/
@Update("UPDATE CAMUNDA_JUMP_POINT SET JUMP_ACTIVITY_IDS = '' WHERE ID = #{id}")
void deleteJumpPointsById(@Param("id") String id);
}
2.6.3 流程发起代办任务留痕表操作mapper
package cn.git.camunda.mapper;
import cn.git.camunda.entity.CamundaUnfinishedFlow;
import cn.git.oracle.mapper.BaseMybatisPlusMapper;
/**
* @description: 流程发起代办任务留痕表操作mapper
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2023-09-12 04:19:32
*/
public interface CamundaUnfinishedFlowMapper extends BaseMybatisPlusMapper<CamundaUnfinishedFlow> {
}
2.7 工具类
camunda网关枚举信息工具类
package cn.git.camunda.util;
import camundafeel.de.odysseus.el.ExpressionFactoryImpl;
import camundafeel.de.odysseus.el.util.SimpleContext;
import camundafeel.de.odysseus.el.util.SimpleResolver;
import camundafeel.javax.el.ExpressionFactory;
import camundafeel.javax.el.ValueExpression;
import cn.git.common.exception.ServiceException;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @description: camunda流程通用类
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2023-09-13 08:52:15
*/
@Slf4j
@Component
public class CamundaUtil {
/**
* 通过 templateKey 模板id获取enum对象
* @param templateKey 模板id
* @return WorkFlowProductEnum 枚举类型
*/
public CamundaFlowTypeEnum getCamundaEnumByTemplateKey(String templateKey) {
for (CamundaFlowTypeEnum value : CamundaFlowTypeEnum.values()) {
if (value.getProcessTemplateKey().equals(templateKey)) {
return value;
}
}
return null;
}
/**
* 表达式验证是否成立
* @param condition 条件
* @param variablesMap 参数map
* @return
*/
public Boolean camundaEvalExpress(Object condition, Map<String, Object> variablesMap) {
try {
boolean flag;
String conditionStr = StrUtil.toString(condition);
ExpressionFactory factory = new ExpressionFactoryImpl();
SimpleContext context = new SimpleContext(new SimpleResolver());
for (String key : variablesMap.keySet()) {
if (conditionStr.indexOf(key) > 0) {
factory.createValueExpression(context, "#{" + key + "}", String.class).setValue(context, variablesMap.get(key));
}
}
ValueExpression valueExpression = factory.createValueExpression(context, conditionStr, boolean.class);
flag = (Boolean) valueExpression.getValue(context);
return flag;
} catch (Exception e) {
e.printStackTrace();
throw new ServiceException(StrUtil.format("传入表达式验证报错了condition[{}],参数信息为[{}]", condition, JSONObject.toJSONString(variablesMap)));
}
}
}
CamundaFlowPage分页实体
package cn.git.camunda.page;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @program: bank-credit-sy
* @description:
* @author: lixuchun
* @create: page流程列表分页对象类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CamundaFlowPage<T> {
/**
* 总记录数
*/
private int total;
/**
* 结果集
*/
private List<T> result;
/**
* 第几页
*/
private int pageNum;
/**
* 每页记录数
*/
private int pageSize;
/**
* 总页数
*/
private int pages;
}
分页工具类
package cn.git.camunda.page;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* page分页对象
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2021-06-07
*/
@Component
public class PageUtil<T> {
/**
* 默认首页页码
*/
private static final int DEFAULT_PAGE_NUM = 1;
/**
* 将结果进行分页显示
* @param workMapList 要分页的流程workMapList
* @param pageNum 页码
* @param pageSize 每页显示多少条
* @return list返回分页后流程结果集
*/
public CamundaFlowPage<T> setFlowListPage(List<T> workMapList, int pageNum, int pageSize) {
// 最终返回手工分页对象
CamundaFlowPage<T> camundaFlowPage = new CamundaFlowPage<T>();
// 页码,每页多少条数据属性赋值
camundaFlowPage.setPageNum(pageNum);
// 每页多少条
camundaFlowPage.setPageSize(pageSize);
// 分页总条数
camundaFlowPage.setTotal(workMapList.size());
// 开始位置
int startNum = (pageNum - 1) * pageSize;
// 总页数
int pages = this.getTotalPage(pageSize, workMapList.size());
camundaFlowPage.setPages(pages);
// 页码等于最后一页
if (pageNum > pages) {
CamundaFlowPage page = new CamundaFlowPage<>();
page.setPageSize(pageSize);
page.setPageNum(DEFAULT_PAGE_NUM);
return page;
} else if (pageNum == pages) {
workMapList = workMapList.subList(startNum, camundaFlowPage.getTotal());
} else {
int endNum = startNum + pageSize;
workMapList = workMapList.subList(startNum, endNum);
}
camundaFlowPage.setResult(workMapList);
return camundaFlowPage;
}
/**
* 已经分页结果,组装分页信息
* @param workMapList 要分页的流程workMapList
* @param pageNum 页码
* @param pageSize 每页显示多少条
* @param totalCount 总共多少条
* @return list返回分页后流程结果集
*/
public CamundaFlowPage<T> setCountFlowListPage(List<T> workMapList, int pageNum, int pageSize, int totalCount) {
// 最终返回手工分页对象
CamundaFlowPage<T> camundaFlowPage = new CamundaFlowPage<T>();
// 页码,每页多少条数据属性赋值
camundaFlowPage.setPageNum(pageNum);
// 每页多少条
camundaFlowPage.setPageSize(pageSize);
// 分页总条数
camundaFlowPage.setTotal(totalCount);
// 开始位置
int startNum = (pageNum - 1) * pageSize;
// 总页数
int pages = this.getTotalPage(pageSize, totalCount);
camundaFlowPage.setPages(pages);
// 页码等于最后一页
camundaFlowPage.setResult(workMapList);
return camundaFlowPage;
}
/**
* 根据总条数获取总页数
* @param pageSize 每页记录数
* @param total 总记录数
* @return int
*/
public int getTotalPage(int pageSize, int total){
int pages;
if (total % pageSize == 0) {
pages = total / pageSize;
} else {
pages = total / pageSize + 1;
}
return pages;
}
/**
* 获取开始页第几条
* @param pageNum
* @param pageSize
* @return
*/
public int getStartSizeNum(int pageNum, int pageSize) {
if (pageNum <= 1) {
return 0;
}
return (pageNum - 1) * pageSize;
}
}
2.8 服务启动类
package cn.git.camunda;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @description: 流程服务启动类,流程引擎优化,由原有 activiti 5.22.0 -> camunda7流程引擎,有点为高扩展,高并发,取消webService调用
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2023-09-04 10:23:18
*/
@SpringBootApplication(scanBasePackages = "cn.git")
@MapperScan("cn.git.camunda.mapper")
public class CamundaApplication {
public static void main(String[] args) {
SpringApplication.run(CamundaApplication.class, args);
}
}
2.9 流程初始配置文件processes.xml
注意文件目录如下
<?xml version="1.0" encoding="UTF-8"?>
<!-- 定义一个进程应用的配置文件,用于配置Camunda进程应用的相关属性。 -->
<process-application
xmlns="http://www.camunda.org/schema/1.0/ProcessApplication"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- 配置进程归档属性,指定进程引擎和相关属性。 -->
<process-archive>
<!-- 指定使用的进程引擎,默认为default。 -->
<process-engine>default</process-engine>
<!-- 配置进程归档的属性。 -->
<properties>
<!-- 指定是否在卸载时删除进程定义,false表示不删除。 -->
<property name="isDeleteUponUndeploy">false</property>
<!-- 指定是否在应用部署时扫描进程定义,true表示是。 -->
<property name="isScanForProcessDefinitions">true</property>
</properties>
</process-archive>
</process-application>
2.10 自定义表camunda_custom_init.sql
--自定义在途任务表
CREATE TABLE CAMUNDA_UNFINISHED_FLOW (
id varchar(32) NOT NULL,
OPTION_USER_CD varchar(20),
OPTION_ORG_CD varchar(20),
CUSTOMER_NUM varchar(20),
CUSTOMER_NAME varchar(50),
PROCESS_ID varchar(60),
BUSINESS_KEY varchar(50),
BIZ_NAME varchar(100),
PROCESS_TEMPLATE_KEY varchar(50),
SYSTEM_FLAG varchar(20),
ctime date DEFAULT sysdate,
mtime date DEFAULT sysdate,
is_del varchar(1) DEFAULT 0,
PRIMARY KEY (id)
)
COMMENT ON TABLE SCMS_RAT.CAMUNDA_UNFINISHED_FLOW IS '自定义在途任务表';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_UNFINISHED_FLOW.ID IS '主键';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_UNFINISHED_FLOW.OPTION_USER_CD IS '操作柜员编号';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_UNFINISHED_FLOW.OPTION_ORG_CD IS '操作机构编号';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_UNFINISHED_FLOW.CUSTOMER_NUM IS '客户编号';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_UNFINISHED_FLOW.CUSTOMER_NAME IS '客户名称';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_UNFINISHED_FLOW.PROCESS_ID IS '流程实例id';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_UNFINISHED_FLOW.BUSINESS_KEY IS '业务编号';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_UNFINISHED_FLOW.BIZ_NAME IS '业务名称';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_UNFINISHED_FLOW.PROCESS_TEMPLATE_KEY IS '流程模板编号';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_UNFINISHED_FLOW.SYSTEM_FLAG IS '发起系统标识';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_UNFINISHED_FLOW.CTIME IS '创建时间';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_UNFINISHED_FLOW.MTIME IS '修改时间';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_UNFINISHED_FLOW.IS_DEL IS '任务是否结束 0 否 1 是';
--岗位信息跳转配置表
CREATE TABLE CAMUNDA_JUMP_POINT (
id varchar(32) NOT NULL,
process_template_name varchar(100) NOT NULL,
process_template_key varchar(100) NOT NULL,
activity_id varchar(50) NOT NULL,
activity_name varchar(50) NOT NULL,
jump_activity_ids varchar(200),
template_version varchar(10),
own_org varchar(50),
no_jump_flag varchar(1) DEFAULT '0',
create_time DATE DEFAULT sysdate,
update_time DATE DEFAULT sysdate,
is_del varchar(1) DEFAULT '0',
PRIMARY KEY (id)
)
COMMENT ON TABLE SCMS_RAT.CAMUNDA_JUMP_POINT IS '岗位信息跳转配置表';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_JUMP_POINT.ID IS '主键';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_JUMP_POINT.PROCESS_TEMPLATE_NAME IS '模板名称';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_JUMP_POINT.PROCESS_TEMPLATE_KEY IS '模板key';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_JUMP_POINT.ACTIVITY_ID IS '任务定义id';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_JUMP_POINT.ACTIVITY_NAME IS '任务定义名称';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_JUMP_POINT.JUMP_ACTIVITY_IDS IS '当前任务可跳岗位id 多个用逗号分隔';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_JUMP_POINT.TEMPLATE_VERSION IS '流程模板版本';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_JUMP_POINT.OWN_ORG IS '所属机构';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_JUMP_POINT.NO_JUMP_FLAG IS '当前任务是否允许跳岗 0 允许 1 不允许';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_JUMP_POINT.CREATE_TIME IS '创建时间';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_JUMP_POINT.UPDATE_TIME IS '修改时间';
COMMENT ON COLUMN SCMS_RAT.CAMUNDA_JUMP_POINT.IS_DEL IS '删除标识 0 否 1 是';
2.11 log4j2.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<Configuration schema="Log4J-V2.0.xsd" monitorInterval="600">
<Properties>
<!-- 日志生成目录 -->
<Property name="LOG_HOME">logs</Property>
<!-- 日志生系统名称 -->
<property name="FILE_NAME">camunda</property>
<!-- 日志输出格式以及含义
[%d{yyyy-MM-dd'T'HH:mm:ss.SSSZZ}] 日期 美国时间
[%level{length=5}] 级别
[%X{X-B3-TraceId},%X{X-B3-SpanId}] zipkin 链路追踪信息
[%thread-%tid] 线程id
[%logger] // 日志输出信息
[${sys:hostName}] hostname
[${sys:ip}]
[${sys:applicationName}] 应用名称
[%F,%L,%C,%M] / [当前执行类, 行号, 全类名, 方法名称]
[%m] 日志输出内容
## 自己特殊约定
'%ex'%n 两个引号将异常包裹,打出异常时候方便解析 如何抛异常 和 换行
实际打印日志对比
[2021-01-12T21:00:10.615+08:00]
[INFO]
[main-1]
[com.imooc.collector.Application]
[]
[]
[]
[StartupInfoLogger.java,50,org.springframework.boot.StartupInfoLogger,logStarting]
[Starting Application on DESKTOP-0VMS7VD with PID 5608 (D:\idea_workspace_kafka\collector\target\classes started by A in D:\idea_workspace_kafka\collector)] 日志内容
##
''
-->
<!-- elk日志展示 -->
<property name="patternLayout">[%d{yyyy-MM-dd'T'HH:mm:ss.SSSZZ}] [%level{length=5}] [%traceId] [%logger] [${sys:hostName}] [${sys:ip}] [${sys:applicationName}] [%F,%L,%C,%M] [%m] ## '%ex'%n</property>
</Properties>
<Appenders>
<Console name="CONSOLE" target="SYSTEM_OUT">
<PatternLayout pattern="${patternLayout}"/>
<!--控制台只输出level及其以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
</Console>
<!-- 文件按照格式要求在固定目录下生成文件 "app-${FILE_NAME}.log" -->
<RollingRandomAccessFile name="appAppender" fileName="${LOG_HOME}/app-${FILE_NAME}.log" filePattern="${LOG_HOME}/app-${FILE_NAME}-%d{yyyy-MM-dd}-%i.log" >
<PatternLayout pattern="${patternLayout}" />
<Policies>
<!--
根据当前filePattern配置"%d{yyyy-MM-dd}",每interval天滚动一次
"%d{yyyy-MM-dd HH-mm}" 则为每interval分钟滚动一次
-->
<TimeBasedTriggeringPolicy interval="1"/>
<!--日志文件大于500MB 滚动一次-->
<SizeBasedTriggeringPolicy size="500MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖 -->
<DefaultRolloverStrategy max="20"/>
</RollingRandomAccessFile>
<RollingRandomAccessFile name="druidSqlRollingFile" fileName="${LOG_HOME}/druid/app-${FILE_NAME}-druid.log" filePattern="${LOG_HOME}/app-${FILE_NAME}-druid-%d{yyyy-MM-dd}-%i.log" >
<PatternLayout pattern="${patternLayout}" />
<Policies>
<!--
根据当前filePattern配置"%d{yyyy-MM-dd}",每interval天滚动一次
"%d{yyyy-MM-dd HH-mm}" 则为每interval分钟滚动一次
-->
<TimeBasedTriggeringPolicy interval="1"/>
<!--日志文件大于500MB 滚动一次-->
<SizeBasedTriggeringPolicy size="500MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖 -->
<DefaultRolloverStrategy max="20"/>
</RollingRandomAccessFile>
<!-- skywalking grpc 日志收集 -->
<GRPCLogClientAppender name="grpc-log">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</GRPCLogClientAppender>
</Appenders>
<Loggers>
<!-- 关闭kafka打印日志信息 -->
<logger name="org.apache.kafka" level="off"/>
<!-- 记录druid-sql 的记录-->
<logger name="druid" level="error" additivity="false">
<appender-ref ref="druidSqlRollingFile"/>
</logger>
<!-- skywalking日志 -->
<logger name="cn.git.*" level="info" additivity="false">
<AppenderRef ref="grpc-log"/>
</logger>
<!-- 业务相关 异步logger 不影响系统性能 -->
<AsyncLogger name="cn.git.*" level="info" includeLocation="true">
<AppenderRef ref="appAppender"/>
</AsyncLogger>
<root level="info">
<AppenderRef ref="CONSOLE"/>
<Appender-Ref ref="appAppender"/>
<AppenderRef ref="grpc-log"/>
</root>
</Loggers>
</Configuration>
2.12 服务配置文件
当前为微服务环境,使用nacos作为注册中心,配置全部在nacos中,项目中配置如下:
spring:
application:
name: @project.artifactId@
main:
allow-bean-definition-overriding: true
引入discover模块,读取nacos配置文件,此配置文件中,引用符$引用通用配置文件内容,这里不进行展示了
spring:
cloud:
nacos:
username: nacos
password: xxx
discovery:
server-addr: xxx:8848
namespace: UAT2_CUS
config:
# nacos的服务端地址
server-addr: xxx:8848
# 配置文件格式
file-extension: yml
group: GIT_GROUP
namespace: UAT2_CUS
# 长连接超时时间
config-long-poll-timeout: 60000
# 轮询重试时间
config-retry-time: 2000
# 长轮询最大重试次数
max-retry: 3
# 开启监听和自动刷新
refresh-enabled: true
ext-config:
# 通用配置信息在此文件中
- data-id: git-common-config-uat.yml
group: GIT_GROUP
refresh: true
namespace: UAT2_CUS
camunda-server.yml配置文件如下
server:
port: ${git.camunda-server.port}
spring:
datasource:
# camunda服务地址优化
driver-class-name: oracle.jdbc.OracleDriver
url: ${git.oracle.camunda-server.url}
username: ${git.oracle.camunda-server.username}
password: ${git.oracle.camunda-server.password}
#初始化连接池的连接数量 大小,最小,最大
initial-size: 5
min-idle: 5
max-active: 20
#配置获取连接等待超时的时间 毫秒
max-wait: 60000
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 30000
validation-query: SELECT 1 FROM DUAL
ribbon:
ReadTimeout: 30000
ConnectTimeout: 30000
# SCHEMA-NAME MUST USE UPPERCASE FOR ORACLE
# Camunda BPM配置
camunda:
# BPM(业务流程管理)模块配置
bpm:
# 指定默认的过程引擎名称
process-engine-name: default
# 控制是否自动部署流程定义文件
# 若设置为false,则需要手动部署流程定义
auto-deployment-enabled: false
# 数据库相关配置
database:
# 设置使用的数据库类型,此处为Oracle
type: oracle
# 是否开启JDBC批量处理功能
# 若设置为false,则关闭批处理,可能影响数据操作性能
jdbc-batch-processing: false
# 数据库模式(schema)名称
schema-name: SCMS_RAT
# 表名前缀,用于区分不同应用或租户的数据表
table-prefix: SCMS_RAT.
# 是否允许自动更新数据库模式
# 若设置为true,将根据BPMN模型自动创建、更新数据库表结构
schema-update: true
3 启动服务,进行测试吧
3.1 启动服务
3.2 测试类代码如下
专门的一个测试类controller
package cn.git.camunda.controller;
import cn.git.camunda.consts.CamundaConst;
import cn.git.camunda.dto.*;
import cn.git.camunda.service.CamundaCommonService;
import cn.git.camunda.util.CamundaFlowTypeEnum;
import cn.git.camunda.util.CamundaSysEnum;
import cn.git.camunda.util.CamundaUtil;
import com.alibaba.fastjson.JSONObject;
import org.camunda.bpm.engine.IdentityService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.variable.VariableMap;
import org.camunda.bpm.engine.variable.Variables;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @description: camunda测试类
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2023-09-05 11:14:00
*/
@RestController
@RequestMapping("/userTask")
public class CamundaTestController {
@Autowired
private RuntimeService runtimeService;
@Autowired
private IdentityService identityService;
@Autowired
private CamundaUtil camundaUtil;
@Autowired
private CamundaCommonService camundaCommonService;
/**
* 开始任务 任务定义key
* @param processKey
*/
@GetMapping("/start/{processKey}/{businessKey}")
public void start(@PathVariable(value = "processKey") String processKey, @PathVariable(value = "businessKey") String businessKey){
identityService.setAuthenticatedUserId("331326:3313");
// 设置传递参数信息
VariableMap variableMap = Variables.createVariables();
List<String> videoNameList = new ArrayList<>();
videoNameList.add("电影");
videoNameList.add("电视剧");
videoNameList.add("综艺节目");
variableMap.putValue("videoNames", videoNameList);
variableMap.putValue("leaveDays", 5L);
// variableMap.putValue("processTemplateKey", "Process_exlusive_gateway_other");
runtimeService.startProcessInstanceByKey(processKey, businessKey, variableMap);
}
/**
* 开始任务 任务定义key
* @param processKey
*/
@GetMapping("/start/multi/{processKey}")
public void startMulti(@PathVariable(value = "processKey") String processKey){
identityService.setAuthenticatedUserId("javasdk");
// 设置传递参数信息
VariableMap variableMap = Variables.createVariables();
// 设置多实例任务审批员
List<String> leaderList = new ArrayList<>();
leaderList.add("jack");
leaderList.add("tom");
leaderList.add("rose");
variableMap.putValue("leaders", leaderList);
runtimeService.startProcessInstanceByKey(processKey, variableMap);
}
/**
* 开始任务 任务定义key
* @param processKey
*/
@GetMapping("/start/script/{processKey}")
public void startScript(@PathVariable(value = "processKey") String processKey){
identityService.setAuthenticatedUserId("tom");
// 设置传递参数信息
VariableMap variableMap = Variables.createVariables();
variableMap.putValue("originDays", 10);
runtimeService.startProcessInstanceByKey(processKey, variableMap);
}
/**
* 事件网关,发起一个执行信号,事件网关对应方法便可以执行
*/
@GetMapping("/signal/gateway")
public void sendSignalGateway() {
// 可以自定义设置参数
runtimeService.createSignalEvent("Signal_direct_leader").send();
}
/**
* 测试发起流程
* @param processKey
*/
@GetMapping("/start/dics/{processKey}/{time}")
public void startDICS(@PathVariable(value = "processKey") String processKey,
@PathVariable(value = "time") String time) {
CamundaStartProcessDTO camundaStartProcessDTO = new CamundaStartProcessDTO();
camundaStartProcessDTO.setCamundaSysEnum(CamundaSysEnum.DICS);
camundaStartProcessDTO.setOrgCd("sdk");
camundaStartProcessDTO.setUserCd("java");
CamundaFlowTypeEnum camundaFlowTypeEnum = camundaUtil.getCamundaEnumByTemplateKey(processKey);
camundaStartProcessDTO.setCamundaFlowTypeEnum(camundaFlowTypeEnum);
camundaStartProcessDTO.setBusinessKey("MCON20230913".concat(time));
camundaStartProcessDTO.setCustomerName("大连东港橙汁制造");
camundaStartProcessDTO.setCustomerNum("KCH202011212");
camundaCommonService.startProcess(camundaStartProcessDTO);
}
/**
* 测试结束任务
*/
@GetMapping("/end/task")
public void endTask() {
CamundaEndTaskDTO endTaskDTO = new CamundaEndTaskDTO();
endTaskDTO.setBusinessKey("MCON202309130958");
endTaskDTO.setTaskId("7ccff2b6-5391-11ee-810b-005056c00001");
endTaskDTO.setOrgCd("3313");
endTaskDTO.setUserCd("331326");
endTaskDTO.setOpinion("我去 结束了");
endTaskDTO.setForceEndTask(CamundaConst.STR_1);
Map<String, Object> paramMap = new HashMap<>(CamundaConst.INT_16);
paramMap.put("approver", "331326:3313");
endTaskDTO.setParamsMap(paramMap);
camundaCommonService.endProcess(endTaskDTO);
}
/**
* 提交方法
*/
@GetMapping("/submit/normal")
public void submitNormalTask() {
CamundaSubmitTaskDTO camundaSubmitTaskDTO = new CamundaSubmitTaskDTO();
camundaSubmitTaskDTO.setTaskId("612a9dc2-5391-11ee-810b-005056c00001");
camundaSubmitTaskDTO.setOpinion("我同意了啊。。。。");
camundaSubmitTaskDTO.setNextUserCd("331326");
camundaSubmitTaskDTO.setNextOrgCd("3313");
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("leaveDays", 5L);
camundaSubmitTaskDTO.setVariableMap(paramMap);
CamundaSubmitTaskRspDTO camundaSubmitTaskRspDTO = camundaCommonService.submitNormalTask(camundaSubmitTaskDTO);
System.out.println(JSONObject.toJSONString(camundaSubmitTaskRspDTO));
}
/**
* 获取下一岗位
*/
@GetMapping("/nextPosition")
public void nextPosition() {
CamundaNextPositionDTO camundaNextPositionDTO = new CamundaNextPositionDTO();
camundaNextPositionDTO.setOrgCd("3313");
camundaNextPositionDTO.setUserCd("331326");
camundaNextPositionDTO.setTaskId("ecac9405-52c2-11ee-beeb-005056c00001");
CamundaNextPositionRspDTO rspDTO = camundaCommonService.getNextPositionList(camundaNextPositionDTO);
System.out.println(JSONObject.toJSONString(rspDTO));
}
/**
* 流程定义信息
* @param processDefinitionId
*/
@GetMapping("/getProcessDefinition/{processDefinitionId}/{orgCd}")
public void getProcessDefinition(@PathVariable(value = "processDefinitionId") String processDefinitionId,
@PathVariable(value = "orgCd") String orgCd) {
camundaCommonService.loadProcessDefinition(processDefinitionId, orgCd);
}
}