瀏覽代碼

1. 增加区间实体和区间工具类
2. 信息点校验器

yucheng 3 年之前
父節點
當前提交
d5adfa2675
共有 18 個文件被更改,包括 1172 次插入1 次删除
  1. 6 1
      dc-business/dc-digital/src/main/java/com/persagy/dc/define/controller/ObjectInfoController.java
  2. 3 0
      dc-business/dc-digital/src/main/java/com/persagy/dc/define/entity/ObjectInfo.java
  3. 17 0
      dc-business/dc-digital/src/main/java/com/persagy/dc/parser/entity/EnumVO.java
  4. 60 0
      dc-business/dc-digital/src/main/java/com/persagy/dc/parser/entity/ParserResult.java
  5. 108 0
      dc-business/dc-digital/src/main/java/com/persagy/dc/parser/entity/RegionVO.java
  6. 21 0
      dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/IInfoDataParser.java
  7. 57 0
      dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/InfoDataFactory.java
  8. 138 0
      dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/AbstractInfoDataParser.java
  9. 46 0
      dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/AttachmentInfoParser.java
  10. 46 0
      dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/BooleanInfoParser.java
  11. 173 0
      dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/DateInfoParser.java
  12. 14 0
      dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/DoubleInfoParser.java
  13. 66 0
      dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/EnumInfoParser.java
  14. 14 0
      dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/IntegerInfoParser.java
  15. 95 0
      dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/NumberInfoParser.java
  16. 73 0
      dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/StringInfoParser.java
  17. 30 0
      dc-common/src/main/java/com/persagy/dc/common/model/data/RegionValue.java
  18. 205 0
      dc-common/src/main/java/com/persagy/dc/common/utils/RegionUtil.java

+ 6 - 1
dc-business/dc-digital/src/main/java/com/persagy/dc/define/controller/ObjectInfoController.java

@@ -43,7 +43,12 @@ public class ObjectInfoController {
         DigitalCommonUtils.ensureProjectCriteria(wrapper);
         DigitalCommonUtils.ensureProjectCriteria(wrapper);
         // 转换查询条件
         // 转换查询条件
         criteria.toWrapper(wrapper);
         criteria.toWrapper(wrapper);
-        Page page = service.queryByCondition(criteria.toPage(), wrapper);
+        Page page = criteria.toPage();
+        // 没有排序条件时,按默认条件排序
+        if(CollUtil.isEmpty(page.getOrders())) {
+            wrapper.orderByAsc("show_order");
+        }
+        page = service.queryByCondition(criteria.toPage(), wrapper);
         return ResultHelper.multi(page.getRecords());
         return ResultHelper.multi(page.getRecords());
     }
     }
 
 

+ 3 - 0
dc-business/dc-digital/src/main/java/com/persagy/dc/define/entity/ObjectInfo.java

@@ -1,6 +1,8 @@
 package com.persagy.dc.define.entity;
 package com.persagy.dc.define.entity;
 
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.persagy.dc.common.model.entity.AuditableEntity;
 import com.persagy.dc.common.model.entity.AuditableEntity;
 import lombok.Data;
 import lombok.Data;
@@ -48,6 +50,7 @@ public class ObjectInfo extends AuditableEntity {
     /** 数据格式 */
     /** 数据格式 */
     private String formatter;
     private String formatter;
     /** 取值范围 */
     /** 取值范围 */
+    @TableField(typeHandler = JacksonTypeHandler.class)
     private ArrayNode dataSource;
     private ArrayNode dataSource;
     /** 备注 */
     /** 备注 */
     private String remark;
     private String remark;

+ 17 - 0
dc-business/dc-digital/src/main/java/com/persagy/dc/parser/entity/EnumVO.java

@@ -0,0 +1,17 @@
+package com.persagy.dc.parser.entity;
+
+import lombok.Data;
+
+/**
+ * 枚举数据
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+@Data
+public class EnumVO {
+
+    /** 编码 */
+    private String code;
+    /** 上级编码 */
+    private String parentCode;
+}

+ 60 - 0
dc-business/dc-digital/src/main/java/com/persagy/dc/parser/entity/ParserResult.java

@@ -0,0 +1,60 @@
+package com.persagy.dc.parser.entity;
+
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.core.util.StrUtil;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.persagy.dc.define.entity.ObjectInfo;
+import lombok.Data;
+
+/**
+ * 信息点 处理结果
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+@Data
+public class ParserResult {
+    /** 信息点定义 */
+    private ObjectInfo infoDefine;
+    /** 信息点值 */
+    private JsonNode valueInfo;
+    /** 错误信息 */
+    private StringBuilder errorMsg = new StringBuilder();
+
+    public ParserResult(ObjectInfo infoDefine, JsonNode valueInfo) {
+        this.infoDefine = infoDefine;
+        this.valueInfo = valueInfo;
+    }
+
+    /**
+     * 是否复选
+     * @return
+     */
+    public boolean isMulti() {
+        return BooleanUtil.isTrue(infoDefine.getMultipleFlag());
+    }
+
+    /**
+     * 是否区间
+     * @return
+     */
+    public boolean isRegion() {
+        return BooleanUtil.isTrue(infoDefine.getRegionFlag());
+    }
+
+    /**
+     * 追加错误信息
+     * @param error 错误信息
+     */
+    public void addErrorMsg(String error) {
+        errorMsg.append(error);
+    }
+
+    /**
+     * 追加错误信息
+     * @param error 错误信息
+     * @param params 格式信息
+     */
+    public void addErrorMsg(String error, Object... params) {
+        errorMsg.append(StrUtil.format(error, params));
+    }
+}

+ 108 - 0
dc-business/dc-digital/src/main/java/com/persagy/dc/parser/entity/RegionVO.java

@@ -0,0 +1,108 @@
+package com.persagy.dc.parser.entity;
+
+import cn.hutool.core.collection.CollUtil;
+import com.fasterxml.jackson.annotation.JsonAlias;
+import com.persagy.dc.common.model.data.RegionValue;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 区间数据
+ * @param <T> 数据泛型
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+@Data
+public class RegionVO<T extends Comparable> {
+
+    /** 大于 */
+    @JsonAlias(value = "$gt")
+    public T great;
+    /** 大于等于 */
+    @JsonAlias(value = "$gte")
+    public T greatEqual;
+    /** 小于 */
+    @JsonAlias(value = "$lt")
+    public T less;
+    /** 小于等于 */
+    @JsonAlias(value = "$lte")
+    public T lessEqual;
+
+    public RegionVO() {
+    }
+
+    public RegionVO(T great, T greatEqual, T less, T lessEqual) {
+        this.great = great;
+        this.greatEqual = greatEqual;
+        this.less = less;
+        this.lessEqual = lessEqual;
+    }
+
+    /**
+     * 是否为空
+     * @return
+     */
+    public boolean isEmpty() {
+        return great == null && greatEqual == null && less == null && lessEqual == null;
+    }
+
+    /**
+     * 转换为RegionValue
+     * @return
+     */
+    public RegionValue<T> toRegionValue() {
+        RegionValue region = new RegionValue();
+        // 区间开始赋值
+        if(great != null) {
+            if(greatEqual == null || great.compareTo(greatEqual) >= 0) {
+                region.setStart(great);
+                region.setContainStart(false);
+            } else {
+                region.setStart(greatEqual);
+                region.setContainStart(true);
+            }
+        } else {
+            // 只有大于等于
+            if(greatEqual != null) {
+                region.setStart(greatEqual);
+                region.setContainStart(true);
+            }
+        }
+        // 区间结束赋值
+        if(less != null) {
+            if(lessEqual == null || less.compareTo(lessEqual) <= 0) {
+                region.setEnd(less);
+                region.setContainEnd(false);
+            } else {
+                region.setEnd(lessEqual);
+                region.setContainEnd(true);
+            }
+        } else {
+            // 只有小于等于
+            if(lessEqual != null) {
+                region.setEnd(lessEqual);
+                region.setContainEnd(true);
+            }
+        }
+        return region;
+    }
+
+    /**
+     * 转换为RegionValue
+     * @param values
+     * @param <T>
+     * @return
+     */
+    public static <T extends Comparable> List<RegionValue<T>> toRegionValueList(List<RegionVO<T>> values) {
+        if(CollUtil.isEmpty(values)) {
+            return null;
+        }
+        List<RegionValue<T>> regionList = new ArrayList<>();
+        for(RegionVO<T> value:values) {
+            regionList.add(value.toRegionValue());
+        }
+        return regionList;
+    }
+}

+ 21 - 0
dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/IInfoDataParser.java

@@ -0,0 +1,21 @@
+package com.persagy.dc.parser.service;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.persagy.dc.define.entity.ObjectInfo;
+import com.persagy.dc.parser.entity.ParserResult;
+
+/**
+ * 信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public interface IInfoDataParser {
+
+    /**
+     * 处理信息点
+     * @param infoDefine 信息点 定义信息
+     * @param valueInfo 信息点 值信息
+     * @return ParserResult
+     */
+    ParserResult parse(ObjectInfo infoDefine, JsonNode valueInfo);
+}

+ 57 - 0
dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/InfoDataFactory.java

@@ -0,0 +1,57 @@
+package com.persagy.dc.parser.service;
+
+import cn.hutool.core.map.MapUtil;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.persagy.dc.basic.constant.DigitalDataType;
+import com.persagy.dc.common.exception.BusinessException;
+import com.persagy.dc.define.entity.ObjectInfo;
+import com.persagy.dc.parser.entity.ParserResult;
+import com.persagy.dc.parser.service.impl.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 信息点 处理工厂
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class InfoDataFactory {
+
+    /** 信息点处理器Map<DataType, Parser> */
+    private static Map<String, IInfoDataParser> parserMap = new HashMap<>(16);
+
+    /**
+     * 处理信息点
+     * @param infoDefine 信息点 定义信息
+     * @param valueInfo 信息点 值信息
+     * @return ParserResult
+     */
+    public static ParserResult parse(ObjectInfo infoDefine, JsonNode valueInfo) {
+        IInfoDataParser parser = getParser(infoDefine.getDataType());
+        return parser.parse(infoDefine, valueInfo);
+    }
+
+    /**
+     * 根据数据类型获取信息点处理器
+     * @param dataType 数据类型
+     * @return
+     */
+    public static IInfoDataParser getParser(String dataType) {
+        // 懒加载
+        if(MapUtil.isEmpty(parserMap)) {
+            parserMap.put(DigitalDataType.ATTACHMENT.getIndex(), new AttachmentInfoParser());
+            parserMap.put(DigitalDataType.BOOLEAN.getIndex(), new BooleanInfoParser());
+            parserMap.put(DigitalDataType.DATETIME.getIndex(), new DateInfoParser());
+            parserMap.put(DigitalDataType.DOUBLE.getIndex(), new DoubleInfoParser());
+            parserMap.put(DigitalDataType.ENUM.getIndex(), new EnumInfoParser());
+            parserMap.put(DigitalDataType.INTEGER.getIndex(), new IntegerInfoParser());
+            parserMap.put(DigitalDataType.STRING.getIndex(), new StringInfoParser());
+        }
+        // 校验类型传值
+        if(!parserMap.containsKey(dataType)) {
+            throw new BusinessException("找不到对应数据类型的处理器!");
+        }
+        return parserMap.get(dataType);
+    }
+}

+ 138 - 0
dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/AbstractInfoDataParser.java

@@ -0,0 +1,138 @@
+package com.persagy.dc.parser.service.impl;
+
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.JsonNodeType;
+import com.persagy.dc.basic.constant.DigitalDataCategory;
+import com.persagy.dc.common.helper.SpringHelper;
+import com.persagy.dc.common.model.data.RegionValue;
+import com.persagy.dc.define.entity.ObjectInfo;
+import com.persagy.dc.parser.entity.ParserResult;
+import com.persagy.dc.parser.entity.RegionVO;
+import com.persagy.dc.parser.service.IInfoDataParser;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 信息点 抽象处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public abstract class AbstractInfoDataParser implements IInfoDataParser {
+
+    private static ObjectMapper objectMapper;
+
+    /**
+     * 接口实现
+     * @param infoDefine 信息点 定义信息
+     * @param valueInfo 信息点 值信息
+     * @return
+     */
+    @Override
+    public ParserResult parse(ObjectInfo infoDefine, JsonNode valueInfo) {
+        ParserResult result = new ParserResult(infoDefine, valueInfo);
+        // 校验信息点定义
+        if(!validateDefine(result)) {
+            return result;
+        }
+        // 空值、非静态信息点不需要值校验
+        if(valueInfo == null ||
+                JsonNodeType.NULL == valueInfo.getNodeType() ||
+                DigitalDataCategory.STATIC.getIndex().equalsIgnoreCase(infoDefine.getCategory())) {
+            return result;
+        }
+        // 值校验
+        validateValue(result);
+        return result;
+    }
+
+    /**
+     * 信息点定义校验
+     * @param result 校验参数
+     * @return 是否校验通过
+     */
+    protected abstract boolean validateDefine(ParserResult result);
+
+    /**
+     * 信息点值校验
+     * @param result 校验参数
+     * @return 是否校验通过
+     */
+    protected abstract boolean validateValue(ParserResult result);
+
+    /**
+     * 获取数据
+     * @param value
+     * @param clazz
+     * @param <T>
+     * @return
+     */
+    protected <T> T formatValue(JsonNode value, Class<T> clazz) throws IOException {
+        if(value == null || JsonNodeType.NULL == value.getNodeType()) {
+            return null;
+        }
+        return objectMapper.readValue(value.toString(), clazz);
+    }
+
+    /**
+     * 获取数据
+     * @param value
+     * @param clazz
+     * @param <T>
+     * @return
+     */
+    protected <T> List<T> formatListValue(JsonNode value, Class<T> clazz) throws IOException {
+        if(value == null || JsonNodeType.NULL == value.getNodeType()) {
+            return null;
+        }
+        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, clazz);
+        return objectMapper.readValue(value.toString(), javaType);
+    }
+
+    /**
+     * 获取数据
+     * @param value json
+     * @param clazz 泛型类
+     * @param <T>
+     * @return RegionValue
+     */
+    protected <T extends Comparable> RegionValue<T> formatRegionValue(JsonNode value, Class<T> clazz) throws IOException {
+        if(value == null || JsonNodeType.NULL == value.getNodeType()) {
+            return null;
+        }
+        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(RegionVO.class, clazz);
+        RegionVO<T> region = objectMapper.readValue(value.toString(), javaType);
+        return region == null ? null:region.toRegionValue();
+    }
+
+    /**
+     * 获取数据
+     * @param value
+     * @param clazz 泛型类
+     * @param <T>
+     * @return List<RegionValue<T>>
+     */
+    protected <T extends Comparable> List<RegionValue<T>> formatRegionListValue(JsonNode value, Class<T> clazz) throws IOException {
+        if(value == null || JsonNodeType.NULL == value.getNodeType()) {
+            return null;
+        }
+        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(RegionVO.class, clazz);
+        javaType = objectMapper.getTypeFactory().constructParametricType(List.class, javaType);
+        List<RegionVO<T>> regionList = objectMapper.readValue(value.toString(), javaType);
+        return RegionVO.toRegionValueList(regionList);
+    }
+
+    /**
+     * 获取ObjectMapper
+     * @return
+     */
+    protected ObjectMapper getObjectMapper() {
+        if(objectMapper == null) {
+            objectMapper = SpringHelper.getBean(ObjectMapper.class);
+        }
+        return objectMapper;
+    }
+}

+ 46 - 0
dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/AttachmentInfoParser.java

@@ -0,0 +1,46 @@
+package com.persagy.dc.parser.service.impl;
+
+import cn.hutool.core.util.BooleanUtil;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.persagy.dc.parser.entity.ParserResult;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 附件信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class AttachmentInfoParser extends AbstractInfoDataParser {
+
+    @Override
+    protected boolean validateDefine(ParserResult result) {
+        boolean regionFlag = BooleanUtil.isTrue(result.getInfoDefine().getRegionFlag());
+        // 不支持区间格式
+        if(regionFlag) {
+            result.addErrorMsg("信息点[{}]定义有误,Attachment类型不允许定义区间!", result.getInfoDefine().getCode());
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    protected boolean validateValue(ParserResult result) {
+        boolean multiFlag = BooleanUtil.isTrue(result.getInfoDefine().getMultipleFlag());
+        // 数据源 - 应为区间列表格式
+        try {
+            // 复数
+            if(multiFlag) {
+                List<ObjectNode> valueList = formatListValue(result.getValueInfo(), ObjectNode.class);
+            } else {
+                // 单数
+                ObjectNode value = formatValue(result.getValueInfo(), ObjectNode.class);
+            }
+        } catch (IOException e) {
+            result.addErrorMsg("信息点[{}]数据格式有误!", result.getInfoDefine().getCode());
+            return false;
+        }
+        return true;
+    }
+}

+ 46 - 0
dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/BooleanInfoParser.java

@@ -0,0 +1,46 @@
+package com.persagy.dc.parser.service.impl;
+
+import cn.hutool.core.util.BooleanUtil;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.persagy.dc.parser.entity.ParserResult;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 布尔信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class BooleanInfoParser extends AbstractInfoDataParser {
+
+    @Override
+    protected boolean validateDefine(ParserResult result) {
+        boolean regionFlag = BooleanUtil.isTrue(result.getInfoDefine().getRegionFlag());
+        // 不支持区间格式
+        if(regionFlag) {
+            result.addErrorMsg("信息点[{}]定义有误,Boolean类型不允许定义区间!", result.getInfoDefine().getCode());
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    protected boolean validateValue(ParserResult result) {
+        boolean multiFlag = BooleanUtil.isTrue(result.getInfoDefine().getMultipleFlag());
+        // 数据源 - 应为区间列表格式
+        try {
+            // 复数
+            if(multiFlag) {
+                List<Boolean> valueList = formatListValue(result.getValueInfo(), Boolean.class);
+            } else {
+                // 单数
+                Boolean value = formatValue(result.getValueInfo(), Boolean.class);
+            }
+        } catch (IOException e) {
+            result.addErrorMsg("信息点[{}]数据格式有误!", result.getInfoDefine().getCode());
+            return false;
+        }
+        return true;
+    }
+}

+ 173 - 0
dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/DateInfoParser.java

@@ -0,0 +1,173 @@
+package com.persagy.dc.parser.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.core.util.StrUtil;
+import com.persagy.dc.common.model.data.RegionValue;
+import com.persagy.dc.common.utils.RegionUtil;
+import com.persagy.dc.parser.entity.ParserResult;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 日期信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class DateInfoParser extends AbstractInfoDataParser {
+
+    @Override
+    protected boolean validateDefine(ParserResult result) {
+        // 格式默认为yyyyMMddHHmmss
+        if(StrUtil.isBlank(result.getInfoDefine().getFormatter())) {
+            result.getInfoDefine().setFormatter("yyyyMMddHHmmss");
+        }
+        String formatter = result.getInfoDefine().getFormatter();
+        // 数据源 - 应为区间列表格式
+        try {
+            List<RegionValue<String>> dataSource = formatRegionListValue(result.getInfoDefine().getDataSource(), String.class);
+            // 区间格式校验
+            if(!matchRegionDataFormat(formatter, dataSource)) {
+                result.addErrorMsg("信息点[{}]定义有误,数据源格式有误!", result.getInfoDefine().getCode());
+                return false;
+            }
+        } catch (IOException e) {
+            result.addErrorMsg("信息点[{}]定义有误,数据源格式有误!", result.getInfoDefine().getCode());
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    protected boolean validateValue(ParserResult result) {
+        boolean multiFlag = BooleanUtil.isTrue(result.getInfoDefine().getMultipleFlag());
+        boolean regionFlag = BooleanUtil.isTrue(result.getInfoDefine().getRegionFlag());
+        String formatter = result.getInfoDefine().getFormatter();
+        try {
+            // 数据源定义信息
+            List<RegionValue<String>> dataSource = formatRegionListValue(result.getInfoDefine().getDataSource(), String.class);
+            // 复数
+            if(multiFlag) {
+                // 复数区间
+                if(regionFlag) {
+                    List<RegionValue<String>> valueList = formatRegionListValue(result.getValueInfo(), String.class);
+                    // 区间格式校验
+                    if (!matchRegionDataFormat(formatter, valueList)) {
+                        result.addErrorMsg("信息点[{}]数据格式有误!", result.getInfoDefine().getCode());
+                        return false;
+                    }
+                    // 区间范围校验
+                    if (CollUtil.isNotEmpty(dataSource)) {
+                        if (!RegionUtil.allContains(dataSource, valueList)) {
+                            result.addErrorMsg("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode());
+                            return false;
+                        }
+                    }
+                } else {
+                    // 复数非区间
+                    List<String> valueList = formatListValue(result.getValueInfo(), String.class);
+                    // 区间格式校验
+                    if (!matchDataFormat(formatter, valueList)) {
+                        result.addErrorMsg("信息点[{}]数据格式有误!", result.getInfoDefine().getCode());
+                        return false;
+                    }
+                    // 区间范围校验
+                    if (CollUtil.isNotEmpty(dataSource)) {
+                        if (!RegionUtil.allContain(dataSource, valueList)) {
+                            result.addErrorMsg("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode());
+                            return false;
+                        }
+                    }
+                }
+            } else {
+                // 单数区间
+                if(regionFlag) {
+                    RegionValue<String> value = formatRegionValue(result.getValueInfo(), String.class);
+                    // 日期格式校验
+                    if (!matchRegionDataFormat(formatter, CollUtil.newArrayList(value))) {
+                        result.addErrorMsg("信息点[{}]数据格式有误!", result.getInfoDefine().getCode());
+                        return false;
+                    }
+                    if (CollUtil.isNotEmpty(dataSource)) {
+                        // 区间范围校验
+                        if (!RegionUtil.anyContains(dataSource, value)) {
+                            result.addErrorMsg("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode());
+                            return false;
+                        }
+                    }
+                } else {
+                    // 单数非区间
+                    String value = formatValue(result.getValueInfo(), String.class);
+                    // 日期格式校验
+                    if (!matchDataFormat(formatter, value)) {
+                        result.addErrorMsg("信息点[{}]数据格式有误!", result.getInfoDefine().getCode());
+                        return false;
+                    }
+                    if (CollUtil.isNotEmpty(dataSource)) {
+                        // 区间范围校验
+                        if (!RegionUtil.anyContain(dataSource, value)) {
+                            result.addErrorMsg("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode());
+                            return false;
+                        }
+                    }
+                }
+            }
+        } catch (IOException e) {
+            result.addErrorMsg("信息点[{}]数据格式有误!", result.getInfoDefine().getCode());
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 是否为指定格式日期区间
+     * @param formatter 格式
+     * @param regions 区间
+     * @return
+     */
+    private boolean matchRegionDataFormat(String formatter, List<RegionValue<String>> regions) {
+        if(CollUtil.isEmpty(regions) || StrUtil.isBlank(formatter)) {
+            return true;
+        }
+        for(RegionValue<String> region:regions) {
+            // 如果都匹配,则继续判断
+            if(matchDataFormat(formatter, region.getStart()) && matchDataFormat(formatter, region.getEnd())) {
+                continue;
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 是否为指定格式日期
+     * @param formatter 格式
+     * @param valueList 日期字符串
+     * @return
+     */
+    private boolean matchDataFormat(String formatter, List<String> valueList) {
+        if(CollUtil.isEmpty(valueList) || StrUtil.isBlank(formatter)) {
+            return true;
+        }
+        for(String value:valueList) {
+            // 如果匹配,则继续判断
+            if(matchDataFormat(formatter, value)) {
+                continue;
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 是否为指定格式日期
+     * @param formatter 格式
+     * @param value 日期字符串
+     * @return
+     */
+    private boolean matchDataFormat(String formatter, String value) {
+        // 日期可以任意匹配,因此只可判断长度是否一致
+        return StrUtil.isBlank(formatter) || StrUtil.isBlank(value) || formatter.length() == value.length();
+    }
+}

+ 14 - 0
dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/DoubleInfoParser.java

@@ -0,0 +1,14 @@
+package com.persagy.dc.parser.service.impl;
+
+/**
+ * 数值信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class DoubleInfoParser extends NumberInfoParser<Double> {
+
+    @Override
+    protected Class<Double> getClassType() {
+        return Double.class;
+    }
+}

+ 66 - 0
dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/EnumInfoParser.java

@@ -0,0 +1,66 @@
+package com.persagy.dc.parser.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import com.persagy.dc.parser.entity.EnumVO;
+import com.persagy.dc.parser.entity.ParserResult;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 枚举信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class EnumInfoParser extends AbstractInfoDataParser {
+
+    @Override
+    protected boolean validateDefine(ParserResult result) {
+        // 字符串类型不支持区间格式
+        if(result.isRegion()) {
+            result.addErrorMsg("信息点[{}]定义有误,ENUM类型不允许定义区间!", result.getInfoDefine().getCode());
+            return false;
+        }
+        // 数据源 - 应为区间列表格式
+        try {
+            formatListValue(result.getInfoDefine().getDataSource(), EnumVO.class);
+        } catch (IOException e) {
+            result.addErrorMsg("信息点[{}]定义有误,数据源格式有误!", result.getInfoDefine().getCode());
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    protected boolean validateValue(ParserResult result) {
+        try {
+            // 数据源定义信息
+            List<EnumVO> dataSource = formatListValue(result.getInfoDefine().getDataSource(), EnumVO.class);
+            Set<String> codeSet = new HashSet<>();
+            for(EnumVO enumVO:dataSource) {
+                codeSet.add(enumVO.getCode());
+            }
+            // 复数
+            if(result.isMulti()) {
+                List<String> valueList = formatListValue(result.getValueInfo(), String.class);
+                if(!CollUtil.containsAll(codeSet, valueList)) {
+                    result.addErrorMsg("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode());
+                    return false;
+                }
+            } else {
+                // 单数
+                String value = formatValue(result.getValueInfo(), String.class);
+                if(!codeSet.contains(value)) {
+                    result.addErrorMsg("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode());
+                    return false;
+                }
+            }
+        } catch (IOException e) {
+            result.addErrorMsg("信息点[{}]数据格式有误!", result.getInfoDefine().getCode());
+            return false;
+        }
+        return true;
+    }
+}

+ 14 - 0
dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/IntegerInfoParser.java

@@ -0,0 +1,14 @@
+package com.persagy.dc.parser.service.impl;
+
+/**
+ * 整数信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class IntegerInfoParser extends NumberInfoParser<Integer> {
+
+    @Override
+    protected Class<Integer> getClassType() {
+        return Integer.class;
+    }
+}

+ 95 - 0
dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/NumberInfoParser.java

@@ -0,0 +1,95 @@
+package com.persagy.dc.parser.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import com.persagy.dc.common.model.data.RegionValue;
+import com.persagy.dc.common.utils.RegionUtil;
+import com.persagy.dc.parser.entity.ParserResult;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 数值信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class NumberInfoParser <T extends Comparable> extends AbstractInfoDataParser {
+
+    @Override
+    protected boolean validateDefine(ParserResult result) {
+        // 数据源 - 应为区间列表格式
+        try {
+            formatRegionListValue(result.getInfoDefine().getDataSource(), getClassType());
+        } catch (IOException e) {
+            result.addErrorMsg("信息点[{}]定义有误,数据源格式有误!", result.getInfoDefine().getCode());
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    protected boolean validateValue(ParserResult result) {
+        try {
+            // 数据源定义信息
+            List<RegionValue<T>> dataSource = formatRegionListValue(result.getInfoDefine().getDataSource(), getClassType());
+            // 复数
+            if(result.isMulti()) {
+                // 复数区间
+                if(result.isRegion()) {
+                    List<RegionValue<T>> valueList = formatRegionListValue(result.getValueInfo(), getClassType());
+                    // 区间范围校验
+                    if (CollUtil.isNotEmpty(dataSource)) {
+                        if (!RegionUtil.allContains(dataSource, valueList)) {
+                            result.addErrorMsg("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode());
+                            return false;
+                        }
+                    }
+                } else {
+                    // 复数非区间
+                    List<T> valueList = formatListValue(result.getValueInfo(), getClassType());
+                    // 区间范围校验
+                    if (CollUtil.isNotEmpty(dataSource)) {
+                        if (!RegionUtil.allContain(dataSource, valueList)) {
+                            result.addErrorMsg("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode());
+                            return false;
+                        }
+                    }
+                }
+            } else {
+                // 单数区间
+                if(result.isRegion()) {
+                    RegionValue<T> value = formatRegionValue(result.getValueInfo(), getClassType());
+                    if (CollUtil.isNotEmpty(dataSource)) {
+                        // 区间范围校验
+                        if (!RegionUtil.anyContains(dataSource, value)) {
+                            result.addErrorMsg("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode());
+                            return false;
+                        }
+                    }
+                } else {
+                    // 单数非区间
+                    T value = formatValue(result.getValueInfo(), getClassType());
+                    if (CollUtil.isNotEmpty(dataSource)) {
+                        // 区间范围校验
+                        if (!RegionUtil.anyContain(dataSource, value)) {
+                            result.addErrorMsg("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode());
+                            return false;
+                        }
+                    }
+                }
+            }
+        } catch (IOException e) {
+            result.addErrorMsg("信息点[{}]数据格式有误!", result.getInfoDefine().getCode());
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 泛型类
+     * @return
+     */
+    protected Class<T> getClassType() {
+        return null;
+    }
+}

+ 73 - 0
dc-business/dc-digital/src/main/java/com/persagy/dc/parser/service/impl/StringInfoParser.java

@@ -0,0 +1,73 @@
+package com.persagy.dc.parser.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.BooleanUtil;
+import com.persagy.dc.common.model.data.RegionValue;
+import com.persagy.dc.common.utils.RegionUtil;
+import com.persagy.dc.parser.entity.ParserResult;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 字符串信息点 处理器
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class StringInfoParser extends AbstractInfoDataParser{
+
+    @Override
+    protected boolean validateDefine(ParserResult result) {
+        boolean regionFlag = BooleanUtil.isTrue(result.getInfoDefine().getRegionFlag());
+        // 字符串类型不支持区间格式
+        if(regionFlag) {
+            result.addErrorMsg("信息点[{}]定义有误,STRING类型不允许定义区间!", result.getInfoDefine().getCode());
+            return false;
+        }
+        // 数据源 - 应为区间列表格式
+        try {
+            formatRegionListValue(result.getInfoDefine().getDataSource(), Integer.class);
+        } catch (IOException e) {
+            result.addErrorMsg("信息点[{}]定义有误,数据源格式有误!", result.getInfoDefine().getCode());
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    protected boolean validateValue(ParserResult result) {
+        boolean multiFlag = BooleanUtil.isTrue(result.getInfoDefine().getMultipleFlag());
+        try {
+            // 数据源定义信息
+            List<RegionValue<Integer>> dataSource = formatRegionListValue(result.getInfoDefine().getDataSource(), Integer.class);
+            // 复数
+            if(multiFlag) {
+                List<String> valueList = formatListValue(result.getValueInfo(), String.class);
+                if(CollUtil.isNotEmpty(dataSource)) {
+                    // 字符串长度校验
+                    List<Integer> lengthList = valueList.stream().map(String::length).collect(Collectors.toList());
+                    if(!RegionUtil.allContain(dataSource, lengthList)) {
+                        result.addErrorMsg("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode());
+                        return false;
+                    }
+                }
+            } else {
+                // 单数
+                String value = formatValue(result.getValueInfo(), String.class);
+                if(CollUtil.isNotEmpty(dataSource)) {
+                    // 字符串长度校验
+                    if(!RegionUtil.anyContain(dataSource, value.length())) {
+                        result.addErrorMsg("信息点[{}]数据有误,超出区间范围!", result.getInfoDefine().getCode());
+                        return false;
+                    }
+                }
+            }
+        } catch (IOException e) {
+            result.addErrorMsg("信息点[{}]数据格式有误!", result.getInfoDefine().getCode());
+            return false;
+        }
+        return true;
+    }
+
+}

+ 30 - 0
dc-common/src/main/java/com/persagy/dc/common/model/data/RegionValue.java

@@ -0,0 +1,30 @@
+package com.persagy.dc.common.model.data;
+
+import lombok.Data;
+
+/**
+ * 区间数据
+ * @param <T> 数据泛型
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+@Data
+public class RegionValue<T extends Comparable> {
+
+    /** 开始位置 */
+    private T start;
+    /** 结束位置 */
+    private T end;
+    /** 是否包含开始值 */
+    private boolean containStart;
+    /** 是否包含结束值 */
+    private boolean containEnd;
+
+    /**
+     * 是否为空区间
+     * @return
+     */
+    public boolean isEmpty() {
+        return start == null && end == null;
+    }
+}

+ 205 - 0
dc-common/src/main/java/com/persagy/dc/common/utils/RegionUtil.java

@@ -0,0 +1,205 @@
+package com.persagy.dc.common.utils;
+
+import cn.hutool.core.collection.CollUtil;
+import com.persagy.dc.common.model.data.RegionValue;
+
+import java.util.List;
+
+/**
+ * 区间 工具类
+ * 暂时提供判断包含方法,后续再扩展相交、相连、取交集、取并集、取最小开始、取最大结束等区间工具方法
+ * @author Charlie Yu
+ * @date 2021-07-12
+ */
+public class RegionUtil {
+
+    /**
+     * 是否包含
+     * @param region 区间
+     * @param value 待比较数据
+     * @return value是否在region范围内
+     */
+    public static <T extends Comparable> boolean contain(RegionValue<T> region, T value) {
+        if(region == null || region.isEmpty() || value == null) {
+            return false;
+        }
+        // 区间有开始
+        if(region.getStart() != null) {
+            // 值小于区间开始,不包含
+            if(value.compareTo(region.getStart()) < 0) {
+                return false;
+            } else if(value.compareTo(region.getStart()) == 0 && !region.isContainStart()) {
+                // 值等于区间开始,但区间不包含开始,不包含
+                return false;
+            }
+        }
+        // 区间有结束
+        if(region.getEnd() != null) {
+            // 值大于区间结束,不包含
+            if(value.compareTo(region.getEnd()) > 0) {
+                return false;
+            } else if(value.compareTo(region.getEnd()) == 0 && !region.isContainEnd()) {
+                // 值等于区间结束,但区间不包含结束,不包含
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 是否全部包含
+     * @param region 区间
+     * @param valueList 待比较数据
+     * @return valueList是否全部在region范围内
+     */
+    public static <T extends Comparable> boolean containAll(RegionValue<T> region, List<T> valueList) {
+        if(region == null || region.isEmpty() || CollUtil.isEmpty(valueList)) {
+            return false;
+        }
+        for(T value:valueList) {
+            if(contain(region, value)) {
+                continue;
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 是否全部包含
+     * @param regionList 区间列表
+     * @param value 待比较数据
+     * @return value是否在regionList范围内
+     */
+    public static <T extends Comparable> boolean anyContain(List<RegionValue<T>> regionList, T value) {
+        if(CollUtil.isEmpty(regionList) || value == null) {
+            return false;
+        }
+        for(RegionValue<T> region:regionList) {
+            if(contain(region, value)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 是否全部包含
+     * @param regionList 区间列表
+     * @param valueList 待比较数据
+     * @return valueList是否全部在regionList范围内
+     */
+    public static <T extends Comparable> boolean allContain(List<RegionValue<T>> regionList, List<T> valueList) {
+        if(CollUtil.isEmpty(regionList) || CollUtil.isEmpty(valueList)) {
+            return false;
+        }
+        for(T value:valueList) {
+            if(anyContain(regionList, value)) {
+                continue;
+            }
+            // 有一个数据不在区间列表中,就是不符合
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 是否包含
+     * @param region 区间
+     * @param value 待比较数据
+     * @return value是否在region范围内
+     */
+    public static <T extends Comparable> boolean contains(RegionValue<T> region, RegionValue<T> value) {
+        if(region == null || region.isEmpty() || value == null || value.isEmpty()) {
+            return false;
+        }
+        // value区间开始为空,region区间有开始,则一定不包含
+        if(value.getStart() == null && region.getStart() != null) {
+            return false;
+        }
+        // value区间结束为空,region区间有结束,则一定不包含
+        if(value.getEnd() == null && region.getEnd() != null) {
+            return false;
+        }
+        // 到此,value和region只会开始或结束都同时有值
+        if(value.getStart() != null) {
+            // 开始有值判断
+            if(region.getStart().compareTo(value.getStart()) > 0) {
+                // region开始在value开始之后则一定不包含
+                return false;
+            } else if(region.getStart().compareTo(value.getStart()) == 0 && !region.isContainStart() && value.isContainStart()) {
+                // 如果region和value开始相同,但region不包含开始,value包含开始,也为不包含
+                return false;
+            }
+        }
+        // 结束有值判断
+        if(value.getEnd() != null) {
+            if(region.getEnd().compareTo(value.getEnd()) < 0) {
+                // 开始都为空,那结束一定都不为空,region结束在value结束之前则一定不包含
+                return false;
+            } else if(region.getEnd().compareTo(value.getEnd()) == 0 && !region.isContainEnd() && value.isContainEnd()) {
+                // 如果region和value结束相同,但region不包含结束,value包含结束,也为不包含
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 是否全部包含
+     * @param region 区间
+     * @param valueList 待比较数据
+     * @return valueList是否全部在region范围内
+     */
+    public static <T extends Comparable> boolean containsAll(RegionValue<T> region, List<RegionValue<T>> valueList) {
+        if(region == null || region.isEmpty() || CollUtil.isEmpty(valueList)) {
+            return false;
+        }
+        for(RegionValue<T> value:valueList) {
+            if(contains(region, value)) {
+                continue;
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 是否全部包含
+     * @param regionList 区间列表
+     * @param value 待比较数据
+     * @return value是否在regionList范围内
+     */
+    public static <T extends Comparable> boolean anyContains(List<RegionValue<T>> regionList, RegionValue<T> value) {
+        if(CollUtil.isEmpty(regionList) || value == null || value.isEmpty()) {
+            return false;
+        }
+        for(RegionValue<T> region:regionList) {
+            if(contains(region, value)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 是否全部包含
+     * @param regionList 区间列表
+     * @param valueList 待比较数据
+     * @return valueList是否全部在regionList范围内
+     */
+    public static <T extends Comparable> boolean allContains(List<RegionValue<T>> regionList, List<RegionValue<T>> valueList) {
+        if(CollUtil.isEmpty(regionList) || CollUtil.isEmpty(valueList)) {
+            return false;
+        }
+        for(RegionValue<T> value:valueList) {
+            if(anyContains(regionList, value)) {
+                continue;
+            }
+            // 有一个数据不在区间列表中,就是不符合
+            return false;
+        }
+        return true;
+    }
+
+}