简单的系统拖拽规则

简单的系统拖拽规则

1. 需求

公司想要一个规则控制功能,在功能执行过程中,可以动态的改变原来的执行逻辑,让业务人员可以进行简单的配置,并且实现拖拽功能,原有的drools规则引擎部分因为编译结果未知,执行出问题不太好定位问题,以及提示不能最快定为到底是什么规则触发引起的报错,代码部分也不能快速定为,所以对规则部分进行了一个二次开发,此次放弃使用规则引擎,直接全部自己手动实现,功能相对简单。

2. 实现思路

实现的步骤以及思路还是跟以前的drools规则实现差不多,主要分为规则模块以及非规则业务模块,最终简单的实现思路以及执行过程如下:

  • 启动规则模块服务加载全部规则,将规则信息(入参,出参,描述等)加载到缓存中,提供规则详情调用具体实现方法
  • 启动业务子模块,加载规则调用入口(既各个按钮等功能接口),将入口inVO参数以及入口信息描述等加入缓存中
  • 业务人员进行规则链编辑,将需要加入规则的controller接口,配置上需要调用的规则链,同时校验controller的方法入参是否满足规则链中各个规则的入参信息
  • 客户端调用规则链入口方法,首先执行切面方法,获取当前请求uri是否配置规则链,如果配置则依次循环调用规则模块规则详情方法,执行通过则进入controller对应的method方法,失败则进行失败信息提示即可,不进入controller方法

简单的实现思路图:
在这里插入图片描述
简单的逻辑调用图:
在这里插入图片描述

3. 页面设计

业务实现基本设置四个简单页面,大体有规则列表页面,规则编辑页面,规则链列表页面,规则链编辑页面,具体页面设计如下:

  • 规则列表页面
    在这里插入图片描述
  • 规则详情页面:可以进行规则链
    在这里插入图片描述
  • 规则链列表页面:进行规则链的分页展示
    在这里插入图片描述
  • 规则链页面:可以进行规则链的编辑
    在这里插入图片描述
  • 规则链编辑提示页面:这部分会提示规则链的规则是否合法,不合法的话提示具体哪些规则哪些字段不合法
    在这里插入图片描述
  • 产品规则列表展示:此页面进行产品规则的分页以及展示,点击新增可以新增产品规则链,操作与普通规则链相同
    在这里插入图片描述

4. 具体实现

实现部分主要包含客户端以及规则服务端,客户端提供规则接口入口信息,服务启动将接口信息上传至缓存中供规则模块规则链管理,服务端提供规则管理,规则链管理以及规则执行的具体实现。

4.1 客户端

具体逻辑为启动服务,扫描带有**@DragRule**的注解接口,将接口的对应的入参参数inVO,接口名称,描述信息等统一存入缓存,redis缓存使用结构为hash形式,我们使用的是微服务,服务启动执行需要枪锁执行。具体实现的主要代码如下所示

  1. DragRule注解信息,此注解是接口扫描注解,只有标记此注解才会被扫描进入缓存信息中

    package cn.git.common.annotation;
    
    import java.lang.annotation.*;
    
    /**
     * @description: 拖拽规则注解
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2024-02-20 09:38:40
     */
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface DragRule {
    
        /**
         * 描述信息
         * @return
         */
        String ruleDesc() default "";
    
    }
    
    
  2. DragRuleBeanDefinitionProcessor,此类在服务启动时候,获取全部规定目录下的所有有效bean的定义信息,并且封装成map

    package cn.git.common.drag.processor;
    
    import cn.git.common.annotation.DragRule;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @description: 获取拖拽规则注解定义类
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2024-02-29 04:33:16
     */
    @Slf4j
    @Component
    public class DragRuleBeanDefinitionProcessor implements BeanDefinitionRegistryPostProcessor {
    
        /**
         * controller类前缀
         */
        private static final String CONTROLLER_PREFIX = "cn.git";
    
        /**
         * controller类类名后缀
         */
        private static final String CONTROLLER_SUFFIX = "Controller";
    
        /**
         * 基础拖拽规则bean定义列表
         * 扫描所有controller类,如果类中包含@DragRule注解的,就添加到beanDefinitionList中
         */
        public static List<BeanDefinition> BASE_DRAG_RULE_BEAN_DEFINITION = new ArrayList<>();
    
        /**
         * Modify the application context's internal bean definition registry after its
         * standard initialization. All regular bean definitions will have been loaded,
         * but no beans will have been instantiated yet. This allows for adding further
         * bean definitions before the next post-processing phase kicks in.
         *
         * @param registry the bean definition registry used by the application context
         * @throws BeansException in case of errors
         */
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
            for (String beanName : registry.getBeanDefinitionNames()) {
                // 判定类是否为cn.git路径下以及controller类名后缀
                BeanDefinition definition = registry.getBeanDefinition(beanName);
                Class<?> clazz;
                try {
                    clazz = Class.forName(definition.getBeanClassName());
                    for (Method method : clazz.getDeclaredMethods()) {
                        if (method.isAnnotationPresent(DragRule.class) && !BASE_DRAG_RULE_BEAN_DEFINITION.contains(definition)) {
                            BASE_DRAG_RULE_BEAN_DEFINITION.add(definition);
                        }
                    }
                } catch (Exception ignored) {
                    // 加载失败,无需做处理
                }
            }
        }
    
        /**
         * Modify the application context's internal bean factory after its standard
         * initialization. All bean definitions will have been loaded, but no beans
         * will have been instantiated yet. This allows for overriding or adding
         * properties even to eager-initializing beans.
         *
         * @param beanFactory the bean factory used by the application context
         * @throws BeansException in case of errors
         */
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        }
    }
    
    
  3. CommonClientRuleUriInit ,服务初始化执行方法,主要进行bean定义信息解析,并且筛选出@DragRule标记类,存入缓存中

    package cn.git.common.drag;
    
    import cn.git.common.annotation.DragRule;
    import cn.git.common.drag.dto.DragChainDTO;
    import cn.git.common.drag.mapper.CommonDragRuleMapper;
    import cn.git.common.drag.processor.DragRuleBeanDefinitionProcessor;
    import cn.git.common.exception.ServiceException;
    import cn.git.common.lock.LockTypeEnum;
    import cn.git.common.lock.SimpleDistributeLock;
    import cn.git.common.util.CommonDragRuleUtil;
    import cn.git.redis.RedisUtil;
    import cn.hutool.core.util.ObjectUtil;
    import cn.hutool.core.util.StrUtil;
    import com.alibaba.csp.sentinel.slots.block.RuleConstant;
    import com.alibaba.fastjson.JSONObject;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiModelProperty;
    import io.swagger.annotations.ApiOperation;
    import io.swagger.annotations.ApiParam;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.boot.ApplicationArguments;
    import org.springframework.boot.ApplicationRunner;
    import org.springframework.scheduling.annotation.EnableScheduling;
    import org.springframework.stereotype.Component;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.lang.reflect.Parameter;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    import java.util.function.Function;
    import java.util.stream.Collectors;
    
    /**
     * @description: 拖拽规则规则链初始化
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2024-02-28 01:40:24
     */
    @Slf4j
    @Component
    @EnableScheduling
    public class CommonClientRuleUriInit implements ApplicationRunner {
    
        @Value("${spring.application.name}")
        private String applicationName;
    
        /**
         * 规则服务名称
         */
        private static final String RULE_SERVER_NAME = "rule-manage-server";
    
        /**
         * 风控服务名称
         */
        private static final String RISK_SERVER_NAME = "risk-server";
    
        @Autowired
        private CommonDragRuleMapper commonDragRuleMapper;
    
        @Autowired
        private RedisUtil redisUtil;
    
        @Autowired
        private CommonDragRuleUtil commonDragRuleUtil;
    
        @Autowired
        private SimpleDistributeLock simpleLock;
    
        /**
         * 拖拽规则规则链初始化
         * 获取拖拽规则对应的入参参数包含值,方便后续保存规则的时候进行满足参数的校验
         * @throws Exception
         */
        @Override
        public void run(ApplicationArguments args) throws Exception {
            // 加锁,服务发版启动,只有一个服务可以执行
            String lock = simpleLock.tryLock(LockTypeEnum.DRAG_RULE_URI_LOCK, applicationName);
            try {
                // 加锁成功并且服务为业务子模块服务则可以进行规则模块信息加载,否则不进行加载
                if (StrUtil.isNotBlank(lock) && commonDragRuleUtil.checkIfLoadDragChain(applicationName)) {
                    log.info("拖拽规则[{}]初始化规则链开始!", applicationName);
                    // 获取定义好的拖拽注解实现方法类类型
                    List<BeanDefinition> beanDefinitionList = DragRuleBeanDefinitionProcessor.BASE_DRAG_RULE_BEAN_DEFINITION;
    
                    // mapper中获取规则链信息,并且将list转换为map信息,其中key为规则链uri,value为规则链信息,并且过滤掉其他模块的规则链信息
                    String chainUriPrefix = applicationName.replace(StrUtil.DASHED, StrUtil.UNDERLINE).toUpperCase();
                    List<DragChainDTO> dragChainDTOList = commonDragRuleMapper.getDragChainList();
                    Map<String, DragChainDTO> dragChainMap = dragChainDTOList
                            .stream()
                            .filter(chainDTO -> {
                                // 只获取当前服务自己的规则链信息
                                return chainDTO.getUri().startsWith(chainUriPrefix);
                            })
                            .collect(Collectors.toMap(
                                    DragChainDTO::getUri, Function.identity(), (k1, k2) -> k2)
                            );
    
                    // 获取 DragRule.class注解对应的方法以及参数信息
                    for (BeanDefinition beanDefinition : beanDefinitionList) {
                        // 获取类名
                        String className = beanDefinition.getBeanClassName();
                        // 获取类对象
                        Class<?> clazz = Class.forName(className);
    
                        // 获取controller名称
                        String controllerName = clazz.getSimpleName();
    
                        // 获取请求头上面的RequestMapping路径信息
                        RequestMapping controllerRequestMapping = clazz.getAnnotation(RequestMapping.class);
                        String uriPrefix = controllerRequestMapping.value()[0];
    
                        // 获取controller描述信息
                        String controllerDesc = null;
                        if (clazz.isAnnotationPresent(Api.class)) {
                            Api api = clazz.getAnnotation(Api.class);
                            controllerDesc = api.tags()[0];
                        }
                        // 循环获取DragRule注解的方法信息以及参数信息
                        for (Method method : clazz.getDeclaredMethods()) {
                            if (method.isAnnotationPresent(DragRule.class)) {
                                // 获取方法的描述信息
                                String methodDesc = null;
                                if (method.isAnnotationPresent(ApiOperation.class)) {
                                    ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
                                    methodDesc = apiOperation.value();
                                }
                                String methodName = method.getName();
    
                                // 获取方法请求uri后缀部分
                                String suffixUri = null;
                                if (method.isAnnotationPresent(RequestMapping.class)) {
                                    // request请求方法uri
                                    suffixUri = method.getAnnotation(RequestMapping.class).value()[0];
                                } else if (method.isAnnotationPresent(GetMapping.class)) {
                                    // get请求方法uri
                                    suffixUri = method.getAnnotation(GetMapping.class).value()[0];
                                } else if (method.isAnnotationPresent(PostMapping.class)) {
                                    // post请求方法uri
                                    suffixUri = method.getAnnotation(PostMapping.class).value()[0];
                                }
                                // 判断是否为path路径带有参数信息
                                if (suffixUri.contains(StrUtil.DELIM_START)) {
                                    suffixUri = suffixUri.substring(0, suffixUri.indexOf(StrUtil.DELIM_START) - 1);
                                }
                                // 整体全路径为
                                String allPathUri = uriPrefix.concat(suffixUri);
    
                                // 获取参数信息
                                JSONObject paramJSON = new JSONObject(true);
                                // 参数描述信息
                                List<DragChainDTO.DragRuleInVOParamsDesc> inVOParamsDescList = new ArrayList<>();
                                Parameter[] parameters = method.getParameters();
                                Class<?>[] parameterTypes = method.getParameterTypes();
                                for (int i = 0; i < parameters.length; i++) {
                                    // 当前参数
                                    Parameter parameter = parameters[i];
                                    // 当前参数类型
                                    Class<?> parameterType = parameterTypes[i];
                                    // 简单类型处理
                                    if ("String".equals(parameterType.getSimpleName())
                                            || "Integer".equals(parameterType.getSimpleName())
                                            || "Long".equals(parameterType.getSimpleName())
                                            || "Double".equals(parameterType.getSimpleName())
                                            || "Float".equals(parameterType.getSimpleName())
                                            || "Boolean".equals(parameterType.getSimpleName())
                                            || "Date".equals(parameterType.getSimpleName())) {
                                        ApiParam annotation = parameter.getAnnotation(ApiParam.class);
                                        if (ObjectUtil.isNotNull(annotation)) {
                                            DragChainDTO.DragRuleInVOParamsDesc inVOParamsDesc = new DragChainDTO.DragRuleInVOParamsDesc();
                                            inVOParamsDesc.setInParamDesc(annotation.value());
                                            inVOParamsDesc.setInParamName(parameter.getName());
                                            inVOParamsDesc.setInParamType(parameterType.getSimpleName());
                                            inVOParamsDescList.add(inVOParamsDesc);
                                        }
                                        paramJSON.put(parameter.getName(), StrUtil.EMPTY);
                                    } else {
                                        // 复杂类类型
                                        Field[] declaredFields = parameterType.getDeclaredFields();
                                        for (Field field : declaredFields) {
                                            DragChainDTO.DragRuleInVOParamsDesc inVOParamsDesc = null;
                                            ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
                                            if (ObjectUtil.isNotNull(apiModelProperty)) {
                                                inVOParamsDesc = new DragChainDTO.DragRuleInVOParamsDesc();
                                                inVOParamsDesc.setInParamDesc(apiModelProperty.value());
                                                inVOParamsDesc.setInParamName(field.getName());
                                                inVOParamsDesc.setInParamType(field.getType().getSimpleName());
                                                inVOParamsDescList.add(inVOParamsDesc);
                                            }
                                            paramJSON.put(field.getName(), StrUtil.EMPTY);
                                        }
                                    }
                                }
                                // 设置最终路径信息,模块名:uri
                                String finalUri = chainUriPrefix
                                        .toUpperCase()
                                        .concat(StrUtil.COLON)
                                        .concat(allPathUri);
    
                                // 信息包含controller方法入参信息,规则链信息
                                DragChainDTO dragChainDTO = new DragChainDTO();
                                dragChainDTO.setMethodDesc(methodDesc);
                                dragChainDTO.setMethodName(methodName);
                                dragChainDTO.setControllerDesc(controllerDesc);
                                dragChainDTO.setControllerName(controllerName);
                                dragChainDTO.setMethodInParam(paramJSON.toJSONString());
                                dragChainDTO.setInVOParamsDescList(inVOParamsDescList);
                                dragChainDTO.setUri(finalUri);
                                dragChainDTO.setIfLoadDB(CommonDragRuleConstant.NUM_STR_0);
                                dragChainDTO.setDragRuleChainId(controllerName.concat(StrUtil.DOT).concat(methodName));
                                dragChainDTO.setDragChainModule(applicationName.replace(StrUtil.DASHED, StrUtil.UNDERLINE).toUpperCase());
                                if (ObjectUtil.isNotNull(dragChainMap.get(finalUri))) {
                                    // 设置规则链信息
                                    dragChainDTO.setIsDel(dragChainMap.get(finalUri).getIsDel());
                                    dragChainDTO.setIfLoadDB(CommonDragRuleConstant.NUM_STR_1);
                                    dragChainDTO.setDragRuleChain(dragChainMap.get(finalUri).getDragRuleChain());
                                    // 规则链校验 dragRule1,dragRule2,dragRule3联调校验入参,回参信息
                                    commonDragRuleUtil.checkDragRuleWithParamLegal(dragChainDTO);
                                }
    
                                // 设置规则链参数信息
                                redisUtil.hset(CommonDragRuleConstant.DRAG_RULE_CHAIN_FLAG,
                                        finalUri, JSONObject.toJSONString(dragChainDTO));
                            }
                        }
                    }
    
                    // 释放锁信息
                    simpleLock.releaseLock(LockTypeEnum.DRAG_RULE_URI_LOCK, applicationName, lock);
                }
            } catch (Exception e) {
                throw new ServiceException(e.getMessage());
            } finally {
                // 释放锁信息
                simpleLock.releaseLock(LockTypeEnum.DRAG_RULE_URI_LOCK, applicationName, lock);
            }
        }
    }
    
    
  4. client工具类,主要进行规则链的规则是否合法校验,如果不合法则服务停止启动并且进行提示

    package cn.git.common.util;
    
    import cn.git.common.drag.CommonDragRuleConstant;
    import cn.git.common.drag.dto.DragChainDTO;
    import cn.git.common.drag.dto.DragRuleDTO;
    import cn.git.common.exception.ServiceException;
    import cn.git.redis.RedisUtil;
    import cn.hutool.core.util.ObjectUtil;
    import cn.hutool.core.util.StrUtil;
    import com.alibaba.fastjson.JSONObject;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.Set;
    import java.util.stream.Collectors;
    
    /**
     * @description: 拖拽规则通用工具类
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2024-03-04 09:21:01
     */
    @Component
    public class CommonDragRuleUtil {
    
        @Autowired
        private RedisUtil redisUtil;
    
        /**
         * 入参规则链校验,其中必须有规则调用切入点(既调用controller方法uri)
         * dragRuleChain规则链,多个规则使用逗号分割
         * @param dragChainDTO 入参规则链信息
         */
        public void checkDragRuleWithParamLegal(DragChainDTO dragChainDTO) {
            // 参数信息校验
            if (ObjectUtil.isNull(dragChainDTO)
                    || StrUtil.isBlank(dragChainDTO.getUri())
                    || StrUtil.isBlank(dragChainDTO.getDragRuleChain())
                    || StrUtil.isBlank(dragChainDTO.getMethodInParam())) {
                throw new ServiceException(StrUtil.format("拖拽规则[{}],方法[{}]入参参数校验失败,请确认!",
                        dragChainDTO.getControllerDesc(), dragChainDTO.getMethodDesc()));
            }
    
            // 开始参数校验,入参参数需要满足调用规则参数校验,并且入参参数+规则返回参数(传递参数)需要满足规则链下一个规则的入参
            String dragRuleChain = dragChainDTO.getDragRuleChain();
            List<String> dragRuleChainList = Arrays.asList(dragRuleChain.split(StrUtil.COMMA).clone())
                    .stream()
                    .map(String::trim)
                    .collect(Collectors.toList());
    
            // 只有一个规则,直接校验入参是否满足规则链第一个规则入参即可
            String errorMessage;
            if (dragRuleChainList.size() == 1) {
                String dragRuleId = dragRuleChainList.get(0);
                DragRuleDTO dragRuleDTO = getDragRuleDTO(dragRuleId);
                // 分别获取规则参数以及规则链入参进行比较,如果入参不满足规则链第一个规则入参,直接抛出异常
                JSONObject dragRuleInParam = JSONObject.parseObject(dragRuleDTO.getInputParam());
                JSONObject dragChainInParam = JSONObject.parseObject(dragChainDTO.getMethodInParam());
                // 参数空值校验
                if (ObjectUtil.isEmpty(dragRuleInParam)) {
                    errorMessage = StrUtil.format("拖拽规则规则链[{}]对应规则方法[{}]获取规则入参参数为空,规则id为[{}]请确认!",
                            dragChainDTO.getControllerName(),
                            dragChainDTO.getMethodName(),
                            dragRuleDTO.getDragRuleId());
                    throw new ServiceException(errorMessage);
                }
                if (ObjectUtil.isEmpty(dragChainInParam)) {
                    errorMessage = StrUtil.format("拖拽规则规则链[{}]切入点[{}]入参参数为空,请确认!",
                            dragChainDTO.getControllerName(),
                            dragChainDTO.getMethodName());
                    throw new ServiceException(errorMessage);
                }
                // 参数包含校验,比较参数,切入点入参必须包含规则链第一个规则入参,不满足直接抛出异常
                Set<String> dragRuleInParamKeySet = dragRuleInParam.keySet();
                Set<String> dragChainInParamKeySet = dragChainInParam.keySet();
                Set<String> diffKeySet = dragRuleInParamKeySet.stream()
                        .filter(element -> !dragChainInParamKeySet.contains(element))
                        .collect(Collectors.toSet());
                if (ObjectUtil.isNotEmpty(diffKeySet)) {
                    // Set集合数据转换为字符串,逗号分割
                    String dragRuleDiffKeyStr = diffKeySet.stream()
                            .map(String::valueOf)
                            .collect(Collectors.joining(StrUtil.COMMA));
                    errorMessage = StrUtil.format("规则链id[{}],规则包含列表第[1]个规则[{}],其入参参数不满足要求,\n缺少入参信息为[{}],请确认!",
                            dragChainDTO.getDragRuleChainId(),
                            dragRuleDTO.getDragRuleId(),
                            dragRuleDiffKeyStr);
                    throw new ServiceException(errorMessage);
                }
            } else {
                // 空值校验
                JSONObject dragChainInParam = JSONObject.parseObject(dragChainDTO.getMethodInParam());
                if (ObjectUtil.isEmpty(dragChainInParam)) {
                    errorMessage = StrUtil.format("拖拽规则规则链[{}]控制层方法切入点[{}]入参参数为空,请确认!",
                            dragChainDTO.getControllerName(),
                            dragChainDTO.getMethodName());
                    throw new ServiceException(errorMessage);
                }
                // 入参结果集,第一次入参参数为规则链切入点的入参参数,之后循环规则链规则,为规则链返回传递参数+切入点入参参数,再与下一个规则入参进行对比
                JSONObject resultInParam = dragChainInParam.clone();
                for (int i = 0; i < dragRuleChainList.size(); i++) {
                    // 通过规则id,获取规则入参信息
                    String dragRuleId = dragRuleChainList.get(i);
                    DragRuleDTO dragRuleDTO = getDragRuleDTO(dragRuleId);
                    JSONObject dragRuleInParam = JSONObject.parseObject(dragRuleDTO.getInputParam());
                    // 进行参数校验,如果入参不满足规则链循环规则入参,直接抛出异常
                    Set<String> dragRuleInParamKeySet = dragRuleInParam.keySet();
                    Set<String> dragChainInParamKeySet = resultInParam.keySet();
                    Set<String> diffKeySet = dragRuleInParamKeySet.stream()
                            .filter(element -> !dragChainInParamKeySet.contains(element))
                            .collect(Collectors.toSet());
                    if (ObjectUtil.isNotEmpty(diffKeySet)) {
                        // Set集合数据转换为字符串,逗号分割
                        String dragRuleDiffKeyStr = diffKeySet.stream()
                                .map(String::valueOf)
                                .collect(Collectors.joining(StrUtil.COMMA));
                        errorMessage = StrUtil.format("规则链id[{}],规则包含列表第[{}]个规则[{}],其入参参数不满足要求,\n缺少入参信息为[{}]",
                                dragChainDTO.getDragRuleChainId(),
                                i + 1,
                                dragRuleDTO.getDragRuleId(),
                                dragRuleDiffKeyStr);
                        throw new ServiceException(errorMessage);
                    }
                    // 设置规则返回参数作为传递参数设定到切入点入参参数中,作为下一入参参数校验集合,传递参数为字符串,多个参数以逗号分割
                    if (StrUtil.isNotBlank(dragRuleDTO.getCrossParam())) {
                        String[] crossParams = dragRuleDTO.getCrossParam().split(StrUtil.COMMA);
                        for (int j = 0; j < crossParams.length; j++) {
                            resultInParam.put(crossParams[j], StrUtil.EMPTY);
                        }
                    }
                }
            }
        }
    
        /**
         * 通过规则id获取规则信息
         * @param dragRuleId
         */
        public DragRuleDTO getDragRuleDTO(String dragRuleId) {
            Object dragRuleObj = redisUtil.hget(CommonDragRuleConstant.DRAG_RULES, dragRuleId);
            if (ObjectUtil.isNotNull(dragRuleObj)) {
                return JSONObject.parseObject(StrUtil.toString(dragRuleObj), DragRuleDTO.class);
            }
            throw new ServiceException(StrUtil.format("拖拽规则通过缓存获取规则Id[{}]不存在,请确认规则服务成功启动!", dragRuleId));
        }
    
        /**
         * 检查当前服务是否需要进行加载规则链
         * @param serverName 服务名称
         * @return
         */
        public boolean checkIfLoadDragChain(String serverName) {
            // 空值校验
            if (StrUtil.isBlank(serverName)) {
                return false;
            }
    
            // 设定加载的模块名称
            boolean ifLoad = serverName.equalsIgnoreCase("account-server")
                    || serverName.equalsIgnoreCase("afterloan-server")
                    || serverName.equalsIgnoreCase("collateral-server")
                    || serverName.equalsIgnoreCase("credit-server")
                    || serverName.equalsIgnoreCase("loan-server")
                    || serverName.equalsIgnoreCase("management-server")
                    || serverName.equalsIgnoreCase("rat-server")
                    || serverName.equalsIgnoreCase("store-server")
                    || serverName.equalsIgnoreCase("warning-server")
                    || serverName.equalsIgnoreCase("product-server");
    
            return ifLoad;
        }
    
    }
    
    
  5. 规则链mapper类,进行规则链的列表查询

    package cn.git.common.drag.mapper;
    
    import cn.git.common.drag.dto.DragChainDTO;
    import org.apache.ibatis.annotations.Select;
    
    import java.util.List;
    
    /**
     * @description: 拖拽规则通用mapper
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2024-02-29 02:44:11
     */
    public interface CommonDragRuleMapper {
    
        /**
         * 获取拖拽规则链列表信息
         * @return
         */
        @Select("SELECT * FROM MANAGE.TB_SYS_DRAG_CHAIN")
        List<DragChainDTO> getDragChainList();
    
    }
    
    
  6. DTO参数类,拖拽规则链DTO以及拖拽规则详情DTO

    package cn.git.common.drag.dto;
    
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.util.List;
    
    /**
     * @description: 拖拽规则链表
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2024-02-20 03:32:00
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ApiModel(value = "拖拽规则链表信息", description = "拖拽规则链表信息")
    public class DragChainDTO {
    
        /**
         * 规则链id
         */
        @ApiModelProperty("规则链id,由controllerName + methodName组合而成,eg: DragRuleTestController.test0001")
        private String dragRuleChainId;
    
        /**
         * 产品cd
         */
        @ApiModelProperty("产品cd")
        private String productCd;
    
        /**
         * 产品规则链id
         */
        @ApiModelProperty("产品规则链id")
        private String productChainId;
    
        /**
         * 切入点controller描述信息
         */
        @ApiModelProperty("切入点controller描述信息")
        private String controllerDesc;
    
        /**
         * 切入点controller名称
         */
        @ApiModelProperty("切入点controller名称")
        private String controllerName;
    
        /**
         * 规则链调用方法描述
         */
        @ApiModelProperty("规则链调用方法描述")
        private String methodDesc;
    
    
        /**
         * 规则链调用方法名称
         */
        @ApiModelProperty("规则链调用方法名称")
        private String methodName;
    
        /**
         * 方法入参参数
         */
        @ApiModelProperty("方法入参参数")
        private String methodInParam;
    
        /**
         * 作用方法地址,其实为controller对应method地址
         * 具体格式为: server-name:uri
         */
        @ApiModelProperty("作用方法地址,其实为controller对应method地址,server-name:uri")
        private String uri;
    
        /**
         * 规则链详情,多个规则按序逗号分割
         */
        @ApiModelProperty("规则链详情,多个规则按序逗号分割")
        private String dragRuleChain;
    
        /**
         * 产品规则链详情,多个规则按序逗号分割
         */
        @ApiModelProperty("规则链详情,多个规则按序逗号分割")
        private String dragProductRuleChain;
    
        /**
         * 删除标识
         */
        @ApiModelProperty("删除标识,非展示字段")
        private String isDel;
    
        /**
         * 模块信息
         */
        @ApiModelProperty("模块信息 eg: ACCOUNT_SERVER")
        private String dragChainModule;
    
        /**
         * 规则是否已经保存落库,如果没有落库,规则则展示灰色,如果落库,则展示正常颜色
         */
        @ApiModelProperty("规则链是否已经保存落库,如果没有落库,规则则展示灰色,如果落库,则展示正常颜色")
        private String ifLoadDB;
    
        /**
         * 拖拽规则inVO描述信息
         */
        @ApiModelProperty("拖拽规则inVO描述信息")
        private List<DragRuleInVOParamsDesc> inVOParamsDescList;
    
        /**
         * @description: 规则入参描述信息
         * @program: bank-credit-sy
         * @author: lixuchun
         * @create: 2024-03-05 10:43:51
         */
        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        @ApiModel(value = "规则入参描述信息", description = "规则入参描述信息")
        public static class DragRuleInVOParamsDesc {
    
            /**
             * 描述信息
             */
            @ApiModelProperty("描述信息,属性值中文含义")
            private String inParamDesc;
    
            /**
             * 参数名称
             */
            @ApiModelProperty("属性名称")
            private String inParamName;
    
            /**
             * 参数类型
             */
            @ApiModelProperty("参数类型")
            private String inParamType;
        }
    
    }
    
    
    package cn.git.common.drag.dto;
    
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.util.List;
    
    
    /**
     * @description: 拖拽规则详情DTO
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2024-03-01 02:07:06
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ApiModel(value = "拖拽规则详情信息", description = "拖拽规则详情信息")
    public class DragRuleDTO {
    
        /**
         * 规则id,eg: LOANRule0001
         */
        @ApiModelProperty("规则id,eg: LOANRule0001")
        private String dragRuleId;
    
        /**
         * 规则描述
         */
        @ApiModelProperty("规则描述")
        private String ruleDesc;
    
        /**
         * 传递参数,多个以逗号分割
         */
        @ApiModelProperty("传递参数,多个以逗号分割,同crossParamList")
        private String crossParam;
    
        /**
         * 传递参数list
         */
        @ApiModelProperty("传递参数list")
        private List<String> crossParamList;
    
        /**
         * 拖拽规则方法入参
         */
        @ApiModelProperty("拖拽规则方法入参")
        private String inputParam;
    
        /**
         * 拖拽规则入参描述信息
         */
        @ApiModelProperty("拖拽规则入参描述信息")
        private List<DragRuleDTO.DragRuleParamsDesc> inputParamDescList;
    
        /**
         * 拖拽规则方法出参
         */
        @ApiModelProperty("拖拽规则方法出参")
        private String outputParam;
    
        /**
         * 拖拽规则出参描述信息
         */
        @ApiModelProperty("拖拽规则出参描述信息")
        private List<DragRuleDTO.DragRuleParamsDesc> outputParamDescList;
    
        /**
         * 拖拽规则传递参数描述信息
         */
        @ApiModelProperty("拖拽规则传递参数描述信息")
        private List<DragRuleDTO.DragRuleParamsDesc> crossParamDescList;
    
        /**
         * 自定义参数比较规则信息,为jsonArray格式
         */
        @ApiModelProperty("自定义参数比较规则信息,多个用逗号隔开,同customOptionParamList")
        private String customOptionParam;
    
        /**
         * 删除标识
         */
        @ApiModelProperty("删除标识,非展示字段")
        private String isDel;
    
        /**
         * 规则是否已经保存落库,如果没有落库,规则则展示灰色,如果落库,则展示正常颜色
         */
        @ApiModelProperty("规则是否已经保存落库,如果没有落库,规则则展示灰色,如果落库,则展示正常颜色")
        private String ifLoadDB;
    
        /**
         * 自定义参数比较规则信息列表
         */
        @ApiModelProperty("自定义参数比较规则信息列表")
        private List<List<CustomOptionParam>> customOptionParamList;
    
        /**
         * @description: 自定义参数比较规则信息
         * @program: bank-credit-sy
         * @author: lixuchun
         * @create: 2024-03-05 11:26:44
         */
        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        @ApiModel(value = "自定义参数比较规则信息", description = "自定义参数比较规则信息")
        public static class CustomOptionParam {
    
            @ApiModelProperty("自定义操作类型: 0-操作标识符, 1-outVO参数信息, 2-自定义值")
            private String optionType;
    
            @ApiModelProperty("参数类型 eg: BigDecimal, Date, Long...")
            private String paramType;
    
            @ApiModelProperty("参数描述,eg: 合同金额,如果为操作标识,则设定 ''")
            private String paramDesc;
    
            @ApiModelProperty("参数名称,eg: contractAmt")
            private String paramName;
    
            @ApiModelProperty("自定义值时候给送,其余不送")
            private String value;
    
        }
    
        /**
         * @description: 拖拽规则参数描述信息
         * @program: bank-credit-sy
         * @author: lixuchun
         * @create: 2024-03-05 10:43:51
         */
        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        @ApiModel(value = "拖拽规则参数描述信息", description = "拖拽规则参数描述信息")
        public static class DragRuleParamsDesc {
    
            /**
             * 描述信息
             */
            @ApiModelProperty("描述信息,属性值中文含义")
            private String paramDesc;
    
            /**
             * 参数名称
             */
            @ApiModelProperty("属性名称")
            private String paramName;
    
            /**
             * 参数类型
             */
            @ApiModelProperty("参数类型")
            private String paramType;
        }
    }
    
    
  7. client客户端常量类

    package cn.git.common.drag;
    
    /**
     * @description: 拖拽规则通用常量类
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2024-02-29 02:58:34
     */
    public class CommonDragRuleConstant {
    
        /**
         * 规则链标识
         * 存储结构 redis hash hashKey customKey customValue
         * eg: DRAG_RULE_CHAIN server-name:uri -> {methodParams,controllerName,controllerDesc,methodDesc,methodName}
         */
        public static final String DRAG_RULE_CHAIN_FLAG = "DRAG_RULE_CHAIN";
    
        /**
         * 产品规则链标识
         * 存储结构 redis hash hashKey customKey customValue
         * eg: DRAG_RULE_PRODUCT_CHAIN server-name:uri:productCd -> {uri,productCd,productDragChain}
         */
        public static final String DRAG_RULE_PRODUCT_CHAIN_FLAG = "DRAG_RULE_PRODUCT_CHAIN";
    
        /**
         * 产品编码标识
         */
        public static final String PRODUCT_CD = "productCd";
    
        /**
         * 拖拽规则redis hash 结构 名称
         */
        public static final String DRAG_RULES = "DRAG_RULES";
    
        /**
         * 规则链
         */
        public static final String DRAG_RULE_CHAIN = "dragRuleChain";
    
        /**
         * 存入拖拽规则入参参数
         */
        public static final String DRAG_RULE_CHAIN_DTO = "dragChainDTO";
    
        /**
         * 方法参数信息
         */
        public static final String METHOD_PARAMS = "methodParams";
    
        /**
         * controller名称
         */
        public static final String CONTROLLER_NAME = "controllerName";
    
        /**
         * controller描述
         */
        public static final String CONTROLLER_DESC = "controllerDesc";
    
        /**
         * 方法描述
         */
        public static final String METHOD_DESC = "methodDesc";
    
        /**
         * 方法名称
         */
        public static final String METHOD_NAME = "methodName";
    
        /**
         * URI
         */
        public static final String CONTROLLER_URI = "URI";
    
        /**
         * 数字类型标识
         */
        public static final String NUM_STR_0 = "0";
        public static final String NUM_STR_1 = "1";
    
        /**
         * 下载文件类型XML
         */
        public static final String APPLICATION_XML = "application/xml";
    
        /**
         * 描述信息标识
         */
        public static final String CONTENT_DISPOSITION = "Content-Disposition";
    
    }
    
    
  8. DragRuleAspect客户端切面类具体实现

    package cn.git.rules.aspect;
    
    import cn.git.common.drag.CommonDragRuleConstant;
    import cn.git.common.drag.dto.DragChainDTO;
    import cn.git.common.exception.ServiceException;
    import cn.git.common.result.Result;
    import cn.git.common.result.ResultStatusEnum;
    import cn.git.redis.RedisUtil;
    import cn.git.rules.constant.RuleConstant;
    import cn.git.rules.dto.BaseAspectDTO;
    import cn.git.rules.feign.DragRuleFeignApi;
    import cn.git.rules.feign.RuleFeignApi;
    import cn.git.rules.results.RuleResult;
    import cn.git.rules.util.BaseAspectUtil;
    import cn.git.rules.util.RuleUtil;
    import cn.hutool.core.util.ObjectUtil;
    import cn.hutool.core.util.StrUtil;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONArray;
    import com.alibaba.fastjson.JSONObject;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.ApplicationContext;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import javax.servlet.http.HttpServletRequest;
    import java.lang.reflect.Method;
    import java.math.BigDecimal;
    import java.util.*;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    import java.util.stream.Collectors;
    
    /**
     * 通用规则调用切面方法
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2022-04-01
     */
    @Component
    @Aspect
    @Order(value = RuleConstant.ASPECT_BEFORE_ORDER)
    public class DragRuleAspect {
    
        @Value("${spring.application.name}")
        private String applicationName;
    
        @Autowired
        private RedisUtil redisUtil;
    
        @Autowired
        private RuleUtil ruleUtil;
    
        @Autowired
        private ApplicationContext context;
    
        @Autowired
        private BaseAspectUtil baseAspectUtil;
    
        /**
         * 规则引擎提前通知切面
         * @param joinPoint 切面参数
         */
        @Before("@annotation(cn.git.common.annotation.DragRule)")
        public void doBeforeRuleCheck(JoinPoint joinPoint) throws Throwable {
            // 通过postMapping或者getMapping标签获取请求uri,对应uri为不带参数对应uri
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
    
            // 获取正确的请径地址求路信息
            BaseAspectDTO baseAspectDTO = baseAspectUtil.getEffectiveURI(method, request);
            // 完整请求路径,包含传递参数信息
            String uri = baseAspectDTO.getUri();
            // 带参数url请求地址
            String requestWithParamUri = baseAspectDTO.getRequestWithParamUri();
    
            // 设置最终路径信息,模块名:uri
            String finalUri = applicationName
                    .replace(StrUtil.DASHED, StrUtil.UNDERLINE)
                    .toUpperCase()
                    .concat(StrUtil.COLON)
                    .concat(uri);
    
            // 如果redis中含有对应规则
            if (redisUtil.hHasKey(CommonDragRuleConstant.DRAG_RULE_CHAIN_FLAG, finalUri)) {
                // 校验无论post或者get请求都必填
                if (ObjectUtil.isEmpty(joinPoint.getArgs())) {
                    throw new ServiceException("规则校验对应 controller 方法参数必须有请求参数!");
                }
    
                // 获取缓存信息中的拖拽规则缓存链信息
                DragChainDTO dragChainDTO = JSONObject.parseObject(redisUtil.hget(CommonDragRuleConstant.DRAG_RULE_CHAIN_FLAG, finalUri).toString(),
                        DragChainDTO.class);
    
                String cacheChainStr = dragChainDTO.getDragRuleChain();
                if (StrUtil.isNotBlank(cacheChainStr)) {
                    // 获取请求参数并且转换位jsonObject格式
                    Object argsObject = null;
                    if (joinPoint.getArgs().length > 1) {
                        // 定义为请求url中带有参数,进行参数匹配,重新封装为key,value类型数据
                        List<String> uriParamList = baseAspectUtil.getPathParamConfig(requestWithParamUri);
                        Map<String, Object> paramMap = new HashMap<>(RuleConstant.DEFAULT_MAP_SIZE);
                        for (int i = 0; i < uriParamList.size(); i++) {
                            paramMap.put(uriParamList.get(i), joinPoint.getArgs()[i]);
                        }
                        argsObject = paramMap;
                    } else if (joinPoint.getArgs().length == 1) {
                        argsObject = joinPoint.getArgs()[0];
                        // 如果为简单类型,必须设定为key value 对应json数据格式
                        if (argsObject instanceof String
                                || argsObject instanceof BigDecimal
                                || argsObject instanceof Integer
                                || argsObject instanceof Date
                                || argsObject instanceof Long
                                || argsObject instanceof Double) {
                            List<String> uriParamList = baseAspectUtil.getPathParamConfig(requestWithParamUri);
                            Map<String, Object> paramMap = new HashMap<>(RuleConstant.NUM_1);
                            paramMap.put(uriParamList.get(RuleConstant.NUM_0), joinPoint.getArgs()[0]);
                            argsObject = paramMap;
                        }
                    }
    
                    // argsObject 转换为json并且去除 null 值
                    JSONObject jsonParam = JSONObject.parseObject(JSONObject.toJSONString(argsObject));
    
                    // 获取产品信息校验,缓存的key为 uri + ":" + productCd,如果当前产品配置规则链,则使用产品配置规则链信息,否则使用默认规则链
                    String productCd = jsonParam.getString(CommonDragRuleConstant.PRODUCT_CD);
                    // 从整理号的请求参数中获取产品cd,如果有则查看当前产品是否配置产品规则链
                    if (StrUtil.isNotBlank(productCd)) {
                        String cacheKey = dragChainDTO.getUri().concat(StrUtil.COLON).concat(productCd);
                        Object productRuleObj = redisUtil.hget(CommonDragRuleConstant.DRAG_RULE_PRODUCT_CHAIN_FLAG, cacheKey);
                        if (ObjectUtil.isNotNull(productRuleObj)) {
                            // 获取产品规则链
                            JSONObject productJson = JSONObject.parseObject(productRuleObj.toString());
                            String productChain = productJson.getString(CommonDragRuleConstant.DRAG_RULE_CHAIN);
                            if (StrUtil.isNotBlank(productChain)) {
                                // 替换默认规则链到产品规则链
                                dragChainDTO.setDragRuleChain(productChain);
                            }
                        }
                    }
    
                    jsonParam.put(CommonDragRuleConstant.DRAG_RULE_CHAIN_DTO, JSONObject.toJSONString(dragChainDTO));
    
                    // 错误前缀
                    String ruleErrorPrefix = "拖拽规则校验提示: ";
                    // 调用规则模块,进行规则验证
                    DragRuleFeignApi dragRuleFeignApi = context.getBean(DragRuleFeignApi.class);
                    // 调用远程方法
                    Result rspRuleResult = dragRuleFeignApi.checkDragRule(jsonParam);
                    if (ObjectUtil.isNotEmpty(rspRuleResult) && rspRuleResult.getCode() == ResultStatusEnum.ERROR.getCode()) {
                        throw new ServiceException(ruleErrorPrefix.concat(rspRuleResult.getMsg()));
                    }
                }
            }
        }
    }
    
    
  9. 公共dragFeign接口

    package cn.git.rules.feign;
    
    import cn.git.common.result.Result;
    import com.alibaba.fastjson.JSONObject;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    /**
     * @description:
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2024-02-22 02:20:31
     */
    @FeignClient(value = "rule-manage-server", fallbackFactory = RuleFeignApiFallCallBackFactory.class)
    @RequestMapping("/rule/feign")
    public interface DragRuleFeignApi {
    
        /**
         * 校验拖拽规则feign方法
         *
         * @param dragRuleJsonParam 请求对象
         * @return Result 校验结果
         */
        @PostMapping("/drag/rule")
        Result checkDragRule(@RequestBody JSONObject dragRuleJsonParam);
    
    }
    

4.2 拖拽规则服务端

服务端主要进行提供规则链规则的管理,以及子模块进行规则逻辑执行调用Feign接口的具体实现逻辑。服务端的代码pom为:

<?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-rule-manage</artifactId>
        <groupId>cn.git</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>rule-manage-server</artifactId>
    <description>规则引擎服务端</description>

    <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>
                <exclusion>
                    <groupId>cn.git</groupId>
                    <artifactId>database-synchronize-client</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>credit-log-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>credit-swagger-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>rule-manage-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <!-- 规则引擎jar包 -->
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-core</artifactId>
            <version>7.6.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-compiler</artifactId>
            <version>7.6.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-templates</artifactId>
            <version>7.6.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-api</artifactId>
            <version>7.6.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-spring</artifactId>
            <version>7.6.0.Final</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-tx</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-beans</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-core</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-context</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>credit-redis-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>credit-discovery-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- 监听nacos配置信息变更 -->
        <dependency>
            <groupId>com.purgeteam</groupId>
            <artifactId>dynamic-config-spring-boot-starter</artifactId>
            <version>0.1.1.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </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>
        <!-- 影像平台使用jar -->
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>clientQuery</artifactId>
            <version>v1.0.0</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>SunECMClient</artifactId>
            <version>v3.1.5</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>sun-ws-all-v2.0</artifactId>
            <version>v2.0</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>sun-ws-all-v3.1.5</artifactId>
            <version>v3.1.5</version>
        </dependency>

        <!-- app影像上传使用 -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>3.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>3.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>3.0.9</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>dom4j</artifactId>
            <version>v1.6.1</version>
        </dependency>
        <dependency>
            <groupId>cn.git</groupId>
            <artifactId>converter-api</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
        <!--app影像上传使用 -->
        <!-- 拖拽规则使用 -->
        <dependency>
            <groupId>org.camunda.bpm.model</groupId>
            <artifactId>camunda-bpmn-model</artifactId>
            <version>7.19.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>

其余对应具体的主要实现代码如下所示

4.2.1 规则链管理相关类
  1. DragRuleController,拖拽规则管理controller,主要管理增删改查入口类

    package cn.git.rules.controller;
    
    import cn.git.common.annotation.TableCode;
    import cn.git.common.drag.dto.DragChainDTO;
    import cn.git.common.drag.dto.DragRuleDTO;
    import cn.git.common.exception.ServiceException;
    import cn.git.common.page.PageBean;
    import cn.git.common.result.Result;
    import cn.git.rules.drag.enums.DragRuleSequenceEnum;
    import cn.git.rules.dto.drag.DragRuleChainAllParamDTO;
    import cn.git.rules.mapstruct.DragRuleConvert;
    import cn.git.rules.service.drag.DragRuleService;
    import cn.git.rules.vo.drag.*;
    import cn.hutool.core.util.ObjectUtil;
    import cn.hutool.core.util.StrUtil;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import io.swagger.annotations.ApiParam;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.multipart.MultipartFile;
    
    import javax.validation.Valid;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @description: 拖拽规则controller
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2024-02-23 04:46:26
     */
    @RestController
    @RequestMapping("/rule")
    @Api(tags = "拖拽规则服务controller", value = "拖拽规则服务controller")
    public class DragRuleController {
    
        @Autowired
        private DragRuleConvert dragRuleConvert;
    
        @Autowired
        private DragRuleService dragRuleService;
    
        /**
         * 添加拖拽规则
         * @param dragRuleInVO
         * @return
         */
        @ApiOperation(value = "添加拖拽规则", notes = "添加拖拽规则")
        @PostMapping(value = "/drag/add")
        public Result addDragRule(
                @ApiParam(name = "dragRuleAddInVO", value = "添加拖拽规则inVO", required = true)
                @Valid @RequestBody DragRuleInVO dragRuleInVO) {
            // 获取传递参数
            DragRuleDTO dragRuleDTO = dragRuleConvert.dragRuleInVOToDTO(dragRuleInVO);
            // 进行自定义参数信息赋值
            if (ObjectUtil.isNotEmpty(dragRuleInVO.getCustomOptionParamList())) {
                List<List<DragRuleDTO.CustomOptionParam>> dtoCustomParamList = new ArrayList<>();
                dragRuleInVO.getCustomOptionParamList().forEach(inVOParamList -> {
                    // 空值判定
                    if (ObjectUtil.isEmpty(inVOParamList)) {
                        throw new ServiceException("保存自定义参数值为空,请正确设置自定义参数!");
                    }
    
                    // 设置dto自定义参数列表信息
                    List<DragRuleDTO.CustomOptionParam> dtoParamList = new ArrayList<>();
                    inVOParamList.forEach(inVOParam -> {
                        DragRuleDTO.CustomOptionParam dtoParam = dragRuleConvert.inVOCustomOptionParamToDTO(inVOParam);
                        dtoParamList.add(dtoParam);
                    });
                    dtoCustomParamList.add(dtoParamList);
                });
                dragRuleDTO.setCustomOptionParamList(dtoCustomParamList);
            }
    
            dragRuleService.addDragRule(dragRuleDTO);
            return Result.ok("添加拖拽规则成功!", null);
        }
    
        /**
         * 查询单条拖拽规则
         * @param id
         * @return
         */
        @ApiOperation(value = "查询单条拖拽规则", notes = "查询单条拖拽规则")
        @GetMapping(value = "/drag/{id}")
        public Result<DragRuleOutVO> findDragRule(@PathVariable("id") String id) {
            // 获取单条拖拽规则,并且转换为outVO
            DragRuleDTO dragRuleDTO = dragRuleService.findById(id);
            DragRuleOutVO outVO = dragRuleConvert.dragRuleDTOToDragRuleOutVO(dragRuleDTO);
    
            // dto 自定义参数信息转换为 outVO自定义信息参数
            if (ObjectUtil.isNotEmpty(dragRuleDTO.getCustomOptionParamList())) {
                List<List<DragRuleOutVO.CustomOptionParam>> outVOParamsList = new ArrayList<>();
                dragRuleDTO.getCustomOptionParamList().forEach(dtoParamList -> {
                    List<DragRuleOutVO.CustomOptionParam> outVOParamList = new ArrayList<>();
                    dtoParamList.forEach(dtoParam -> {
                        DragRuleOutVO.CustomOptionParam outVOParam = dragRuleConvert.dtoCustomOptionParamToDTO(dtoParam);
                        outVOParamList.add(outVOParam);
                    });
                    outVOParamsList.add(outVOParamList);
                });
                outVO.setCustomOptionParamList(outVOParamsList);
            }
            return Result.ok(outVO);
        }
    
        /**
         * 修改拖拽规则
         * @param dragRuleInVO
         * @return
         */
        @ApiOperation(value = "修改拖拽规则", notes = "修改拖拽规则")
        @PostMapping(value = "/drag/update")
        public Result updateDragRule(
                @ApiParam(name = "dragRuleInVO", value = "修改拖拽规则inVO", required = true)
                @Valid @RequestBody DragRuleInVO dragRuleInVO) {
            // 获取传递参数
            DragRuleDTO dragRuleDTO = dragRuleConvert.dragRuleInVOToDTO(dragRuleInVO);
    
            // 进行自定义参数信息赋值
            if (ObjectUtil.isNotEmpty(dragRuleInVO.getCustomOptionParamList())) {
                List<List<DragRuleDTO.CustomOptionParam>> dtoCustomParamList = new ArrayList<>();
                dragRuleInVO.getCustomOptionParamList().forEach(inVOParamList -> {
                    // 空值判定
                    if (ObjectUtil.isEmpty(inVOParamList)) {
                        throw new ServiceException("修改自定义参数值为空,请正确设置自定义参数!");
                    }
    
                    // 设置dto自定义参数列表信息
                    List<DragRuleDTO.CustomOptionParam> dtoParamList = new ArrayList<>();
                    inVOParamList.forEach(inVOParam -> {
                        DragRuleDTO.CustomOptionParam dtoParam = dragRuleConvert.inVOCustomOptionParamToDTO(inVOParam);
                        dtoParamList.add(dtoParam);
                    });
                    dtoCustomParamList.add(dtoParamList);
                });
                dragRuleDTO.setCustomOptionParamList(dtoCustomParamList);
            }
            dragRuleService.updateDragRule(dragRuleDTO);
            return Result.ok("修改成功!", null);
        }
    
        /**
         * 删除拖拽规则
         * @param id
         * @return
         */
        @ApiOperation(value = "删除拖拽规则", notes = "删除拖拽规则")
        @PostMapping(value = "/drag/delete/{id}")
        public Result deleteDragById(
                @ApiParam(name = "id", value = "删除拖拽规则id", required = true)
                @PathVariable("id") String id) {
            dragRuleService.deleteDragRule(id);
            return Result.ok("删除成功!", null);
        }
    
        /**
         * 规则列表获取
         * @param dragRulePageInVO
         * @return
         */
        @ApiOperation(value = "拖拽规则分页查询", notes = "拖拽规则分页查询")
        @PostMapping(value = "/drag/page")
        @TableCode(keyNameMapping = "ifLoadDB=YesornoInd")
        public Result<DragRulePageOutVO> dragPage(
                @ApiParam(name = "dragRuleInVO", value = "拖拽规则分页查询inVO", required = true)
                @Valid @RequestBody DragRulePageInVO dragRulePageInVO) {
            // 获取传递参数
            DragRuleDTO dragRuleDTO = dragRuleConvert.dragRulePageInVOToDTO(dragRulePageInVO);
            PageBean<DragRuleDTO> pageBean = dragRuleService.getDragRulePage(dragRuleDTO);
            DragRulePageOutVO pageOutVO = new DragRulePageOutVO();
            pageOutVO.setDragRuleDTOPageBean(pageBean);
            return Result.ok(pageOutVO);
        }
    
        /**
         * 单个规则链获取
         * @param dragRuleChainOpInVO
         * @return
         */
        @ApiOperation(value = "单个规则链获取", notes = "单个规则链获取")
        @PostMapping(value = "/drag/chain")
        public Result<DragRuleChainOutVO> getDragRuleChainByUri(
                @ApiParam(name = "dragRuleChainOpInVO", value = "拖拽规则链查询删除操作inVO", required = true)
                @Valid @RequestBody DragRuleChainOpInVO dragRuleChainOpInVO) {
            DragChainDTO dragChainDTO = dragRuleService.getDragChain(dragRuleChainOpInVO.getUri());
            DragRuleChainOutVO chainOutVO = dragRuleConvert.dragChainDTOtoOutVO(dragChainDTO);
            return Result.ok(chainOutVO);
        }
    
        /**
         * 选定产品单个规则链获取
         * @param dragRuleChainOpInVO
         * @return
         */
        @ApiOperation(value = "选定产品单个规则链获取", notes = "选定产品单个规则链获取")
        @PostMapping(value = "/drag/product/chain")
        public Result<DragRuleChainOutVO> getDragProductRuleChainByUri(
                @ApiParam(name = "dragRuleChainOpInVO", value = "拖拽规则链查询删除操作inVO", required = true)
                @Valid @RequestBody DragRuleChainOpInVO dragRuleChainOpInVO) {
            // 产品cd空值校验
            if (StrUtil.isBlank(dragRuleChainOpInVO.getProductCd())) {
                throw new ServiceException("产品cd不能为空!");
            }
            DragChainDTO dragChainDTO = dragRuleService.getDragProductChain(dragRuleChainOpInVO.getUri(),
                    dragRuleChainOpInVO.getProductCd());
            DragRuleChainOutVO chainOutVO = dragRuleConvert.dragChainDTOtoOutVO(dragChainDTO);
            return Result.ok(chainOutVO);
        }
    
    
        /**
         * 下载文件
         * @param dragRuleChainOpInVO
         * @return
         */
        @ApiOperation(value = "单个规则链文件获取", notes = "单个规则链文件获取")
        @PostMapping(value = "/drag/chain/file")
        public void downloadFile(
                @ApiParam(name = "dragRuleChainOpInVO", value = "拖拽规则链查询删除操作inVO", required = true)
                @Valid @RequestBody DragRuleChainOpInVO dragRuleChainOpInVO) throws IOException {
            // 获取文件
            dragRuleService.downloadFile(dragRuleChainOpInVO.getUri());
        }
    
        /**
         * 单个产品规则链文件获取
         * @param dragRuleChainOpInVO
         * @return
         */
        @ApiOperation(value = "单个产品规则链文件获取", notes = "单个产品规则链文件获取")
        @PostMapping(value = "/drag/chain/product/file")
        public void downloadProductFile(
                @ApiParam(name = "dragRuleChainOpInVO", value = "拖拽规则链查询删除操作inVO", required = true)
                @Valid @RequestBody DragRuleChainOpInVO dragRuleChainOpInVO) throws IOException {
            // 产品信息空值校验
            if (StrUtil.isBlank(dragRuleChainOpInVO.getProductCd())) {
                throw new ServiceException("规则链对应产品cd不能为空!");
            }
            // 获取文件
            dragRuleService.downloadProductFile(dragRuleChainOpInVO.getUri(), dragRuleChainOpInVO.getProductCd());
        }
    
        /**
         * 获取文件xml信息
         * @param dragRuleChainOpInVO
         * @return
         */
        @ApiOperation(value = "获取文件xml信息", notes = "获取文件xml信息")
        @PostMapping(value = "/drag/chain/xml")
        public Result<String> getXMLStr(
                @ApiParam(name = "dragRuleChainOpInVO", value = "拖拽规则链查询删除操作inVO", required = true)
                @Valid @RequestBody DragRuleChainOpInVO dragRuleChainOpInVO) throws IOException {
            // 获取文件
            String xmlStr = dragRuleService.getXMLStr(dragRuleChainOpInVO.getUri());
            return Result.ok(xmlStr);
        }
    
        /**
         * 获取产品规则链文件xml信息
         * @param dragRuleChainOpInVO
         * @return
         */
        @ApiOperation(value = "获取产品规则链文件xml信息", notes = "获取产品规则链文件xml信息")
        @PostMapping(value = "/drag/product/chain/xml")
        public Result<String> getProductXMLStr(
                @ApiParam(name = "dragRuleChainOpInVO", value = "拖拽规则链查询删除操作inVO", required = true)
                @Valid @RequestBody DragRuleChainOpInVO dragRuleChainOpInVO) throws IOException {
            // 产品信息空值校验
            if (StrUtil.isBlank(dragRuleChainOpInVO.getProductCd())) {
                throw new ServiceException("规则链对应产品cd不能为空!");
            }
    
            // 获取文件
            String xmlStr = dragRuleService.getProductXMLStr(dragRuleChainOpInVO.getUri(), dragRuleChainOpInVO.getProductCd());
            return Result.ok(xmlStr);
        }
    
        /**
         * 拖拽规则链删除
         * @param dragRuleChainOpInVO
         * @return
         */
        @ApiOperation(value = "删除拖拽规则", notes = "删除拖拽规则")
        @PostMapping(value = "/drag/chain/delete")
        public Result deleteChainById(
                @ApiParam(name = "dragRuleChainOpInVO", value = "拖拽规则链查询删除操作inVO", required = true)
                @Valid @RequestBody DragRuleChainOpInVO dragRuleChainOpInVO) {
            dragRuleService.deleteChainByUri(dragRuleChainOpInVO.getUri());
            return Result.ok("删除拖拽规则成功!", null);
        }
    
        /**
         * 拖拽产品规则链单个删除
         * @param dragRuleChainOpInVO
         * @return
         */
        @ApiOperation(value = "拖拽产品规则链单个删除", notes = "拖拽产品规则链单个删除")
        @PostMapping(value = "/drag/product/chain/delete")
        public Result deleteProductChainByURIAndProductCd(
                @ApiParam(name = "dragRuleChainOpInVO", value = "拖拽规则链查询删除操作inVO", required = true)
                @Valid @RequestBody DragRuleChainOpInVO dragRuleChainOpInVO) {
            // 空值校验
            if (StrUtil.isBlank(dragRuleChainOpInVO.getProductCd())) {
                throw new ServiceException("规则链对应产品cd不能为空!");
            }
            dragRuleService.deleteProductChainByUriAndProductCd(dragRuleChainOpInVO.getUri(),
                    dragRuleChainOpInVO.getProductCd());
            return Result.ok("产品删除拖拽规则成功!", null);
        }
    
        /**
         * 拖拽产品规则链集合删除
         * @param dragRuleChainOpInVO
         * @return
         */
        @ApiOperation(value = "拖拽产品规则链集合删除", notes = "拖拽产品规则链集合删除")
        @PostMapping(value = "/drag/product/chain/uri/delete")
        public Result deleteProductChainByURI(
                @ApiParam(name = "dragRuleChainOpInVO", value = "拖拽规则链查询删除操作inVO", required = true)
                @Valid @RequestBody DragRuleChainOpInVO dragRuleChainOpInVO) {
            // 空值校验
            if (StrUtil.isNotBlank(dragRuleChainOpInVO.getProductCd())) {
                throw new ServiceException("拖拽产品规则链集合删除,产品cd必须为空!");
            }
            dragRuleService.deleteProductChainByUri(dragRuleChainOpInVO.getUri());
            return Result.ok("产品删除拖拽规则成功!", null);
        }
    
        /**
         * 添加拖拽规则链
         * @param dragRuleChain 规则链,多个规则id逗号分割
         * @param file 文件
         * @param module 模块
         * @param methodPath 请求路径
         * @return
         */
        @ApiOperation(value = "添加拖拽规则链", notes = "添加拖拽规则链")
        @PostMapping(value = "/drag/chain/add")
        public Result addDragChain(
                @ApiParam(name = "file", value = "拖拽规则文件", required = true)
                @RequestParam(value = "file") MultipartFile file,
                @ApiParam(name = "module", value = "模块uri用 : 分割前缀 ge: ACCOUNT_SERVER", required = true)
                @RequestParam(value = "module") String module,
                @ApiParam(name = "methodPath", value = "uri除去模块后缀,将请求地址中的 '/' 更换为 '_',eg: _account_drag_test0002", required = true)
                @RequestParam(value = "methodPath") String methodPath,
                @ApiParam(name = "dragRuleChain", value = "规则链规则详情,多个规则id逗号分割", required = true)
                @RequestParam(value = "dragRuleChain") String dragRuleChain) throws IOException {
            // bpmn文件信息解析校验
            if (ObjectUtil.isNull(file)) {
                Result.error("规则链文件为空,请确认!");
            }
    
            // 组成uri地址
            String uri = module.concat(StrUtil.COLON).concat(methodPath.replaceAll(StrUtil.UNDERLINE, StrUtil.SLASH));
    
            // 获取传递参数
            dragRuleService.addChain(dragRuleChain, uri, file);
            return Result.ok("添加拖拽规则链成功!", null);
        }
    
        /**
         * 添加产品拖拽规则链初始方法
         * @param module 模块
         * @param methodPath 请求路径
         * @return
         */
        @ApiOperation(value = "添加产品拖拽规则链初始方法", notes = "添加产品拖拽规则链初始方法")
        @PostMapping(value = "/drag/chain/product/add/init")
        public Result addDragProductChainInit(
                @ApiParam(name = "productCd", value = "产品cd", required = true)
                @RequestParam(value = "productCd") String productCd,
                @ApiParam(name = "module", value = "模块uri用 : 分割前缀 ge: ACCOUNT_SERVER", required = true)
                @RequestParam(value = "module") String module,
                @ApiParam(name = "methodPath", value = "uri除去模块后缀,将请求地址中的 '/' 更换为 '_',eg: _account_drag_test0002", required = true)
                @RequestParam(value = "methodPath") String methodPath) throws IOException {
    
            // 组成uri地址
            String uri = module.concat(StrUtil.COLON).concat(methodPath.replaceAll(StrUtil.UNDERLINE, StrUtil.SLASH));
    
            // 获取传递参数
            dragRuleService.addProductChainInit(uri, productCd);
            return Result.ok("初始化校验通过!", null);
        }
    
        /**
         * 添加产品拖拽规则链
         * @param dragRuleChain 规则链,多个规则id逗号分割
         * @param file 文件
         * @param module 模块
         * @param methodPath 请求路径
         * @return
         */
        @ApiOperation(value = "添加产品拖拽规则链", notes = "添加产品拖拽规则链")
        @PostMapping(value = "/drag/chain/product/add")
        public Result addDragProductChain(
                @ApiParam(name = "file", value = "拖拽规则文件", required = true)
                @RequestParam(value = "file") MultipartFile file,
                @ApiParam(name = "productCd", value = "产品cd", required = true)
                @RequestParam(value = "productCd") String productCd,
                @ApiParam(name = "module", value = "模块uri用 : 分割前缀 ge: ACCOUNT_SERVER", required = true)
                @RequestParam(value = "module") String module,
                @ApiParam(name = "methodPath", value = "uri除去模块后缀,将请求地址中的 '/' 更换为 '_',eg: _account_drag_test0002", required = true)
                @RequestParam(value = "methodPath") String methodPath,
                @ApiParam(name = "dragRuleChain", value = "规则链规则详情,多个规则id逗号分割", required = true)
                @RequestParam(value = "dragRuleChain") String dragRuleChain) throws IOException {
            // bpmn文件信息解析校验
            if (ObjectUtil.isNull(file)) {
                Result.error("规则链文件为空,请确认!");
            }
    
            // 组成uri地址
            String uri = module.concat(StrUtil.COLON).concat(methodPath.replaceAll(StrUtil.UNDERLINE, StrUtil.SLASH));
    
            // 获取传递参数
            dragRuleService.addProductChain(dragRuleChain, uri, file, productCd);
            return Result.ok("添加产品拖拽规则链成功!", null);
        }
    
        /**
         * 修改规则链
         * @param dragRuleChain 规则链,多个规则id逗号分割
         * @param file 文件
         * @param module 模块
         * @param methodPath 请求路径
         * @return
         */
        @ApiOperation(value = "修改规则链", notes = "修改规则链")
        @PostMapping(value = "/drag/chain/update")
        public Result updateDragChain(
                @ApiParam(name = "file", value = "拖拽规则文件", required = true)
                @RequestParam(value = "file") MultipartFile file,
                @ApiParam(name = "module", value = "模块uri用 : 分割前缀 ge: ACCOUNT_SERVER", required = true)
                @RequestParam(value = "module") String module,
                @ApiParam(name = "methodPath", value = "uri除去模块后缀,将请求地址中的 '/' 更换为 '_',eg: _account_drag_test0002", required = true)
                @RequestParam(value = "methodPath") String methodPath,
                @ApiParam(name = "dragRuleChain", value = "规则链规则详情,多个规则id逗号分割", required = true)
                @RequestParam(value = "dragRuleChain") String dragRuleChain) throws IOException {
            // 文件非空校验
            if (ObjectUtil.isNull(file)) {
                Result.error("规则链文件为空,请确认!");
            }
    
            // 组成uri地址
            String uri = module.concat(StrUtil.COLON).concat(methodPath.replaceAll(StrUtil.UNDERLINE, StrUtil.SLASH));
    
            // 获取传递参数
            dragRuleService.updateChain(dragRuleChain, uri, file);
            return Result.ok("修改规则链成功!", null);
        }
    
        /**
         * 修改规则链
         * @param dragRuleChain 规则链,多个规则id逗号分割
         * @param file 文件
         * @param module 模块
         * @param methodPath 请求路径
         * @return
         */
        @ApiOperation(value = "修改产品规则链", notes = "修改产品规则链")
        @PostMapping(value = "/drag/chain/product/update")
        public Result updateDragChain(
                @ApiParam(name = "file", value = "拖拽规则文件", required = true)
                @RequestParam(value = "file") MultipartFile file,
                @ApiParam(name = "productCd", value = "产品cd", required = true)
                @RequestParam(value = "productCd") String productCd,
                @ApiParam(name = "module", value = "模块uri用 : 分割前缀 ge: ACCOUNT_SERVER", required = true)
                @RequestParam(value = "module") String module,
                @ApiParam(name = "methodPath", value = "uri除去模块后缀,将请求地址中的 '/' 更换为 '_',eg: _account_drag_test0002", required = true)
                @RequestParam(value = "methodPath") String methodPath,
                @ApiParam(name = "dragRuleChain", value = "规则链规则详情,多个规则id逗号分割", required = true)
                @RequestParam(value = "dragRuleChain") String dragRuleChain) throws IOException {
            // 文件非空校验
            if (ObjectUtil.isNull(file)) {
                Result.error("规则链文件为空,请确认!");
            }
    
            // 组成uri地址
            String uri = module.concat(StrUtil.COLON).concat(methodPath.replaceAll(StrUtil.UNDERLINE, StrUtil.SLASH));
    
            // 获取传递参数
            dragRuleService.updateProductChain(dragRuleChain, uri, file, productCd);
            return Result.ok("修改规则链成功!", null);
        }
    
        /**
         * 规则链列表获取
         * @param dragRuleChainInVO
         * @return
         */
        @ApiOperation(value = "规则链列表获取", notes = "规则链列表获取")
        @PostMapping(value = "/drag/chain/page")
        @TableCode(keyNameMapping = "ifLoadDB=YesornoInd")
        public Result<DragRuleChainPageOutVO> dragChainPage(
                @ApiParam(name = "DragRuleChainPageInVO", value = "规则链分页操作inVO", required = true)
                @Valid @RequestBody DragRuleChainPageInVO dragRuleChainInVO) {
            // 获取传递参数
            DragChainDTO dragChainDTO = dragRuleConvert.dragRulePageInVOtoDTO(dragRuleChainInVO);
            PageBean<DragChainDTO> pageBean = dragRuleService.getDragChainPage(dragChainDTO);
            // 回参参数
            DragRuleChainPageOutVO chainPageOutVO = new DragRuleChainPageOutVO();
            chainPageOutVO.setPageBean(pageBean);
            return Result.ok(chainPageOutVO);
        }
    
        /**
         * 产品规则链列表获取
         * @param pageInVO
         * @return
         */
        @ApiOperation(value = "产品规则链列表获取", notes = "产品规则链列表获取")
        @PostMapping(value = "/drag/product/chain/page")
        public Result<DragRuleChainPageOutVO> dragProductChainPage(
                @ApiParam(name = "DragRuleProductPageInVO", value = "产品规则链列表获取", required = true)
                @Valid @RequestBody DragRuleProductPageInVO pageInVO) {
            // 产品cd非空校验
            if (StrUtil.isBlank(pageInVO.getProductCd())) {
                throw new ServiceException("产品cd不能为空!");
            }
    
            // 获取传递参数,转换为DTO
            DragChainDTO dragChainDTO = dragRuleConvert.dragRuleProductPageInVOtoDTO(pageInVO);
    
            // 开始获取分页列表细信息
            PageBean<DragChainDTO> pageBean = dragRuleService.getDragProductChainPage(dragChainDTO);
            // 回参参数
            DragRuleChainPageOutVO chainPageOutVO = new DragRuleChainPageOutVO();
            chainPageOutVO.setPageBean(pageBean);
            return Result.ok(chainPageOutVO);
        }
    
        /**
         * 校验并获取规则链全部参数信息
         * @param dragRuleChainInVO
         * @return
         */
        @ApiOperation(value = "校验并获取规则链全部参数信息", notes = "校验并获取规则链全部参数信息")
        @PostMapping(value = "/drag/chain/params")
        public Result<DragRuleChainAllParamDescOutVO> checkDragRuleChainAllParamDesc(
                @Valid @RequestBody DragRuleChainAllParamDescInVO dragRuleChainInVO) {
            // 参数非空校验
            if (StrUtil.isNotBlank(dragRuleChainInVO.getDragRuleChain()) && StrUtil.isBlank(dragRuleChainInVO.getUri())) {
                throw new ServiceException(StrUtil.format("如果传入规则链规则信息,规则链uri必填!"));
            }
    
            // 参数转换
            DragRuleChainAllParamDTO allParamDTO = new DragRuleChainAllParamDTO();
            allParamDTO.setUri(dragRuleChainInVO.getUri());
            allParamDTO.setDragRuleChain(dragRuleChainInVO.getDragRuleChain());
    
            // 获取规则链全部参数以及校验参数是否合法
            allParamDTO = dragRuleService.checkDragRuleChainAllParamDesc(allParamDTO);
            DragRuleChainAllParamDescOutVO allParamDescOutVO = dragRuleConvert.dragRuleChainAllParamDescToOutVO(allParamDTO);
            return Result.ok(allParamDescOutVO);
        }
    
        @ApiOperation(value = "开发人员使用获取拖拽规则规则名称", notes = "开发人员使用获取拖拽规则规则名称")
        @GetMapping(value = "/drag/sequence/name")
        public Result<String> getDragSequenceName(@RequestParam DragRuleSequenceEnum dragRuleSequenceEnum) {
            // 通过枚举获取各模块规则信息
            String dragRuleName = dragRuleService.getDragSequenceName(dragRuleSequenceEnum);
            return Result.ok(dragRuleName);
        }
    }
    
    
  2. dragRuleService以及对应的serviceImpl实现类

    package cn.git.rules.service.drag;
    
    import cn.git.common.drag.dto.DragChainDTO;
    import cn.git.common.drag.dto.DragRuleDTO;
    import cn.git.common.page.PageBean;
    import cn.git.rules.drag.enums.DragRuleSequenceEnum;
    import cn.git.rules.dto.drag.DragRuleChainAllParamDTO;
    import org.springframework.web.multipart.MultipartFile;
    
    import java.io.IOException;
    
    /**
     * @description: 拖拽规则service
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2024-02-22 11:55:33
     */
    public interface DragRuleService {
    
        /**
         * 添加拖拽规则方法
         * @param dragRuleDTO
         */
        void addDragRule(DragRuleDTO dragRuleDTO);
    
        /**
         * 通过id查询拖拽规则
         * @param dragRuleId
         * @return
         */
        DragRuleDTO findById(String dragRuleId);
    
        /**
         * 修改拖拽规则
         * @param dragRuleDTO
         */
        void updateDragRule(DragRuleDTO dragRuleDTO);
    
        /**
         * 删除拖拽规则
         * @param id
         */
        void deleteDragRule(String id);
    
        /**
         * 分页查询拖拽规则信息
         * 参数有规则描述信息,模糊查询
         * 参数有规则id信息,精确查询
         * 查询结果由两部分拼接而成,注意:只有表数据中有数据才能进行规则链添加
         *  1:通过缓存信息,可以获取规则入参,出参等信息
         *  2:通过表数据,可以获取传递参数,自定义比较参数等
         *
         * @param dragRuleDTO
         * @return
         */
        PageBean<DragRuleDTO> getDragRulePage(DragRuleDTO dragRuleDTO);
    
        /**
         * 添加链信息
         * @param dragRuleChain
         * @param uri
         * @param file
         */
        void addChain(String dragRuleChain, String uri, MultipartFile file) throws IOException;
    
        /**
         * 添加产品链信息初始化校验
         * @param uri uri
         * @param productCd 产品cd
         */
        void addProductChainInit(String uri, String productCd) throws IOException;
    
        /**
         * 添加产品链信息
         * @param dragRuleChain 规则链多个逗号分割
         * @param uri uri
         * @param file 文件
         * @param productCd 产品cd
         */
        void addProductChain(String dragRuleChain, String uri, MultipartFile file, String productCd) throws IOException;
    
        /**
         * 修改链信息
         * @param dragRuleChain 规则链
         * @param uri uri
         * @param file 文件
         */
        void updateChain(String dragRuleChain, String uri, MultipartFile file) throws IOException;
    
        /**
         * 修改产品链信息
         * @param dragRuleChain 规则链
         * @param uri uri
         * @param file 文件
         */
        void updateProductChain(String dragRuleChain, String uri, MultipartFile file, String productCd) throws IOException;
    
        /**
         * 通过uri删除链信息
         * @param uri
         * @return
         */
        void deleteChainByUri(String uri);
    
        /**
         * 通过uri以及产品cd删除产品链信息
         * @param uri
         * @return
         */
        void deleteProductChainByUriAndProductCd(String uri, String productCd);
    
        /**
         * 通过uri删除多条产品链信息
         * @param uri
         * @return
         */
        void deleteProductChainByUri(String uri);
    
        /**
         * 通过uri查询链信息
         * @param uri
         * @return
         */
        DragChainDTO getDragChain(String uri);
    
        /**
         * 通过uri和productCd查询链信息
         * @param uri
         * @param productCd
         * @return
         */
        DragChainDTO getDragProductChain(String uri, String productCd);
    
        /**
         * 获取规则文件信息
         * @param uri
         * @throws IOException
         */
        void downloadFile(String uri) throws IOException;
    
        /**
         * 单个产品规则链文件获取
         * @param uri
         * @param productCd
         *
         * @throws IOException
         */
        void downloadProductFile(String uri, String productCd) throws IOException;
    
        /**
         * 获取规则文件xml信息
         * @param uri
         * @throws IOException
         */
        String getXMLStr(String uri) throws IOException;
    
        /**
         * 获取产品规则文件xml信息
         * @param uri
         * @throws IOException
         */
        String getProductXMLStr(String uri, String productCd) throws IOException;
    
        /**
         * 分页查询链信息
         * @param dragChainDTO
         * @return
         */
        PageBean<DragChainDTO> getDragChainPage(DragChainDTO dragChainDTO);
    
        /**
         * 分页查询产品链信息
         * @param dragChainDTO
         * @return
         */
        PageBean<DragChainDTO> getDragProductChainPage(DragChainDTO dragChainDTO);
    
        /**
         * 校验并获取规则链全部参数信息
         * @param allParamDTO
         * @return
         */
        DragRuleChainAllParamDTO checkDragRuleChainAllParamDesc(DragRuleChainAllParamDTO allParamDTO);
    
        /**
         * 开发人员使用获取拖拽规则规则名称
         * @param sequenceEnum
         * @return
         */
        String getDragSequenceName(DragRuleSequenceEnum sequenceEnum);
    
    }
    
    

    规则实现类代码过多,所以新增一个单独记录地址记录,DragRuleServiceImpl 详情请点击

  3. 规则注解类,标注此类的接口会被扫描到规则缓存中

    package cn.git.rules.drag;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * @description: 规则属性解释注解
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2024-02-22 08:44:44
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD, ElementType.TYPE})
    public @interface DragRuleDesc {
    
        /**
         * 拖拽规则field作用注释
         * @return
         */
        String fieldDesc() default "属性字段描述";
    
        /**
         * 拖拽规则bean作用注释
         * @return
         */
        String beanDesc() default "拖拽规则类描述";
    
    }
    
  4. server端工具类

    package cn.git.rules.drag;
    
    import cn.git.api.util.NewCoreProperties;
    import cn.git.common.drag.CommonDragRuleConstant;
    import cn.git.common.drag.dto.DragChainDTO;
    import cn.git.common.drag.dto.DragRuleDTO;
    import cn.git.common.exception.ServiceException;
    import cn.git.common.lock.LockTypeEnum;
    import cn.git.common.lock.SimpleDistributeLock;
    import cn.git.common.util.LogUtil;
    import cn.git.redis.RedisUtil;
    import cn.git.rules.constant.RuleConstant;
    import cn.git.rules.entity.TbSysDragChain;
    import cn.git.rules.entity.TbSysDragRule;
    import cn.git.rules.entity.TbSysProductDragChain;
    import cn.git.rules.mapper.TbSysDragRuleMapper;
    import cn.git.rules.mapper.TbSysProductDragChainMapper;
    import cn.git.rules.mapstruct.DragRuleConvert;
    import cn.hutool.core.date.DatePattern;
    import cn.hutool.core.date.DateUtil;
    import cn.hutool.core.util.ObjectUtil;
    import cn.hutool.core.util.StrUtil;
    import com.alibaba.fastjson.JSONObject;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.aop.framework.Advised;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.ApplicationContext;
    import org.springframework.stereotype.Component;
    
    import javax.script.*;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.*;
    import java.util.function.Function;
    import java.util.stream.Collectors;
    
    /**
     * @description: DragRule拖拽规则工具类
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2024-02-21 03:01:12
     */
    @Slf4j
    @Component
    public class DragRuleServerUtil {
    
        @Autowired
        private DragRuleConvert dragRuleConvert;
    
        @Autowired
        private RedisUtil redisUtil;
    
        @Autowired
        private TbSysDragRuleMapper tbSysDragRuleMapper;
    
        @Autowired
        private TbSysProductDragChainMapper productDragChainMapper;
    
        @Autowired
        private ApplicationContext applicationContext;
    
        @Autowired
        private SimpleDistributeLock simpleDistributeLock;
    
        @Value("${spring.application.name}")
        private String applicationName;
    
        /**
         * 初始化拖拽规则详情信息,设置规则信息DRAG_RULE供其他子模块获取使用
         * 规则格式如下: hset DRAG_RULE DragRuleId RuleInfo
         */
        public void initDragRule() throws Exception {
            // 获取锁信息
            String lockResult = simpleDistributeLock.tryLock(LockTypeEnum.DRAG_RULE_INIT_LOCK, applicationName);
            try {
                if (StrUtil.isNotBlank(lockResult)) {
                    // 扫描服务所有DragRule注解类信息,此处需要将获取bean由cglib转换为真实对象
                    Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(DragRuleDesc.class);
                    beansWithAnnotation.replaceAll((key, value) -> {
                        if (value instanceof Advised) {
                            Advised advised = (Advised) value;
                            Object target = null;
                            try {
                                target = advised.getTargetSource().getTarget();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                            return target;
                        } else {
                            return value;
                        }
                    });
    
                    // 获取全部拖拽规则信息
                    List<TbSysDragRule> dragRuleList = tbSysDragRuleMapper.selectList(null);
                    Map<String, TbSysDragRule> dragRuleMap = new HashMap<>(NewCoreProperties.FLAG_INT_16);
    
                    // 如果规则不为空,则证明规则进行过设置,需要校验规则类是否有修改,规则是否存在校验
                    if (ObjectUtil.isNotEmpty(dragRuleList)) {
                        // 获取注解类名称,判定数据库是否有配置,如果没有则抛出异常
                        for (TbSysDragRule dragRule : dragRuleList) {
                            dragRuleMap.put(dragRule.getDragRuleId(), dragRule);
                            // 获取规则id eg: TESTDragRule0001
                            String dragRuleId = dragRule.getDragRuleId();
                            // 查看beansWithAnnotation中是否有当前处理规则,如果没有则抛出异常信息
                            if (!beansWithAnnotation.containsKey(dragRuleId.concat(RuleConstant.TRAN_SUFFIX))) {
                                throw new ServiceException(StrUtil
                                        .format("数据库表[MANAGE.TB_SYS_DRAG_RULE]中规则[{}]代码已经删除,请确认!", dragRuleId));
                            }
                        }
                    }
    
                    // 设置规则入参出参信息到规则缓存中
                    Map<String, Object> dragRuleDTOMap = new HashMap<>(NewCoreProperties.FLAG_INT_16);
                    for (Map.Entry<String, Object> entry : beansWithAnnotation.entrySet()) {
                        Class<?> dragRuleTranClass = entry.getValue().getClass();
                        // 获取process方法
                        Method[] methods = dragRuleTranClass.getMethods();
                        if (ObjectUtil.isEmpty(methods)) {
                            log.error("规则[{}]没有设定方法,请正确设置方法!", dragRuleTranClass.getName());
                            continue;
                        }
                        // methods转换为List并且过滤出process方法
                        Method method = Arrays.stream(methods).filter(method1 ->
                                method1.getName().equals("process")
                        ).findFirst().orElse(null);
                        if (ObjectUtil.isNull(method)) {
                            log.error("规则[{}]没有设定process方法,请正确设置process方法!", dragRuleTranClass.getName());
                            continue;
                        }
    
                        // 获取方法参数信息
                        Class<?> parameterType = method.getParameterTypes()[0];
                        // 复杂类类型
                        Field[] declaredFields = parameterType.getDeclaredFields();
                        // 入参信息处理
                        JSONObject inputParamJSON = new JSONObject();
                        List<DragRuleDTO.DragRuleParamsDesc> inputParamDescList = new ArrayList<>();
                        for (Field field : declaredFields) {
                            // 获取描述信息
                            DragRuleDesc dragRuleDesc = field.getAnnotation(DragRuleDesc.class);
                            if (ObjectUtil.isNotNull(dragRuleDesc) && StrUtil.isNotBlank(dragRuleDesc.fieldDesc())) {
                                DragRuleDTO.DragRuleParamsDesc fieldDesc = new DragRuleDTO.DragRuleParamsDesc();
                                fieldDesc.setParamDesc(dragRuleDesc.fieldDesc());
                                fieldDesc.setParamType(field.getType().getSimpleName());
                                fieldDesc.setParamName(field.getName());
                                inputParamDescList.add(fieldDesc);
                            } else {
                                throw new ServiceException(StrUtil.format("拖拽规则入参DTO[{}]对应属性[{}]未设置@DragRuleDesc的fieldDesc属性",
                                        parameterType.getSimpleName(),
                                        field.getName()));
                            }
                            inputParamJSON.put(field.getName(), StrUtil.EMPTY);
                        }
                        // 设置出参信息,首先获取出参内部类
                        String simpleClassName = parameterType.getSimpleName().replace("DTO", "OUTDTO");
                        String className = parameterType.getName();
                        JSONObject outputParamJSON;
                        List<DragRuleDTO.DragRuleParamsDesc> outputParamDescList = new ArrayList<>();
                        try {
                            Class<?> innerClass = Class.forName(className.concat("$").concat(simpleClassName));
                            outputParamJSON = new JSONObject();
    
                            for (Field field : innerClass.getDeclaredFields()) {
                                DragRuleDesc dragRuleDesc = field.getAnnotation(DragRuleDesc.class);
                                if (ObjectUtil.isNotNull(dragRuleDesc) && StrUtil.isNotBlank(dragRuleDesc.fieldDesc())) {
                                    DragRuleDTO.DragRuleParamsDesc fieldDesc = new DragRuleDTO.DragRuleParamsDesc();
                                    fieldDesc.setParamDesc(dragRuleDesc.fieldDesc());
                                    fieldDesc.setParamType(field.getType().getSimpleName());
                                    fieldDesc.setParamName(field.getName());
                                    outputParamDescList.add(fieldDesc);
                                } else {
                                    throw new ServiceException(StrUtil.format("拖拽规则出参DTO[{}]对应属性[{}]未设置@DragRuleDesc的fieldDesc属性",
                                            innerClass.getSimpleName(),
                                            field.getName()));
                                }
                                outputParamJSON.put(field.getName(), StrUtil.EMPTY);
                            }
                        } catch (ClassNotFoundException e) {
                            throw new ServiceException(StrUtil.format("获取出参内部类失败,请检查[{}]类是否正确配置!",
                                    simpleClassName));
                        }
    
                        // 获取bean描述信息
                        String beanDesc = dragRuleTranClass.getAnnotation(DragRuleDesc.class).beanDesc();
                        if (StrUtil.isBlank(beanDesc)) {
                            throw new ServiceException(StrUtil.format("规则类[{}]对应@DragRuleDesc注解beanDesc没有设置", dragRuleTranClass.getName()));
                        }
                        // 封装参数信息,入参出参从反射中获取,其余参数如果数据库查询有值则设定,如果没有则不设定
                        String ruleId = StrUtil.upperFirst(entry.getKey()).replace("Tran", StrUtil.EMPTY);
                        TbSysDragRule dragRule = dragRuleMap.get(ruleId);
                        DragRuleDTO dragRuleDTO;
                        if (ObjectUtil.isNotNull(dragRule)) {
                            // 转换拖拽规则
                            dragRuleDTO = dragRuleConvert.dragRuleToDragRuleDTO(dragRule);
                            // 设置描述信息
                            dragRuleDTO.setRuleDesc(beanDesc);
                            // 是否落库
                            dragRuleDTO.setIfLoadDB(RuleConstant.NUM_1_STR);
                            // 设置crossParam列表以及自定义操作参数列表
                            if (StrUtil.isNotBlank(dragRule.getCrossParam())) {
                                List<String> crossParamList = Arrays.asList(dragRule.getCrossParam().split(StrUtil.COMMA));
                                dragRuleDTO.setCrossParamList(crossParamList);
                                dragRuleDTO.setCrossParam(dragRule.getCrossParam());
                                // 将outParamDescList转换为map,获取crossParamDesc描述信息
                                Map<String, DragRuleDTO.DragRuleParamsDesc> outParamDescMap = outputParamDescList.stream()
                                        .collect(
                                                Collectors.toMap(DragRuleDTO.DragRuleParamsDesc::getParamName,
                                                        Function.identity())
                                        );
                                List<DragRuleDTO.DragRuleParamsDesc> crossParamDescList = new ArrayList<>();
                                crossParamList.forEach(paramName -> {
                                    DragRuleDTO.DragRuleParamsDesc dragRuleParamsDesc = outParamDescMap.get(paramName);
                                    if (ObjectUtil.isNotNull(dragRuleParamsDesc)) {
                                        crossParamDescList.add(dragRuleParamsDesc);
                                    }
                                });
                                dragRuleDTO.setCrossParamDescList(crossParamDescList);
                            }
    
                            // 设置自定义参数信息
                            if (StrUtil.isNotBlank(dragRule.getCustomOptionParam())) {
                                // 将json类型转换为 List<List<DragRuleDTO.CustomOptionParam>> 类型
                                List customOptionParamsList = JSONObject.parseArray(dragRule.getCustomOptionParam(), List.class);
                                List<List<DragRuleDTO.CustomOptionParam>> typeList = new ArrayList<>();
                                for (Object customParamList : customOptionParamsList) {
                                    List<JSONObject> jsonParamList = (List<JSONObject>) customParamList;
                                    List<DragRuleDTO.CustomOptionParam> innerParamList = jsonParamList.stream().map(jsonParam -> {
                                        return JSONObject.parseObject(jsonParam.toJSONString(), DragRuleDTO.CustomOptionParam.class);
                                    }).collect(Collectors.toList());
                                    typeList.add(innerParamList);
                                }
                                dragRuleDTO.setCustomOptionParamList(typeList);
                            }
                        } else {
                            // 新增dragRuleDTO,添加入参出参以及其他通用参数信息
                            dragRuleDTO = new DragRuleDTO();
                            dragRuleDTO.setDragRuleId(ruleId);
                            dragRuleDTO.setRuleDesc(beanDesc);
                            dragRuleDTO.setIfLoadDB(RuleConstant.NUM_0_STR);
                        }
                        // 设置入参出参信息
                        dragRuleDTO.setInputParamDescList(inputParamDescList);
                        dragRuleDTO.setOutputParamDescList(outputParamDescList);
                        dragRuleDTO.setInputParam(inputParamJSON.toJSONString());
                        dragRuleDTO.setOutputParam(outputParamJSON.toJSONString());
                        dragRuleDTOMap.put(ruleId, JSONObject.toJSONString(dragRuleDTO));
                    }
                    if (ObjectUtil.isNotEmpty(dragRuleDTOMap)) {
                        // 删除原有规则
                        redisUtil.del(RuleConstant.DRAG_RULES);
                        // 重新加载
                        redisUtil.hmset(RuleConstant.DRAG_RULES, dragRuleDTOMap);
                    }
    
                    // 清除产品规则链缓存
                    redisUtil.del(CommonDragRuleConstant.DRAG_RULE_PRODUCT_CHAIN_FLAG);
    
                    // 开始初始化产品相关规则链信息到缓存中,缓存key为 uri + ":" + productCd格式
                    List<TbSysProductDragChain> productDragChainList = productDragChainMapper.selectList(null);
                    if (ObjectUtil.isNotEmpty(productDragChainList)) {
                        Map<String, Object> productMap = productDragChainList.stream()
                                .collect(Collectors.toMap(
                                        product -> product.getUri().concat(StrUtil.COLON).concat(product.getProductCd()),
                                        Function.identity()
                                ));
                        redisUtil.hmset(CommonDragRuleConstant.DRAG_RULE_PRODUCT_CHAIN_FLAG, productMap);
                    }
    
                    // 释放锁
                    simpleDistributeLock.releaseLock(LockTypeEnum.DRAG_RULE_INIT_LOCK, applicationName, lockResult);
                } else {
                    log.error("当前服务拖拽规则引擎服务初始化加锁失败,未执行拖拽规则服务初始化!");
                }
            } catch (Exception e) {
                throw new ServiceException(e.getMessage());
            } finally {
                // 释放锁
                simpleDistributeLock.releaseLock(LockTypeEnum.DRAG_RULE_INIT_LOCK, applicationName, lockResult);
            }
        }
    
        /**
         * 自定义检查自定义参数比较规则
         *
         * @param paramList
         */
        public void checkCustomOptionParam(List<DragRuleDTO.CustomOptionParam> paramList) {
            // 日期判定,如果参数类型中有一个日期类型,则判定当前自定义校验参数为日期参数校验
            List<DragRuleDTO.CustomOptionParam> dateParamList = paramList.stream().filter(optionParam ->
                    StrUtil.isNotBlank(optionParam.getParamType())
                    && RuleConstant.NUM_1_STR.equals(optionParam.getOptionType())
                    && RuleConstant.DATE_FLAG.equals(optionParam.getParamType())
            ).collect(Collectors.toList());
    
            // 不为空为日期类型参数
            if (ObjectUtil.isNotEmpty(dateParamList)) {
                // 日期类型首个参数必须为日期
                DragRuleDTO.CustomOptionParam customParam = paramList.get(0);
                if (!RuleConstant.DATE_FLAG.equals(customParam.getParamType())) {
                    throw new ServiceException("自定义参数日期类型校验,首个参数必须为规则响应信息中的日期类型参数,请确认!");
                }
    
                // 日期类型参数校验,长度必须为3,并且参数只允许为日期参数或者自定义参数
                if (paramList.size() != RuleConstant.NUM_3) {
                    throw new ServiceException("自定义参数比较规则中,日期类型比较参数必须为3个[参数日期,标识符,比较日期]!");
                }
    
                // 参数类型校验,必须包含
                List<DragRuleDTO.CustomOptionParam> optionTypeParamList = paramList.stream().filter(optionParam -> {
                    // 类型判定
                    boolean ifOptionType = RuleConstant.NUM_0_STR.equals(optionParam.getOptionType());
                    // 操作符判定
                    boolean ifOptionValue = ">=".equals(optionParam.getParamName())
                            || ">".equals(optionParam.getParamName())
                            || "<=".equals(optionParam.getParamName())
                            || "<".equals(optionParam.getParamName())
                            || "==".equals(optionParam.getParamName())
                            || "!=".equals(optionParam.getParamName());
                    return ifOptionType && ifOptionValue;
                }).collect(Collectors.toList());
                if (ObjectUtil.isEmpty(optionTypeParamList) || optionTypeParamList.size() != 1) {
                    throw new ServiceException("日期类型自定义参数校验失败,日期自定义参数设置至少一个比较标识符");
                }
    
                // 自定义值格式校验
                List<DragRuleDTO.CustomOptionParam> customValueParamList = paramList.stream().filter(optionParam -> {
                    // 获取自定义值信息
                    return ObjectUtil.isNotNull(optionParam) && RuleConstant.NUM_2_STR.equals(optionParam.getOptionType());
                }).collect(Collectors.toList());
                if (ObjectUtil.isNotEmpty(customValueParamList)) {
                    // 必须唯一校验
                    if (customValueParamList.size() != 1) {
                        throw new ServiceException("日期类型自定义值比较只能设置一个自定义值信息,请确认!");
                    } else {
                        // 唯一格式校验
                        DragRuleDTO.CustomOptionParam customOptionParam = customValueParamList.get(0);
                        if (!customOptionParam.getValue().matches(RuleConstant.DATE_PATTERN)) {
                            throw new ServiceException("自定义日期格式设置异常,请设置为yyyy-MM-dd格式,请确认!");
                        }
                    }
                }
            } else {
                // 非日期类型,既数字类型校验,数字类型参数之中只能有BigDecimal类型以及操作标识符
                List<DragRuleDTO.CustomOptionParam> otherErrorParamList = paramList.stream().filter(optionParam -> {
                    // 是否数字判定
                    return RuleConstant.NUM_1_STR.equals(optionParam.getOptionType())
                            && !(RuleConstant.BIG_DECIMAL_FLAG.equalsIgnoreCase(optionParam.getParamType())
                            || RuleConstant.INT_FLAG.equalsIgnoreCase(optionParam.getParamType())
                            || RuleConstant.INTEGER_FLAG.equalsIgnoreCase(optionParam.getParamType())
                            || RuleConstant.LONG_FLAG.equalsIgnoreCase(optionParam.getParamType())
                            || RuleConstant.DOUBLE_FLAG.equalsIgnoreCase(optionParam.getParamType())
                    );
                }).collect(Collectors.toList());
                if (ObjectUtil.isNotEmpty(otherErrorParamList)) {
                    // 获取paramName,然后使用逗号进行分割
                    String errorMessage = otherErrorParamList.stream().map(
                            DragRuleDTO.CustomOptionParam::getParamName
                    ).collect(Collectors.joining(StrUtil.COMMA));
                    throw new ServiceException(StrUtil
                            .format("自定义数字类型比较只能设置数字类型参数,此部分字段[{}]设定非法,请确认!", errorMessage));
                }
    
                // 进行参数格式校验,进行执行器预编译,首先获取执行eval字符串
                StringBuffer numberCheckBuffer = new StringBuffer();
                for (DragRuleDTO.CustomOptionParam customOptionParam : paramList) {
                    // 参数类型判定
                    if (RuleConstant.NUM_0_STR.equals(customOptionParam.getOptionType())) {
                        // 操作符标识
                        numberCheckBuffer.append(customOptionParam.getParamName()).append(StrUtil.SPACE);
                    } else if (RuleConstant.NUM_1_STR.equals(customOptionParam.getOptionType())) {
                        // outVO参数信息,参数必须为数字类型
                        boolean isNum = RuleConstant.BIG_DECIMAL_FLAG.equals(customOptionParam.getParamType())
                                || RuleConstant.INT_FLAG.equalsIgnoreCase(customOptionParam.getParamType())
                                || RuleConstant.INTEGER_FLAG.equalsIgnoreCase(customOptionParam.getParamType())
                                || RuleConstant.LONG_FLAG.equalsIgnoreCase(customOptionParam.getParamType())
                                || RuleConstant.DOUBLE_FLAG.equalsIgnoreCase(customOptionParam.getParamType());
                        // 如果为数字,则替换字段信息为 1,方便后续预编译计算
                        if (isNum) {
                            numberCheckBuffer.append(customOptionParam.getParamName()).append(StrUtil.SPACE);
                        } else {
                            throw new ServiceException(StrUtil.format("自定义比较参数[{}]数字类型不正确,请确认!",
                                    customOptionParam.getParamName()));
                        }
                    } else if (RuleConstant.NUM_2_STR.equals(customOptionParam.getOptionType())) {
                        // 自定义参数,进行自定义参数信息校验
                        String customValue = customOptionParam.getValue();
                        if (StrUtil.isBlank(customValue)) {
                            throw new ServiceException(StrUtil
                                    .format("自定义参数比较获取自定义参数[{}]为空,请确认!",
                                            customOptionParam.getValue()));
                        }
    
                        // 数字类型格式校验
                        if (!customValue.matches(RuleConstant.NUMBER_PATTERN)) {
                            throw new ServiceException(StrUtil
                                    .format("自定义参数比较获取自定义参数[{}]数字类型不正确,请确认!",
                                            customOptionParam.getValue()));
                        }
                        numberCheckBuffer.append(customValue).append(StrUtil.SPACE);
                    }
                }
    
                // 开始进行预编译校验
                try {
                    ScriptEngineManager manager = new ScriptEngineManager();
                    ScriptEngine engine = manager.getEngineByName(RuleConstant.JAVA_SCRIPT);
                    Compilable compilableEngine = (Compilable) engine;
                    compilableEngine.compile(numberCheckBuffer.toString());
                } catch (ScriptException e) {
                    // 如果脚本不合法,这里会抛出异常
                    e.printStackTrace();
                    log.error(e.getMessage());
                    throw new ServiceException(StrUtil
                            .format("拖拽规则的表达式自定义数字类型编译失败,编译结果为[{}]请确认格式是否正确!",
                                    numberCheckBuffer.toString()));
                }
            }
        }
    
        /**
         * 自定义检查拖拽规则选项比较
         *
         * @param rspJsonObject 响应参数信息
         * @param paramList 自定义参数信息
         * @param dragRuleId 规则名称
         * @return
         */
        public void checkOptionCompare(JSONObject rspJsonObject,
                                       List<DragRuleDTO.CustomOptionParam> paramList,
                                       String dragRuleId) {
            // 非空校验
            if (ObjectUtil.isEmpty(paramList)) {
                return;
            }
    
            // 先确定是否为日期类型自定义参数信息比较
            DragRuleDTO.CustomOptionParam firstParam = paramList.get(0);
            if (RuleConstant.DATE_FLAG.equals(firstParam.getParamType())) {
                // 日期比较,要求参数值为3个,进行长度判定
                if (paramList.size() != RuleConstant.NUM_3) {
                    throw new ServiceException(StrUtil
                            .format("日期类型比较参数必须为3个[参数日期,标识符,比较日期],规则[{}]日期自定义参数设置不正确!",
                                    dragRuleId));
                }
    
                // 进行日期类型格式校验,获取日期信息
                Object rspDateObj = rspJsonObject.get(firstParam.getParamName());
                // 响应基准日期
                Date customDate;
                // 比较日期(自定义或者除基准日期之外的其他响应日期)
                Date compareDate = null;
                if (rspDateObj instanceof String) {
                    customDate = DateUtil.parse(StrUtil.toString(rspDateObj));
                } else if (rspDateObj instanceof Long) {
                    customDate = new Date((Long) rspDateObj);
                } else {
                    throw new ServiceException(StrUtil
                            .format("拖拽规则[{}]自定义参数比较获取响应参数[{}]日期类型不正确,请确认!", dragRuleId, firstParam.getParamName()));
                }
    
                // 根据参数操作类型,获取比较日期信息,转换为日期Date类型
                if (ObjectUtil.isNotNull(paramList.get(2)) && RuleConstant.NUM_2_STR.equals(paramList.get(2).getOptionType())) {
                    DragRuleDTO.CustomOptionParam compareDateParam = paramList.get(2);
                    // 获取自定义值信息,并且校验是否是合法日期类型
                    if (!compareDateParam.getValue().matches(RuleConstant.DATE_PATTERN)) {
                        throw new ServiceException(StrUtil
                                .format("规则[{}]自定义日期参数格式设置异常,请设置为yyyy-MM-dd格式,请确认!", dragRuleId));
                    }
                    compareDate = DateUtil.parse(compareDateParam.getValue());
                } else if (ObjectUtil.isNotNull(paramList.get(2)) && RuleConstant.NUM_1_STR.equals(paramList.get(2).getOptionType())) {
                    // 获取compare响应比较日期信息
                    Object compareDateObj = rspJsonObject.get(firstParam.getParamName());
                    // 获取响应参数信息rspParam值
                    if (compareDateObj instanceof String) {
                        compareDate = DateUtil.parse(StrUtil.toString(rspDateObj));
                    } else if (compareDateObj instanceof Long) {
                        compareDate = new Date((Long) rspDateObj);
                    } else {
                        throw new ServiceException(StrUtil
                                .format("拖拽规则[{}]自定义参数比较获取响应参数[{}]日期类型不正确,请确认!", dragRuleId, firstParam.getParamName()));
                    }
                }
                String compareResultFlag;
                if (DateUtil.compare(customDate, compareDate) > 0) {
                    compareResultFlag = ">";
                } else if (DateUtil.compare(customDate, compareDate) == 0) {
                    compareResultFlag = "=";
                } else {
                    compareResultFlag = "<";
                }
                // 此处认为只要我的比较符号包含该比较结果标识,则认为通过
                String optionFlag = paramList.get(1).getParamName();
                if (!optionFlag.contains(compareResultFlag)) {
                    // 响应参数比较
                    String errorMessage;
                    if (RuleConstant.NUM_1_STR.equals(paramList.get(2).getOptionType())) {
                        errorMessage = StrUtil
                                .format("拖拽规则[{}]日期参数[{}][{}] {} 规则响应日期参数[{}][{}]校验失败,请确认!",
                                        dragRuleId,
                                        paramList.get(0).getParamDesc(),
                                        DateUtil.format(customDate, DatePattern.NORM_DATE_PATTERN),
                                        optionFlag,
                                        paramList.get(2).getParamDesc(),
                                        DateUtil.format(compareDate, DatePattern.NORM_DATE_PATTERN));
                    } else {
                        // 自定义参数比较
                        errorMessage = StrUtil
                                .format("拖拽规则[{}]日期参数[{}][{}] {} 规则自定义日期[{}]校验失败,请确认!",
                                        dragRuleId,
                                        paramList.get(0).getParamDesc(),
                                        DateUtil.format(customDate, DatePattern.NORM_DATE_PATTERN),
                                        optionFlag,
                                        DateUtil.format(compareDate, DatePattern.NORM_DATE_PATTERN));
                    }
                    throw new ServiceException(errorMessage);
                }
    
            } else {
                // 进行数字类型信息校验,进行数字比较信息拼接,一个是eval函数表达式,一个是错误提示信息
                StringBuilder numberCheckBuffer = new StringBuilder();
                StringBuilder numberCheckMessage = new StringBuilder();
    
                // 开始循环拼装校验参数信息
                for (DragRuleDTO.CustomOptionParam customOptionParam : paramList) {
                    // 参数类型判定
                    if (RuleConstant.NUM_0_STR.equals(customOptionParam.getOptionType())) {
                        // 操作符标识
                        numberCheckBuffer.append(customOptionParam.getParamName()).append(StrUtil.SPACE);
                        numberCheckMessage.append(customOptionParam.getParamDesc()).append(StrUtil.SPACE);
                    } else if (RuleConstant.NUM_1_STR.equals(customOptionParam.getOptionType())) {
                        // outVO参数信息
                        Object rspDataObject = rspJsonObject.get(customOptionParam.getParamName());
                        if (ObjectUtil.isNotNull(rspDataObject)) {
                            if (!StrUtil.toString(rspDataObject).matches(RuleConstant.NUMBER_PATTERN)) {
                                throw new ServiceException(StrUtil
                                        .format("拖拽规则[{}]自定义参数比较获取响应参数[{}]数字类型不正确,请确认!",
                                                dragRuleId,
                                                customOptionParam.getParamName()));
                            }
                            numberCheckBuffer.append(StrUtil.toString(rspDataObject)).append(StrUtil.SPACE);
                            numberCheckMessage.append(customOptionParam.getParamDesc()).append(StrUtil.SPACE);
                        } else {
                            throw new ServiceException(StrUtil
                                    .format("拖拽规则[{}]自定义参数比较获取响应参数[{}]为空,请确认!",
                                            dragRuleId,
                                            customOptionParam.getParamName()));
                        }
                    } else if (RuleConstant.NUM_2_STR.equals(customOptionParam.getOptionType())) {
                        // 自定义参数,进行自定义参数信息校验
                        String customValue = customOptionParam.getValue();
                        if (StrUtil.isBlank(customValue)) {
                            throw new ServiceException(StrUtil
                                    .format("拖拽规则[{}]自定义参数比较获取自定义参数[{}]为空,请确认!",
                                            dragRuleId,
                                            customOptionParam.getValue()));
                        }
    
                        // 数字类型格式校验
                        if (!customValue.matches(RuleConstant.NUMBER_PATTERN)) {
                            throw new ServiceException(StrUtil
                                    .format("拖拽规则[{}]自定义参数比较获取自定义参数[{}]数字类型不正确,请确认!",
                                            dragRuleId,
                                            customOptionParam.getValue()));
                        }
                        numberCheckBuffer.append(customValue).append(StrUtil.SPACE);
                        numberCheckMessage.append(customValue).append(StrUtil.SPACE);
                    }
                }
    
                // 数字类型比较,创建ScriptEngine对象,使用eval表达式进行比较
                ScriptEngineManager manager = new ScriptEngineManager();
                ScriptEngine engine = manager.getEngineByName(RuleConstant.JAVA_SCRIPT);
                try {
                    // 开始执行eval函数解析表达式
                    if (engine.eval(numberCheckBuffer.toString()) == Boolean.FALSE) {
                        String errorMessage = StrUtil
                                .format("拖拽规则[{}]\n自定义参数校验[{}]\n执行结果为[{}]\n校验未通过,请确认!",
                                        dragRuleId,
                                        numberCheckMessage.toString(),
                                        numberCheckBuffer.toString());
                        throw new ServiceException(errorMessage);
                    }
                } catch (ScriptException e) {
                    String errorMessage = LogUtil.getStackTraceInfo(e);
                    log.error(errorMessage);
                    e.printStackTrace();
                    throw new ServiceException("拖拽规则开始执行eval函数解析表达式异常,异常信息为 : ".concat(errorMessage));
                }
            }
    
        }
    
        /**
         * 检查数字格式
         * @param input 输入字符串
         * @return true:数字类型
         */
        public boolean isNumber(Object input) {
            // 空值校验
            if (ObjectUtil.isNull(input)) {
                return false;
            }
    
            // 正则匹配数字
            return StrUtil.toString(input).matches(RuleConstant.NUMBER_PATTERN);
        }
    
        /**
         * 获取缓存拖拽规则信息
         * @param dragRuleId
         * @return
         */
        public DragRuleDTO getCacheDragRule(String dragRuleId) {
            // 返回信息
            DragRuleDTO dragRule = null;
            // 通过缓存获取拖拽信息
            Object dragRuleJsonObject = redisUtil.hget(RuleConstant.DRAG_RULES, dragRuleId);
            if (ObjectUtil.isNotNull(dragRuleJsonObject)) {
                // 转换json为对象信息
                dragRule = JSONObject.parseObject(StrUtil.toString(dragRuleJsonObject), DragRuleDTO.class);
            }
            return dragRule;
        }
    
        /**
         * 检查拖拽规则更新信息,一个规则修改,需要检查所有引入当前规则的规则链是否参数都合法
         * @param dragRuleChain 规则链
         * @param dragRuleDTO 当前修改规则
         */
        public void checkDragRuleUpdateLegal(TbSysDragChain dragRuleChain, DragRuleDTO dragRuleDTO) {
            // 获取规则链,多个规则使用逗号分割,然后封装成list
            String dragRuleChainStr = dragRuleChain.getDragRuleChain();
            List<String> dragRuleChainList = Arrays.asList(dragRuleChainStr.split(StrUtil.COMMA).clone())
                    .stream()
                    .map(String::trim)
                    .collect(Collectors.toList());
    
            // 通过uri获取规则链入参缓存信息,cacheDragChainDTO
            Object dragRuleChainObj = redisUtil.hget(CommonDragRuleConstant.DRAG_RULE_CHAIN_FLAG, dragRuleChain.getUri());
            if (ObjectUtil.isNull(dragRuleChainObj)) {
                throw new ServiceException(StrUtil.format("通过规则链uri[{}]获取缓存规则链信息失败,请确认!", dragRuleChain.getUri()));
            }
            DragChainDTO cacheDragChainDTO = JSONObject.parseObject(StrUtil.toString(dragRuleChainObj), DragChainDTO.class);
    
            // 如果规则链长度为1,则只有一个规则既当前规则,无需校验,如果修改规则在最后一个,没有下一个规则使用传递参数,则也无需校验
            if (dragRuleChainList.size() == 1 || dragRuleChainList.indexOf(dragRuleDTO.getDragRuleId()) == dragRuleChainList.size() - 1) {
                return;
            }
    
            // 开始规则链校验,既当前修改规则在规则链的中间位置执行,需要完整校验规则链参数返回值是否合法
            String errorMessage = null;
            JSONObject dragChainInParam = JSONObject.parseObject(cacheDragChainDTO.getMethodInParam());
            if (ObjectUtil.isEmpty(dragChainInParam)) {
                errorMessage = StrUtil.format("拖拽规则修改,校验拖拽规则规则链[{}]控制层方法切入点[{}]入参参数为空,请确认!",
                        cacheDragChainDTO.getControllerName(),
                        cacheDragChainDTO.getMethodName());
                throw new ServiceException(errorMessage);
            }
    
            // 入参结果集,第一次入参参数为规则链切入点的入参参数,之后循环规则链规则,为规则链返回传递参数+切入点入参参数,再与下一个规则入参进行对比
            JSONObject resultInParam = dragChainInParam.clone();
            for (int i = 0; i < dragRuleChainList.size(); i++) {
                String dragRuleId = dragRuleChainList.get(i);
                DragRuleDTO checkDragRuleDTO = null;
                if (!dragRuleDTO.getDragRuleId().equals(dragRuleId)) {
                    checkDragRuleDTO = getCacheDragRule(dragRuleId);
                } else {
                    checkDragRuleDTO = dragRuleDTO;
                }
                JSONObject dragRuleInParam = JSONObject.parseObject(checkDragRuleDTO.getInputParam());
                // 进行参数校验,如果入参不满足规则链循环规则入参,直接抛出异常
                Set<String> dragRuleInParamKeySet = dragRuleInParam.keySet();
                Set<String> dragChainInParamKeySet = resultInParam.keySet();
                Set<String> diffKeySet = dragRuleInParamKeySet.stream()
                        .filter(element -> !dragChainInParamKeySet.contains(element))
                        .collect(Collectors.toSet());
                if (ObjectUtil.isNotEmpty(diffKeySet)) {
                    // Set集合数据转换为字符串,逗号分割
                    String dragRuleDiffKeyStr = diffKeySet.stream()
                            .map(String::valueOf)
                            .collect(Collectors.joining(StrUtil.COMMA));
                    errorMessage = StrUtil.format("规则修改后,影响规则链[{}]第[{}]个规则[{}]入参参数缺少[{}],修改失败!",
                            cacheDragChainDTO.getDragRuleChainId(),
                            i + 1,
                            checkDragRuleDTO.getDragRuleId(),
                            dragRuleDiffKeyStr);
                    throw new ServiceException(errorMessage);
                }
    
                // 设置规则返回参数作为传递参数设定到切入点入参参数中,作为下一入参参数校验集合,传递参数为字符串,多个参数以逗号分割
                if (StrUtil.isNotBlank(checkDragRuleDTO.getCrossParam())) {
                    String[] crossParams = checkDragRuleDTO.getCrossParam().split(StrUtil.COMMA);
                    for (int j = 0; j < crossParams.length; j++) {
                        resultInParam.put(crossParams[j], StrUtil.EMPTY);
                    }
                }
            }
    
        }
    
        /**
         * 通过规则id获取规则信息
         * @param dragRuleId
         */
        public DragRuleDTO getDragRuleDTO(String dragRuleId) {
            Object dragRuleObj = redisUtil.hget(CommonDragRuleConstant.DRAG_RULES, dragRuleId);
            if (ObjectUtil.isNotNull(dragRuleObj)) {
                return JSONObject.parseObject(StrUtil.toString(dragRuleObj), DragRuleDTO.class);
            }
            throw new ServiceException(StrUtil.format("拖拽规则通过缓存获取规则Id[{}]不存在,请确认规则服务成功启动!", dragRuleId));
        }
    
        /**
         * 英文模块描述转换为中文描述
         * @param modelEnDesc
         */
        public String modelEnDescToCHDesc(String modelEnDesc) {
            // 空值校验
            if (StrUtil.isBlank(modelEnDesc)) {
                return null;
            }
    
            // 将模块描述进行小写转换
            String enDescLowerCase = modelEnDesc.toLowerCase();
            if (enDescLowerCase.contains("account")) {
                return "客户模块";
            } else if (enDescLowerCase.contains("collateral")) {
                return "押品模块";
            } else if (enDescLowerCase.equals("risk")) {
                return "风险模块";
            } else if (enDescLowerCase.equals("credit")) {
                return "评级授信模块";
            } else if (enDescLowerCase.equals("loan")) {
                return "用信放款模块";
            } else if (enDescLowerCase.equals("management")) {
                return "公共管理模块";
            } else if (enDescLowerCase.equals("afterloan")) {
                return "贷后模块";
            } else if (enDescLowerCase.equals("warning")) {
                return "风险预警模块";
            } else if (enDescLowerCase.equals("query")) {
                return "综合查询模块";
            } else if (enDescLowerCase.equals("foreign")) {
                return "外围服务模块";
            } else {
                return null;
            }
        }
    
        /**
         * 校验规则链节点类型
         *
         * @param nodeTypeName
         */
        public Boolean checkProcessFileType(String nodeTypeName) {
            // 空值校验
            if (StrUtil.isBlank(nodeTypeName)) {
                return false;
            }
    
            // 当前校验节点类型 task,start,end,sequence
            switch (nodeTypeName) {
                case "SequenceFlowImpl":
                case "TaskImpl":
                case "EndEventImpl":
                case "StartEventImpl":
                    return true;
                default:
                    return false;
            }
        }
    }
    
    
  5. 规则具体类通用父类

    package cn.git.rules.drag.tran.base;
    
    import cn.git.common.result.Result;
    
    import javax.validation.Valid;
    
    /**
     * @description: 拖拽规则执行方法基类
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2024-02-22 10:33:09
     */
    public interface BaseDragRuleTran<T> {
    
        /**
         * 决策执行方法
         * @param requestParam 请求参数
         * @return
         */
        Result process(@Valid T requestParam);
    
    }
    
    
  6. 规则详情实例,注意规则详情名称命名要求必须此格式,controller中可以调用开发人员使用获取拖拽规则规则名称方法获取

    package cn.git.rules.drag.tran;
    
    import cn.git.common.result.Result;
    import cn.git.rules.drag.DragRuleDesc;
    import cn.git.rules.drag.dto.TESTDragRule0001DTO;
    import cn.git.rules.drag.tran.base.BaseDragRuleTran;
    import cn.hutool.core.date.DateUtil;
    import org.springframework.stereotype.Component;
    import org.springframework.validation.annotation.Validated;
    
    import javax.validation.Valid;
    import java.math.BigDecimal;
    
    /**
     * @description:
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2024-02-22 10:13:27
     */
    @Validated
    @Component
    @DragRuleDesc(beanDesc = "借据申请日期金额校验")
    public class TESTDragRule0001Tran implements BaseDragRuleTran<TESTDragRule0001DTO> {
    
        /**
         * 决策执行方法
         *
         * @param requestParam 请求参数
         * @return
         */
        @Override
        public Result<TESTDragRule0001DTO.TESTDragRule0001OUTDTO> process(@Valid TESTDragRule0001DTO requestParam) {
            // 请求信息
            System.out.println(requestParam);
    
            // 响应参数
            TESTDragRule0001DTO.TESTDragRule0001OUTDTO outDTO = new TESTDragRule0001DTO.TESTDragRule0001OUTDTO();
            outDTO.setBorrowAmt(new BigDecimal(500));
            outDTO.setContractDate(DateUtil.parseDate("2020-11-5"));
            outDTO.setContractTotalAmt(BigDecimal.valueOf(50000));
            outDTO.setCheckDragRule0001ResultDate(DateUtil.parseDate("2020-11-5"));
            return Result.ok(outDTO);
        }
    }
    
    
  7. 参数信息,注意参数名称命名要求必须此格式

    package cn.git.rules.drag.dto;
    
    import cn.git.rules.drag.DragRuleDesc;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import javax.validation.constraints.NotBlank;
    import java.math.BigDecimal;
    import java.util.Date;
    
    /**
     * @description: 拖拽规则测试方法入参出参信息
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2024-02-22 10:31:37
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class TESTDragRule0001DTO {
    
        @NotBlank(message = "TESTDragRule0001DTO规则入参客户编号不能为空!")
        @DragRuleDesc(fieldDesc = "客户编号")
        private String customerNum;
    
        @NotBlank(message = "TESTDragRule0001DTO规则入参合同编号不能为空!")
        @DragRuleDesc(fieldDesc = "合同编号")
        private String contractNum;
    
        /**
         * @description: 出参信息
         * @program: bank-credit-sy
         * @author: lixuchun
         * @create: 2024-02-22 10:31:25
         */
        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        public static class TESTDragRule0001OUTDTO {
    
            @DragRuleDesc(fieldDesc = "合同金额")
            private BigDecimal contractTotalAmt;
    
            @DragRuleDesc(fieldDesc = "借据金额")
            private BigDecimal borrowAmt;
    
            @DragRuleDesc(fieldDesc = "合同日期")
            private Date contractDate;
    
            @DragRuleDesc(fieldDesc = "测试响应日期")
            private Date checkDragRule0001ResultDate;
    
        }
    }
    
    
  8. 通用的枚举类型

    package cn.git.rules.drag.enums;
    
    import lombok.Getter;
    
    /**
     * @description: 拖拽规则链模块枚举
     * @program: bank_credit_sy
     * @author: lixuchun
     * @create: 2024_03_07 10:59:00
     */
    @Getter
    public enum DragChainModulesEnum {
    
        /**
         * 子模块数据源信息
         */
        MANAGE("MANAGEMENT_SERVER", "通用管理模块"),
        ACCOUNT("ACCOUNT_SERVER", "客户信息模块"),
        LOAN("LOAN_SERVER", "用信放款模块"),
        WORKFLOW("WORKFLOW_SERVER", "流程模块"),
        COLLATERAL("COLLATERAL_SERVER", "押品模块"),
        AFTER_LOAN("AFTERLOAN_SERVER", "贷后模块"),
        QUERY("QUERY_SERVER", "综合查询模块"),
        CREDIT("CREDIT_SERVER", "评级授信模块"),
        RISK("RISK_SERVER", "风险模块"),
        WARNING("WARNING_SERVER", "预警模块");
    
        /**
         * 拖拽规则链服务名称
         */
        @Getter
        private String dragServerName;
    
        /**
         * 服务描述
         */
        @Getter
        private String serverDesc;
    
        /**
         * 构造函数
         * @param dragServerName
         * @param serverDesc
         */
        DragChainModulesEnum(String dragServerName, String serverDesc) {
            this.dragServerName = dragServerName;
            this.serverDesc = serverDesc;
        }
    
    }
    
    
    package cn.git.rules.drag.enums;
    
    import lombok.Getter;
    
    /**
     * @description: 拖拽规则序列信息生成枚举类型
     * @program: bank-credit-sy
     * @author: lixuchun
     * @create: 2024-06-03
     */
    @Getter
    public enum DragRuleSequenceEnum {
    
        /**
         * 序列模块分类描述信息
         */
        ACCOUNT("account-server", "ACC","客户模块"),
        AFTER("afterloan-server", "AFT", "贷后模块"),
        COLL("collateral-server", "COL", "押品模块"),
        CREDIT("credit-server", "CRE", "授信模块"),
        LOAN("loan-server", "LOA", "用信模块"),
        MANAGE("management-server", "MAN", "公共模块"),
        RAT("rat-server", "RAT", "新评级模块"),
        STORE("store-server", "STO", "储备模块"),
        WARNING("warning-server", "WAR", "预警模块"),
        PRODUCT("product-server", "PRO", "产品工厂模块")
    
        ;
    
        /**
         * 模块
         */
        private String module;
    
        /**
         * 模块别名
         */
        private String moduleAlias;
    
        /**
         * 描述
         */
        private String desc;
    
        DragRuleSequenceEnum(String module, String moduleAlias, String desc) {
            this.module = module;
            this.moduleAlias = moduleAlias;
            this.desc = desc;
        }
    
    }
    
    
4.2.2 规则链规则feign调用实现
  1. Feign接口调用impl实现类
    package cn.git.rules.manage;
    	
    	import cn.git.common.drag.CommonDragRuleConstant;
    	import cn.git.common.drag.dto.DragChainDTO;
    	import cn.git.common.drag.dto.DragRuleDTO;
    	import cn.git.common.exception.ServiceException;
    	import cn.git.common.result.Result;
    	import cn.git.common.util.LogUtil;
    	import cn.git.rules.drag.DragRuleServerUtil;
    	import cn.git.rules.drag.tran.base.BaseDragRuleTran;
    	import cn.git.rules.feign.DragRuleFeignApi;
    	import cn.hutool.core.util.ObjectUtil;
    	import cn.hutool.core.util.StrUtil;
    	import com.alibaba.fastjson.JSON;
    	import com.alibaba.fastjson.JSONObject;
    	import lombok.extern.slf4j.Slf4j;
    	import org.springframework.beans.factory.annotation.Autowired;
    	import org.springframework.context.ApplicationContext;
    	import org.springframework.web.bind.annotation.RestController;
    	
    	import javax.validation.ConstraintViolationException;
    	import java.util.List;
    	
    	/**
    	 * @description:
    	 * @program: bank-credit-sy
    	 * @author: lixuchun
    	 * @create: 2024-02-22 02:32:24
    	 */
    	@Slf4j
    	@RestController
    	public class DragRuleFeignApiImpl implements DragRuleFeignApi {
    	
    	    /**
    	     * 拖拽规则参数入参出参dto包名
    	     */
    	    private static final String DRAG_DTO_PACKAGE = "cn.git.rules.drag.dto.";
    	
    	    /**
    	     * dto尾缀
    	     */
    	    public static final String SUFFIX_DTO = "DTO";
    	
    	    @Autowired
    	    private DragRuleServerUtil dragRuleServerUtil;
    	
    	    @Autowired
    	    private ApplicationContext applicationContext;
    	
    	    /**
    	     * 校验拖拽规则feign方法
    	     *
    	     * @param dragRuleJsonParam 请求对象
    	     * @return Result 校验结果
    	     */
    	    @Override
    	    public Result checkDragRule(JSONObject dragRuleJsonParam) {
    	        // 获取规则链表 多个规则用逗号分割
    	        String dragRuleDTOJSON = dragRuleJsonParam.getString(CommonDragRuleConstant.DRAG_RULE_CHAIN_DTO);
    	        DragChainDTO dragChainDTO = JSON.parseObject(dragRuleDTOJSON, DragChainDTO.class);
    	        String[] dragRuleChain = dragChainDTO.getDragRuleChain().split(StrUtil.COMMA);
    	
    	        // 设置入参json的克隆参数
    	        JSONObject dragRuleJsonParamClone = dragRuleJsonParam.clone();
    	
    	        // 循环执行规则链的规则信息
    	        for (int i = 0; i < dragRuleChain.length; i++) {
    	            // 规则名称
    	            String dragRuleName = dragRuleChain[i];
    	
    	            // 规则入参参数转换为dto对象
    	            String fullClassName = DRAG_DTO_PACKAGE.concat(dragRuleName).concat(SUFFIX_DTO);
    	
    	            Object reqObject;
    	            try {
    	                // 通过类名获取类类型,再获取参数实例信息
    	                Class reqClazz = Class.forName(fullClassName);
    	                reqObject = JSONObject.parseObject(dragRuleJsonParamClone.toJSONString(), reqClazz);
    	            } catch (ClassNotFoundException e) {
    	                return Result.error(StrUtil
    	                        .format("拖拽规则[{}]规则校验名称DTO[{}]解析失败,请确认是否正确!", dragRuleName, fullClassName));
    	            }
    	
    	            // 获取规则执行类
    	            BaseDragRuleTran dragRuleTran = null;
    	            try {
    	                dragRuleTran = applicationContext.getBean(dragRuleName.concat("Tran"), BaseDragRuleTran.class);
    	            } catch (Exception e) {
    	                String errorMessage = StrUtil.format("拖拽规则[{}]获取规则执行类失败,请确认参数是否正确!", dragRuleName);
    	                return Result.error(errorMessage);
    	            }
    	
    	            // 开始执行规则
    	            Result result = null;
    	            try {
    	                result = dragRuleTran.process(reqObject);
    	            } catch (ConstraintViolationException e) {
    	                e.printStackTrace();
    	                String errorMessage = StrUtil
    	                        .format("拖拽规则[{}]请求参数校验异常,异常信息为[{}]",
    	                                dragRuleName,
    	                                LogUtil.getStackTraceInfo(e));
    	                log.error(errorMessage);
    	                return Result.error(e.getMessage());
    	            } catch (ServiceException e) {
    	                e.printStackTrace();
    	                // 抛出自定义异常信息
    	                String errorMessage = StrUtil.format("拖拽规则[{}]请求执行异常,异常信息为[{}]", dragRuleName, e.getMessage());
    	                return Result.error(errorMessage);
    	            } catch (Exception e) {
    	                e.printStackTrace();
    	                // 其他异常信息
    	                String errorMessage = LogUtil.getStackTraceInfo(e);
    	                return Result.error(StrUtil
    	                        .format("拖拽规则[{}]请求执行异常,异常信息为[{}]", dragRuleName, errorMessage));
    	            }
    	
    	            // 检查是否有传递参数,如果有则将传递参数设置为下一规则的入参
    	            DragRuleDTO dragRule = dragRuleServerUtil.getCacheDragRule(dragRuleName);
    	            if (StrUtil.isNotBlank(dragRule.getCrossParam())) {
    	                String[] crossParams = dragRule.getCrossParam().split(StrUtil.COMMA);
    	                for (String crossParam : crossParams) {
    	                    // 获取返回参数中传输数据信息
    	                    JSONObject rspJsonObject = JSON.parseObject(JSONObject.toJSONString(result.getData()));
    	                    if (rspJsonObject.containsKey(crossParam)) {
    	                        dragRuleJsonParamClone.put(crossParam, rspJsonObject.get(crossParam));
    	                    } else {
    	                        return Result.error(StrUtil
    	                                .format("拖拽规则[{}]从响应参数中获取传递参数获取为空,请确认[{}]传递参数!", dragRuleName, crossParam));
    	                    }
    	                }
    	            }
    	
    	            // 自定义比较方法,执行自定义比较逻辑
    	            List<List<DragRuleDTO.CustomOptionParam>> customOptionParamsList = dragRule.getCustomOptionParamList();
    	            if (ObjectUtil.isNotEmpty(customOptionParamsList)) {
    	                // 获取返回参数中传输数据信息
    	                JSONObject rspJsonObject = JSON.parseObject(JSONObject.toJSONString(result.getData()));
    	                if (ObjectUtil.isNull(rspJsonObject)) {
    	                    return Result.error(StrUtil.format("拖拽规则[{}]"));
    	                }
    	                // 参数进行转化
    	                for (List<DragRuleDTO.CustomOptionParam> paramList : customOptionParamsList) {
    	                    // 进行自定义操作参数比对,可以比对日期与数值
    	                    try {
    	                        dragRuleServerUtil.checkOptionCompare(rspJsonObject, paramList, dragRuleName);
    	                    } catch (ServiceException e) {
    	                        return Result.error(e.getMessage());
    	                    } catch (Exception e) {
    	                        e.printStackTrace();
    	                        String errorMessage = LogUtil.getStackTraceInfo(e);
    	                        return Result.error(StrUtil
    	                                .format("拖拽规则[{}]自定义操作参数比对异常,异常信息为[{}]", dragRuleName, errorMessage));
    	                    }
    	                }
    	            }
    	        }
    	        return Result.ok("拖拽规则规则验证通过");
    	    }
    	}
    

4.3 数据库表结构

主要包含三张表,分别为拖拽规则表,规则链表以及产品规则链表

--拖拽规则表
DROP TABLE TB_SYS_DRAG_RULE
CREATE TABLE TB_SYS_DRAG_RULE (
	DRAG_RULE_ID varchar(32) NOT NULL,
	RULE_DESC varchar(100),
	CROSS_PARAM varchar(200),
	CUSTOM_OPTION_PARAM varchar(3000),
	ctime date DEFAULT sysdate,
	mtime date DEFAULT sysdate,
	is_del varchar(1) DEFAULT 0,
	primary key(DRAG_RULE_ID)
)

COMMENT ON TABLE MANAGE.TB_SYS_DRAG_RULE IS '拖拽规则表';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_RULE.DRAG_RULE_ID IS '规则id,名称,同组件名称eg:LOANTest0001';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_RULE.RULE_DESC IS '规则描述';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_RULE.CROSS_PARAM IS '多个规则规则链传递值,多个以英文逗号分割';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_RULE.CUSTOM_OPTION_PARAM IS '自定义参数比较规则信息,多个用逗号隔开, 响应信息返回值 loanAmt<= 5000, eg:{"optionDesc": "描述信息", "customKey": "loanAmt","optionFlag": ">=","compareValue": 5000}';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_RULE.CTIME IS '创建时间';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_RULE.MTIME IS '修改时间';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_RULE.IS_DEL IS '是否删除标识';

--规则链表
DROP TABLE TB_SYS_DRAG_CHAIN
CREATE TABLE TB_SYS_DRAG_CHAIN (
	DRAG_RULE_CHAIN_ID varchar(200),
	CONTROLLER_DESC varchar(300),
	CONTROLLER_NAME varchar(100),
	METHOD_NAME varchar(100),
	METHOD_DESC varchar(500),
	METHOD_IN_PARAM varchar(3000),
	URI varchar(500),
	DRAG_RULE_CHAIN varchar(500),
	CHAIN_FILE clob,
	CHAIN_FILE_NAME varchar(50),
	ctime date DEFAULT sysdate,
	mtime date DEFAULT sysdate,
	is_del varchar(1) DEFAULT 0,
	primary key(DRAG_RULE_CHAIN_ID)
)

COMMENT ON TABLE MANAGE.TB_SYS_DRAG_CHAIN IS '拖拽规则链表';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_CHAIN.DRAG_RULE_CHAIN_ID IS '规则链id';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_CHAIN.CONTROLLER_DESC IS '切入点controller描述信息';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_CHAIN.CONTROLLER_NAME IS '切入点controller名称';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_CHAIN.METHOD_NAME IS '规则链调用方法名称';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_CHAIN.METHOD_DESC IS '规则链调用方法描述';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_CHAIN.METHOD_IN_PARAM IS '方法入参参数';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_CHAIN.URI IS '作用方法地址';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_CHAIN.DRAG_RULE_CHAIN IS '规则链详情,多个规则按序逗号分割';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_CHAIN.CHAIN_FILE IS '文件内容base64字符串信息';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_CHAIN.CHAIN_FILE_NAME IS '文件名称';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_CHAIN.CTIME IS '创建时间';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_CHAIN.MTIME IS '修改时间';
COMMENT ON COLUMN MANAGE.TB_SYS_DRAG_CHAIN.IS_DEL IS '是否删除';

--产品规则信息
DROP TABLE TB_SYS_PRODUCT_DRAG_CHAIN
CREATE TABLE TB_SYS_PRODUCT_DRAG_CHAIN (
	PRODUCT_CHAIN_ID varchar(200),
	PRODUCT_CD varchar(50),
	URI varchar(500),
	DRAG_RULE_CHAIN varchar(500),
	CHAIN_FILE clob,
	CHAIN_FILE_NAME varchar(50),
	ctime date DEFAULT sysdate,
	mtime date DEFAULT sysdate,
	is_del varchar(1) DEFAULT 0,
	primary key(PRODUCT_CHAIN_ID)
)

COMMENT ON TABLE MANAGE.TB_SYS_PRODUCT_DRAG_CHAIN IS '拖拽规则作用产品定义信息表';
COMMENT ON COLUMN MANAGE.TB_SYS_PRODUCT_DRAG_CHAIN.PRODUCT_CHAIN_ID IS '主键id';
COMMENT ON COLUMN MANAGE.TB_SYS_PRODUCT_DRAG_CHAIN.PRODUCT_CD IS '产品cd';
COMMENT ON COLUMN MANAGE.TB_SYS_PRODUCT_DRAG_CHAIN.URI IS '产品作用点请求路径';
COMMENT ON COLUMN MANAGE.TB_SYS_PRODUCT_DRAG_CHAIN.DRAG_RULE_CHAIN IS '规则链,具体规则信息,多个使用逗号分割';
COMMENT ON COLUMN MANAGE.TB_SYS_PRODUCT_DRAG_CHAIN.CHAIN_FILE IS '规则文件';
COMMENT ON COLUMN MANAGE.TB_SYS_PRODUCT_DRAG_CHAIN.CHAIN_FILE_NAME IS '规则文件名称';
COMMENT ON COLUMN MANAGE.TB_SYS_PRODUCT_DRAG_CHAIN.CTIME IS '创建时间';
COMMENT ON COLUMN MANAGE.TB_SYS_PRODUCT_DRAG_CHAIN.MTIME IS '修改时间';
COMMENT ON COLUMN MANAGE.TB_SYS_PRODUCT_DRAG_CHAIN.IS_DEL IS '删除标识';

5. 管理页面展示

5.1 规则管理page页面介绍

此页面为规则分页查询,注意操作栏落库按钮代表此规则是否存入数据库,未存入的不能进行后续规则链操作,已经入库的可以进行修改以及清空

管理页面可以观察当前所有规则信息,需要使用管理员账号登录 310907 ,管理页面位置位于 系统管理 => 参数管理 => 规则管理
在这里插入图片描述

5.2 落库修改新增操作页面介绍

规则校验部分,主要是针对出参参数信息,可以对出参信息进行自定义校验,需要注意需要满足正常操作符规则

  • 入参参数:入参参数即为规则自定义的入参参数信息,此例为 TESTDragRule0001DTO 参数信息

  • 出参参数:出参参数即为规则自定义的出参参数信息,此例为 TESTDragRule0001OUTDTO 出参参数信息

  • 中转参数:中转参数,必须为OUTDTO中的参数,此值没有类型要求,会传递到下一规则中,供下一规则使用

    注意:如果规则中的中转参数下一规则入参使用,那么在规则链固定好后,此中转参数不能随意删除,必须先解除规则链,再删除中转参数

  • 自定义参数:此参数必须为OUTDTO中的数字类型参数,或者为日期类型参数,其中数字类型参数需要满足正常的操作运算格式,日期类型则要求日期必须为第一个参数,只能进行简单的日期比较,整体可选比较格式如下所列:

    表达式案例解释
    ( 合同金额 + 借据金额 ) / 2 < 合同金额 / 2000复杂数字计算,包含参数比较,设置自定义参数值
    合同金额 < 50000简单数字类型比较
    合同日期 < 合同到期日期日期类型参数比较
    合同日期 < 2023-05-03日期类型自定义参数比较

    在这里插入图片描述

5.3 规则链列表页面

此页面为规则调用入口列表页面,位于 系统管理 => 参数管理 => 规则链管理,管理了可以进行规则调用的入口接口列表页面,同样如果规则链的操作栏配置落库后,才能进行修改删除操作,未配置落库则不能进行操作

在这里插入图片描述

5.4 拖拽规则页面

此页面可以进行规则链详情配置,展示信息包含两部分

  • 首先是规则链基本信息,包含id信息(controller.method)以及规则链描述信息,还有规则链入参信息
    在这里插入图片描述
  • 第二部分为规则拖拽部分,可以进行规则链拖拽选择,可以自己定义规则执行逻辑,双击规则可以进行规则转换
    在这里插入图片描述
  • 双击后展示规则选择页面,主要可以观察当前规则链包含哪些规则信息,并且选择规则时候,会提示当前规则调用入口(controller.method)方法是否满足当前规则,如果不满足条件,会提示出为何不满足
    在这里插入图片描述
  • 在下面的规则列表中可以选择规则信息,点击规则id,可以进行规则信息查看,展示信息与规则管理页面相同
    在这里插入图片描述
  • 最终保存的规则链信息如下:规则调用会按照顺序执行 TESTDragRule0001 -> TESTDragRule0002 -> TESTDragRule0003 -> TESTDragRule0004
    在这里插入图片描述

5.5 产品规则

产品规则位于 系统管理 => 参数管理 => 业务品种管理 嵌套的tab页面中,代码部分与常有规则链一致,可以对固定产品进行规则配置,但是有以下前提

  • 产品规则对应作用接口需要配置好默认的执行规则
  • 产品规则接口中必须要有productCd参数,以便于规则判定时获取产品对应的规则链,然后执行对应的规则链,在调用过程中,如果接口inVO带有productCd参数,并且对应规则配置了响应的productCd产品对应规则链,则执行产品规则链,未匹配到productCd,则执行默认规则链
5.5.1 产品规则列表
  • 按照标注按钮可以找到对应的产品规则链
    在这里插入图片描述
  • 点击查看按钮,进入到当前规则链详情信息,如果产品规则未配置,则可以进行产品规则新增,如果已经配置,则产品规则展示规则id,多个id逗号分割,并且可以进行修改以及删除操作
    在这里插入图片描述
  • 点击修改或者新增按钮,进入到规则链编辑页面,与之前规则链编辑页面一致,编辑保存会有规则是否合法校验,校验通过则可以进行规则链调用
    在这里插入图片描述
5.5.2 编辑规则页面

此页面展示当前规则链可以选择哪些规则进行设置,并且提示规则是否合法,如果不合法则显示具体哪个规则对应哪个字段不满足规则入参条件
在这里插入图片描述

6. 测试部分

规则链配置成功之后,直接在规则链入口对应的controller.method进行调用即可 DragRuleTestController.test0001
在这里插入图片描述
执行结果展示如下:
在这里插入图片描述

  • 15
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值