简单的springboot整合activiti5.22.0

news2024/11/18 17:51:41

简单的springboot整合activiti5.22.0

1. 需求

我们公司原本的流程服务是本地workflow模块以及一个远程的webService对应的activiti服务,其中activiti版本为5.22.0,之前想将activiiti5.22.0进行升级,选择了camunda,也对项目进行了部分改造,新增camunda-server服务,但是后来觉得数据迁移比较费劲,并且行里数据准确性要求比较高,原有的老数据不能丢失,历史记录必须完整保存,所以因为历史数据原因就没有使用camnuda了,而是进行了workflow-server服务的改造,将activiti5.22.0对应的webService服务迁移至本地服务,由于本webService服务提供了风险与信贷两个系统的流程服务,所以在workflow-server中还提供了风险调用原webService接口,并且也是改造成了fiegn调用形式

2. 具体实现

以下为改造的具体实现,具体主要包含两个部分,具体如下:

  • 第一部分为本地服务提供的接口,包含流程的发布,部署,流程图获取,以及流程的发起提交结束等基本操作。
  • 第二部分则是为风险系统提供的流程操作接口,主要包含发起提交结束等

2.1 本地服务改造

2.1.1 pom修改

原有的workflow-server对应的pom中新增springboot整合activiti对应的jar包,具体添加部分如下标注activiti所示

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>credit-workflow</artifactId>
        <groupId>cn.git</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>workflow-server</artifactId>
    <dependencies>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>business-common</artifactId>
            <version>1.0-SNAPSHOT</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.alibaba.cloud</groupId>
                    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>credit-swagger-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>credit-log-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>cache-manage-client</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>workflow-client</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>afterloan-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>credit-discovery-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>loan-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>account-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>management-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>query-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>credit-monitor-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-log4j-2.x</artifactId>
            <version>8.6.0</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>rule-manage-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <!-- activiti 5.22.0启动器,排除mybatis依赖 -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter-basic</artifactId>
            <version>5.22.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.mybatis</groupId>
                    <artifactId>mybatis</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-diagram-rest</artifactId>
            <version>5.22.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- compiler -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>${mapstruct.version}</version>
                        </path>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>${lombok.version}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
            <!-- package -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
2.1.2 controller修改

主要修改了部分controller方法,添加原有webService服务提供的流程部署,流程图获取,xml获取,部署流程列表等方法,具体代码如下:

package cn.git.workflow.controller;

import cn.git.common.limit.ApiLimitSlidingWindow;
import cn.git.common.limit.SlidingWindowEnum;
import cn.git.common.page.PageBean;
import cn.git.common.result.Result;
import cn.git.common.result.ResultStatusEnum;
import cn.git.redis.RedisUtil;
import cn.git.workflow.constant.WorkFlowServerConstant;
import cn.git.workflow.dto.*;
import cn.git.workflow.dto.activiti.WorkFlowLoadTemplateDTO;
import cn.git.workflow.entity.PageTbConVote;
import cn.git.workflow.entity.WorkFlowUndoTask;
import cn.git.workflow.entity.activiti.WorkFlowLoadTemplate;
import cn.git.workflow.mapstruct.WorkFlowConvert;
import cn.git.workflow.page.WorkFlowPage;
import cn.git.workflow.service.WorkFlowService;
import cn.git.workflow.util.WorkFlowUtil;
import cn.git.workflow.vo.*;
import cn.git.workflow.vo.activiti.WorkFlowLoadTemplateInVO;
import cn.git.workflow.vo.activiti.WorkFlowLoadTemplateOutVO;
import cn.git.workflow.webservice.process.Exception_Exception;
import cn.git.workflow.webservice.query.BpmException_Exception;
import cn.hutool.core.util.StrUtil;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.xml.sax.SAXException;

import javax.validation.Valid;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * 流程通用controller
 *
 * @program: bank-credit-sy
 * @author: lixuchun
 * @create: 2021-06-09
 */
@Api(value = "WorkFlowController流程通用controller", tags = "WorkFlowController流程通用controller")
@RestController
@RequestMapping("/workflow")
@Slf4j
public class WorkFlowController {

    @Autowired
    private WorkFlowUtil workFlowUtil;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private WorkFlowConvert workFlowConvert;

    @Autowired
    private WorkFlowService workFlowService;

    /**
     * 代办未分类列表信息count查询
     *
     * @param userCd 柜员号
     * @param orgCd  机构号
     * @return WorkFlowPage 分页对象
     */
    @ApiOperation(value = "代办未分类列表信息count查询", notes = "代办未分类列表信息count查询")
    @ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
    @GetMapping(value = "/listUndoWorkInfoInit")
    public Result<WorkFlowPage<List<Map<String, Object>>>> listUndoWorkInfoInit(
            @ApiParam(name = "userCd", value = "柜员号", required = true)
                    String userCd,
            @ApiParam(name = "orgCd", value = "机构号", required = true)
                    String orgCd) {
        try {
            log.info("代办未分类列表信息count查询参数userCd[{}],orgCd[{}]!", userCd, orgCd);
            return Result.ok(workFlowService.findWorkCountFlowList(userCd, orgCd));
        } catch (Exception e) {
            e.printStackTrace();
            log.error(workFlowUtil.getStackTraceInfo(e));
            return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
        }
    }

    /**
     * 代办未分类列表信息count查询
     *
     * @param userCd 柜员号
     * @param orgCd  机构号
     * @param systemFlag 系统标识
     * @return WorkFlowPage 分页对象
     */
    @ApiOperation(value = "系统代办未分类列表信息count查询", notes = "系统代办未分类列表信息count查询")
    @ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
    @GetMapping(value = "/listSysUndoWorkInfoInit")
    public Result<WorkFlowPage<List<Map<String, Object>>>> listSysUndoWorkInfoInit(
            @ApiParam(name = "userCd", value = "柜员号", required = true)
                    String userCd,
            @ApiParam(name = "orgCd", value = "机构号", required = true)
                    String orgCd,
            @ApiParam(name = "systemFlag", value = "系统标识,0或者空为信贷,1为风险,2为储备系统", required = true)
                    String systemFlag) {
        try {
            log.info("代办未分类列表信息count查询参数userCd[{}],orgCd[{}]!", userCd, orgCd);
            return Result.ok(workFlowService.findSysWorkCountFlowList(userCd, orgCd, systemFlag));
        } catch (Exception e) {
            e.printStackTrace();
            log.error(workFlowUtil.getStackTraceInfo(e));
            return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
        }
    }

    /**
     * 获取流程图
     * @param processId
     * @return
     * @throws Exception_Exception
     */
    @GetMapping(value = "/findProcessPic")
    @ApiResponses({@ApiResponse(code = 1, message = "OK")})
    @ResponseBody
    public String findProcessPic(@ApiParam(value = "流程ID", name = "processId", required = true)
                                             String processId) throws Exception_Exception, IOException {
        return workFlowService.findProcessPic(processId);
    }

    /**
     * 具体业务代办列表查询
     *
     * @param workFlowUndoTaskInVO 代办分类任务查询inVO
     * @return WorkFlowPage 分页对象
     */
    @ApiOperation(value = "具体业务代办列表", notes = "具体业务代办列表")
    @ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
    @GetMapping(value = "/listUndoWorkInfoDetail")
    public Result<WorkFlowPage<WorkFlowUndoTask>> listUndoWorkInfoDetail(
            @ApiParam(name = "workFlowUndoTaskInVO", value = "代办分类任务查询inVO", required = true)
                    WorkFlowUndoTaskInVO workFlowUndoTaskInVO) throws BpmException_Exception {
        try {
            return Result.ok(workFlowService.findUndoWorkTaskDetailList(
                    workFlowConvert.workFlowTaskInVoConvertTaskDto(workFlowUndoTaskInVO)));
        } catch (Exception e) {
            e.printStackTrace();
            log.error(workFlowUtil.getStackTraceInfo(e));
            return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
        }
    }

    /**
     * 点击代办列表bizNo跳转到详情页面
     *
     * @param taskId 任务id
     * @param userCd 用户cd
     * @param orgCd  机构号
     * @return Result
     */
    @ApiOperation(value = "点击代办列表bizNo跳转到详情页面", notes = "点击代办列表bizNo跳转到详情页面")
    @ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class),
            @ApiResponse(code = -1, message = "ERROR", response = Result.class)})
    @GetMapping(value = "/findTaskDetailInfo/{taskId}/{userCd}/{orgCd}")
    public Result findTaskDetailInfo(
            @ApiParam(name = "taskId", value = "代办任务id", required = true)
            @PathVariable(value = "taskId") String taskId,
            @ApiParam(name = "userCd", value = "柜员cd", required = true)
            @PathVariable(value = "userCd") String userCd,
            @ApiParam(name = "orgCd", value = "机构cd", required = true)
            @PathVariable(value = "orgCd") String orgCd) {
        WorkFlowUndoTaskDetailDTO workFlowDTO = workFlowService.findTaskDetailInfo(taskId, userCd, orgCd);
        if(StrUtil.isNotBlank(workFlowDTO.getErrorMessage())){
            return Result.error(workFlowDTO.getErrorMessage());
        }
        return Result.ok(workFlowDTO);
    }

    /**
     * 跟踪列表初始化列表信息查询
     *
     * @param workFlowTraceListInVO inVo
     * @return Result<WorkFlowTraceListOutVO>
     */
    @ApiLimitSlidingWindow(slidingWindowEnum = SlidingWindowEnum.WORKFLOW_NEW_TRACE_HIS_WINDOW)
    @ApiOperation(value = "跟踪列表初始化列表信息查询", notes = "跟踪列表初始化列表信息查询")
    @ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
    @GetMapping(value = "/findTraceList")
    public Result<WorkFlowTraceListOutVO> findTractList(
            @ApiParam(name = "workFlowTraceListInVO", value = "跟踪列表inVo")
                    WorkFlowTraceListInVO workFlowTraceListInVO) throws BpmException_Exception {
        try {
            WorkFlowTraceListDTO workFlowTraceListDTO = workFlowService.findTraceList(
                    workFlowConvert.workFlowTractListInVoConvertTractDto(workFlowTraceListInVO));
            return Result.ok(workFlowConvert.workFlowTractDtoConvertListOutVo(workFlowTraceListDTO));
        } catch (Exception e) {
            e.printStackTrace();
            log.error(workFlowUtil.getStackTraceInfo(e));
            return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
        }
    }

    /**
     * 历史统跟踪列表初始化列表信息查询
     *
     * @param workFlowTraceListInVO inVo
     * @return Result<WorkFlowTraceListOutVO>
     */
    @ApiLimitSlidingWindow(slidingWindowEnum = SlidingWindowEnum.WORKFLOW_TRACE_HIS_WINDOW)
    @ApiOperation(value = "历史跟踪列表初始化列表信息查询", notes = "历史跟踪列表初始化列表信息查询")
    @ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
    @GetMapping(value = "/old/findTraceList")
    public Result<WorkFlowTraceListOutVO> findOldSysTractList(
            @ApiParam(name = "workFlowTraceListInVO", value = "跟踪列表inVo")
                    WorkFlowTraceListInVO workFlowTraceListInVO) {
        try {
            WorkFlowTraceListDTO workFlowTraceListDTO = workFlowService.findOldTraceList(
                    workFlowConvert.workFlowTractListInVoConvertTractDto(workFlowTraceListInVO));
            return Result.ok(workFlowConvert.workFlowTractDtoConvertListOutVo(workFlowTraceListDTO));
        } catch (Exception e) {
            e.printStackTrace();
            log.error(workFlowUtil.getStackTraceInfo(e));
            return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
        }
    }

    /**
     * 查询跟踪列表单个任务历史记录
     *
     * @param historyListInVO inVo
     * @return WorkFlowTraceHistoryListOutVO outVo
     */
    @ApiOperation(value = "查询跟踪列表单个任务历史记录", notes = "查询跟踪列表单个任务历史记录")
    @ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
    @GetMapping("/findTraceTaskHistoryList")
    public Result<WorkFlowTraceHistoryListOutVO> findTraceTaskHistoryList(
            @ApiParam(name = "historyListInVO", value = "跟踪列表历史查询inVo")
                    WorkFlowTraceHistoryListInVO historyListInVO) throws BpmException_Exception {
        try {
            WorkFlowTraceHistoryListDTO workFlowTraceHistoryListDTO = workFlowService.findTraceHistoryList(
                    workFlowConvert.workflowTraceHisInVoConvertHisDto(historyListInVO));
            return Result.ok(workFlowConvert.workflowTraceHisDtoConvertHistoryListOutVo(workFlowTraceHistoryListDTO));
        } catch (Exception e) {
            e.printStackTrace();
            log.error(workFlowUtil.getStackTraceInfo(e));
            return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
        }
    }

    /**
     * 通过客户号获取贷审会列表信息
     * 包含urlName路径信息,点击进行跳转
     * @param customerNum 客户号
     * @return 贷审会列表信息
     */
    @ApiOperation(value = "柜员登录后选定客户查看贷审会列表获取", notes = "贷审会列表获取")
    @ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
    @GetMapping(value = "/findVoteMeetingList/{customerNum}")
    public Result<PageBean<PageTbConVote>> findVoteMeetingList(@PathVariable("customerNum") String customerNum) {
        try {
            PageBean<PageTbConVote> votePageBean = workFlowService.pageVoteMeetingList(customerNum);
            return Result.ok(votePageBean);
        } catch (Exception e) {
            log.error(workFlowUtil.getStackTraceInfo(e));
            return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
        }
    }

    /**
     * 获取下一处理环节
     * @param workFlowEndProcessDTO dto
     * @return WorkFlowNextPositionDTO dto
     */
    @ApiOperation(value = "获取下一处理环节", notes = "获取下一处理环节")
    @ApiResponses({@ApiResponse(code = 1, message = "OK")})
    @GetMapping(value = "/coreFindNextPositionList")
    public Result<WorkFlowNextPositionDTO> findNextPositionList(
            @ApiParam(value = "workFlowEndProcessDTO", name = "获取下一处理环节岗位信息dto", required = true)
            WorkFlowNextPositionDTO workFlowEndProcessDTO) {
        try {
            WorkFlowNextPositionDTO workFlowNextPositionDTO = workFlowService.findNextPositionList(workFlowEndProcessDTO);
            return Result.ok(workFlowNextPositionDTO);
        } catch (Exception e) {
            e.printStackTrace();
            log.error(workFlowUtil.getStackTraceInfo(e));
            return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
        }
    }

    /**
     * 获取下一处理人列表信息
     * @param workFlowNextUserListDTO dto
     * @return WorkFlowNextUserListDTO dto
     */
    @ApiOperation(value = "获取下一处理人列表信息", notes = "获取下一处理人列表信息")
    @ApiResponses({@ApiResponse(code = 1, message = "OK")})
    @GetMapping(value = "/coreFindNextUserInfoList")
    public Result<WorkFlowNextUserListDTO> findNextUserInfoList(
            @ApiParam(value = "workFlowNextUserListDTO", name = "获取下一处理人列表信息dto", required = true)
            WorkFlowNextUserListDTO workFlowNextUserListDTO) {
        try {
            return Result.ok(workFlowService.findNextUserInfoList(workFlowNextUserListDTO));
        } catch (Exception e) {
            e.printStackTrace();
            log.error(workFlowUtil.getStackTraceInfo(e));
            return Result.error(ResultStatusEnum.WORKFLOW_EXCEPTION.getCode(), e.getMessage());
        }
    }

    /**
     * 设置webService访问路径 todo: 测试环境使用,生产删除此方法
     * @param serviceType 类型
     * @return Result
     */
    @ApiOperation(value = "设置webService访问路径", notes = "设置webService访问路径")
    @ApiResponses({@ApiResponse(code = 1, message = "OK")})
    @GetMapping(value = "/webServiceType/{serviceType}")
    public Result setWebServiceType(
            @ApiParam(name = "serviceType", value = "service类型,UAT,TEST", required = true)
            @PathVariable(value = "serviceType") String serviceType) {
        if (!WorkFlowServerConstant.WEB_SERVICE_URL_UAT.equals(serviceType)
                && !WorkFlowServerConstant.WEB_SERVICE_URL_TEST.equals(serviceType)) {
            return Result.error("正确填入 环境类型, UAT 或者 TEST");
        } else {
            redisUtil.set(WorkFlowServerConstant.WEB_SERVICE_URL_KEY, serviceType);
            return Result.ok();
        }
    }

    /**
     * 回退流程到上一岗位
     * @return Result
     */
    @ApiOperation(value = "回退流程到上一岗位", notes = "回退流程到上一岗位")
    @ApiResponses({@ApiResponse(code = 1, message = "OK")})
    @GetMapping(value = "/submitBackPrevious")
    public Result submitBackPrevious(
            @ApiParam(value = "workFlowBackPreviousInVO", name = "退回上一岗位基本信息", required = true)
            WorkFlowBackPreviousInVO workFlowBackPreviousInVO)
            throws cn.git.workflow.webservice.task.BpmException_Exception, BpmException_Exception {
        String errorMessage = workFlowService
                .submitBackPrevious(workFlowConvert.backInVoConvertDto(workFlowBackPreviousInVO));
        if (StrUtil.isNotBlank(errorMessage)) {
            return Result.error(errorMessage);
        }
        return Result.ok();
    }

    /**
     * 通过文件部署流程图, 文件格式为xml
     * @return
     */
    @ApiOperation(value = "直接通过文件部署新流程图", notes = "部署新流程图,返回流程部署成功的流程定义id[processDefinitionId]")
    @PostMapping(value = "/deploy/process")
    public Result<String> uploadProcessDefinition(@RequestParam MultipartFile file) throws IOException,
            ParserConfigurationException, SAXException {
        // 获取文件进行部署
        String processDefinitionId = workFlowService.deployProcess(file);
        return Result.ok(processDefinitionId);
    }

    /**
     * 获取流程已经部署信息
     *
     * @param  loadTemplateInVO
     * @return WorkFlowPage 分页对象
     */
    @ApiOperation(value = "获取流程已经部署信息", notes = "获取流程已经部署信息")
    @ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
    @PostMapping(value = "/load/template/page")
    public Result<WorkFlowLoadTemplateOutVO> getLoadTemplatePage(
            @Valid @RequestBody WorkFlowLoadTemplateInVO loadTemplateInVO) {
        // 参数赋值操作
        WorkFlowLoadTemplateDTO templateDTO = new WorkFlowLoadTemplateDTO();
        templateDTO.setTemplateKey(loadTemplateInVO.getTemplateKey());
        templateDTO.setVersion(loadTemplateInVO.getVersion());

        // 进行查询
        WorkFlowPage<WorkFlowLoadTemplate> loadTemplatePage = workFlowService
                .getLoadTemplatePage(templateDTO);
        WorkFlowLoadTemplateOutVO outVO = new WorkFlowLoadTemplateOutVO();
        outVO.setPageBean(loadTemplatePage);
        return Result.ok(outVO);
    }

    /**
     * 根据流程部署key获取xml信息
     *
     * @param  loadTemplateInVO
     * @return WorkFlowPage 分页对象
     */
    @ApiOperation(value = "根据流程部署key获取xml信息", notes = "根据流程部署key获取xml信息")
    @ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
    @PostMapping(value = "/load/template/xml")
    public void downLoadTemplateXML(@RequestBody WorkFlowLoadTemplateInVO loadTemplateInVO) throws IOException {
        // 参数赋值操作
        WorkFlowLoadTemplateDTO templateDTO = new WorkFlowLoadTemplateDTO();
        templateDTO.setTemplateKey(loadTemplateInVO.getTemplateKey());
        templateDTO.setVersion(loadTemplateInVO.getVersion());

        // 进行查询
        workFlowService.getLoadTemplateXML(templateDTO);
    }

    /**
     * 根据流程部署key获取xml信息
     *
     * @param  loadTemplateInVO
     * @return WorkFlowPage 分页对象
     */
    @ApiOperation(value = "根据流程部署key获取xml信息", notes = "根据流程部署key获取xml信息")
    @ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
    @PostMapping(value = "/load/template/xml/str")
    public Result<String> getLoadTemplateXMLStr(@RequestBody WorkFlowLoadTemplateInVO loadTemplateInVO) throws IOException {
        // 参数赋值操作
        WorkFlowLoadTemplateDTO templateDTO = new WorkFlowLoadTemplateDTO();
        templateDTO.setTemplateKey(loadTemplateInVO.getTemplateKey());
        templateDTO.setVersion(loadTemplateInVO.getVersion());

        // 进行查询
        String loadTemplateXMLStr = workFlowService.getLoadTemplateXMLStr(templateDTO);
        return Result.ok(loadTemplateXMLStr);
    }

    /**
     * 根据流程部署key获取部署图片信息
     *
     * @param  loadTemplateInVO
     * @return WorkFlowPage 分页对象
     */
    @ApiOperation(value = "根据流程部署key获取xml信息", notes = "根据流程部署key获取xml信息")
    @ApiResponses({@ApiResponse(code = 1, message = "OK", response = Result.class)})
    @PostMapping(value = "/load/template/png")
    public void getLoadTemplatePIC(@RequestBody WorkFlowLoadTemplateInVO loadTemplateInVO) throws IOException {
        // 参数赋值操作
        WorkFlowLoadTemplateDTO templateDTO = new WorkFlowLoadTemplateDTO();
        templateDTO.setTemplateKey(loadTemplateInVO.getTemplateKey());
        templateDTO.setVersion(loadTemplateInVO.getVersion());

        // 进行查询
        workFlowService.getLoadTemplatePIC(templateDTO);
    }
}

2.1.3 具体的serviceImpl实现

流程的主要部分则是在此处实现,具体包含了发起,提交,撤销,退回,结束,跳岗,历史信息查询等功能,具体实现代码过多,所以单写了两片博文记录,地址分别如下

  • 第一部分代码 : 简单的springboot整合activiti5-serviceImpl部分(1)
  • 第二部分代码 : 简单的springboot整合activiti5-serviceImpl部分(2)
2.1.4 工具类实现

此处只记录activiti5.22.0使用的工具包了,其余部分都是业务实现逻辑util则不进行展示了

package cn.git.workflow.util;

import cn.git.common.exception.ServiceException;
import cn.git.workflow.constant.WorkFlowServerConstant;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.javax.el.ExpressionFactory;
import org.activiti.engine.impl.javax.el.ValueExpression;
import org.activiti.engine.impl.juel.ExpressionFactoryImpl;
import org.activiti.engine.impl.juel.SimpleContext;
import org.activiti.engine.impl.juel.SimpleResolver;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @description: activiti5.22.0 专用util包
 * @program: bank-credit-sy
 * @author: lixuchun
 * @create: 2024-06-14
 */
@Component
public class ActivitiUtil {

    @Autowired
    private TaskService taskService;

    /**
     * @description: 验证表达式
     *
     * @param condition 表达式
     * @param variablesMap 参数
     * @return: boolean
     */
    public boolean evalExpress(Object condition, Map<String, Object> variablesMap) {
        try {
            boolean flag;
            String conditionStr = StrUtil.toString(condition);
            ExpressionFactory factory = new ExpressionFactoryImpl();
            SimpleContext context = new SimpleContext(new SimpleResolver());
            for (String key : variablesMap.keySet()) {
                if (conditionStr.indexOf(key) > 0) {
                    factory.createValueExpression(context, "#{" + key + "}", String.class).setValue(context, variablesMap.get(key));
                }
            }

            ValueExpression valueExpression = factory.createValueExpression(context, conditionStr, boolean.class);
            flag = (Boolean) valueExpression.getValue(context);
            return flag;
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException(StrUtil.format("传入表达式验证报错了condition[{}],参数信息为[{}]",
                    condition, JSONObject.toJSONString(variablesMap)));
        }
    }

    /**
     * 获取排他网关正确的下一节点信息
     * @param currentActivity 当前节点信息
     * @param currentVariablesMap 当前节点处参数信息
     * @return
     */
    public List<PvmActivity> getNextPositionByExclusiveGateway(PvmActivity currentActivity, Map<String, Object> currentVariablesMap) {
        // 返回结果信息
        List<PvmActivity> activityList = new ArrayList<>();

        // 获取当前节点对外连接信息,并且计算最终选择哪条路线
        List<PvmTransition> transitionList = currentActivity.getOutgoingTransitions();
        for (PvmTransition transition : transitionList) {
            // 获取当前任务判定条件,注意此处不是节点,为对外条件flowSequence
            Object condition = transition.getProperty(WorkFlowServerConstant.CONDITION_TEXT);
            // 节点条件判定是否满足
            if (ObjectUtil.isNotNull(condition) && evalExpress(condition, currentVariablesMap)) {
                // 此处为对外指向flowSequence指向满足条件的节点
                activityList.add(transition.getDestination());
            }
        }
        return activityList;
    }

    /**
     * 获取并行网关正确的下一节点信息
     * @param currentActivity 当前节点信息
     * @return
     */
    public List<PvmActivity> getNextPositionByParallelGateway(PvmActivity currentActivity) {
        // 返回结果信息
        List<PvmActivity> activityList = new ArrayList<>();

        // 获取当前并行网关节点对外连接信息 transitionList 为并行网关对外的 -> 连线
        List<PvmTransition> transitionList = currentActivity.getOutgoingTransitions();
        for (PvmTransition transition : transitionList) {
            // 获取当前任务判定条件,注意此处不是节点,为对外条件 flowSequence,获取destination则为 -> 对应后面的节点
            PvmActivity destinationActivity = transition.getDestination();
            String activityNodeType = StrUtil.toString(destinationActivity.getProperty(WorkFlowServerConstant.NODE_TYPE));

            // 如果目标节点为userTask节点,则直接加入执行节点
            if (WorkFlowServerConstant.USER_TASK_FLAG.equalsIgnoreCase(activityNodeType)) {
                activityList.add(transition.getDestination());
            }
        }
        return activityList;
    }

    /**
     * 流程转向操作
     *
     * @param taskId 任务id
     * @param currentActivity 当前节点
     * @param destinationActivity 目标节点
     * @param variables 流程变量
     */
    public void turnTransitionForUTask(String taskId,
                                       ActivityImpl currentActivity,
                                       ActivityImpl destinationActivity,
                                       Map<String, Object> variables) {
        // 清空当前流向(存在风险,如果出现异常,则当前流向就消失了)
        List<PvmTransition> oriPvmTransitionList = clearTransition(currentActivity);

        try {
            // 当前节点创建新流向
            TransitionImpl newTransition = currentActivity.createOutgoingTransition();
            // 设置新流向的目标节点
            newTransition.setDestination(destinationActivity);
            // 执行转向任务
            if (ObjectUtil.isNotEmpty(variables)) {
                taskService.complete(taskId, variables);
            } else {
                taskService.complete(taskId);
            }
            // 删除目标节点新流入
            destinationActivity.getIncomingTransitions().remove(newTransition);
            // 还原以前流向
            restoreTransition(currentActivity, oriPvmTransitionList);
        } catch (Exception e) {
            e.printStackTrace();
            // 如果出现异常,则恢复以前流向
            restoreTransition(currentActivity, oriPvmTransitionList);
        }
    }

    /**
     * 清空指定活动节点流向
     *
     * @param activityImpl 活动节点
     * @return 节点流向集合
     */
    public List<PvmTransition> clearTransition(ActivityImpl activityImpl) {
        // 存储当前节点所有流向临时变量
        List<PvmTransition> pvmTransitionList = activityImpl.getOutgoingTransitions();
        // 获取当前节点所有流向,存储到临时变量,然后清空
        List<PvmTransition> oriPvmTransitionList = new ArrayList<>(pvmTransitionList);
        // 清空当前节点所有流向
        pvmTransitionList.clear();

        return oriPvmTransitionList;
    }

    /**
     * 还原指定活动节点流向
     *
     * @param activityImpl 活动节点
     * @param oriPvmTransitionList 原有节点流向集合
     */
    public void restoreTransition(ActivityImpl activityImpl, List<PvmTransition> oriPvmTransitionList) {
        // 清空现有流向
        List<PvmTransition> pvmTransitionList = activityImpl.getOutgoingTransitions();
        pvmTransitionList.clear();
        // 还原以前流向
        pvmTransitionList.addAll(oriPvmTransitionList);
    }

}

2.2 风险实现

风险部分主要是原有调用webService部分的三个接口类,需要信贷系统这边提供feign接口进行补充实现,三个接口分别为

  • ActProcessWebServiceApi,流程定义信息查询service api接口
  • ActQueryWebServiceApi,综合历史等查询service api接口
  • ActTaskWebServiceApi,任务信息查询service api接口
2.2.1 风险实现的api接口定义实现

ActProcessWebServiceApi实现如下

package cn.git.workflow.service.impl;

import cn.git.common.exception.ServiceException;
import cn.git.workflow.constant.WorkFlowServerConstant;
import cn.git.workflow.dto.activiti.WorkFlowActProcessInstanceDTO;
import cn.git.workflow.dto.activiti.WorkFlowEndProcessDTO;
import cn.git.workflow.dto.activiti.WorkFlowStartProcessDTO;
import cn.git.workflow.mapstruct.ActivitiConvert;
import cn.git.workflow.service.ActProcessWebService;
import cn.git.workflow.util.ActivitiUtil;
import cn.hutool.core.util.ObjectUtil;
import org.activiti.engine.*;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;


/**
 * @description: activiti5.22.0,流程定义信息查询service
 * @program: bank-credit-sy
 * @author: lixuchun
 * @create: 2024-06-14
 */
@Service
public class ActProcessWebServiceImpl implements ActProcessWebService {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private ProcessEngine processEngine;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private IdentityService identityService;

    @Autowired
    private ActivitiUtil activitiUtil;

    @Autowired
    private ActivitiConvert activitiConvert;

    /**
     * 根据流程id查询流程信息,包含参数信息
     *
     * @param processId 流程实例id
     * @return
     */
    @Override
    public WorkFlowActProcessInstanceDTO findProcessByPId(String processId) {
        // 获取流程实例信息
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processId)
                .includeProcessVariables()
                .singleResult();

        // 返回转换内容信息
        return activitiConvert.processInstanceCovertToDTO(processInstance);
    }

    /**
     * 开启一个流程信息
     *
     * @param startProcessDTO
     * @return
     */
    @Override
    public WorkFlowStartProcessDTO startProcess(WorkFlowStartProcessDTO startProcessDTO) {
        // 权限设置
        identityService.setAuthenticatedUserId(startProcessDTO.getUserId());
        // 发起流程
        ProcessInstance processInstance;

        // 发起流程
        if (ObjectUtil.isNotEmpty(startProcessDTO.getParamMap())) {
            // 带参数
            processInstance = runtimeService.startProcessInstanceByKey(
                    startProcessDTO.getProcessKey(),
                    startProcessDTO.getBizId(),
                    startProcessDTO.getParamMap());
        } else {
            // 不带自定义参数信息
            processInstance = runtimeService.startProcessInstanceByKey(
                    startProcessDTO.getProcessKey(),
                    startProcessDTO.getBizId());
        }

        // 获取当前任务列表,刚刚发起业务,应该只有一个值
        List<Task> list = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).list();
        // 设置返回信息
        if (ObjectUtil.isNotEmpty(list)) {
            // 获取第一个任务
            Task task = list.get(0);
            WorkFlowStartProcessDTO.WorkFlowStartProcessOUTDTO processOUTDTO = new WorkFlowStartProcessDTO.WorkFlowStartProcessOUTDTO();
            processOUTDTO.setProcessId(processInstance.getProcessInstanceId());
            processOUTDTO.setActivityName(task.getName());
            processOUTDTO.setTaskDefKey(task.getTaskDefinitionKey());
            processOUTDTO.setTaskId(task.getId());
            startProcessDTO.setWorkFlowStartProcessOUTDTO(processOUTDTO);
        }
        return startProcessDTO;
    }

    /**
     * 根据流程id取消流程
     *
     * @param processId 流程实例id
     * @param userId    用户id userCd + ":" + orgCd
     */
    @Override
    public void cancelProcessByProcessId(String processId, String userId) {
        // 权限认证
        identityService.setAuthenticatedUserId(userId);

        // 开始进行业务撤销
        runtimeService.deleteProcessInstance(processId, WorkFlowServerConstant.DEFAULT_CANCEL_REASON);
    }

    /**
     * 结束流程
     *
     * @param flowEndProcessDTO
     */
    @Override
    public void endProcess(WorkFlowEndProcessDTO flowEndProcessDTO) {
        // 获取当前任务信息
        Task currentTask = taskService.createTaskQuery()
                .taskId(flowEndProcessDTO.getTaskId())
                .singleResult();

        // 获取流程定义信息
        ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                .getDeployedProcessDefinition(currentTask.getProcessDefinitionId());

        // 获取流程定义节点详情信息
        List<ActivityImpl> allActivityList = processDefinition.getActivities();

        // 过滤出end节点信息
        ActivityImpl endActivity = allActivityList.stream().filter(activity ->
                ObjectUtil.isEmpty(activity.getOutgoingTransitions())
        ).findAny().orElse(null);

        // 空值判定
        if (ObjectUtil.isEmpty(endActivity)) {
            throw new ServiceException("获取流程end节点信息为空,请确认流程图有end节点信息配置正确!");
        }

        // 获取当前节点定义信息
        ActivityImpl currentTaskActivity = processDefinition.findActivity(currentTask.getTaskDefinitionKey());
        // 进行任务跳转,既结束任务
        activitiUtil.turnTransitionForUTask(currentTask.getId(),
                currentTaskActivity,
                endActivity,
                flowEndProcessDTO.getParamMap());

    }

}

ActQueryWebServiceImpl实现如下

package cn.git.workflow.service.impl;

import cn.git.common.exception.ServiceException;
import cn.git.workflow.constant.WorkFlowServerConstant;
import cn.git.workflow.dto.activiti.WorkFlowActHisActInstListDTO;
import cn.git.workflow.dto.activiti.WorkFlowActHisProcessListDTO;
import cn.git.workflow.dto.activiti.WorkFlowActWorkListDTO;
import cn.git.workflow.entity.ActHiProcinst;
import cn.git.workflow.mapper.ActHiProcinstMapper;
import cn.git.workflow.mapstruct.ActivitiConvert;
import cn.git.workflow.service.ActQueryWebService;
import cn.git.workflow.util.ActivitiUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @description: activiti5.22.0,综合历史等查询service
 * @program: bank-credit-sy
 * @author: lixuchun
 * @create: 2024-06-14
 */
@Service
public class ActQueryWebServiceImpl implements ActQueryWebService {

    @Autowired
    private ActHiProcinstMapper actHiProcinstMapper;

    @Autowired
    private ActivitiConvert activitiConvert;

    @Autowired
    private TaskService taskService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private ActivitiUtil activitiUtil;

    /**
     * 通过用户id获取此用户全部业务信息
     *
     * @param userId
     * @return
     */
    @Override
    public List<WorkFlowActWorkListDTO> queryWorkList(String userId) {
        // 空值校验
        if (StrUtil.isBlank(userId)) {
            throw new ServiceException("userId参数为空,查询用户流程信息失败!");
        }

        // 分页查询初始化任务列表信息,processVariableValueEquals可以对参数进行过滤,此处用不到
        TaskQuery taskQuery = taskService.createTaskQuery()
                // 当前处理人
                .taskAssignee(userId)
                // 活动流程任务
                .active()
                // 查询包含参数信息,可以过滤使用
                .includeProcessVariables()
                // 创建时间排序
                .orderByTaskCreateTime()
                // 倒序排序
                .desc();

        // 进行数据查询,此处无需分页处理,直接查询全部
        List<Task> taskList = taskQuery.list();

        // 空值判定
        if (ObjectUtil.isEmpty(taskList)) {
            return new ArrayList<>();
        }

        // 转换为可用对象
        List<WorkFlowActWorkListDTO> workList = taskList.stream().map(task ->
                activitiConvert.taskConvertToActList(task)
        ).collect(Collectors.toList());

        return workList;
    }

    /**
     * 通过processId获取流程历史信息
     *
     * @param processId
     * @return
     */
    @Override
    public List<WorkFlowActHisActInstListDTO> queryHisTaskList(String processId) {
        // 获取历史活动实例
        HistoricActivityInstanceQuery activityInstanceQuery = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processId)
                .orderByHistoricActivityInstanceId()
                .desc();
        // 获取历史活动实例列表
        List<HistoricActivityInstance> activityInstanceList = activityInstanceQuery.list();

        // 类型信息转换
        List<WorkFlowActHisActInstListDTO> actHisActInstListDTOList = activityInstanceList.stream().map(instance ->
                activitiConvert.hisInstanceToActList(instance)
        ).collect(Collectors.toList());

        // 进行非task节点信息判定,排除无用节点
        actHisActInstListDTOList = actHisActInstListDTOList.stream().filter(actInst -> {
            boolean ifRightType = actInst.getActivityType().equals(WorkFlowServerConstant.EXCLUSIVE_GATEWAY)
                    || actInst.getActivityType().equals(WorkFlowServerConstant.PARALLEL_GATEWAY)
                    || actInst.getActivityType().equals(WorkFlowServerConstant.INCLUSIVE_GATEWAY)
                    || actInst.getActivityType().equals(WorkFlowServerConstant.EVENT_GATEWAY);
            return !ifRightType;
        }).collect(Collectors.toList());

        // 设置common评论信息
        actHisActInstListDTOList.forEach(actInst -> {
            // 获取common信息
            List<Comment> commentList = taskService.getTaskComments(actInst.getTaskId());
            if (ObjectUtil.isNotEmpty(commentList)) {
                // 设置评论信息
                actInst.setOpinion(commentList.get(0).getFullMessage());
            }
        });

        return actHisActInstListDTOList;
    }

    /**
     * 获取新流程已经结束的历史信息
     *
     * @param userId 用户id
     * @param finishStatus 流程状态 finished,running
     * @return 任务列表
     */
    public List<WorkFlowActHisProcessListDTO> queryStatusHisList(String userId, String finishStatus) {
        // 参数校验
        if (StrUtil.isBlank(userId)) {
            throw new ServiceException("历史信息查询时候,用户id为空,请确认");
        }

        // 设置查询条件
        HistoricProcessInstanceQuery instanceQuery = historyService.createHistoricProcessInstanceQuery()
                // 参与用户id
                .involvedUser(userId)
                // 按照时间倒序排序
                .orderByProcessInstanceStartTime()
                .desc();
        // 是否结束条件判定 0否1是
        if (WorkFlowServerConstant.WORKFLOW_STATUS_FINISHED.equals(finishStatus)) {
            instanceQuery.finished();
        } else {
            // 解决空值情况下,默认查询历史为running状态
            finishStatus = WorkFlowServerConstant.WORKFLOW_STATUS_RUNNING;
            instanceQuery.unfinished();
        }

        // 获取查询结果集合
        List<HistoricProcessInstance> historicProcessInstanceList = instanceQuery.list();

        // 查询信息进行转换
        List<WorkFlowActHisProcessListDTO> actHisProcessListDTOList = historicProcessInstanceList
                .stream().map(historyInstance ->
                        activitiConvert.hisProcessInstanceCovertToDTO(historyInstance)
                ).collect(Collectors.toList());

        // 跟踪列表查询数据不正确 优化处理
        List<ActHiProcinst> historyInstanceList = actHiProcinstMapper.listHistoryInstance(finishStatus, userId);

        // 非空判定
        if (ObjectUtil.isNotEmpty(historyInstanceList)) {
            Map<String, String> instanceMap = new HashMap<>();
            for (ActHiProcinst actHiProcinst : historyInstanceList) {
                String businessKey = actHiProcinst.getBusinessKey();
                instanceMap.put(businessKey, businessKey);
            }
            // 去除不正确处理人
            List<WorkFlowActHisProcessListDTO> removeList = new ArrayList<>();
            for (WorkFlowActHisProcessListDTO vo : actHisProcessListDTOList) {
                if (instanceMap.get(vo.getBusinessKey()) == null) {
                    removeList.add(vo);
                }
            }
            // 删除错误信息
            if (removeList.size() > 0) {
                actHisProcessListDTOList.removeAll(removeList);
            }
        } else {
            // 如果正确查询没有信息,则全部去除即可
            actHisProcessListDTOList = new ArrayList<>();
        }
        return actHisProcessListDTOList;
    }
}

ActTaskWebServiceImpl实现如下

package cn.git.workflow.service.impl;

import cn.git.common.exception.ServiceException;
import cn.git.workflow.constant.WorkFlowServerConstant;
import cn.git.workflow.dto.activiti.*;
import cn.git.workflow.service.ActTaskWebService;
import cn.git.workflow.util.ActivitiUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.task.TaskDefinition;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description: activiti5.22.0,任务信息查询service
 * @program: bank-credit-sy
 * @author: lixuchun
 * @create: 2024-06-14
 */
@Service
public class ActTaskWebServiceImpl implements ActTaskWebService {

    @Autowired
    private ActivitiUtil activitiUtil;

    @Autowired
    private TaskService taskService;

    @Autowired
    private IdentityService identityService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private RuntimeService runtimeService;

    /**
     * 根据任务id和用户id查询任务信息
     *
     * @param workFlowTaskInfoDTO
     * @return
     */
    @Override
    public WorkFlowTaskInfoDTO findTaskByInAndUserId(WorkFlowTaskInfoDTO workFlowTaskInfoDTO) {
        // 设置权限
        identityService.setAuthenticatedUserId(workFlowTaskInfoDTO.getUserId());

        // 获取task信息
        Task task = taskService.createTaskQuery()
                .taskId(workFlowTaskInfoDTO.getTaskId())
                .includeProcessVariables()
                .singleResult();

        // 设置响应信息
        WorkFlowTaskInfoDTO.WorkFlowTaskInfoOutDTO taskOutDTO = new WorkFlowTaskInfoDTO.WorkFlowTaskInfoOutDTO();
        taskOutDTO.setTaskName(task.getName());
        taskOutDTO.setTaskDefKey(task.getTaskDefinitionKey());
        taskOutDTO.setTaskVariableMap(task.getProcessVariables());
        taskOutDTO.setProcessId(task.getProcessInstanceId());
        workFlowTaskInfoDTO.setWorkFlowTaskInfoOutDTO(taskOutDTO);

        return workFlowTaskInfoDTO;
    }

    /**
     * 退回到发起岗位
     *
     * @param workFlowBackToStartDTO
     * @return
     */
    @Override
    public WorkFlowBackToStartDTO submitTaskBack(WorkFlowBackToStartDTO workFlowBackToStartDTO) {
        // 获取使用参数信息
        String userId = workFlowBackToStartDTO.getUserId();
        String taskId = workFlowBackToStartDTO.getTaskId();
        String opinion = workFlowBackToStartDTO.getOpinion();

        // 设置权限信息
        identityService.setAuthenticatedUserId(userId);

        // 获取任务信息
        Task currentTask = taskService.createTaskQuery()
                .taskId(taskId)
                .includeProcessVariables()
                .singleResult();

        // 设置意见信息
        if (StrUtil.isNotBlank(workFlowBackToStartDTO.getOpinion())) {
            //只保留一条批注记录
            List<Comment> commentList = taskService.getTaskComments(currentTask.getId());
            if(ObjectUtil.isNotEmpty(commentList)){
                commentList.forEach(common -> {
                    taskService.deleteComment(common.getId());
                });
            }
            // 添加新的批注信息
            taskService.addComment(currentTask.getId(),
                    currentTask.getProcessInstanceId(), workFlowBackToStartDTO.getOpinion());
        }

        // 获取当前任务参数信息
        Map<String, Object> opinionMap = currentTask.getProcessVariables();
        opinionMap.put(WorkFlowServerConstant.COMMENT_FLAG, opinion);
        opinionMap.put(WorkFlowServerConstant.OPINION_FLAG, opinion);

        // 对历史任务进行正序排序,获取最早的任务节点
        List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery()
                // 流程执行id
                .executionId(currentTask.getProcessInstanceId())
                // 按照时间排序
                .orderByHistoricActivityInstanceStartTime()
                .asc()
                .list();

        // 找到第一个userTask类型的任务节点,既为发起节点
        HistoricActivityInstance firstActivityInstance = activityInstanceList.stream().filter(activityInstance ->
                WorkFlowServerConstant.USER_TASK_FLAG.equalsIgnoreCase(activityInstance.getActivityType())
        ).findFirst().orElse(null);

        // 获取实际发起节点的流程定义信息
        ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                .getDeployedProcessDefinition(firstActivityInstance.getProcessDefinitionId());

        // 获取发起节点定义信息
        ActivityImpl startActivity = processDefinition.findActivity(firstActivityInstance.getActivityId());

        // 获取当前节点定义信息
        ActivityImpl currentTaskActivity = processDefinition.findActivity(currentTask.getTaskDefinitionKey());

        // 退回首节点校验,首节点不能再次退回首节点
        if(startActivity.getId().equals(currentTask.getTaskDefinitionKey())){
            throw new ServiceException("当前节点为首节点,无法退回");
        }

        // 退回首节点校验,首节点不能再次退回首节点
        if(startActivity.getId().equals(currentTask.getTaskDefinitionKey())){
            throw new ServiceException("当前节点为首节点,无法退回");
        }

        // 通过流程实例id以及任务定义key获取同级别任务列表信息,既需要退回的任务
        List<Task> backTaskList = taskService.createTaskQuery()
                .processInstanceId(currentTask.getProcessInstanceId())
                .taskDefinitionKey(currentTask.getTaskDefinitionKey())
                .list();

        // 进行回退操作
        backTaskList.forEach(task -> {
            // 进行任务跳转
            activitiUtil.turnTransitionForUTask(task.getId(),
                    currentTaskActivity,
                    startActivity,
                    opinionMap);
        });

        // 通过processId获取最新的一个task任务信息
        Task nextTask = taskService.createTaskQuery()
                // 流程实例id
                .processInstanceId(currentTask.getProcessInstanceId())
                // 存活状态
                .active()
                // 按照日期排序,最新的一个
                .orderByTaskCreateTime()
                .desc()
                .singleResult();

        // 获取此流程发起人信息
        Map<String, Object> processVariables = currentTask.getProcessVariables();
        String creator = (String) processVariables.get(WorkFlowServerConstant.CREATOR_FLAG);

        // 进行处理人强制转换,修改流程处理人信息
        nextTask.setAssignee(creator);
        taskService.saveTask(nextTask);
        taskService.claim(nextTask.getId(), creator);

        // 设置响应信息
        WorkFlowBackToStartDTO.WorkFlowBackToStartOutDTO taskOutDTO = new WorkFlowBackToStartDTO.WorkFlowBackToStartOutDTO();
        taskOutDTO.setProcessId(nextTask.getAssignee());
        taskOutDTO.setTaskName(nextTask.getName());
        taskOutDTO.setTaskDefKey(nextTask.getTaskDefinitionKey());
        taskOutDTO.setTaskVariableMap(nextTask.getProcessVariables());
        taskOutDTO.setCreator(nextTask.getAssignee());
        workFlowBackToStartDTO.setWorkFlowBackToStartOutDTO(taskOutDTO);

        return workFlowBackToStartDTO;
    }

    /**
     * 提交普通任务
     *
     * @param workFlowSubmitNormalDTO 参数信息
     * @return
     */
    @Override
    public WorkFlowSubmitNormalDTO submitNormalTask(WorkFlowSubmitNormalDTO workFlowSubmitNormalDTO) {
        // 获取使用参数信息
        String userId = workFlowSubmitNormalDTO.getWfusers();
        String taskId = workFlowSubmitNormalDTO.getTaskId();
        String taskComment = workFlowSubmitNormalDTO.getComment();

        // 设置权限信息
        identityService.setAuthenticatedUserId(userId);

        // 获取当前任务信息
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .includeProcessVariables()
                .singleResult();

        // 获取执行id
        String executionId = task.getExecutionId();

        // 设置留言信息,只留一条批注信息
        List<Comment> commentList = taskService.getTaskComments(task.getId());
        if(ObjectUtil.isNotEmpty(commentList)){
            for(Comment comment : commentList){
                // 删除现有批注信息
                taskService.deleteComment(comment.getId());
            }
        }

        // 添加批注信息
        taskService.addComment(task.getId(), task.getProcessInstanceId(), taskComment);

        // 获取参数信息
        Map<String, Object> paramMap = workFlowSubmitNormalDTO.getVariableMap();
        paramMap.put("comment", taskComment);

        // 设置参数信息
        runtimeService.setVariables(executionId, paramMap);

        // 开始提交任务
        taskService.complete(task.getId(), paramMap);

        // 获取下一个任务信息
        List<Task> taskList = taskService.createTaskQuery()
                // 执行id
                .executionId(executionId)
                .list();

        // 进行认领操作,默认第一个任务
        if (ObjectUtil.isNotEmpty(taskList)) {
            // 进行处理人强制转换
            Task nextTask = taskService.createTaskQuery()
                    .taskId(taskList.get(0).getId())
                    .singleResult();
            nextTask.setAssignee(userId);
            taskService.saveTask(nextTask);
            taskService.claim(nextTask.getId(), userId);

            // 设置响应信息
            WorkFlowSubmitNormalDTO.WorkFlowSubmitNormalOutDTO outDTO = new WorkFlowSubmitNormalDTO.WorkFlowSubmitNormalOutDTO();
            outDTO.setNextTaskId(nextTask.getId());
            outDTO.setTaskDefKey(nextTask.getTaskDefinitionKey());
            outDTO.setTaskName(nextTask.getName());
            workFlowSubmitNormalDTO.setWorkFlowSubmitNormalOutDTO(outDTO);
        }

        return workFlowSubmitNormalDTO;
    }

    /**
     * 保存任务
     *
     * @param workFlowSaveTaskDTO 参数dto
     */
    @Override
    public void saveTask(WorkFlowSaveTaskDTO workFlowSaveTaskDTO) {
        // 获取任务service
        Task task = taskService.createTaskQuery()
                .taskId(workFlowSaveTaskDTO.getTaskId())
                .singleResult();

        // 设置意见信息
        String comment = workFlowSaveTaskDTO.getComment();
        if (StrUtil.isNotBlank(comment)) {
            //只保留一条批注记录
            List<Comment> commentList = taskService.getTaskComments(task.getId());
            if(ObjectUtil.isNotEmpty(commentList)){
                commentList.forEach(common -> {
                    taskService.deleteComment(common.getId());
                });
            }
            // 添加新的批注信息
            taskService.addComment(task.getId(), task.getProcessInstanceId(), comment);
        }

        // 保存参数
        if (ObjectUtil.isNotEmpty(workFlowSaveTaskDTO.getParamMap())) {
            taskService.setVariables(task.getId(), workFlowSaveTaskDTO.getParamMap());
        }
    }

    /**
     * 委派任务
     *
     * @param delegator
     * @param taskId
     */
    @Override
    public void delegateTask(String delegator, String taskId) {
        // 获取任务信息
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .singleResult();

        // 进行任务委派
        task.setAssignee(delegator);
        task.setOwner(task.getAssignee());
        taskService.saveTask(task);
    }

    /**
     * 跳转任务
     *
     * @param workFlowGoToTaskDTO 参数dto
     */
    @Override
    public void gotoTask(WorkFlowGoToTaskDTO workFlowGoToTaskDTO) {
        // 获取使用参数信息
        String taskId = workFlowGoToTaskDTO.getTaskId();
        String nextTaskDefinitionKey = workFlowGoToTaskDTO.getDesTaskDefinitionKey();
        String authUserId = workFlowGoToTaskDTO.getUserId();


        // 获取任务信息
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .singleResult();

        // 设置意见信息
        if (StrUtil.isNotBlank(workFlowGoToTaskDTO.getComment())) {
            //只保留一条批注记录
            List<Comment> commentList = taskService.getTaskComments(task.getId());
            if(ObjectUtil.isNotEmpty(commentList)){
                commentList.forEach(common -> {
                    taskService.deleteComment(common.getId());
                });
            }
            // 添加新的批注信息
            taskService.addComment(task.getId(), task.getProcessInstanceId(), workFlowGoToTaskDTO.getComment());
        }

        // 如果未传入权限设置id,则设置为当前task权限
        if (StrUtil.isBlank(authUserId)) {
            authUserId = task.getAssignee();
        }

        // 设置权限信息
        identityService.setAuthenticatedUserId(authUserId);

        // 任务进行跳节点,获取实际发起节点的流程定义信息
        ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                .getDeployedProcessDefinition(task.getProcessDefinitionId());

        // 获取当前节点定义信息以及目标节点的节点信息
        ActivityImpl currentTaskActivity = processDefinition.findActivity(task.getTaskDefinitionKey());
        ActivityImpl destinationTaskActivity = processDefinition.findActivity(nextTaskDefinitionKey);

        // 通过流程实例id以及任务定义key获取同级别任务列表信息,既需要退回的任务
        List<Task> backTaskList = taskService.createTaskQuery()
                .processInstanceId(task.getProcessInstanceId())
                .taskDefinitionKey(task.getTaskDefinitionKey())
                .list();

        // 设置参数信息,我们系统userTask里面处理人的属性都是使用的wfuser,如果没有设定,跳转会报错,先默认设定一个,跳转之后再进行修改处理人即可
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put(WorkFlowServerConstant.WORKFLOW_USERS_FLAG, authUserId);

        backTaskList.forEach(backTask -> {
            // 进行任务跳转
            activitiUtil.turnTransitionForUTask(backTask.getId(),
                    currentTaskActivity,
                    destinationTaskActivity,
                    paramMap);
        });
    }

    /**
     * 查询下一节点信息
     *
     * @param nextPositionInfoDTO
     * @return
     */
    @Override
    public WorkFlowNextPositionInfoDTO findNextActivityUserInfo(WorkFlowNextPositionInfoDTO nextPositionInfoDTO) {
        // 获取参数信息
        String taskId = nextPositionInfoDTO.getTaskId();

        // 获取task信息
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .singleResult();

        // 获取全部流程自定义变量信息
        Map<String, Object> taskVariables = runtimeService.getVariables(task.getExecutionId());

        // 任务进行跳节点,获取实际发起节点的流程定义信息
        ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                .getDeployedProcessDefinition(task.getProcessDefinitionId());

        // 获取当前节点信息,可以获取outgoingSequenceFlows,结合自定义变量信息,可以获取下一节点信息
        ActivityImpl currentActivity = processDefinition.findActivity(task.getTaskDefinitionKey());

        // 获取当前节点对外指向,并且对指向进行分析
        List<PvmTransition> transitionList = currentActivity.getOutgoingTransitions();
        if (ObjectUtil.isEmpty(transitionList)) {
            throw new ServiceException("当前节点没有下一节点信息");
        }

        // 最终获取全部下一处理岗位定义节点
        List<PvmActivity> finalActivityList = new ArrayList<>();

        // 循环获取目标节点信息,当前行内服务,只使用排他网关,所以后续分支只支持单一条件满足,下一节点为单一分支
        for (PvmTransition transition : transitionList) {
            // 获取目标节点
            PvmActivity destinationActivity = transition.getDestination();
            // 获取目标节点nodeType类型
            String activityNodeType = StrUtil.toString(destinationActivity.getProperty(WorkFlowServerConstant.NODE_TYPE));
            // 目标节点不同类型进行不同处理,
            if (WorkFlowServerConstant.EXCLUSIVE_GATEWAY.equals(activityNodeType) || WorkFlowServerConstant.INCLUSIVE_GATEWAY.equals(activityNodeType)) {
                // 注意此处为 节点->排他网关/包含网关->节点 形式,更复杂形式需要针对业务进行调整
                List<PvmActivity> exclusiveGateActivityList = activitiUtil.getNextPositionByExclusiveGateway(destinationActivity, taskVariables);
                finalActivityList.addAll(exclusiveGateActivityList);
            } else if (WorkFlowServerConstant.PARALLEL_GATEWAY.equals(activityNodeType)) {
                // 并行网关 节点->并行网关->节点
                List<PvmActivity> parallelGateActivityList = activitiUtil.getNextPositionByParallelGateway(destinationActivity);
                finalActivityList.addAll(parallelGateActivityList);
            } else if (WorkFlowServerConstant.USER_TASK_FLAG.equalsIgnoreCase(activityNodeType)) {
                // 普通用户任务 节点->节点
                finalActivityList.add(destinationActivity);
            } else {
                throw new ServiceException(StrUtil.format("当前获取下一岗位信息暂时activityNodeType[{}]暂时不支持!", activityNodeType));
            }
        }

        // 获取下一岗位信息非空判定
        if (ObjectUtil.isEmpty(finalActivityList)) {
            throw new ServiceException(StrUtil.format("当前taskId[{}]对应节点[{}]获取下一岗位信息为空!",
                    taskId, task.getTaskDefinitionKey()));
        }

        // 获取下一岗位名称id信息
        ActivityImpl nextActivity = (ActivityImpl)finalActivityList.get(0);
        String nextTaskName = nextActivity.getProperty(WorkFlowServerConstant.NAME_FLAG).toString();
        // 下一岗位id
        TaskDefinition taskDefinition = (TaskDefinition)nextActivity.getProperty(WorkFlowServerConstant.TASK_DEFINITION);
        String nextDefinitionKey = taskDefinition.getKey();

        // 设置响应参数
        WorkFlowNextPositionInfoDTO.WorkFlowNextPositionInfoOutDTO outDTO = new WorkFlowNextPositionInfoDTO.WorkFlowNextPositionInfoOutDTO();
        outDTO.setNextTaskName(nextTaskName);
        outDTO.setNextTaskDefinitionKey(nextDefinitionKey);
        nextPositionInfoDTO.setWorkFlowNextPositionInfoOutDTO(outDTO);

        return nextPositionInfoDTO;
    }
}

3. 测试效果

以下为流程测试部分,截取几个比较重要的操作,简单进行以下接口测试

3.1 部署一个流程

在这里插入图片描述

3.2 获取部署列表

在这里插入图片描述
在这里插入图片描述

3.3 发起流程

在这里插入图片描述
在这里插入图片描述

3.4 其余接口

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

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

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

相关文章

Houdini 通过wedge来做模拟参数对比 (PDG TOP)

我们的设定如下例子 这是个简单的布料悬挂的例子。上方两个角分别被固定住了&#xff0c;然后在distance约束下布料下垂。 我们现在的目的是想要对比不同的streach stiffness对模拟的影响。 第一步&#xff1a;找到stiffness参数&#xff0c;右键expression->edit expre…

centos7迁移部分成功

早闻CentOS不再维护的消息&#xff0c;确实有些遗憾&#xff0c;毕竟这个系统好用又简单&#xff0c;已经成为了我们工作中的一种习惯。然而&#xff0c;2024年6月30日这一天如约而至&#xff0c;CentOS 7停止维护后&#xff0c;随之而来的安全漏洞又该如何防范&#xff1f;系统…

华为云x86架构下部署mysql

华为云x86架构下部署mysql 1. 配置X86架构ESC2. 查看本系统中有没有安装mariadb相关的组件&#xff0c;有则卸载3. 安装mysql4. 启动mysql5. 登录MySQL&#xff0c;修改密码&#xff0c;开放访问权限 1. 配置X86架构ESC 2. 查看本系统中有没有安装mariadb相关的组件&#xff0c…

餐饮行业气体泄露风险预警:可燃气体报警器的校准检测策略

在餐饮行业中&#xff0c;使用天然气、液化石油气等可燃气体作为烹饪能源是普遍现象。 然而&#xff0c;气体泄露问题时常威胁着餐饮场所的安全&#xff0c;一旦发生泄露&#xff0c;可能导致火灾、爆炸等严重事故。 因此&#xff0c;为了确保餐饮场所的安全&#xff0c;安装…

十年,亚马逊云科技合作伙伴网络开启AI新征程

“十年之前&#xff0c;你不认识我&#xff0c;我不认识你&#xff0c;因为云计算我们携手并肩&#xff1b;十年之后&#xff0c;我们仍是伙伴&#xff0c;更是朋友&#xff0c;因为人工智能再次起程。”这就是今天的亚马逊云科技与其合作伙伴的真实写照。 2024年是亚马逊云科技…

STM8定时器

目录 一、定时器的工作原理 二、定时器功能的实现 &#xff08;a&#xff09;官方提供的定时器4的例程 &#xff08;b&#xff09;修改官方提供的例程&#xff0c;使其更加符合我们的需求 &#xff08;c&#xff09;代码分析 &#xff08;d&#xff09;代码汇总 三、利用…

Python24 机器学习之决策树

1.什么是机器学习&#xff1f; 机器学习是人工智能&#xff08;AI&#xff09;的一个分支&#xff0c;它使计算机系统能够从经验中学习并根据这些学习的数据做出决策或预测&#xff0c;而无需进行明确的编程。简而言之&#xff0c;机器学习涉及算法和统计模型的使用&#xff0…

ZNB40 矢量网络分析仪

ZNB40 矢量网络分析仪 100kHz至40GHz的宽频率范围&#xff0c;具有四个端口和附加信号发生器 概述 R&SZNB40 提供 100 kHz 至 40 GHz 的宽频率范围&#xff0c;具有四个端口和附加信号发生器。 罗德与施瓦茨带四个端口和附加内部信号源的 40 GHz 中档矢量网络分析仪&…

【C++题解】1715. 输出满足条件的整数5

问题&#xff1a;1715. 输出满足条件的整数5 类型&#xff1a;简单循环 题目描述&#xff1a; 有这样一个四位数,其千位和百位之和为偶数&#xff0c;十位和个位之和为奇数&#xff0c;且前两位之和大于后两位之和&#xff0c;且含有因数 8 &#xff0c;请输出满足上述条件的…

基于weixin小程序校园快递系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;用户管理&#xff0c;订单管理&#xff0c;快递管理&#xff0c;快递记录管理&#xff0c;公告管理&#xff0c;基础数据管理 小程序功能包括&#xff1a;系统首页&#xff0c;…

【SSM】医疗健康平台-管理端-运营数据报表导出

知识目标 熟悉JasperReports的用法&#xff0c;能够使用JasperReports实现PDF文件导出 掌握Excel方式导出运营数据报表的方法&#xff0c;能够使用Apache POI以Excel方式导出运营数据报表 掌握PDF方式导出运营数据报表的方法&#xff0c;能够使用JasperReports以PDF方式导出运…

SpringCloud Alibaba Sentinel中@SentinelResource使用实践总结

Sentinel 提供了 SentinelResource 注解用于定义资源&#xff0c;并提供了 AspectJ 的扩展用于自动定义资源、处理 BlockException 等。 注意&#xff1a;注解方式埋点不支持 private 方法。 官网地址&#xff1a;注解埋点支持 【1】资源名称限流 ① controller方法 GetMapp…

基于requests模块爬取网易云歌曲评论并制作热词云图(2024七月最新可用,超详细讲解,从零开始完成项目,python爬虫高分大作业)

本实践大作业要求 本次实践大作业主要要求主要包括&#xff1a; 1、选择一个热点或者你感兴趣的主题作为本次爬虫实践作业要完成的任务。 2、为了完成本次任务&#xff0c;需要确定从网上爬取的数据对象与范围。 3、利用python及网络爬虫相关技术实现从网上爬取相应内容数据。 …

煤安防爆手机为什么能在煤矿井下使用

煤安防爆手机之所以能在煤矿井下使用&#xff0c;是因为它们经过特殊设计&#xff0c;符合严格的防爆安全标准&#xff0c;能够防止电火花引发爆炸&#xff0c;同时具备防尘防水、抗冲击等特性&#xff0c;确保在恶劣的煤矿环境中稳定可靠地运行&#xff0c;为工作人员提供安全…

【JavaScript】一键入门

目录 一、JS起源 二、JS特点 三、JS组成部分 四、JS引入方式 一、JS起源 Java Script是由网景公司的Live Script发展而来的一种运行在客户端浏览器上的脚本语言&#xff0c;可以实现网页如文本内容、数据动态变化和动画特效等即浏览器与用户交互的这种体验。 二、JS特点 …

【Java Web】三大域对象

目录 一、域对象概述 二、三大域对象 三、域对象使用相关API 一、域对象概述 一些可用于存储数据和传递数据的对象被称为域对象&#xff0c;根据传递数据范围的不同&#xff0c;我们称之为不同的域&#xff0c;不同的域对象代表不同的域&#xff0c;共享数据的范围也不同。 二、…

更难、更好、更快、更强:LLM Leaderboard v2 现已发布

评估和比较大语言模型 (LLMs) 是一项艰巨的任务。我们 RLHF 团队在一年前就意识到了这一点&#xff0c;当时他们试图复现和比较多个已发布模型的结果。这几乎是不可能完成的任务&#xff1a;论文或营销发布中的得分缺乏可复现的代码&#xff0c;有时令人怀疑&#xff0c;大多数…

华为仓颉编程语言

目录 一、引言 二、仓颉编程语言概述 三、技术特征 四、应用场景 五、社区支持 六、结论与展望 一、引言 随着信息技术的快速发展&#xff0c;编程语言作为软件开发的核心工具&#xff0c;其重要性日益凸显。近年来&#xff0c;华为公司投入大量研发资源&#xff0c;成功…

数据结构-分析期末选择题考点(排序)

何似清歌倚桃李 一炉沈水醉红灯 契子 ✨ 上一期给大家提供了大概会考的题型给老铁们复习的大致思路 这一期还会是一样&#xff0c;我将整理一下排序的题型以及解题方法给你们 由于时间还很多&#xff0c;我就慢慢总结吧&#xff0c;一天一章的样子&#xff0c;明天总结串、后天…

【工具分享】ToolsFx

文章目录 ToolsFx介绍如何安装如何运行运行截图 ToolsFx介绍 基于kotlintornadoFx的跨平台密码学工具箱&#xff0c;包含编解码、编码转换、加解密、哈希、MAC、签名、大数运算、压缩、二维码功能、CTF等实用功能&#xff0c;支持插件。 如何安装 GitHub&#xff1a;https:/…