简单的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 {@Autowiredprivate WorkFlowUtil workFlowUtil;@Autowiredprivate RedisUtil redisUtil;@Autowiredprivate WorkFlowConvert workFlowConvert;@Autowiredprivate 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")})@ResponseBodypublic 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 {@Autowiredprivate 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) {// 获取当前任务判定条件,注意此处不是节点,为对外条件flowSequenceObject 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 {@Autowiredprivate RepositoryService repositoryService;@Autowiredprivate TaskService taskService;@Autowiredprivate RuntimeService runtimeService;@Autowiredprivate ProcessEngine processEngine;@Autowiredprivate HistoryService historyService;@Autowiredprivate IdentityService identityService;@Autowiredprivate ActivitiUtil activitiUtil;@Autowiredprivate ActivitiConvert activitiConvert;/*** 根据流程id查询流程信息,包含参数信息** @param processId 流程实例id* @return*/@Overridepublic WorkFlowActProcessInstanceDTO findProcessByPId(String processId) {// 获取流程实例信息ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processId).includeProcessVariables().singleResult();// 返回转换内容信息return activitiConvert.processInstanceCovertToDTO(processInstance);}/*** 开启一个流程信息** @param startProcessDTO* @return*/@Overridepublic 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*/@Overridepublic void cancelProcessByProcessId(String processId, String userId) {// 权限认证identityService.setAuthenticatedUserId(userId);// 开始进行业务撤销runtimeService.deleteProcessInstance(processId, WorkFlowServerConstant.DEFAULT_CANCEL_REASON);}/*** 结束流程** @param flowEndProcessDTO*/@Overridepublic 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 {@Autowiredprivate ActHiProcinstMapper actHiProcinstMapper;@Autowiredprivate ActivitiConvert activitiConvert;@Autowiredprivate TaskService taskService;@Autowiredprivate RuntimeService runtimeService;@Autowiredprivate HistoryService historyService;@Autowiredprivate ActivitiUtil activitiUtil;/*** 通过用户id获取此用户全部业务信息** @param userId* @return*/@Overridepublic 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*/@Overridepublic 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 {@Autowiredprivate ActivitiUtil activitiUtil;@Autowiredprivate TaskService taskService;@Autowiredprivate IdentityService identityService;@Autowiredprivate RepositoryService repositoryService;@Autowiredprivate HistoryService historyService;@Autowiredprivate RuntimeService runtimeService;/*** 根据任务id和用户id查询任务信息** @param workFlowTaskInfoDTO* @return*/@Overridepublic 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*/@Overridepublic 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*/@Overridepublic 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();// 获取执行idString 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*/@Overridepublic void saveTask(WorkFlowSaveTaskDTO workFlowSaveTaskDTO) {// 获取任务serviceTask 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*/@Overridepublic 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*/@Overridepublic 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*/@Overridepublic 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();// 下一岗位idTaskDefinition 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 其余接口
功能比较多,此处就不一一进行测试了,交给测试人员进行测试吧,其余提供功能如下所示: