简单的springboot整合activiti5.22.0

简单的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 其余接口

功能比较多,此处就不一一进行测试了,交给测试人员进行测试吧,其余提供功能如下所示:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/36095.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

1、加密算法-MD5随机盐

一、说明 MD5消息摘要算法&#xff0c;属Hash算法一类。MD5算法对输入任意长度的消息进行运行&#xff0c;产生一个128位的消息摘要(32位的数字字母混合码)。 二、主要特点 不可逆&#xff0c;相同数据的MD5值肯定一样&#xff0c;不同数据的MD5值不一样 (一个MD5理论上的确…

小程序开发平台源码系统——内容付费(知识付费)小程序功能 带完整的安装代码包以及搭建部署教程

系统概述 随着互联网的发展&#xff0c;人们对于知识和信息的获取需求日益增长。内容付费小程序应运而生&#xff0c;为用户提供了一个便捷、高效的知识交易平台。小程序开发平台源码系统则为开发者提供了构建内容付费小程序的基础和工具&#xff0c;使其能够快速打造具有个性化…

十年磨一剑,华火电燃组合灶重磅问世,引领厨房新时代

十年磨一剑&#xff0c;华火研发团队经过不懈努力&#xff0c;成功将等离子电生明火技术与电陶炉红外线光波炉技术精妙融合&#xff0c;打造出的这款具有划时代是意义的电燃组合灶HH-SZQP60&#xff0c;终于在 2024 年6月震撼登场&#xff0c;该灶以其卓越的创新技术和独特的产…

VAE-pytorch代码

import osimport torch import torch.nn as nn import torch.nn.functional as F from torch.utils.data import DataLoaderfrom torchvision import transforms, datasets from torchvision.utils import save_imagefrom tqdm import tqdmclass VAE(nn.Module): # 定义VAE模型…

一步步带你解锁Stable Diffusion:老外都眼馋的 SD 中文提示词插件分享

大家好我是极客菌&#xff01;今天我们继续来分享一个外国人都眼馋的 SD 中文提示词插件。 那我们废话不多说&#xff0c;直接开整。 SD 的插件安装&#xff0c;小伙伴们应该都会了吧&#xff0c;我这里再简单讲下哦&#xff0c;到「扩展」中的「可下载」中点击「加载扩展列表…

国标GB/T 28181详解:国标GBT28181-2022的目录通知流程

目录 一、定义 二、作用 1、实时同步设备目录状态 2、优化资源管理和调度 3、增强系统的可扩展性和灵活性 4、提高系统的可靠性和稳定性 5、支持多级级联和分布式部署 6、便于用户管理和监控 三、基本要求 1、目录通知满足以下基本要求 2、关键要素 &#xff08;1…

python-立方和不等式

[题目描述] 试求满足下述立方和不等式的 m 的整数解。 1^32^3...m^3≤n。本题算法如下&#xff1a; 对指定的 n&#xff0c;设置求和循环&#xff0c;从 i1 开始&#xff0c;i 递增1取值&#xff0c;把 i^3 (或 i∗i∗i)累加到 s&#xff0c;直至 s>n&#xff0c;脱离循环作…

docker配置redis主从复制

下载redis,复制redis.conf 主节点(6379) 修改redis.conf # bind 127.0.0.1 # 注释掉这里 protected-mode no # 改为no port 6379从节点(6380) 修改redis.conf bind 127.0.0.1 protected-mode no # 改为no port 6380 replicaof 172.17.0.2 6379 # 这里的ip为主节点容器的i…

Oracle数据库使用指南基本概念

学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把手教你开发炫酷的vbs脚本制作(完善中……&#xff09; 4、牛逼哄哄的 IDEA编程利器技巧(编写中……&#xff09; 5、面经吐血整理的 面试技…

介绍几种 MySQL 官方高可用方案

前言&#xff1a; MySQL 官方提供了多种高可用部署方案&#xff0c;从最基础的主从复制到组复制再到 InnoDB Cluster 等等。本篇文章以 MySQL 8.0 版本为准&#xff0c;介绍下不同高可用方案架构原理及使用场景。 1.MySQL Replication MySQL Replication 是官方提供的主从同…

HarmonyOS--数据持久化

用户首选项 场景介绍 1、用户首选项为应用提供Key-Value键值型的数据处理能力&#xff0c;支持应用持久化轻量级数据&#xff0c;并对其修改和查询。当用户希望有一个全局唯一存储的地方&#xff0c;可以采用用户首选项来进行存储。 2、Preferences会将该数据缓存在内存中&a…

模型情景制作-制作一棵树

情景模型中&#xff0c;最常用到的也是最能提升情景中生气的就是树。然而&#xff0c;自然的生长和环境的影响使得树的制作变成了考验制作者观察力的一道考题。制作一棵逼真的树&#xff0c;我们可以参考下面的这种方法。 铁丝制树 您需要准备9—12根铁丝&#xff0c;每根的长…

SuperCopy解决文档不能复制问题

有一些文档&#xff0c;我们要使用时&#xff0c;总是面临收费的情况&#xff0c;让我们不能复制&#xff0c;让人头疼不已&#xff01;&#xff01;&#xff01; SuperCopy就可以解决这个问题。 获取SuperCopy步骤 1. 打开浏览器&#xff0c;点击右上角的三个点 2. 找到扩…

老板电器 45 年的烹饪经验,浓缩在这款烹饪大模型中

在科技不断进步的时代&#xff0c;人工智能&#xff08;AI&#xff09;迅速成为推动各行各业发展的重要力量。家电行业也不例外&#xff0c;根据 Gartner 的报告预测&#xff0c;到 2024 年&#xff0c;AI 家电市场的规模将达到万亿美元级别。这一预估凸显了智能化在家电行业中…

网络安全 DVWA通关指南 Cross Site Request Forgery (CSRF)

DVWA Cross Site Request Forgery (CSRF) 文章目录 DVWA Cross Site Request Forgery (CSRF)DVWA Low 级别 CSRFDVWA Medium 级别 CSRFDVWA High 级别 CSRFDVWA Impossible 级别 CSRF CSRF是跨站请求伪造攻击&#xff0c;由客户端发起&#xff0c;是由于没有在执行关键操作时&a…

【黑龙江哪些行业需要做等保?】

黑龙江等保测评是衡量企业网络安全水平的一项主要指标&#xff0c;包括&#xff1a;金融&#xff0c;能源&#xff0c;电信&#xff0c;医疗&#xff0c;教育&#xff0c;交通&#xff0c;制造&#xff0c;电商等。 等保测评是黑龙江省信息化建设的重要组成部分&#xff0c;也…

旅游管理系统源码小程序

便捷旅行&#xff0c;尽在掌握 旅游管理系统是一款基于FastAdminElementUNIAPP开发的多端&#xff08;微信小程序、公众号、H5&#xff09;旅游管理系统&#xff0c;拥有丰富的装修组件、多端分享、模板消息、电子合同、旅游攻略、旅游线路及相关保险预订等功能&#xff0c;提…

1961 Springboot自习室预约系统idea开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot 自习室预约管理系统是一套完善的信息系统&#xff0c;结合springboot框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用springboot框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库…

大型企业组网如何规划网络

大型企业组网是一个复杂的过程&#xff0c;它需要细致的规划和设计&#xff0c;以确保网络能够满足企业的业务需求&#xff0c;同时保证性能、安全性和可扩展性。以下是规划大型企业网络的一些关键步骤和考虑因素&#xff1a; 1. 需求分析 业务需求&#xff1a;与各个业务部门…

EWM学习之旅-1-EWM100

系统学习一个业务模块已经变得越来越重要&#xff0c;开始吧&#xff0c;EWM&#xff01; EWM的Learning Journey中包括7本 ebook,100/110/115/120/125/130/140&#xff0c;一本一本的啃吧&#xff0c;相信很多内容是重复的。 EWM100很适合初学者&#xff0c;了解概念术语&…