# 流程操作权限扩展

# 背景&需求

支持客户对流程操作权限的特殊需求,可实现BPM暴露的扩展接口,实现自定义逻辑。

# 操作步骤&解决方案

BPM提供权限扩展接口BpmOperationSpi,三方SPI工程依赖bpm-facade工程,实现此接口方法,对流程节点权限的校验做扩展处理。BPM服务加载运行时,会执行此工程实现类的逻辑,对流程节点权限进行定制化的校验。

BPM SPI扩展方案 : https://docs.qq.com/doc/DYkZHZFVtdHpNRVd6 V8平台SPI扩展机制和开发文档: https://www.yuque.com/teamdocs/v8-client-kb/nizgyacv5x4oh0wh

# 接口信息:

/**
 * 流程操作权限扩展接口SPI
 **/
public interface BpmOperationSpi {

    /**
     * 节点权限操作校验
     * @param requestDto 校验参数
     * @return 校验结果
     */
    BpmCheckNodePermissionResp checkNodePermission(BpmCheckNodePermissionReq requestDto);

}

###参数说明: ####入参:

@DtoInfo("节点权限操作校验请求")
public class BpmCheckNodePermissionReq {
    @DtoAttribute("流程实例ID")
    private Long caseId;
    @DtoAttribute("事项ID")
    private Long affairId;
    @DtoAttribute("节点权限ID")
    private Long permissionId;
    @DtoAttribute("意见实体")
    private BpmCommentDto commentDto;
    @DtoAttribute("操作编码")
    private String operationCode;

####出参:

@DtoInfo("节点权限操作校验响应")
public class BpmCheckNodePermissionResp {
    @DtoAttribute("是否通过操作合法校验")
    private boolean passOperationVerify = false;
    @DtoAttribute("是否通过操作意见必填校验")
    private boolean passCommentRequiredVerify = false;
    @DtoAttribute("是否通过操作意见长度校验")
    private boolean passCommentLengthVerify = false;

###操作步骤:

# 第一步:

创建工程:依赖bpm-facade

       <dependency>
            <groupId>com.seeyon</groupId>
            <artifactId>bpm-facade</artifactId>
            <version>3.15.0-DEV-SNAPSHOT</version>
        </dependency>

# 第二步:

实现接口BpmOperationSpi 重写方法checkNodePermission

public class BpmOperationSpiImpl implements BpmOperationSpi {
  @Override
    public BpmCheckNodePermissionResp checkNodePermission(BpmCheckNodePermissionReq 	bpmCheckNodePermissionReq) {
	
	}

}

# DEMO:

####业务需求: 客户将节点权限做了合并处理,一个节点权限下拥有了除本身流程操作外,还自定义添加了其他操作,那么当执行绑定了此节点权限的事项时,节点权限校验需要自定义实现,校验自定义后的全量操作。 ####实现代码:

@Slf4j
public class BpmOperationSpiImpl implements BpmOperationSpi {

    @Override
    public BpmCheckNodePermissionResp checkNodePermission(BpmCheckNodePermissionReq bpmCheckNodePermissionReq) {
        log.info("BpmOperationSpiImpl checkNodePermission req : {}", JsonUtils.toJson(bpmCheckNodePermissionReq));
        BpmCheckNodePermissionResp resp = new BpmCheckNodePermissionResp();

        Long caseId = bpmCheckNodePermissionReq.getCaseId();
        String operationCode = bpmCheckNodePermissionReq.getOperationCode();
        BpmCommentDto commentDto = bpmCheckNodePermissionReq.getCommentDto();

        List<BpmNodePermissionOperationSimpleDto> operationList;

        // 根据流程实例ID和用户ID获取事项列表
        List<AffairDto> affairDtoList = CommonUtil.selectAffairList(RequestContext.get().getUserId(), caseId);

        // 根据事项ID获取合并后的节点权限操作列表
        List<Long> affairIds = affairDtoList.stream().map(AffairDto::getId).collect(Collectors.toList());
        operationList = CommonUtil.selectOperationList(affairIds, new ArrayList<>());


        if (CollectionUtils.isNotEmpty(operationList)){
            Map<String, BpmNodePermissionOperationSimpleDto> code2SimpleDtoMap = operationList.stream().collect(Collectors.toMap(BpmNodePermissionOperationSimpleDto::getCode, Function.identity()));

            // 操作合法校验
            if (code2SimpleDtoMap.containsKey(operationCode)){
                resp.setPassOperationVerify(true);
            }

            // 意见必填校验
            BpmNodePermissionOperationSimpleDto simpleDto = code2SimpleDtoMap.get(operationCode);
            Boolean commentRequired = simpleDto.getCommentRequired();
            if (!commentRequired){
                resp.setPassCommentRequiredVerify(true);
            }
            if (commentRequired && commentDto != null && (StringUtils.isNotBlank(commentDto.getContent()) || StringUtils.isBlank(commentDto.getRichContent()))){
                resp.setPassCommentRequiredVerify(true);
            }

            // 意见长度校验
            if (Objects.isNull(simpleDto.getMinOpinionLength())){
                resp.setPassCommentLengthVerify(true);
            }
            int minLength = simpleDto.getMinOpinionLength();
            if (Objects.nonNull(commentDto) && Boolean.TRUE.equals(commentRequired) && minLength > 0){
                if (commentDto.getContent().length() < minLength && commentDto.getRichContent().length() < minLength){
                    resp.setPassCommentLengthVerify(true);
                }
            }
        }

        log.info("BpmOperationSpiImpl checkNodePermission resp : {}", JsonUtils.toJson(resp));
        return resp;
    }
}
编撰人:wensl、liuhf、shugang