简单的springboot整合activiti5.22.0
1. 需求
我们公司原本的流程服务是本地workflow模块以及一个远程的webService对应的activiti服务,其中activiti版本为5.22.0,之前想将activiiti5.22.0进行升级,选择了camunda,也对项目进行了部分改造,新增camunda-server服务,但是后来觉得数据迁移比较费劲,并且行里数据准确性要求比较高,原有的老数据不能丢失,历史记录必须完整保存,所以因为历史数据原因就没有使用camnuda了,而是进行了workflow-server服务的改造,将activiti5.22.0对应的webService服务迁移至本地服务,由于本webService服务提供了风险与信贷两个系统的流程服务,所以在workflow-server中还提供了风险调用原webService接口,并且也是改造成了fiegn调用形式
2. 具体实现
以下为改造的具体实现,具体主要包含两个部分,具体如下:
- 第一部分为本地服务提供的接口,包含流程的发布,部署,流程图获取,以及流程的发起提交结束等基本操作。
- 第二部分则是为风险系统提供的流程操作接口,主要包含发起提交结束等
2.1 本地服务改造
2.1.1 pom修改
原有的workflow-server对应的pom中新增springboot整合activiti对应的jar包,具体添加部分如下标注activiti所示
<?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-workflow</artifactId>
<groupId>cn.git</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>workflow-server</artifactId>
<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>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</exclusion>
</exclusions>
</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>workflow-client</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.git</groupId>
<artifactId>afterloan-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.git</groupId>
<artifactId>credit-discovery-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>cn.git</groupId>
<artifactId>loan-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.git</groupId>
<artifactId>account-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.git</groupId>
<artifactId>management-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.git</groupId>
<artifactId>query-api</artifactId>
<version>1.0-SNAPSHOT</version>
</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>
<dependency>
<groupId>cn.git</groupId>
<artifactId>rule-manage-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- activiti 5.22.0启动器,排除mybatis依赖 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>5.22.0</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-diagram-rest</artifactId>
<version>5.22.0</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.1.2 controller修改
主要修改了部分controller方法,添加原有webService服务提供的流程部署,流程图获取,xml获取,部署流程列表等方法,具体代码如下:
package cn.git.workflow.controller;
import cn.git.common.limit.ApiLimitSlidingWindow;
import cn.git.common.limit.SlidingWindowEnum;
import cn.git.common.page.PageBean;
import cn.git.common.result.Result;
import cn.git.common.result.ResultStatusEnum;
import cn.git.redis.RedisUtil;
import cn.git.workflow.constant.WorkFlowServerConstant;
import cn.git.workflow.dto.*;
import cn.git.workflow.dto.activiti.WorkFlowLoadTemplateDTO;
import cn.git.workflow.entity.PageTbConVote;
import cn.git.workflow.entity.WorkFlowUndoTask;
import cn.git.workflow.entity.activiti.WorkFlowLoadTemplate;
import cn.git.workflow.mapstruct.WorkFlowConvert;
import cn.git.workflow.page.WorkFlowPage;
import cn.git.workflow.service.WorkFlowService;
import cn.git.workflow.util.WorkFlowUtil;
import cn.git.workflow.vo.*;
import cn.git.workflow.vo.activiti.WorkFlowLoadTemplateInVO;
import cn.git.workflow.vo.activiti.WorkFlowLoadTemplateOutVO;
import cn.git.workflow.webservice.process.Exception_Exception;
import cn.git.workflow.webservice.query.BpmException_Exception;
import cn.hutool.core.util.StrUtil;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.xml.sax.SAXException;
import javax.validation.Valid;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* 流程通用controller
*
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2021-06-09
*/
@Api(value = "WorkFlowController流程通用controller", tags = "WorkFlowController流程通用controller")
@RestController
@RequestMapping("/workflow")
@Slf4j
public class WorkFlowController {
@Autowired
private WorkFlowUtil workFlowUtil;
@Autowired
private RedisUtil redisUtil;
@Autowired
private WorkFlowConvert workFlowConvert;
@Autowired
private WorkFlowService workFlowService;
/**
* 代办未分类列表信息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<WorkFlowPage<List<Map<String, Object>>>> listUndoWorkInfoInit(
@ApiParam(name = "userCd", value = "柜员号", required = true)
String userCd,
@ApiParam(name = "orgCd", value = "机构号", required = true)
String orgCd) {
try {
log.info("代办未分类列表信息count查询参数userCd[{}],orgCd[{}]!", userCd, orgCd);
return Result.ok(workFlowService.findWorkCountFlowList(userCd, orgCd));
} catch (Exception e) {
e.printStackTrace();
log.error(workFlowUtil.getStackTraceInfo(e));
return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
}
}
/**
* 代办未分类列表信息count查询
*
* @param userCd 柜员号
* @param orgCd 机构号
* @param systemFlag 系统标识
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "系统代办未分类列表信息count查询", notes = "系统代办未分类列表信息count查询")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@GetMapping(value = "/listSysUndoWorkInfoInit")
public Result<WorkFlowPage<List<Map<String, Object>>>> listSysUndoWorkInfoInit(
@ApiParam(name = "userCd", value = "柜员号", required = true)
String userCd,
@ApiParam(name = "orgCd", value = "机构号", required = true)
String orgCd,
@ApiParam(name = "systemFlag", value = "系统标识,0或者空为信贷,1为风险,2为储备系统", required = true)
String systemFlag) {
try {
log.info("代办未分类列表信息count查询参数userCd[{}],orgCd[{}]!", userCd, orgCd);
return Result.ok(workFlowService.findSysWorkCountFlowList(userCd, orgCd, systemFlag));
} catch (Exception e) {
e.printStackTrace();
log.error(workFlowUtil.getStackTraceInfo(e));
return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
}
}
/**
* 获取流程图
* @param processId
* @return
* @throws Exception_Exception
*/
@GetMapping(value = "/findProcessPic")
@ApiResponses({@ApiResponse(code = 1, message = "OK")})
@ResponseBody
public String findProcessPic(@ApiParam(value = "流程ID", name = "processId", required = true)
String processId) throws Exception_Exception, IOException {
return workFlowService.findProcessPic(processId);
}
/**
* 具体业务代办列表查询
*
* @param workFlowUndoTaskInVO 代办分类任务查询inVO
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "具体业务代办列表", notes = "具体业务代办列表")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@GetMapping(value = "/listUndoWorkInfoDetail")
public Result<WorkFlowPage<WorkFlowUndoTask>> listUndoWorkInfoDetail(
@ApiParam(name = "workFlowUndoTaskInVO", value = "代办分类任务查询inVO", required = true)
WorkFlowUndoTaskInVO workFlowUndoTaskInVO) throws BpmException_Exception {
try {
return Result.ok(workFlowService.findUndoWorkTaskDetailList(
workFlowConvert.workFlowTaskInVoConvertTaskDto(workFlowUndoTaskInVO)));
} catch (Exception e) {
e.printStackTrace();
log.error(workFlowUtil.getStackTraceInfo(e));
return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
}
}
/**
* 点击代办列表bizNo跳转到详情页面
*
* @param taskId 任务id
* @param userCd 用户cd
* @param orgCd 机构号
* @return Result
*/
@ApiOperation(value = "点击代办列表bizNo跳转到详情页面", notes = "点击代办列表bizNo跳转到详情页面")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class),
@ApiResponse(code = -1, message = "ERROR", response = Result.class)})
@GetMapping(value = "/findTaskDetailInfo/{taskId}/{userCd}/{orgCd}")
public Result findTaskDetailInfo(
@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) {
WorkFlowUndoTaskDetailDTO workFlowDTO = workFlowService.findTaskDetailInfo(taskId, userCd, orgCd);
if(StrUtil.isNotBlank(workFlowDTO.getErrorMessage())){
return Result.error(workFlowDTO.getErrorMessage());
}
return Result.ok(workFlowDTO);
}
/**
* 跟踪列表初始化列表信息查询
*
* @param workFlowTraceListInVO inVo
* @return Result<WorkFlowTraceListOutVO>
*/
@ApiLimitSlidingWindow(slidingWindowEnum = SlidingWindowEnum.WORKFLOW_NEW_TRACE_HIS_WINDOW)
@ApiOperation(value = "跟踪列表初始化列表信息查询", notes = "跟踪列表初始化列表信息查询")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@GetMapping(value = "/findTraceList")
public Result<WorkFlowTraceListOutVO> findTractList(
@ApiParam(name = "workFlowTraceListInVO", value = "跟踪列表inVo")
WorkFlowTraceListInVO workFlowTraceListInVO) throws BpmException_Exception {
try {
WorkFlowTraceListDTO workFlowTraceListDTO = workFlowService.findTraceList(
workFlowConvert.workFlowTractListInVoConvertTractDto(workFlowTraceListInVO));
return Result.ok(workFlowConvert.workFlowTractDtoConvertListOutVo(workFlowTraceListDTO));
} catch (Exception e) {
e.printStackTrace();
log.error(workFlowUtil.getStackTraceInfo(e));
return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
}
}
/**
* 历史统跟踪列表初始化列表信息查询
*
* @param workFlowTraceListInVO inVo
* @return Result<WorkFlowTraceListOutVO>
*/
@ApiLimitSlidingWindow(slidingWindowEnum = SlidingWindowEnum.WORKFLOW_TRACE_HIS_WINDOW)
@ApiOperation(value = "历史跟踪列表初始化列表信息查询", notes = "历史跟踪列表初始化列表信息查询")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@GetMapping(value = "/old/findTraceList")
public Result<WorkFlowTraceListOutVO> findOldSysTractList(
@ApiParam(name = "workFlowTraceListInVO", value = "跟踪列表inVo")
WorkFlowTraceListInVO workFlowTraceListInVO) {
try {
WorkFlowTraceListDTO workFlowTraceListDTO = workFlowService.findOldTraceList(
workFlowConvert.workFlowTractListInVoConvertTractDto(workFlowTraceListInVO));
return Result.ok(workFlowConvert.workFlowTractDtoConvertListOutVo(workFlowTraceListDTO));
} catch (Exception e) {
e.printStackTrace();
log.error(workFlowUtil.getStackTraceInfo(e));
return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
}
}
/**
* 查询跟踪列表单个任务历史记录
*
* @param historyListInVO inVo
* @return WorkFlowTraceHistoryListOutVO outVo
*/
@ApiOperation(value = "查询跟踪列表单个任务历史记录", notes = "查询跟踪列表单个任务历史记录")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@GetMapping("/findTraceTaskHistoryList")
public Result<WorkFlowTraceHistoryListOutVO> findTraceTaskHistoryList(
@ApiParam(name = "historyListInVO", value = "跟踪列表历史查询inVo")
WorkFlowTraceHistoryListInVO historyListInVO) throws BpmException_Exception {
try {
WorkFlowTraceHistoryListDTO workFlowTraceHistoryListDTO = workFlowService.findTraceHistoryList(
workFlowConvert.workflowTraceHisInVoConvertHisDto(historyListInVO));
return Result.ok(workFlowConvert.workflowTraceHisDtoConvertHistoryListOutVo(workFlowTraceHistoryListDTO));
} catch (Exception e) {
e.printStackTrace();
log.error(workFlowUtil.getStackTraceInfo(e));
return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
}
}
/**
* 通过客户号获取贷审会列表信息
* 包含urlName路径信息,点击进行跳转
* @param customerNum 客户号
* @return 贷审会列表信息
*/
@ApiOperation(value = "柜员登录后选定客户查看贷审会列表获取", notes = "贷审会列表获取")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@GetMapping(value = "/findVoteMeetingList/{customerNum}")
public Result<PageBean<PageTbConVote>> findVoteMeetingList(@PathVariable("customerNum") String customerNum) {
try {
PageBean<PageTbConVote> votePageBean = workFlowService.pageVoteMeetingList(customerNum);
return Result.ok(votePageBean);
} catch (Exception e) {
log.error(workFlowUtil.getStackTraceInfo(e));
return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
}
}
/**
* 获取下一处理环节
* @param workFlowEndProcessDTO dto
* @return WorkFlowNextPositionDTO dto
*/
@ApiOperation(value = "获取下一处理环节", notes = "获取下一处理环节")
@ApiResponses({@ApiResponse(code = 1, message = "OK")})
@GetMapping(value = "/coreFindNextPositionList")
public Result<WorkFlowNextPositionDTO> findNextPositionList(
@ApiParam(value = "workFlowEndProcessDTO", name = "获取下一处理环节岗位信息dto", required = true)
WorkFlowNextPositionDTO workFlowEndProcessDTO) {
try {
WorkFlowNextPositionDTO workFlowNextPositionDTO = workFlowService.findNextPositionList(workFlowEndProcessDTO);
return Result.ok(workFlowNextPositionDTO);
} catch (Exception e) {
e.printStackTrace();
log.error(workFlowUtil.getStackTraceInfo(e));
return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
}
}
/**
* 获取下一处理人列表信息
* @param workFlowNextUserListDTO dto
* @return WorkFlowNextUserListDTO dto
*/
@ApiOperation(value = "获取下一处理人列表信息", notes = "获取下一处理人列表信息")
@ApiResponses({@ApiResponse(code = 1, message = "OK")})
@GetMapping(value = "/coreFindNextUserInfoList")
public Result<WorkFlowNextUserListDTO> findNextUserInfoList(
@ApiParam(value = "workFlowNextUserListDTO", name = "获取下一处理人列表信息dto", required = true)
WorkFlowNextUserListDTO workFlowNextUserListDTO) {
try {
return Result.ok(workFlowService.findNextUserInfoList(workFlowNextUserListDTO));
} catch (Exception e) {
e.printStackTrace();
log.error(workFlowUtil.getStackTraceInfo(e));
return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
}
}
/**
* 设置webService访问路径 todo: 测试环境使用,生产删除此方法
* @param serviceType 类型
* @return Result
*/
@ApiOperation(value = "设置webService访问路径", notes = "设置webService访问路径")
@ApiResponses({@ApiResponse(code = 1, message = "OK")})
@GetMapping(value = "/webServiceType/{serviceType}")
public Result setWebServiceType(
@ApiParam(name = "serviceType", value = "service类型,UAT,TEST", required = true)
@PathVariable(value = "serviceType") String serviceType) {
if (!WorkFlowServerConstant.WEB_SERVICE_URL_UAT.equals(serviceType)
&& !WorkFlowServerConstant.WEB_SERVICE_URL_TEST.equals(serviceType)) {
return Result.error("正确填入 环境类型, UAT 或者 TEST");
} else {
redisUtil.set(WorkFlowServerConstant.WEB_SERVICE_URL_KEY, serviceType);
return Result.ok();
}
}
/**
* 回退流程到上一岗位
* @return Result
*/
@ApiOperation(value = "回退流程到上一岗位", notes = "回退流程到上一岗位")
@ApiResponses({@ApiResponse(code = 1, message = "OK")})
@GetMapping(value = "/submitBackPrevious")
public Result submitBackPrevious(
@ApiParam(value = "workFlowBackPreviousInVO", name = "退回上一岗位基本信息", required = true)
WorkFlowBackPreviousInVO workFlowBackPreviousInVO)
throws cn.git.workflow.webservice.task.BpmException_Exception, BpmException_Exception {
String errorMessage = workFlowService
.submitBackPrevious(workFlowConvert.backInVoConvertDto(workFlowBackPreviousInVO));
if (StrUtil.isNotBlank(errorMessage)) {
return Result.error(errorMessage);
}
return Result.ok();
}
/**
* 通过文件部署流程图, 文件格式为xml
* @return
*/
@ApiOperation(value = "直接通过文件部署新流程图", notes = "部署新流程图,返回流程部署成功的流程定义id[processDefinitionId]")
@PostMapping(value = "/deploy/process")
public Result<String> uploadProcessDefinition(@RequestParam MultipartFile file) throws IOException,
ParserConfigurationException, SAXException {
// 获取文件进行部署
String processDefinitionId = workFlowService.deployProcess(file);
return Result.ok(processDefinitionId);
}
/**
* 获取流程已经部署信息
*
* @param loadTemplateInVO
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "获取流程已经部署信息", notes = "获取流程已经部署信息")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/load/template/page")
public Result<WorkFlowLoadTemplateOutVO> getLoadTemplatePage(
@Valid @RequestBody WorkFlowLoadTemplateInVO loadTemplateInVO) {
// 参数赋值操作
WorkFlowLoadTemplateDTO templateDTO = new WorkFlowLoadTemplateDTO();
templateDTO.setTemplateKey(loadTemplateInVO.getTemplateKey());
templateDTO.setVersion(loadTemplateInVO.getVersion());
// 进行查询
WorkFlowPage<WorkFlowLoadTemplate> loadTemplatePage = workFlowService
.getLoadTemplatePage(templateDTO);
WorkFlowLoadTemplateOutVO outVO = new WorkFlowLoadTemplateOutVO();
outVO.setPageBean(loadTemplatePage);
return Result.ok(outVO);
}
/**
* 根据流程部署key获取xml信息
*
* @param loadTemplateInVO
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "根据流程部署key获取xml信息", notes = "根据流程部署key获取xml信息")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/load/template/xml")
public void downLoadTemplateXML(@RequestBody WorkFlowLoadTemplateInVO loadTemplateInVO) throws IOException {
// 参数赋值操作
WorkFlowLoadTemplateDTO templateDTO = new WorkFlowLoadTemplateDTO();
templateDTO.setTemplateKey(loadTemplateInVO.getTemplateKey());
templateDTO.setVersion(loadTemplateInVO.getVersion());
// 进行查询
workFlowService.getLoadTemplateXML(templateDTO);
}
/**
* 根据流程部署key获取xml信息
*
* @param loadTemplateInVO
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "根据流程部署key获取xml信息", notes = "根据流程部署key获取xml信息")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/load/template/xml/str")
public Result<String> getLoadTemplateXMLStr(@RequestBody WorkFlowLoadTemplateInVO loadTemplateInVO) throws IOException {
// 参数赋值操作
WorkFlowLoadTemplateDTO templateDTO = new WorkFlowLoadTemplateDTO();
templateDTO.setTemplateKey(loadTemplateInVO.getTemplateKey());
templateDTO.setVersion(loadTemplateInVO.getVersion());
// 进行查询
String loadTemplateXMLStr = workFlowService.getLoadTemplateXMLStr(templateDTO);
return Result.ok(loadTemplateXMLStr);
}
/**
* 根据流程部署key获取部署图片信息
*
* @param loadTemplateInVO
* @return WorkFlowPage 分页对象
*/
@ApiOperation(value = "根据流程部署key获取xml信息", notes = "根据流程部署key获取xml信息")
@ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
@PostMapping(value = "/load/template/png")
public void getLoadTemplatePIC(@RequestBody WorkFlowLoadTemplateInVO loadTemplateInVO) throws IOException {
// 参数赋值操作
WorkFlowLoadTemplateDTO templateDTO = new WorkFlowLoadTemplateDTO();
templateDTO.setTemplateKey(loadTemplateInVO.getTemplateKey());
templateDTO.setVersion(loadTemplateInVO.getVersion());
// 进行查询
workFlowService.getLoadTemplatePIC(templateDTO);
}
}
2.1.3 具体的serviceImpl实现
流程的主要部分则是在此处实现,具体包含了发起,提交,撤销,退回,结束,跳岗,历史信息查询等功能,具体实现代码过多,所以单写了两片博文记录,地址分别如下
- 第一部分代码 : 简单的springboot整合activiti5-serviceImpl部分(1)
- 第二部分代码 : 简单的springboot整合activiti5-serviceImpl部分(2)
2.1.4 工具类实现
此处只记录activiti5.22.0使用的工具包了,其余部分都是业务实现逻辑util则不进行展示了
package cn.git.workflow.util;
import cn.git.common.exception.ServiceException;
import cn.git.workflow.constant.WorkFlowServerConstant;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.javax.el.ExpressionFactory;
import org.activiti.engine.impl.javax.el.ValueExpression;
import org.activiti.engine.impl.juel.ExpressionFactoryImpl;
import org.activiti.engine.impl.juel.SimpleContext;
import org.activiti.engine.impl.juel.SimpleResolver;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @description: activiti5.22.0 专用util包
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2024-06-14
*/
@Component
public class ActivitiUtil {
@Autowired
private TaskService taskService;
/**
* @description: 验证表达式
*
* @param condition 表达式
* @param variablesMap 参数
* @return: boolean
*/
public boolean evalExpress(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)));
}
}
/**
* 获取排他网关正确的下一节点信息
* @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(WorkFlowServerConstant.CONDITION_TEXT);
// 节点条件判定是否满足
if (ObjectUtil.isNotNull(condition) && evalExpress(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(WorkFlowServerConstant.NODE_TYPE));
// 如果目标节点为userTask节点,则直接加入执行节点
if (WorkFlowServerConstant.USER_TASK_FLAG.equalsIgnoreCase(activityNodeType)) {
activityList.add(transition.getDestination());
}
}
return activityList;
}
/**
* 流程转向操作
*
* @param taskId 任务id
* @param currentActivity 当前节点
* @param destinationActivity 目标节点
* @param variables 流程变量
*/
public void turnTransitionForUTask(String taskId,
ActivityImpl currentActivity,
ActivityImpl destinationActivity,
Map<String, Object> variables) {
// 清空当前流向(存在风险,如果出现异常,则当前流向就消失了)
List<PvmTransition> oriPvmTransitionList = clearTransition(currentActivity);
try {
// 当前节点创建新流向
TransitionImpl newTransition = currentActivity.createOutgoingTransition();
// 设置新流向的目标节点
newTransition.setDestination(destinationActivity);
// 执行转向任务
if (ObjectUtil.isNotEmpty(variables)) {
taskService.complete(taskId, variables);
} else {
taskService.complete(taskId);
}
// 删除目标节点新流入
destinationActivity.getIncomingTransitions().remove(newTransition);
// 还原以前流向
restoreTransition(currentActivity, oriPvmTransitionList);
} catch (Exception e) {
e.printStackTrace();
// 如果出现异常,则恢复以前流向
restoreTransition(currentActivity, oriPvmTransitionList);
}
}
/**
* 清空指定活动节点流向
*
* @param activityImpl 活动节点
* @return 节点流向集合
*/
public List<PvmTransition> clearTransition(ActivityImpl activityImpl) {
// 存储当前节点所有流向临时变量
List<PvmTransition> pvmTransitionList = activityImpl.getOutgoingTransitions();
// 获取当前节点所有流向,存储到临时变量,然后清空
List<PvmTransition> oriPvmTransitionList = new ArrayList<>(pvmTransitionList);
// 清空当前节点所有流向
pvmTransitionList.clear();
return oriPvmTransitionList;
}
/**
* 还原指定活动节点流向
*
* @param activityImpl 活动节点
* @param oriPvmTransitionList 原有节点流向集合
*/
public void restoreTransition(ActivityImpl activityImpl, List<PvmTransition> oriPvmTransitionList) {
// 清空现有流向
List<PvmTransition> pvmTransitionList = activityImpl.getOutgoingTransitions();
pvmTransitionList.clear();
// 还原以前流向
pvmTransitionList.addAll(oriPvmTransitionList);
}
}
2.2 风险实现
风险部分主要是原有调用webService部分的三个接口类,需要信贷系统这边提供feign接口进行补充实现,三个接口分别为
- ActProcessWebServiceApi,流程定义信息查询service api接口
- ActQueryWebServiceApi,综合历史等查询service api接口
- ActTaskWebServiceApi,任务信息查询service api接口
2.2.1 风险实现的api接口定义实现
ActProcessWebServiceApi实现如下
package cn.git.workflow.service.impl;
import cn.git.common.exception.ServiceException;
import cn.git.workflow.constant.WorkFlowServerConstant;
import cn.git.workflow.dto.activiti.WorkFlowActProcessInstanceDTO;
import cn.git.workflow.dto.activiti.WorkFlowEndProcessDTO;
import cn.git.workflow.dto.activiti.WorkFlowStartProcessDTO;
import cn.git.workflow.mapstruct.ActivitiConvert;
import cn.git.workflow.service.ActProcessWebService;
import cn.git.workflow.util.ActivitiUtil;
import cn.hutool.core.util.ObjectUtil;
import org.activiti.engine.*;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @description: activiti5.22.0,流程定义信息查询service
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2024-06-14
*/
@Service
public class ActProcessWebServiceImpl implements ActProcessWebService {
@Autowired
private RepositoryService repositoryService;
@Autowired
private TaskService taskService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private ProcessEngine processEngine;
@Autowired
private HistoryService historyService;
@Autowired
private IdentityService identityService;
@Autowired
private ActivitiUtil activitiUtil;
@Autowired
private ActivitiConvert activitiConvert;
/**
* 根据流程id查询流程信息,包含参数信息
*
* @param processId 流程实例id
* @return
*/
@Override
public WorkFlowActProcessInstanceDTO findProcessByPId(String processId) {
// 获取流程实例信息
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(processId)
.includeProcessVariables()
.singleResult();
// 返回转换内容信息
return activitiConvert.processInstanceCovertToDTO(processInstance);
}
/**
* 开启一个流程信息
*
* @param startProcessDTO
* @return
*/
@Override
public WorkFlowStartProcessDTO startProcess(WorkFlowStartProcessDTO startProcessDTO) {
// 权限设置
identityService.setAuthenticatedUserId(startProcessDTO.getUserId());
// 发起流程
ProcessInstance processInstance;
// 发起流程
if (ObjectUtil.isNotEmpty(startProcessDTO.getParamMap())) {
// 带参数
processInstance = runtimeService.startProcessInstanceByKey(
startProcessDTO.getProcessKey(),
startProcessDTO.getBizId(),
startProcessDTO.getParamMap());
} else {
// 不带自定义参数信息
processInstance = runtimeService.startProcessInstanceByKey(
startProcessDTO.getProcessKey(),
startProcessDTO.getBizId());
}
// 获取当前任务列表,刚刚发起业务,应该只有一个值
List<Task> list = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).list();
// 设置返回信息
if (ObjectUtil.isNotEmpty(list)) {
// 获取第一个任务
Task task = list.get(0);
WorkFlowStartProcessDTO.WorkFlowStartProcessOUTDTO processOUTDTO = new WorkFlowStartProcessDTO.WorkFlowStartProcessOUTDTO();
processOUTDTO.setProcessId(processInstance.getProcessInstanceId());
processOUTDTO.setActivityName(task.getName());
processOUTDTO.setTaskDefKey(task.getTaskDefinitionKey());
processOUTDTO.setTaskId(task.getId());
startProcessDTO.setWorkFlowStartProcessOUTDTO(processOUTDTO);
}
return startProcessDTO;
}
/**
* 根据流程id取消流程
*
* @param processId 流程实例id
* @param userId 用户id userCd + ":" + orgCd
*/
@Override
public void cancelProcessByProcessId(String processId, String userId) {
// 权限认证
identityService.setAuthenticatedUserId(userId);
// 开始进行业务撤销
runtimeService.deleteProcessInstance(processId, WorkFlowServerConstant.DEFAULT_CANCEL_REASON);
}
/**
* 结束流程
*
* @param flowEndProcessDTO
*/
@Override
public void endProcess(WorkFlowEndProcessDTO flowEndProcessDTO) {
// 获取当前任务信息
Task currentTask = taskService.createTaskQuery()
.taskId(flowEndProcessDTO.getTaskId())
.singleResult();
// 获取流程定义信息
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(currentTask.getProcessDefinitionId());
// 获取流程定义节点详情信息
List<ActivityImpl> allActivityList = processDefinition.getActivities();
// 过滤出end节点信息
ActivityImpl endActivity = allActivityList.stream().filter(activity ->
ObjectUtil.isEmpty(activity.getOutgoingTransitions())
).findAny().orElse(null);
// 空值判定
if (ObjectUtil.isEmpty(endActivity)) {
throw new ServiceException("获取流程end节点信息为空,请确认流程图有end节点信息配置正确!");
}
// 获取当前节点定义信息
ActivityImpl currentTaskActivity = processDefinition.findActivity(currentTask.getTaskDefinitionKey());
// 进行任务跳转,既结束任务
activitiUtil.turnTransitionForUTask(currentTask.getId(),
currentTaskActivity,
endActivity,
flowEndProcessDTO.getParamMap());
}
}
ActQueryWebServiceImpl实现如下
package cn.git.workflow.service.impl;
import cn.git.common.exception.ServiceException;
import cn.git.workflow.constant.WorkFlowServerConstant;
import cn.git.workflow.dto.activiti.WorkFlowActHisActInstListDTO;
import cn.git.workflow.dto.activiti.WorkFlowActHisProcessListDTO;
import cn.git.workflow.dto.activiti.WorkFlowActWorkListDTO;
import cn.git.workflow.entity.ActHiProcinst;
import cn.git.workflow.mapper.ActHiProcinstMapper;
import cn.git.workflow.mapstruct.ActivitiConvert;
import cn.git.workflow.service.ActQueryWebService;
import cn.git.workflow.util.ActivitiUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @description: activiti5.22.0,综合历史等查询service
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2024-06-14
*/
@Service
public class ActQueryWebServiceImpl implements ActQueryWebService {
@Autowired
private ActHiProcinstMapper actHiProcinstMapper;
@Autowired
private ActivitiConvert activitiConvert;
@Autowired
private TaskService taskService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private HistoryService historyService;
@Autowired
private ActivitiUtil activitiUtil;
/**
* 通过用户id获取此用户全部业务信息
*
* @param userId
* @return
*/
@Override
public List<WorkFlowActWorkListDTO> queryWorkList(String userId) {
// 空值校验
if (StrUtil.isBlank(userId)) {
throw new ServiceException("userId参数为空,查询用户流程信息失败!");
}
// 分页查询初始化任务列表信息,processVariableValueEquals可以对参数进行过滤,此处用不到
TaskQuery taskQuery = taskService.createTaskQuery()
// 当前处理人
.taskAssignee(userId)
// 活动流程任务
.active()
// 查询包含参数信息,可以过滤使用
.includeProcessVariables()
// 创建时间排序
.orderByTaskCreateTime()
// 倒序排序
.desc();
// 进行数据查询,此处无需分页处理,直接查询全部
List<Task> taskList = taskQuery.list();
// 空值判定
if (ObjectUtil.isEmpty(taskList)) {
return new ArrayList<>();
}
// 转换为可用对象
List<WorkFlowActWorkListDTO> workList = taskList.stream().map(task ->
activitiConvert.taskConvertToActList(task)
).collect(Collectors.toList());
return workList;
}
/**
* 通过processId获取流程历史信息
*
* @param processId
* @return
*/
@Override
public List<WorkFlowActHisActInstListDTO> queryHisTaskList(String processId) {
// 获取历史活动实例
HistoricActivityInstanceQuery activityInstanceQuery = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processId)
.orderByHistoricActivityInstanceId()
.desc();
// 获取历史活动实例列表
List<HistoricActivityInstance> activityInstanceList = activityInstanceQuery.list();
// 类型信息转换
List<WorkFlowActHisActInstListDTO> actHisActInstListDTOList = activityInstanceList.stream().map(instance ->
activitiConvert.hisInstanceToActList(instance)
).collect(Collectors.toList());
// 进行非task节点信息判定,排除无用节点
actHisActInstListDTOList = actHisActInstListDTOList.stream().filter(actInst -> {
boolean ifRightType = actInst.getActivityType().equals(WorkFlowServerConstant.EXCLUSIVE_GATEWAY)
|| actInst.getActivityType().equals(WorkFlowServerConstant.PARALLEL_GATEWAY)
|| actInst.getActivityType().equals(WorkFlowServerConstant.INCLUSIVE_GATEWAY)
|| actInst.getActivityType().equals(WorkFlowServerConstant.EVENT_GATEWAY);
return !ifRightType;
}).collect(Collectors.toList());
// 设置common评论信息
actHisActInstListDTOList.forEach(actInst -> {
// 获取common信息
List<Comment> commentList = taskService.getTaskComments(actInst.getTaskId());
if (ObjectUtil.isNotEmpty(commentList)) {
// 设置评论信息
actInst.setOpinion(commentList.get(0).getFullMessage());
}
});
return actHisActInstListDTOList;
}
/**
* 获取新流程已经结束的历史信息
*
* @param userId 用户id
* @param finishStatus 流程状态 finished,running
* @return 任务列表
*/
public List<WorkFlowActHisProcessListDTO> queryStatusHisList(String userId, String finishStatus) {
// 参数校验
if (StrUtil.isBlank(userId)) {
throw new ServiceException("历史信息查询时候,用户id为空,请确认");
}
// 设置查询条件
HistoricProcessInstanceQuery instanceQuery = historyService.createHistoricProcessInstanceQuery()
// 参与用户id
.involvedUser(userId)
// 按照时间倒序排序
.orderByProcessInstanceStartTime()
.desc();
// 是否结束条件判定 0否1是
if (WorkFlowServerConstant.WORKFLOW_STATUS_FINISHED.equals(finishStatus)) {
instanceQuery.finished();
} else {
// 解决空值情况下,默认查询历史为running状态
finishStatus = WorkFlowServerConstant.WORKFLOW_STATUS_RUNNING;
instanceQuery.unfinished();
}
// 获取查询结果集合
List<HistoricProcessInstance> historicProcessInstanceList = instanceQuery.list();
// 查询信息进行转换
List<WorkFlowActHisProcessListDTO> actHisProcessListDTOList = historicProcessInstanceList
.stream().map(historyInstance ->
activitiConvert.hisProcessInstanceCovertToDTO(historyInstance)
).collect(Collectors.toList());
// 跟踪列表查询数据不正确 优化处理
List<ActHiProcinst> historyInstanceList = actHiProcinstMapper.listHistoryInstance(finishStatus, userId);
// 非空判定
if (ObjectUtil.isNotEmpty(historyInstanceList)) {
Map<String, String> instanceMap = new HashMap<>();
for (ActHiProcinst actHiProcinst : historyInstanceList) {
String businessKey = actHiProcinst.getBusinessKey();
instanceMap.put(businessKey, businessKey);
}
// 去除不正确处理人
List<WorkFlowActHisProcessListDTO> removeList = new ArrayList<>();
for (WorkFlowActHisProcessListDTO vo : actHisProcessListDTOList) {
if (instanceMap.get(vo.getBusinessKey()) == null) {
removeList.add(vo);
}
}
// 删除错误信息
if (removeList.size() > 0) {
actHisProcessListDTOList.removeAll(removeList);
}
} else {
// 如果正确查询没有信息,则全部去除即可
actHisProcessListDTOList = new ArrayList<>();
}
return actHisProcessListDTOList;
}
}
ActTaskWebServiceImpl实现如下
package cn.git.workflow.service.impl;
import cn.git.common.exception.ServiceException;
import cn.git.workflow.constant.WorkFlowServerConstant;
import cn.git.workflow.dto.activiti.*;
import cn.git.workflow.service.ActTaskWebService;
import cn.git.workflow.util.ActivitiUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.task.TaskDefinition;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @description: activiti5.22.0,任务信息查询service
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2024-06-14
*/
@Service
public class ActTaskWebServiceImpl implements ActTaskWebService {
@Autowired
private ActivitiUtil activitiUtil;
@Autowired
private TaskService taskService;
@Autowired
private IdentityService identityService;
@Autowired
private RepositoryService repositoryService;
@Autowired
private HistoryService historyService;
@Autowired
private RuntimeService runtimeService;
/**
* 根据任务id和用户id查询任务信息
*
* @param workFlowTaskInfoDTO
* @return
*/
@Override
public WorkFlowTaskInfoDTO findTaskByInAndUserId(WorkFlowTaskInfoDTO workFlowTaskInfoDTO) {
// 设置权限
identityService.setAuthenticatedUserId(workFlowTaskInfoDTO.getUserId());
// 获取task信息
Task task = taskService.createTaskQuery()
.taskId(workFlowTaskInfoDTO.getTaskId())
.includeProcessVariables()
.singleResult();
// 设置响应信息
WorkFlowTaskInfoDTO.WorkFlowTaskInfoOutDTO taskOutDTO = new WorkFlowTaskInfoDTO.WorkFlowTaskInfoOutDTO();
taskOutDTO.setTaskName(task.getName());
taskOutDTO.setTaskDefKey(task.getTaskDefinitionKey());
taskOutDTO.setTaskVariableMap(task.getProcessVariables());
taskOutDTO.setProcessId(task.getProcessInstanceId());
workFlowTaskInfoDTO.setWorkFlowTaskInfoOutDTO(taskOutDTO);
return workFlowTaskInfoDTO;
}
/**
* 退回到发起岗位
*
* @param workFlowBackToStartDTO
* @return
*/
@Override
public WorkFlowBackToStartDTO submitTaskBack(WorkFlowBackToStartDTO workFlowBackToStartDTO) {
// 获取使用参数信息
String userId = workFlowBackToStartDTO.getUserId();
String taskId = workFlowBackToStartDTO.getTaskId();
String opinion = workFlowBackToStartDTO.getOpinion();
// 设置权限信息
identityService.setAuthenticatedUserId(userId);
// 获取任务信息
Task currentTask = taskService.createTaskQuery()
.taskId(taskId)
.includeProcessVariables()
.singleResult();
// 设置意见信息
if (StrUtil.isNotBlank(workFlowBackToStartDTO.getOpinion())) {
//只保留一条批注记录
List<Comment> commentList = taskService.getTaskComments(currentTask.getId());
if(ObjectUtil.isNotEmpty(commentList)){
commentList.forEach(common -> {
taskService.deleteComment(common.getId());
});
}
// 添加新的批注信息
taskService.addComment(currentTask.getId(),
currentTask.getProcessInstanceId(), workFlowBackToStartDTO.getOpinion());
}
// 获取当前任务参数信息
Map<String, Object> opinionMap = currentTask.getProcessVariables();
opinionMap.put(WorkFlowServerConstant.COMMENT_FLAG, opinion);
opinionMap.put(WorkFlowServerConstant.OPINION_FLAG, opinion);
// 对历史任务进行正序排序,获取最早的任务节点
List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery()
// 流程执行id
.executionId(currentTask.getProcessInstanceId())
// 按照时间排序
.orderByHistoricActivityInstanceStartTime()
.asc()
.list();
// 找到第一个userTask类型的任务节点,既为发起节点
HistoricActivityInstance firstActivityInstance = activityInstanceList.stream().filter(activityInstance ->
WorkFlowServerConstant.USER_TASK_FLAG.equalsIgnoreCase(activityInstance.getActivityType())
).findFirst().orElse(null);
// 获取实际发起节点的流程定义信息
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(firstActivityInstance.getProcessDefinitionId());
// 获取发起节点定义信息
ActivityImpl startActivity = processDefinition.findActivity(firstActivityInstance.getActivityId());
// 获取当前节点定义信息
ActivityImpl currentTaskActivity = processDefinition.findActivity(currentTask.getTaskDefinitionKey());
// 退回首节点校验,首节点不能再次退回首节点
if(startActivity.getId().equals(currentTask.getTaskDefinitionKey())){
throw new ServiceException("当前节点为首节点,无法退回");
}
// 退回首节点校验,首节点不能再次退回首节点
if(startActivity.getId().equals(currentTask.getTaskDefinitionKey())){
throw new ServiceException("当前节点为首节点,无法退回");
}
// 通过流程实例id以及任务定义key获取同级别任务列表信息,既需要退回的任务
List<Task> backTaskList = taskService.createTaskQuery()
.processInstanceId(currentTask.getProcessInstanceId())
.taskDefinitionKey(currentTask.getTaskDefinitionKey())
.list();
// 进行回退操作
backTaskList.forEach(task -> {
// 进行任务跳转
activitiUtil.turnTransitionForUTask(task.getId(),
currentTaskActivity,
startActivity,
opinionMap);
});
// 通过processId获取最新的一个task任务信息
Task nextTask = taskService.createTaskQuery()
// 流程实例id
.processInstanceId(currentTask.getProcessInstanceId())
// 存活状态
.active()
// 按照日期排序,最新的一个
.orderByTaskCreateTime()
.desc()
.singleResult();
// 获取此流程发起人信息
Map<String, Object> processVariables = currentTask.getProcessVariables();
String creator = (String) processVariables.get(WorkFlowServerConstant.CREATOR_FLAG);
// 进行处理人强制转换,修改流程处理人信息
nextTask.setAssignee(creator);
taskService.saveTask(nextTask);
taskService.claim(nextTask.getId(), creator);
// 设置响应信息
WorkFlowBackToStartDTO.WorkFlowBackToStartOutDTO taskOutDTO = new WorkFlowBackToStartDTO.WorkFlowBackToStartOutDTO();
taskOutDTO.setProcessId(nextTask.getAssignee());
taskOutDTO.setTaskName(nextTask.getName());
taskOutDTO.setTaskDefKey(nextTask.getTaskDefinitionKey());
taskOutDTO.setTaskVariableMap(nextTask.getProcessVariables());
taskOutDTO.setCreator(nextTask.getAssignee());
workFlowBackToStartDTO.setWorkFlowBackToStartOutDTO(taskOutDTO);
return workFlowBackToStartDTO;
}
/**
* 提交普通任务
*
* @param workFlowSubmitNormalDTO 参数信息
* @return
*/
@Override
public WorkFlowSubmitNormalDTO submitNormalTask(WorkFlowSubmitNormalDTO workFlowSubmitNormalDTO) {
// 获取使用参数信息
String userId = workFlowSubmitNormalDTO.getWfusers();
String taskId = workFlowSubmitNormalDTO.getTaskId();
String taskComment = workFlowSubmitNormalDTO.getComment();
// 设置权限信息
identityService.setAuthenticatedUserId(userId);
// 获取当前任务信息
Task task = taskService.createTaskQuery()
.taskId(taskId)
.includeProcessVariables()
.singleResult();
// 获取执行id
String executionId = task.getExecutionId();
// 设置留言信息,只留一条批注信息
List<Comment> commentList = taskService.getTaskComments(task.getId());
if(ObjectUtil.isNotEmpty(commentList)){
for(Comment comment : commentList){
// 删除现有批注信息
taskService.deleteComment(comment.getId());
}
}
// 添加批注信息
taskService.addComment(task.getId(), task.getProcessInstanceId(), taskComment);
// 获取参数信息
Map<String, Object> paramMap = workFlowSubmitNormalDTO.getVariableMap();
paramMap.put("comment", taskComment);
// 设置参数信息
runtimeService.setVariables(executionId, paramMap);
// 开始提交任务
taskService.complete(task.getId(), paramMap);
// 获取下一个任务信息
List<Task> taskList = taskService.createTaskQuery()
// 执行id
.executionId(executionId)
.list();
// 进行认领操作,默认第一个任务
if (ObjectUtil.isNotEmpty(taskList)) {
// 进行处理人强制转换
Task nextTask = taskService.createTaskQuery()
.taskId(taskList.get(0).getId())
.singleResult();
nextTask.setAssignee(userId);
taskService.saveTask(nextTask);
taskService.claim(nextTask.getId(), userId);
// 设置响应信息
WorkFlowSubmitNormalDTO.WorkFlowSubmitNormalOutDTO outDTO = new WorkFlowSubmitNormalDTO.WorkFlowSubmitNormalOutDTO();
outDTO.setNextTaskId(nextTask.getId());
outDTO.setTaskDefKey(nextTask.getTaskDefinitionKey());
outDTO.setTaskName(nextTask.getName());
workFlowSubmitNormalDTO.setWorkFlowSubmitNormalOutDTO(outDTO);
}
return workFlowSubmitNormalDTO;
}
/**
* 保存任务
*
* @param workFlowSaveTaskDTO 参数dto
*/
@Override
public void saveTask(WorkFlowSaveTaskDTO workFlowSaveTaskDTO) {
// 获取任务service
Task task = taskService.createTaskQuery()
.taskId(workFlowSaveTaskDTO.getTaskId())
.singleResult();
// 设置意见信息
String comment = workFlowSaveTaskDTO.getComment();
if (StrUtil.isNotBlank(comment)) {
//只保留一条批注记录
List<Comment> commentList = taskService.getTaskComments(task.getId());
if(ObjectUtil.isNotEmpty(commentList)){
commentList.forEach(common -> {
taskService.deleteComment(common.getId());
});
}
// 添加新的批注信息
taskService.addComment(task.getId(), task.getProcessInstanceId(), comment);
}
// 保存参数
if (ObjectUtil.isNotEmpty(workFlowSaveTaskDTO.getParamMap())) {
taskService.setVariables(task.getId(), workFlowSaveTaskDTO.getParamMap());
}
}
/**
* 委派任务
*
* @param delegator
* @param taskId
*/
@Override
public void delegateTask(String delegator, String taskId) {
// 获取任务信息
Task task = taskService.createTaskQuery()
.taskId(taskId)
.singleResult();
// 进行任务委派
task.setAssignee(delegator);
task.setOwner(task.getAssignee());
taskService.saveTask(task);
}
/**
* 跳转任务
*
* @param workFlowGoToTaskDTO 参数dto
*/
@Override
public void gotoTask(WorkFlowGoToTaskDTO workFlowGoToTaskDTO) {
// 获取使用参数信息
String taskId = workFlowGoToTaskDTO.getTaskId();
String nextTaskDefinitionKey = workFlowGoToTaskDTO.getDesTaskDefinitionKey();
String authUserId = workFlowGoToTaskDTO.getUserId();
// 获取任务信息
Task task = taskService.createTaskQuery()
.taskId(taskId)
.singleResult();
// 设置意见信息
if (StrUtil.isNotBlank(workFlowGoToTaskDTO.getComment())) {
//只保留一条批注记录
List<Comment> commentList = taskService.getTaskComments(task.getId());
if(ObjectUtil.isNotEmpty(commentList)){
commentList.forEach(common -> {
taskService.deleteComment(common.getId());
});
}
// 添加新的批注信息
taskService.addComment(task.getId(), task.getProcessInstanceId(), workFlowGoToTaskDTO.getComment());
}
// 如果未传入权限设置id,则设置为当前task权限
if (StrUtil.isBlank(authUserId)) {
authUserId = task.getAssignee();
}
// 设置权限信息
identityService.setAuthenticatedUserId(authUserId);
// 任务进行跳节点,获取实际发起节点的流程定义信息
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(task.getProcessDefinitionId());
// 获取当前节点定义信息以及目标节点的节点信息
ActivityImpl currentTaskActivity = processDefinition.findActivity(task.getTaskDefinitionKey());
ActivityImpl destinationTaskActivity = processDefinition.findActivity(nextTaskDefinitionKey);
// 通过流程实例id以及任务定义key获取同级别任务列表信息,既需要退回的任务
List<Task> backTaskList = taskService.createTaskQuery()
.processInstanceId(task.getProcessInstanceId())
.taskDefinitionKey(task.getTaskDefinitionKey())
.list();
// 设置参数信息,我们系统userTask里面处理人的属性都是使用的wfuser,如果没有设定,跳转会报错,先默认设定一个,跳转之后再进行修改处理人即可
Map<String, Object> paramMap = new HashMap<>();
paramMap.put(WorkFlowServerConstant.WORKFLOW_USERS_FLAG, authUserId);
backTaskList.forEach(backTask -> {
// 进行任务跳转
activitiUtil.turnTransitionForUTask(backTask.getId(),
currentTaskActivity,
destinationTaskActivity,
paramMap);
});
}
/**
* 查询下一节点信息
*
* @param nextPositionInfoDTO
* @return
*/
@Override
public WorkFlowNextPositionInfoDTO findNextActivityUserInfo(WorkFlowNextPositionInfoDTO nextPositionInfoDTO) {
// 获取参数信息
String taskId = nextPositionInfoDTO.getTaskId();
// 获取task信息
Task task = taskService.createTaskQuery()
.taskId(taskId)
.singleResult();
// 获取全部流程自定义变量信息
Map<String, Object> taskVariables = runtimeService.getVariables(task.getExecutionId());
// 任务进行跳节点,获取实际发起节点的流程定义信息
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(task.getProcessDefinitionId());
// 获取当前节点信息,可以获取outgoingSequenceFlows,结合自定义变量信息,可以获取下一节点信息
ActivityImpl currentActivity = processDefinition.findActivity(task.getTaskDefinitionKey());
// 获取当前节点对外指向,并且对指向进行分析
List<PvmTransition> transitionList = currentActivity.getOutgoingTransitions();
if (ObjectUtil.isEmpty(transitionList)) {
throw new ServiceException("当前节点没有下一节点信息");
}
// 最终获取全部下一处理岗位定义节点
List<PvmActivity> finalActivityList = new ArrayList<>();
// 循环获取目标节点信息,当前行内服务,只使用排他网关,所以后续分支只支持单一条件满足,下一节点为单一分支
for (PvmTransition transition : transitionList) {
// 获取目标节点
PvmActivity destinationActivity = transition.getDestination();
// 获取目标节点nodeType类型
String activityNodeType = StrUtil.toString(destinationActivity.getProperty(WorkFlowServerConstant.NODE_TYPE));
// 目标节点不同类型进行不同处理,
if (WorkFlowServerConstant.EXCLUSIVE_GATEWAY.equals(activityNodeType) || WorkFlowServerConstant.INCLUSIVE_GATEWAY.equals(activityNodeType)) {
// 注意此处为 节点->排他网关/包含网关->节点 形式,更复杂形式需要针对业务进行调整
List<PvmActivity> exclusiveGateActivityList = activitiUtil.getNextPositionByExclusiveGateway(destinationActivity, taskVariables);
finalActivityList.addAll(exclusiveGateActivityList);
} else if (WorkFlowServerConstant.PARALLEL_GATEWAY.equals(activityNodeType)) {
// 并行网关 节点->并行网关->节点
List<PvmActivity> parallelGateActivityList = activitiUtil.getNextPositionByParallelGateway(destinationActivity);
finalActivityList.addAll(parallelGateActivityList);
} else if (WorkFlowServerConstant.USER_TASK_FLAG.equalsIgnoreCase(activityNodeType)) {
// 普通用户任务 节点->节点
finalActivityList.add(destinationActivity);
} else {
throw new ServiceException(StrUtil.format("当前获取下一岗位信息暂时activityNodeType[{}]暂时不支持!", activityNodeType));
}
}
// 获取下一岗位信息非空判定
if (ObjectUtil.isEmpty(finalActivityList)) {
throw new ServiceException(StrUtil.format("当前taskId[{}]对应节点[{}]获取下一岗位信息为空!",
taskId, task.getTaskDefinitionKey()));
}
// 获取下一岗位名称id信息
ActivityImpl nextActivity = (ActivityImpl)finalActivityList.get(0);
String nextTaskName = nextActivity.getProperty(WorkFlowServerConstant.NAME_FLAG).toString();
// 下一岗位id
TaskDefinition taskDefinition = (TaskDefinition)nextActivity.getProperty(WorkFlowServerConstant.TASK_DEFINITION);
String nextDefinitionKey = taskDefinition.getKey();
// 设置响应参数
WorkFlowNextPositionInfoDTO.WorkFlowNextPositionInfoOutDTO outDTO = new WorkFlowNextPositionInfoDTO.WorkFlowNextPositionInfoOutDTO();
outDTO.setNextTaskName(nextTaskName);
outDTO.setNextTaskDefinitionKey(nextDefinitionKey);
nextPositionInfoDTO.setWorkFlowNextPositionInfoOutDTO(outDTO);
return nextPositionInfoDTO;
}
}
3. 测试效果
以下为流程测试部分,截取几个比较重要的操作,简单进行以下接口测试
3.1 部署一个流程
3.2 获取部署列表
3.3 发起流程
3.4 其余接口
功能比较多,此处就不一一进行测试了,交给测试人员进行测试吧,其余提供功能如下所示: