参数层级嵌套,递归校验(结构体&数组嵌套、其他基本数据类型)

校验C结构体基本数据类型以及数组,和数组、结构体嵌套其他类型 

public class DataTypeSpecCheckUtil {

    static final String MIN = "min";
    static final String MAX = "max";
    static final String UNIT = "unit";
    static final String UNIT_NAME = "unitName";
    static final String STEP = "step";
    static final String RANGE = "range";
    static final String ITEM = "item";
    static final String DATA_TYPE = "dataType";
    static final String TYPE = "type";
    static final String SPECS = "specs";
    static final String LENGTH = "length";
    static final String RULE = "rule";
    static final String SIZE = "size";
    static final String IDENTIFIER = "identifier";
    static final String NAME = "name";
    static final String DESCRIPTION = "description";
    static final String PROPERTY = "property";

    private static final long LONG_MAX_VALUE = 9176873029745254541L;
    private static final long LONG_MIN_VALUE = -9176873029745254541L;
    private static final long INT_MAX_VALUE = 2147483647L;
    private static final long INT_MIN_VALUE = -2147483647L;

    /**
     * 浮点型数据校验
     */
    public static boolean isValidDouble(String doubleStr) {
        if (StringUtils.isNotEmpty(doubleStr)) {
            String regx = "^(-?\\d+)(\\.\\d{0,6})?$;
            Pattern p = Pattern.compile(regx);
            Matcher matcher = p.matcher(doubleStr);
            return matcher.find();
        }
        return false;
    }

    public static boolean isValidNaming4Name(String identifier) {
        if (identifier.length() < 1 || identifier.length() > 64) {
            log.error("标识符长度异常!");
            return false;
        }
        String regx = "^[_A-Za-z0-9\\-\\u4e00-\\u9fa5]+$;
        Pattern p = Pattern.compile(regx);
        Matcher matcher = p.matcher(identifier);
        return matcher.find();
    }

    public static boolean isValidNaming4Identifier(final String identifier) {
        /** List<String> commonTypes =             Arrays.asList("byte","int","float","double","char","array","enum","struct","bool");
         if (commonTypes.contains(identifier)){
         log.error("基本类型不能作为标识符!");
         return false;
         }*/
        if (identifier.length() < 1 || identifier.length() > 64) {
            log.error("标识符长度异常!");
            return false;
        }
        String regx = "^[_a-zA-Z0-9]+$;
        Pattern p = Pattern.compile(regx);
        Matcher matcher = p.matcher(identifier);
        return matcher.find();
    }

    public static boolean isValidNumStr(String num) {
        if ("0".equals(num)) return true;
        if (StringUtils.isNotEmpty(num)) {
            return num.matches("^[\\-1-9]+[0-9]$");
        }
        return false;
    }

    private static boolean isValidArraySpecs(JSONObject arrayJSONObject) {
        try {
            if (arrayJSONObject != null && arrayJSONObject.containsKey(SIZE)
                    && ((arrayJSONObject.getIntValue(SIZE) > 0
                    && arrayJSONObject.getIntValue(SIZE) <= 65535))
                    && arrayJSONObject.containsKey(ITEM)
                    && arrayJSONObject.get(ITEM) != null) {
                JSONObject itemJSONObject = arrayJSONObject.getJSONObject(ITEM);
                if (!itemJSONObject.containsKey(DATA_TYPE)) {
                    log.error("===> isValidArraySpecs array型,数据规格定义 itemJSONObject = {} 错误!缺少dataType节点", itemJSONObject);
                    return false;
                }
                JSONObject dataTypeJSONObject = itemJSONObject.getJSONObject(DATA_TYPE);
                if (!dataTypeJSONObject.containsKey(TYPE) || !dataTypeJSONObject.containsKey(SPECS)) {
                    log.error("===> array型,数据规格定义 dataTypeJSONObject = {} 错误!必须有节点specs和type", dataTypeJSONObject);
                    return false;
                }
                int type = dataTypeJSONObject.getIntValue(TYPE);
                String specs = dataTypeJSONObject.getString(SPECS);
                if (0 == type || 7 == type) {
                    log.error("===> array型,数据规格定义 数组层级下不能是Bytes或者数组 {}", dataTypeJSONObject);
                    return false;
                }
                // 结构体校验
                if (8 == type && dataTypeJSONObject.containsKey(SPECS)) {
                    boolean validStructSpecs = isValidStructSpecs(specs, 2);
                    if (!validStructSpecs) {
                        log.error("===> array型,数据规格定义 数组层级下结构体不合法 {}", dataTypeJSONObject);
                        return false;
                    }
                }
                // 数组里的普通类型
                if (type == 1 || type == 2 || type == 3 || type == 4 || type == 5 || type == 6) {
                    if (!isValidCommonSpecs(type, specs)) return false;
                }
                return true;
            } else {
                log.error("===> array型,数据规格定义为空!");
                return true;
            }
        } catch (Exception e) {
            if (e instanceof IotBusinessException)
                throw e;
            return false;
        }
    }

    private static boolean isValidStructSpecs(String specs, int level) {

        JSONArray retArray = JSON.parseArray(specs);
        if (CollectionUtils.isEmpty(retArray)) {
            throw new IotBusinessException("结构体数据规格定义不允许为空!");
        }
        Set<String> identifierSet = new HashSet<>();
        for (int i = 0; i < retArray.size(); i++) {

            JSONObject jsonObject = retArray.getJSONObject(i);
            log.info("jsonObject = {}, i = {}", jsonObject, i);
            if (jsonObject == null
                    || !jsonObject.containsKey(IDENTIFIER)
                    || !jsonObject.containsKey(NAME)
                    || !jsonObject.containsKey(DATA_TYPE)
                    || !jsonObject.containsKey(DESCRIPTION)) {
                return false;
            }

            if (!isValidNaming4Name(jsonObject.getString(NAME))) {
                log.error("名称,长度异常或者是名称不合法");
                return false;
            }
            if (!isValidNaming4Identifier(jsonObject.getString(IDENTIFIER))) {
                log.error("标识符,长度异常或者是名称不合法");
                return false;

            }
            identifierSet.add(jsonObject.getString(IDENTIFIER));
            JSONObject dataTypeObject = jsonObject.getJSONObject(DATA_TYPE);
            if (!dataTypeObject.containsKey(TYPE) || !dataTypeObject.containsKey(SPECS)) {
                log.error("结构体校验,子元素缺少key dataTypeObject = {}", dataTypeObject);
                return false;
            }

            if (dataTypeObject.getIntValue(TYPE) == 8) {

                level = level - 1;
                if (!isValidStructSpecs(dataTypeObject.getString(SPECS), level)) {
                    log.error("结构体校验嵌套结构体,specs = {}", dataTypeObject.getString(SPECS));
                    return false;
                }

            }
            if (dataTypeObject.getIntValue(TYPE) == 7) {
                if (!isValidArraySpecsByArraySpecsAndLevel(dataTypeObject.getString(SPECS), level - 1))
                    return false;
            }
        }
    }

    private static boolean isValidStructSpecs(String specs, int level) {

        JSONArray retArray = JSON.parseArray(specs);
        if (CollectionUtils.isEmpty(retArray)) {
            throw new IotBusinessException("结构体数据规格定义不允许为空!");
        }
        Set<String> identifierSet = new HashSet<>();
        for (int i = 0; i < retArray.size(); i++) {

            JSONObject jsonObject = retArray.getJSONObject(i);
            log.info("jsonObject = {}, i = {}", jsonObject, i);
            if (jsonObject == null
                    || !jsonObject.containsKey(IDENTIFIER)
                    || !jsonObject.containsKey(NAME)
                    || !jsonObject.containsKey(DATA_TYPE)
                    || !jsonObject.containsKey(DESCRIPTION)) {
                return false;
            }

            if (!isValidNaming4Name(jsonObject.getString(NAME))) {
                log.error("名称,长度异常或者是名称不合法");
                return false;
            }
            if (dataTypeObject.getIntValue(TYPE) != 8 && dataTypeObject.getIntValue(TYPE) != 7) {

                int type = dataTypeObject.getIntValue(TYPE);
                String specsInner = dataTypeObject.getString(SPECS);

//                level = 0;
                if (!isValidCommonSpecs(type, specsInner)) {
                    log.error("结构体内层定义: type = {}, specsInner = {}", type, specsInner);
                    return false;
                }
            }
//            level = 0;


        }
        if (identifierSet.size() != retArray.size()) {
            return false;
        }

        return true;
    }

    private static boolean isValidArraySpecsByArraySpecsAndLevel(String arraySpecs, int level) {
        try {
            JSONObject arrayJSONObject = JSONObject.parseObject(arraySpecs);

            if (arrayJSONObject.containsKey(SIZE)
                    && ((Integer) arrayJSONObject.get(SIZE) >= 0
                    && (Integer) arrayJSONObject.get(SIZE) <= 65535)
                    && arrayJSONObject.containsKey(ITEM)
                    && arrayJSONObject.get(ITEM) != null) {
                JSONObject itemJSONObject = arrayJSONObject.getJSONObject(ITEM);
                if (!itemJSONObject.containsKey(DATA_TYPE)) {
                    log.error("===> isValidArraySpecs array型,数据规格定义 itemJSONObject = {} 错误!缺少dataType节点", itemJSONObject);
                    return false;
                }
                JSONObject dataTypeJSONObject = itemJSONObject.getJSONObject(DATA_TYPE);
                if (!dataTypeJSONObject.containsKey(TYPE) || !dataTypeJSONObject.containsKey(SPECS)) {
                    log.error("===> array型,数据规格定义 dataTypeJSONObject = {} 错误!必须有节点specs和type", dataTypeJSONObject);
                    return false;
                }
                int type = dataTypeJSONObject.getInteger(TYPE);
                String specs = dataTypeJSONObject.getString(SPECS);
                // 数组下不能包含Bytes、数组
                if (0 == type || 7 == type) {
                    log.error("===> array型,数据规格定义 数组层级下不能是Bytes或者数组 {}", dataTypeJSONObject);
                    return false;
                }

                // 结构体校验
                if (8 == type && dataTypeJSONObject.containsKey(SPECS)) {
                    boolean validStructSpecs = isValidStructSpecs(dataTypeJSONObject.getString(SPECS), level - 1);
                    if (!validStructSpecs) {
                        log.error("===> array型,数据规格定义 数组层级下结构体不合法 {}", dataTypeJSONObject);
                        return false;
                    }
                }
                // 数组里的普通类型
                if (type == 1 || type == 2 || type == 3 || type == 4 || type == 5 || type == 6) {
                    if (!isValidCommonSpecs(type, specs)) {
                        log.error("结构体内层定义,一般数据类型: type = {}, specs = {}", type, specs);
                        return false;
                    }
                }

                return true;
            } else {
                log.error("===> array型,数据规格定义 {} 错误!节点缺少或者个数不在规定范围内", arrayJSONObject);
                return false;
            }
        } catch (Exception e) {
            if (e instanceof IotBusinessException)
                throw e;
            log.error("===> array型,数据规格定义错误!某些节点解析错误!");
            return false;
        }
    }

    private static boolean isValidCommonSpecs(int dataType, String specs) {
        JSONObject specsRet = new JSONObject();
        JSONObject parseObject;
        try {
            parseObject = JSON.parseObject(specs);
            if (dataType != 4 && parseObject == null) {
                return false;
            }
        } catch (Exception e) {
            return false;
        }
    }

    private static boolean isValidArraySpecs(JSONObject arrayJSONObject) {
        try {
            if (arrayJSONObject != null && arrayJSONObject.containsKey(SIZE)
                    && ((arrayJSONObject.getIntValue(SIZE) > 0
                    && arrayJSONObject.getIntValue(SIZE) <= 65535))
                    && arrayJSONObject.containsKey(ITEM)
                    && arrayJSONObject.get(ITEM) != null) {
                JSONObject itemJSONObject = arrayJSONObject.getJSONObject(ITEM);
                if (!itemJSONObject.containsKey(DATA_TYPE)) {
                    log.error("===> isValidArraySpecs array型,数据规格定义 itemJSONObject = {} 错误!缺少dataType节点", itemJSONObject);
                    return false;
                }
                JSONObject dataTypeJSONObject = itemJSONObject.getJSONObject(DATA_TYPE);
                if (!dataTypeJSONObject.containsKey(TYPE) || !dataTypeJSONObject.containsKey(SPECS)) {

                    log.error("===> isValidArraySpecs array型,数据规格定义 dataTypeJSONObject = {} 错误!缺少type节点或者缺少spec节点", dataTypeJSONObject);
                    return false;
                }

                switch (dataType) {
                    case 0: // Bytes型
                        /**
                         * {"min":"","max":"","step":"","unit":"","length":1024}
                         */
                        if (parseObject != null && parseObject.containsKey(LENGTH) && parseObject.get(LENGTH) != null) {
                            int length;
                            try {
                                length = parseObject.getIntValue(LENGTH);
                            } catch (Exception e) {
                                return false;
                            }
                            if (length <= 0 || 65535 < length) {
                                return false;
                            }
                        } else {
                            log.error("===> Bytes型,数据规格定义 {} 错误!", specs);
                            return false;
                        }
                        break;
                    case 1: // float型 TODO 精细化浮点型数据 string
                        /**
                         * {"min":"0.1","max":"11.0","step":"0.1","unit":"min","range":["0.1","11.0"]}
                         * 需要注意的是单位能不能为空
                         */

                        if (parseObject.containsKey(STEP)
                                && parseObject.containsKey(UNIT)
                                && parseObject.containsKey(MAX)
                                && parseObject.containsKey(MIN)) {
                            if (parseObject.get(STEP) == null
                                    || parseObject.get(UNIT) == null
                                    || parseObject.get(MIN) == null
                                    || parseObject.get(MAX) == null) { // key 对应的 value不能为空
                                log.error("float型,数据规格定义错误!value不能为空");
                                return false;
                            }
                            String minStr = parseObject.getString(MIN);
                            String maxStr = parseObject.getString(MAX);
                            String stepStr = parseObject.getString(STEP);
                            if (!isValidDouble(maxStr) || !isValidDouble(minStr) || !isValidDouble(stepStr)) {
                                log.error("浮点型数据定义错误!");
                                return false;
                            }

                            BigDecimal min, max, step;
                            try {
                                min = new BigDecimal(parseObject.getString(MIN));
                                max = new BigDecimal(parseObject.getString(MAX));
                                step = new BigDecimal(parseObject.getString(STEP));
                            } catch (Exception e) {
                                return false;
                            }

                            BigDecimal maxValue = new BigDecimal("9007199254740991.0");
                            BigDecimal minValue = new BigDecimal("-9007199254740992.0");

                            if (max.compareTo(maxValue) > 0) {
                                log.error("浮点型数据超过最大值!");
                                return false;
                            }

                            specsRet.put(RANGE, Arrays.asList(parseObject.getDoubleValue(MIN), parseObject.getDoubleValue(MAX)));
                            if (min.compareTo(minValue) < 0) {
                                log.error("浮点型数据不能小于最小值!");
                                return false;
                            }

                            try {
                                parseObject.getDoubleValue(STEP);
                            } catch (Exception e) {
                                log.error("浮点型,数据规格定义错误! step不能转为浮点型数据!");
                                return false;
                            }

                            if (step.compareTo(BigDecimal.ZERO) < 0) {
                                log.error("浮点型,数据规格定义错误 步长必须非负!");
                                return false;
                            }
                            if (min.add(step).compareTo(max) > 0) {
                                throw new IotBusinessException("浮点型,数据规格定义错误 步长错误!最小值加上一个步长不能大于最大值");

                            }
                        } else {
                            log.error("===> 浮点型,数据规格定义 {} 错误!", specs);
                            return false;
                        }
                        break;
                    case 2: // int型
                        /**
                         * {"min":1,"max":10,"step":1,"unit":"min"}
                         * 需要注意的是单位能不能为空
                         */

                        if (parseObject.containsKey(STEP)
                                && parseObject.containsKey(UNIT)
                                && parseObject.containsKey(MIN)
                                && parseObject.containsKey(MAX)) {
                            if (parseObject.get(STEP) == null
                                    || parseObject.get(UNIT) == null
                                    || parseObject.get(MIN) == null || parseObject.get(MAX) == null) { // key 对应的 value不能为空
                                throw new IotBusinessException("int型,数据规格定义错误!value不能为空");

                            }
                            String numMax = parseObject.getString(MAX);
                            String numMin = parseObject.getString(MIN);
                            String numStep = parseObject.getString(STEP);
                            if (!isValidNumStr(numMax) || !isValidNumStr(numMin) || !isValidNumStr(numStep)) {
                                log.error("不能转换成数值!{}", specs);
                                return false;
                            }
                            if (numMax.replaceAll("-", "").length() > 16 || numMin.replaceAll("-", "").length() > 16 || numStep.replaceAll("-", "").length() > 16) {
                                log.error("超过最大整型表示范围!{}", specs);
                                return false;
                            }
                            long step;
                            long min;
                            long max = parseObject.getLongValue(MAX);
                            step = parseObject.getLongValue(STEP);
                            min = parseObject.getLongValue(MIN);
                            String maxStr = parseObject.getString(MAX);
                            if (new BigDecimal(maxStr).compareTo(new BigDecimal(LONG_MAX_VALUE)) > 0) {
                                throw new IotBusinessException("最大值错误!");
                            }

                            if (new BigDecimal(LONG_MIN_VALUE).compareTo(new BigDecimal(min)) > 0)
                                throw new IotBusinessException("最小值错误!");

                            if (step < 0) {
                                throw new IotBusinessException("int型,数据规格定义错误 步长必须为正整数!");
                            }

                            if (IoTALUtil.addWithNoScale(new BigDecimal(step), new BigDecimal(min)).compareTo(new BigDecimal(max)) > 0) {
                                throw new IotBusinessException("int型,数据规格定义错误 步长错误!最小值加上一个步长不能大于最大值");
                            }

                        } else {
                            throw new IotBusinessException("===> int型,数据规格定义错误!specs = " + specs);
                        }
                        break;
                    case 3: // text型
                        /**
                         * {"length":1024}
                         * 设计文档
                         * rule	String	文本合法校验规则,正则表达式,允许填空
                         * length	Int32	字符串最大长度,整型值,必须大于0,允许最大长度65535
                         */
                        if (parseObject.containsKey(LENGTH) && parseObject.get(LENGTH) != null) {
                            int textLength;
                            try {
                                textLength = parseObject.getIntValue(LENGTH);
                            } catch (Exception e) {
                                throw new IotBusinessException("===> text型,数据规格定义 length错误!length = " + parseObject.get(LENGTH));
                            }
                            if (0 < textLength && 65535 >= textLength) {
                                return true;
                            } else {
                                return false;
                            }

                        } else {
                            log.error("===> text型,数据规格定义 {} 错误!", specs);
                            return false;
                        }


                    case 4: // date型
                        if (parseObject.size() != 0)
                            return false;
                        break;
                    case 5: // bool型
                        /**
                         * {"0":"关","1":"开"}
                         */
                        if (!parseObject.containsKey("0")
                                || parseObject.get("0") == null
                                || !parseObject.containsKey("1")
                                || parseObject.get("1") == null) {
                            log.error("===> bool型,数据规格定义 {} 错误!", specs);
                            return false;
                        }
                        break;
                    case 6: // enum型
                        if (parseObject.containsKey("list") && parseObject.get("list") != null /*&& !(parseObject.get("list") instanceof List)*/) {
                            // enum 外层结构正确 校验数组内部元素
                            List<SpecsEnumDTO> specsEnumDTOS;
                            String list = parseObject.getString("list");
                            JSONArray objects = JSON.parseArray(list);
                            int size = objects.size();
                            for (int i = 0; i < size; i++) {
                                JSONObject o = (JSONObject) JSON.parseArray(list).get(i);
                                if (!o.containsKey("description") || !o.containsKey("value") || o.size() != 2) {
                                    log.error("枚举类型校验失败,缺少description字段!i = {}, JSONObject = {}", i, o);
                                    return false;
                                }
                            }

                            try {
                                specsEnumDTOS = JSON.parseArray(list, SpecsEnumDTO.class);
                            } catch (Exception e) {
                                log.error("=====>ProductPropertiesService#add#switch case 6 enum: " + parseObject.get("list"));
                                return false;
                            }
                            if (CollectionUtils.isEmpty(specsEnumDTOS)) {
                                log.error("=====>ProductPropertiesService#add#switch case 6 enum definition specs is empty list! ");
                                return false;
                            }
                            Set<Long> collect = specsEnumDTOS.stream().map(SpecsEnumDTO::getValue).collect(Collectors.toSet());
                            boolean present = collect.stream().anyMatch(a -> a > INT_MAX_VALUE || a < INT_MIN_VALUE);
                            if (present) {
                                log.error("enum型,数据规格定义错误!枚举定义值超过范围");
                                return false;
                            }
                            if (collect.size() < specsEnumDTOS.size()) {
                                log.error("enum型,数据规格定义错误!枚举定义重复");
                                return false;
                            }
                        } else {
                            log.error("===> enum型,数据规格定义 {} 错误!", specs);
                            return false;
                        }
                        break;
                    case 7: // array型 数组可以有0个元素 0~65535 数组下不能有:数组、Bytes
                        /**
                         * {
                         *   "size": 10,
                         *   "item": {
                         *     "dataType": {
                         *       "type": 2,
                         *       "specs": {
                         *         "min": 1,
                         *         "max": 11,
                         *         "step": 1,
                         *         "unit": "min",
                         *         "range": [
                         *           1,
                         *           11
                         *         ]
                         *       }
                         *     }
                         *   }
                         * }
                         */
                        boolean isValidArray = isValidArraySpecs(parseObject);
                        if (!isValidArray) {
                            return false;
                        }
                        break;
                }
                return true;
            }

        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值