瀏覽代碼

第三方导入检查部分逻辑

欧阳劲驰 2 月之前
父節點
當前提交
5ea9014e32
共有 32 個文件被更改,包括 2561 次插入199 次删除
  1. 21 0
      src/main/java/com/shkpr/service/alambizplugin/annotation/ExcelMapping.java
  2. 46 0
      src/main/java/com/shkpr/service/alambizplugin/apiparam/GisSurveyThirdImportParams.java
  3. 211 0
      src/main/java/com/shkpr/service/alambizplugin/bizservice/GisSurveyThirdImportBizService.java
  4. 27 0
      src/main/java/com/shkpr/service/alambizplugin/commproperties/GisSurveyThirdImportProperties.java
  5. 350 188
      src/main/java/com/shkpr/service/alambizplugin/commtools/ExcelUtils.java
  6. 260 0
      src/main/java/com/shkpr/service/alambizplugin/commtools/ExcelUtilsCopy.java
  7. 76 0
      src/main/java/com/shkpr/service/alambizplugin/commtools/GeomUtil.java
  8. 236 0
      src/main/java/com/shkpr/service/alambizplugin/components/GisSurveyThirdImporter.java
  9. 47 0
      src/main/java/com/shkpr/service/alambizplugin/components/checker/DuplicatePointsFinder.java
  10. 93 0
      src/main/java/com/shkpr/service/alambizplugin/components/checker/InvalidLinesFinder.java
  11. 228 0
      src/main/java/com/shkpr/service/alambizplugin/components/checker/InvalidPropertiesFinder.java
  12. 2 0
      src/main/java/com/shkpr/service/alambizplugin/constants/ApiURI.java
  13. 22 0
      src/main/java/com/shkpr/service/alambizplugin/constants/ExcelEnum.java
  14. 57 0
      src/main/java/com/shkpr/service/alambizplugin/constants/GisSurveyImportDefine.java
  15. 35 0
      src/main/java/com/shkpr/service/alambizplugin/constants/GisSurveyImportStatusEnum.java
  16. 4 0
      src/main/java/com/shkpr/service/alambizplugin/constants/ResponseCode.java
  17. 168 4
      src/main/java/com/shkpr/service/alambizplugin/controller/ApiGisSurveyController.java
  18. 2 0
      src/main/java/com/shkpr/service/alambizplugin/controllerfilter/third/ApiJWTGisSurveyBizFilter.java
  19. 27 0
      src/main/java/com/shkpr/service/alambizplugin/dbdao/mapper/GisMetadataLayerTemplateMapper.java
  20. 14 0
      src/main/java/com/shkpr/service/alambizplugin/dbdao/mapper/GisMetadataPropertyTemplateMapper.java
  21. 36 0
      src/main/java/com/shkpr/service/alambizplugin/dbdao/services/GisMetadataLayerTemplateServiceImpl.java
  22. 22 0
      src/main/java/com/shkpr/service/alambizplugin/dbdao/services/intef/GisMetadataLayerTemplateService.java
  23. 77 0
      src/main/java/com/shkpr/service/alambizplugin/dto/GisMetadataLayerTemplate.java
  24. 111 0
      src/main/java/com/shkpr/service/alambizplugin/dto/GisMetadataPropertyTemplate.java
  25. 82 0
      src/main/java/com/shkpr/service/alambizplugin/dto/GisSurveyThirdImportElement.java
  26. 124 0
      src/main/java/com/shkpr/service/alambizplugin/dto/GisSurveyThirdImportResult.java
  27. 27 0
      src/main/java/com/shkpr/service/alambizplugin/dto/GisSurveyThirdImportResultDetail.java
  28. 30 0
      src/main/java/com/shkpr/service/alambizplugin/dto/GisSurveyThirdImportSubtask.java
  29. 19 2
      src/main/java/com/shkpr/service/alambizplugin/globalmgr/ScheduleTaskMgr.java
  30. 9 5
      src/main/resources/application.properties
  31. 93 0
      src/main/resources/mapper/GisMetadataLayerTemplateMapper.xml
  32. 5 0
      src/main/resources/mapper/GisMetadataPropertyTemplateMapper.xml

+ 21 - 0
src/main/java/com/shkpr/service/alambizplugin/annotation/ExcelMapping.java

@@ -0,0 +1,21 @@
+package com.shkpr.service.alambizplugin.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * excel字段映射
+ *
+ * @author 欧阳劲驰
+ * @since 0.0.1
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface ExcelMapping {
+    /**
+     * @return excel表头
+     */
+    String value();
+}

+ 46 - 0
src/main/java/com/shkpr/service/alambizplugin/apiparam/GisSurveyThirdImportParams.java

@@ -0,0 +1,46 @@
+package com.shkpr.service.alambizplugin.apiparam;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * 第三方导入入参
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+@ToString
+public class GisSurveyThirdImportParams {
+    /**
+     * 文件列表
+     */
+    private final List<MultipartFile> files;
+    /**
+     * 操作人
+     */
+    private String operator;
+    /**
+     * 任务id
+     */
+    private String jobId;
+    /**
+     * 用水性质:supply/drain
+     */
+    private String nature;
+    /**
+     * 点线规则
+     */
+    private String codeRule;
+    /**
+     * 忽略失败
+     */
+    private Boolean ignoreFail;
+}

+ 211 - 0
src/main/java/com/shkpr/service/alambizplugin/bizservice/GisSurveyThirdImportBizService.java

@@ -0,0 +1,211 @@
+package com.shkpr.service.alambizplugin.bizservice;
+
+import com.global.base.log.LogLevelFlag;
+import com.global.base.log.LogPrintMgr;
+import com.shkpr.service.alambizplugin.apiparam.GisSurveyThirdImportParams;
+import com.shkpr.service.alambizplugin.components.GisSurveyThirdImporter;
+import com.shkpr.service.alambizplugin.constants.GisSurveyImportStatusEnum;
+import com.shkpr.service.alambizplugin.constants.LogFlagBusiType;
+import com.shkpr.service.alambizplugin.dto.GisSurveyThirdImportResult;
+import com.shkpr.service.alambizplugin.dto.GisSurveyThirdImportSubtask;
+import org.springframework.stereotype.Component;
+import org.springframework.util.concurrent.ListenableFuture;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
+
+/**
+ * 第三方导入管理service
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Component
+public class GisSurveyThirdImportBizService {
+    /**
+     * 任务缓存
+     */
+    private final static Map<String, ListenableFuture<GisSurveyThirdImportResult>> TASK_CACHE = new ConcurrentHashMap<>();
+    /**
+     * 子任务缓存
+     */
+    private final static Map<String, GisSurveyThirdImportSubtask> SUBTASK_CACHE = new ConcurrentHashMap<>();
+    /**
+     * 开始时间缓存
+     */
+    private final static Map<String, LocalDateTime> TIME_CACHE = new ConcurrentHashMap<>();
+    /**
+     * log
+     */
+    private final String mStrClassName;
+    private final String mBizType;
+
+    private final GisSurveyThirdImporter thirdImporter;
+
+
+    public GisSurveyThirdImportBizService(GisSurveyThirdImporter thirdImporter) {
+        mStrClassName = "GisSurveySystemCheckBizService";
+        mBizType = LogFlagBusiType.BUSI_GIS_SURVEY.toStrValue();
+        this.thirdImporter = thirdImporter;
+    }
+
+    /**
+     * 第三方导入
+     *
+     * @param params 第三方导入参数
+     * @return 导入状态
+     */
+    public GisSurveyThirdImportResult thirdImport(GisSurveyThirdImportParams params) {
+        //获取已存在的任务
+        ListenableFuture<GisSurveyThirdImportResult> previousFuture = TASK_CACHE.get(params.getJobId());
+        //如任务已完成,则检查历史失败
+        if (!params.getIgnoreFail() && previousFuture != null && previousFuture.isDone()) {
+            try {
+                //获取结果,并检查失败
+                GisSurveyThirdImportResult thirdImportResult = previousFuture.get();
+                if (Objects.equals(thirdImportResult.getImportStatus(), GisSurveyImportStatusEnum.FAIL.getCode()))
+                    return thirdImportResult;
+            } catch (InterruptedException | ExecutionException e) {
+                //打印报错信息(不太可能走到这)
+                LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
+                        , String.format("检查历史失败异常 任务id:%s msg:%s", params.getJobId(), e.getMessage())
+                );
+            }
+        }
+
+        //系统检查子任务
+        GisSurveyThirdImportSubtask importSubtask = SUBTASK_CACHE.get(params.getJobId());
+        //进行中判断(未完成且未清除)
+        if (previousFuture != null && !previousFuture.isDone() && !previousFuture.isCancelled())
+            return GisSurveyThirdImportResult.inProgress(params, importSubtask, TIME_CACHE.get(params.getJobId()));
+
+        //获取文件流
+        List<InputStream> inputStreams = new ArrayList<>();
+        for (MultipartFile file : params.getFiles()) {
+            try {
+                inputStreams.add(file.getInputStream());
+            } catch (IOException e) {
+                return GisSurveyThirdImportResult.fail(params);
+            }
+        }
+        //启动检查任务
+        startTask(params, inputStreams);
+        //返回进行中
+        return GisSurveyThirdImportResult.inProgress(params, importSubtask, LocalDateTime.now());
+    }
+
+    /**
+     * 取消检查
+     *
+     * @param jobId 任务id
+     * @return 取消结果
+     */
+    public int cancelCheck(String jobId) {
+        //如无缓存,则直接返回不存在
+        if (!TASK_CACHE.containsKey(jobId)) return GisSurveyImportStatusEnum.NOT_EXISTS.getCode();
+        //关闭检查任务
+        return stopTask(jobId) ? GisSurveyImportStatusEnum.SUCCESS.getCode() : GisSurveyImportStatusEnum.FAIL.getCode();
+    }
+
+    /**
+     * 过期任务
+     * <p>用于检查和使任务过期</p>
+     */
+    public void expireResult(Duration ttl) {
+        //获取超时的id
+        List<String> jobIds = TIME_CACHE.entrySet().stream()
+                .filter(entry ->
+                        Duration.between(entry.getValue(), LocalDateTime.now()).compareTo(ttl) > 0
+                )
+                .map(Map.Entry::getKey)
+                .collect(Collectors.toList());
+        //停止超时的任务并删除任务缓存
+        for (String jobid : jobIds) {
+            //如任务不存在,则删除时间缓存
+            if (!TASK_CACHE.containsKey(jobid)) TIME_CACHE.remove(jobid);
+            //停用缓存
+            if (stopTask(jobid)) TIME_CACHE.remove(jobid);
+            else {
+                //打印报错信息
+                LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
+                        , String.format(
+                                "过期任务停止失败 ttl:%s 任务id:%s"
+                                , ttl
+                                , jobid
+                        )
+                );
+            }
+        }
+    }
+
+    /**
+     * 启动任务
+     *
+     * @param params       导入参数
+     * @param inputStreams 文件输入流
+     */
+    private void startTask(GisSurveyThirdImportParams params, List<InputStream> inputStreams) {
+        String jobId = params.getJobId();
+        //获取已存在的任务
+        ListenableFuture<GisSurveyThirdImportResult> previousFuture = TASK_CACHE.get(jobId);
+        //已结束判断,删除缓存
+        if (previousFuture != null && (previousFuture.isDone() || previousFuture.isCancelled())) {
+            removeCache(params.getJobId());
+        }
+        //异步执行第三方导入查任务
+        ListenableFuture<GisSurveyThirdImportResult> checkFuture = thirdImporter.thirdImportTask(params, inputStreams,
+                //缓存子任务句柄
+                subtask -> SUBTASK_CACHE.put(jobId, subtask),
+                //删除子任务句柄
+                subtaskSystemCheckId -> SUBTASK_CACHE.remove(jobId)
+        );
+        //缓存任务句柄
+        TASK_CACHE.put(jobId, checkFuture);
+        //缓存时间
+        TIME_CACHE.put(jobId, LocalDateTime.now());
+    }
+
+    /**
+     * 停止任务
+     *
+     * @param jobId 任务id
+     * @return 关闭状态
+     */
+    private Boolean stopTask(String jobId) {
+        ListenableFuture<GisSurveyThirdImportResult> future = TASK_CACHE.get(jobId);
+        //完成判断,完成删除缓存
+        if (future.isCancelled() || future.isDone()) {
+            removeCache(jobId);
+            return true;
+        }
+        //尝试清除任务
+        boolean cancel = future.cancel(true);
+        //清除成功,删除缓存
+        if (cancel) {
+            removeCache(jobId);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 清除缓存
+     *
+     * @param jobId 任务id
+     */
+    private void removeCache(String jobId) {
+        TASK_CACHE.remove(jobId);
+        SUBTASK_CACHE.remove(jobId);
+        TIME_CACHE.remove(jobId);
+    }
+}

+ 27 - 0
src/main/java/com/shkpr/service/alambizplugin/commproperties/GisSurveyThirdImportProperties.java

@@ -0,0 +1,27 @@
+package com.shkpr.service.alambizplugin.commproperties;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.time.Duration;
+
+/**
+ * 第三方导入属性
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Getter
+@Setter
+@ConfigurationProperties(prefix = "third-import")
+public class GisSurveyThirdImportProperties {
+    /**
+     * 系统检查任务超时时间
+     */
+    private Duration ttl;
+    /**
+     * 超时检查间隔(毫秒)
+     */
+    private Long ttlCheckInterval;
+}

+ 350 - 188
src/main/java/com/shkpr/service/alambizplugin/commtools/ExcelUtils.java

@@ -1,250 +1,340 @@
 package com.shkpr.service.alambizplugin.commtools;
 
+import com.global.base.log.LogLevelFlag;
+import com.global.base.log.LogPrintMgr;
+import com.shkpr.service.alambizplugin.annotation.ExcelMapping;
+import com.shkpr.service.alambizplugin.constants.ExcelEnum;
+import com.shkpr.service.alambizplugin.constants.LogFlagBusiType;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.*;
-import org.apache.poi.xssf.usermodel.*;
-import org.springframework.util.StringUtils;
-
-import java.io.*;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.DateUtil;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.apache.poi.xssf.usermodel.XSSFFont;
+import org.apache.poi.xssf.usermodel.XSSFRichTextString;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.text.DecimalFormat;
-import java.util.*;
-
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+/**
+ * excel工具类
+ *
+ * @author 欧阳劲驰
+ * @serial 1.0.0
+ */
 public class ExcelUtils {
-    public static class SheetObj{
-        private int index = 0; //sheet索引
-        private List<Map<String, Object>> rows2Col = new ArrayList<>();
-
-        public SheetObj() {
-        }
-
-        public SheetObj(int index, List<Map<String, Object>> rows2Col) {
-            this.index = index;
-            this.rows2Col = rows2Col;
-        }
-
-        public int getIndex() {
-            return index;
-        }
-
-        public void setIndex(int index) {
-            this.index = index;
-        }
-
-        public List<Map<String, Object>> getRows2Col() {
-            return rows2Col;
-        }
+    /**
+     * log
+     */
+    private static final String mStrClassName = "ExcelUtils";
+    private static final String mBizType = LogFlagBusiType.BUSI_GIS_SURVEY.toStrValue();
 
-        public void setRows2Col(List<Map<String, Object>> rows2Col) {
-            this.rows2Col = rows2Col;
+    /**
+     * 解析excel文件
+     *
+     * @param path         文件地址
+     * @param headerRowNum 表头行
+     * @param dataRowNum   数据行
+     * @return 数据(key : 页名, v : 数据)
+     */
+    public static Map<String, List<Map<String, String>>> parseExcelFile(String path, Integer headerRowNum, Integer dataRowNum) {
+        //excel枚举
+        ExcelEnum excelEnum = null;
+        //文件后缀
+        String ext = path.substring(path.lastIndexOf("."));
+        //根据后缀名指定枚举
+        if (".xls".equalsIgnoreCase(ext)) excelEnum = ExcelEnum.XLS;
+        else if (".xlsx".equalsIgnoreCase(ext)) excelEnum = ExcelEnum.XLS;
+        if (excelEnum == null) return null;
+        //解析文件
+        try {
+            return parseExcelFile(Files.newInputStream(Paths.get(path)), excelEnum, headerRowNum, dataRowNum);
+        } catch (IOException e) {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
+                    , String.format("excel文件解释失败 msg:%s", e.getMessage())
+            );
+            return null;
         }
     }
 
-    public static List<SheetObj> parseExcelFile(String filePath){
-        List<SheetObj> arrRes = null;
-        if (StringUtils.isEmpty(filePath))
-            return arrRes;
-
-        Workbook wb = getExcelWorkObj(filePath);
-        if (wb == null)
-            return arrRes;
-
-        do {
-            int sheetsNum = wb.getNumberOfSheets();
-            if (sheetsNum <= 0)
-                break;
-            arrRes = new ArrayList<>();
-
-            for (int i = 0; i < sheetsNum; i++)
-                arrRes.add(new SheetObj(i, parseSheetObj(wb.getSheetAt(i))));
-        }while (false);
-
-        if (wb != null){
-            try {
-                wb.close();
-            }catch (Exception e){}
+    /**
+     * 解析excel文件
+     *
+     * @param inputStream  输入流
+     * @param excelEnum    excel类型
+     * @param headerRowNum 表头行
+     * @param dataRowNum   数据行
+     * @return 数据(key : 页名, v : 数据)
+     */
+    public static Map<String, List<Map<String, String>>> parseExcelFile(InputStream inputStream, ExcelEnum excelEnum
+            , Integer headerRowNum, Integer dataRowNum) {
+        if (inputStream == null || excelEnum == null || excelEnum == ExcelEnum.CSV) return null;
+        //读取输入流
+        try (Workbook workbook = excelEnum == ExcelEnum.XLSX ? new XSSFWorkbook(inputStream) : new HSSFWorkbook(inputStream)) {
+            if (workbook.getNumberOfSheets() <= 0) return null;
+            //结果
+            Map<String, List<Map<String, String>>> results = new HashMap<>(workbook.getNumberOfSheets());
+            //遍历页,并解析
+            for (Sheet sheet : workbook) results.put(sheet.getSheetName(), parseSheet(sheet, headerRowNum, dataRowNum));
+            return results;
+        } catch (IOException e) {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
+                    , String.format("excel文件解释失败 msg:%s", e.getMessage())
+            );
+            return null;
         }
-        return arrRes;
     }
 
-    public static List<SheetObj> parseExcelFile(InputStream is, String ext){
-        List<SheetObj> arrRes = null;
-        Workbook wb = getExcelWorkObj(is, ext);
-        if (wb == null)
-            return arrRes;
-
-        do {
-            int sheetsNum = wb.getNumberOfSheets();
-            if (sheetsNum <= 0)
-                break;
-            arrRes = new ArrayList<>();
-
-            for (int i = 0; i < sheetsNum; i++)
-                arrRes.add(new SheetObj(i, parseSheetObj(wb.getSheetAt(i))));
-        }while (false);
-
-        if (wb != null){
-            try {
-                wb.close();
-            }catch (Exception e){}
+    /**
+     * 解析页
+     *
+     * @param sheet        页
+     * @param headerRowNum 表头行
+     * @param dataRowNum   数据行
+     * @return 数据
+     */
+    private static List<Map<String, String>> parseSheet(Sheet sheet, Integer headerRowNum, Integer dataRowNum) {
+        //数据集合
+        List<Map<String, String>> dataList = new ArrayList<>();
+        if (sheet == null) return dataList;
+        //行数
+        int rowsNum = sheet.getPhysicalNumberOfRows();
+        if (rowsNum <= 1) return dataList;
+        //页头行
+        Row rowHead = sheet.getRow(headerRowNum);
+        //字段映射
+        Map<Integer, String> fieldMap = new HashMap<>();
+        for (Cell cell : rowHead) {
+            //获取值,如不为空,则存入索引关系
+            String cellValue = getCellValue(cell);
+            if (!StringUtils.isEmpty(cellValue)) {
+                fieldMap.put(cell.getColumnIndex(), cellValue);
+            }
         }
-        return arrRes;
-    }
-
-    private static Workbook getExcelWorkObj(InputStream is, String ext){
-        Workbook wb = null;
-        if (is != null && !StringUtils.isEmpty(ext)){
-            try {
-                if("xls".equalsIgnoreCase(ext)){
-                    wb = new HSSFWorkbook(is);
-                }else if("xlsx".equalsIgnoreCase(ext)){
-                    wb = new XSSFWorkbook(is);
-                }
-            } catch (FileNotFoundException e) {
-                e.printStackTrace();
-            } catch (IOException e) {
-                e.printStackTrace();
+        //遍历行
+        for (Row row : sheet) {
+            //跳过非数据行
+            if (row == null || row.getRowNum() < dataRowNum) continue;
+            //跳过空行
+            if (IntStream.range(row.getFirstCellNum(), row.getLastCellNum())
+                    .mapToObj(row::getCell)
+                    .allMatch(cell -> cell == null || cell.getCellTypeEnum() == CellType.BLANK)) continue;
+            //数据
+            Map<String, String> data = new HashMap<>();
+            //遍历字段映射
+            for (Map.Entry<Integer, String> entry : fieldMap.entrySet()) {
+                //获取单元格
+                Cell cell = row.getCell(entry.getKey());
+                //设置值
+                data.put(entry.getValue(), getCellValue(cell));
             }
+            //添加数据
+            dataList.add(data);
         }
-        return wb;
+
+        return dataList;
     }
 
-    private static Workbook getExcelWorkObj(String filePath){
-        Workbook wb = null;
-        String ext = filePath.substring(filePath.lastIndexOf("."));
+    /**
+     * excel文件转数据集合
+     *
+     * @param path         文件地址
+     * @param clazz        数据类型
+     * @param headerRowNum 表头行
+     * @param dataRowNum   数据行
+     * @param <E>          数据泛形
+     * @return 数据集合
+     */
+    public static <E> Map<String, List<E>> parseExcelFile(String path, Class<E> clazz, Integer headerRowNum, Integer dataRowNum) {
+        //excel枚举
+        ExcelEnum excelEnum = null;
+        //文件后缀
+        String ext = path.substring(path.lastIndexOf("."));
+        //根据后缀名指定枚举
+        if (".xls".equalsIgnoreCase(ext)) excelEnum = ExcelEnum.XLS;
+        else if (".xlsx".equalsIgnoreCase(ext)) excelEnum = ExcelEnum.XLS;
+        if (excelEnum == null) return null;
+        //解析文件
         try {
-            InputStream is = new FileInputStream(filePath);
-            if(".xls".equalsIgnoreCase(ext)){
-                wb = new HSSFWorkbook(is);
-            }else if(".xlsx".equalsIgnoreCase(ext)){
-                wb = new XSSFWorkbook(is);
-            }
-        } catch (FileNotFoundException e) {
-            e.printStackTrace();
+            return parseExcelFile(Files.newInputStream(Paths.get(path)), clazz, excelEnum, headerRowNum, dataRowNum);
         } catch (IOException e) {
-            e.printStackTrace();
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
+                    , String.format("excel文件解释失败 msg:%s", e.getMessage())
+            );
+            return null;
         }
-        return wb;
     }
 
-    private static List<Map<String, Object>> parseSheetObj(Sheet sheet){
-        List<Map<String, Object>> rows2Col = new ArrayList<>();
-        if (sheet == null)
-            return rows2Col;
-
-        int rowsNum = sheet.getPhysicalNumberOfRows();
-        int colsNum = (rowsNum>0)?sheet.getRow(0).getPhysicalNumberOfCells():0;
-        if (rowsNum <= 1)
-            return rows2Col;
-
-        Row rowHead = sheet.getRow(0);
-        List<String> colsHeads = new ArrayList<>();
-        for (int j = 0; j < colsNum; j++){
-            Cell cell = (rowHead!=null)?rowHead.getCell(j):null;
-            String colHeadName = cell!=null?getCellValue(cell):String.format("col%d",j);
-            colsHeads.add(!StringUtils.isEmpty(colHeadName)?colHeadName:String.format("col%d",j));
-        }
-
-        for (int i = 1; i < rowsNum; i++){
-            Row row = sheet.getRow(i);
-            if (row == null)
-                continue;
-
-            Map<String, Object> oneRow2Cols = new HashMap<>();
-            for (int j = 0; j < colsNum; j++){
-                Cell cell = row.getCell(j);
-                oneRow2Cols.put(colsHeads.get(j), cell!=null?getCellValue(cell):"");
-            }
-            if (oneRow2Cols.size() > 0)
-                rows2Col.add(oneRow2Cols);
+    /**
+     * excel文件转数据集合
+     *
+     * @param inputStream  input流
+     * @param clazz        数据类型
+     * @param excelEnum    excel枚举
+     * @param headerRowNum 表头行
+     * @param dataRowNum   数据行
+     * @param <E>          数据泛形
+     * @return 数据集合
+     */
+    public static <E> Map<String, List<E>> parseExcelFile(InputStream inputStream, Class<E> clazz, ExcelEnum excelEnum
+            , Integer headerRowNum, Integer dataRowNum) {
+        if (inputStream == null || excelEnum == null || excelEnum == ExcelEnum.CSV) return null;
+        //读取表
+        try (Workbook workbook = excelEnum == ExcelEnum.XLSX ? new XSSFWorkbook(inputStream) : new HSSFWorkbook(inputStream)) {
+            if (workbook.getNumberOfSheets() <= 0) return null;
+            //结果
+            Map<String, List<E>> results = new HashMap<>(workbook.getNumberOfSheets());
+            //遍历页,并解析
+            for (Sheet sheet : workbook)
+                results.put(sheet.getSheetName(), parseSheet(sheet, clazz, headerRowNum, dataRowNum));
+            return results;
+        } catch (IOException e) {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
+                    , String.format("excel文件解释失败 msg:%s", e.getMessage())
+            );
+            return null;
         }
-        return rows2Col;
     }
 
-    private static String getCellValue(Cell cell) {
-        String result = "";
-        if (cell == null)
-            return result;
-
+    /**
+     * 解析页
+     *
+     * @param sheet        页
+     * @param clazz        类型
+     * @param headerRowNum 表头行
+     * @param dataRowNum   数据行
+     * @param <E>          数据泛形
+     * @return 数据
+     */
+    private static <E> List<E> parseSheet(Sheet sheet, Class<E> clazz, Integer headerRowNum, Integer dataRowNum) {
         try {
-            switch (cell.getCellTypeEnum()){
-                case NUMERIC:{
-                    if (DateUtil.isCellDateFormatted(cell)){
-                        result = TimeTool.convertDateObj2DateStr(cell.getDateCellValue(), cell.getCellStyle().getDataFormatString());
-                    }else if(String.valueOf(cell.getNumericCellValue()).contains(".")){
-                        DecimalFormat df = new DecimalFormat("#.####");
-                        result = df.format(cell.getNumericCellValue());
-                    }else
-                        result = String.valueOf(cell.getNumericCellValue());;
-                }
-                break;
-                case STRING:{
-                    result = cell.getRichStringCellValue().toString();
-                }
-                break;
-                case BOOLEAN:{
-                    result = String.valueOf(cell.getBooleanCellValue());
-                }
-                break;
-                case FORMULA:{
-                    result = String.valueOf(cell.getNumericCellValue());
+            //数据集合
+            List<E> dataList = new ArrayList<>();
+            if (sheet == null) return dataList;
+            //行数
+            int rowsNum = sheet.getPhysicalNumberOfRows();
+            if (rowsNum <= 1) return dataList;
+            //页头行
+            Row headerRow = sheet.getRow(headerRowNum);
+            //字段映射
+            Map<Integer, Field> fieldMap = Arrays.stream(clazz.getDeclaredFields())
+                    //过滤需要导出的字段
+                    .filter(f -> f.isAnnotationPresent(ExcelMapping.class))
+                    //设置字段公开
+                    .peek(f -> f.setAccessible(true))
+                    .collect(Collectors.toMap(
+                            f -> {
+                                //获取excel映射值
+                                String excelMappingValue = f.getAnnotation(ExcelMapping.class).value();
+                                //获取对应的索引
+                                return IntStream.range(0, headerRow.getLastCellNum())
+                                        //过滤相同的值
+                                        .filter(index -> headerRow.getCell(index).getStringCellValue().equals(excelMappingValue))
+                                        .findFirst().orElse(-1);
+                            }, Function.identity()
+                    ));
+            //遍历行
+            for (Row row : sheet) {
+                //跳过第非数据
+                if (row == null || row.getRowNum() < dataRowNum) continue;
+                //跳过空行
+                if (IntStream.range(row.getFirstCellNum(), row.getLastCellNum())
+                        .mapToObj(row::getCell)
+                        .allMatch(cell -> cell == null || cell.getCellTypeEnum() == CellType.BLANK)) continue;
+                //实列化数据
+                E data = clazz.getDeclaredConstructor().newInstance();
+                //遍历字段映射
+                for (Map.Entry<Integer, Field> fieldEntry : fieldMap.entrySet()) {
+                    //跳过未找到的字段
+                    if (fieldEntry.getKey() == -1) continue;
+                    //获取单元格
+                    Cell cell = row.getCell(fieldEntry.getKey());
+                    //设置值
+                    setObjValue(data, fieldEntry.getValue(), getCellValue(cell));
                 }
-                break;
-                default:{
-                    result = "";
-                }
-                break;
+                //添加数据
+                dataList.add(data);
             }
-        }catch (Exception e){}
-        return result==null?"":result.trim();
+            return dataList;
+        } catch (NoSuchMethodException | InvocationTargetException | InstantiationException |
+                 IllegalAccessException e) {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
+                    , String.format("excel页解释失败 msg:%s", e.getMessage())
+            );
+            return null;
+        }
     }
 
+
     /**
-     *
      * @param rowsWithColsData
      * @param outputStream
      */
-    public static void writeExcel(List<List<Object>> rowsWithColsData, OutputStream outputStream, boolean hasHeader){
+    public static void writeExcel(List<List<Object>> rowsWithColsData, OutputStream outputStream, boolean hasHeader) {
         if (rowsWithColsData == null || rowsWithColsData.size() <= 0 || outputStream == null)
             return;
         XSSFWorkbook xssfWorkbook = new XSSFWorkbook();
         XSSFSheet xssfSheet = xssfWorkbook.createSheet("sheet1");
 
         XSSFCellStyle colHeaderStyle = null;
-        if (hasHeader){
+        if (hasHeader) {
             colHeaderStyle = xssfWorkbook.createCellStyle();
             XSSFFont colHeaderFont = xssfWorkbook.createFont();
             colHeaderFont.setBold(true);
             colHeaderStyle.setFont(colHeaderFont);
         }
 
-        for (int i=0,j=rowsWithColsData.size();i<j;i++){
+        for (int i = 0, j = rowsWithColsData.size(); i < j; i++) {
             XSSFRow xssfRow = xssfSheet.createRow(i);
             List<Object> columnData = rowsWithColsData.get(i);
             if (columnData == null)
                 continue;
 
-            for (int m=0,n=columnData.size();m<n;m++){
+            for (int m = 0, n = columnData.size(); m < n; m++) {
                 XSSFCell xssfCell = xssfRow.createCell(m);
                 Object col = columnData.get(m);
                 if (i == 0 && colHeaderStyle != null)
                     xssfCell.setCellStyle(colHeaderStyle);
 
-                if (col == null){
+                if (col == null) {
                     xssfCell.setCellValue("");
-                }else {
-                    if (col instanceof String){
-                        xssfCell.setCellValue(new XSSFRichTextString((String)col));
-                    }else if (col instanceof Date){
-                        xssfCell.setCellValue((Date)col);
-                    }else if (col instanceof Boolean){
-                        xssfCell.setCellValue((Boolean)col);
-                    }else if (col instanceof Double){
-                        xssfCell.setCellValue((Double)col);
-                    }else
+                } else {
+                    if (col instanceof String) {
+                        xssfCell.setCellValue(new XSSFRichTextString((String) col));
+                    } else if (col instanceof Date) {
+                        xssfCell.setCellValue((Date) col);
+                    } else if (col instanceof Boolean) {
+                        xssfCell.setCellValue((Boolean) col);
+                    } else if (col instanceof Double) {
+                        xssfCell.setCellValue((Double) col);
+                    } else
                         xssfCell.setCellValue(new XSSFRichTextString(String.valueOf(col)));
                 }
 
-                if (i != 0 && i == j-1)
+                if (i != 0 && i == j - 1)
                     xssfSheet.autoSizeColumn(m);
             }
         }
@@ -253,8 +343,80 @@ public class ExcelUtils {
             xssfWorkbook.write(outputStream);
             outputStream.flush();
             outputStream.close();
-        }catch (IOException e) {
+        } catch (IOException e) {
             e.printStackTrace();
         }
     }
+
+    /**
+     * 获取单元格值
+     *
+     * @param cell 单元格
+     * @return 值
+     */
+    private static String getCellValue(Cell cell) {
+        if (cell == null) return null;
+        //值
+        String value = null;
+        try {
+            switch (cell.getCellTypeEnum()) {
+                case NUMERIC: {
+                    if (DateUtil.isCellDateFormatted(cell)) {
+                        value = TimeTool.convertDateObj2DateStr(cell.getDateCellValue(), cell.getCellStyle().getDataFormatString());
+                    } else if (String.valueOf(cell.getNumericCellValue()).contains(".")) {
+                        DecimalFormat df = new DecimalFormat("#.####");
+                        value = df.format(cell.getNumericCellValue());
+                    } else
+                        value = String.valueOf(cell.getNumericCellValue());
+                }
+                break;
+                case STRING:
+                    value = cell.getRichStringCellValue().toString();
+                    break;
+                case BOOLEAN:
+                    value = String.valueOf(cell.getBooleanCellValue());
+                    break;
+                case FORMULA:
+                    value = String.valueOf(cell.getNumericCellValue());
+                    break;
+                default:
+                    break;
+            }
+        } catch (Exception ignored) {
+        }
+        return value == null ? "" : value.trim();
+    }
+
+    /**
+     * 设置数据值
+     *
+     * @param data  数据
+     * @param field 字段
+     * @param value 值
+     * @param <E>   数据泛形
+     * @throws IllegalAccessException 非法访问异常
+     */
+    private static <E> void setObjValue(E data, Field field, Object value) throws IllegalAccessException {
+        //值判断空
+        if (value != null) {
+            //判断数据类型是否相同,如相同直接设置值,如不同,则转换值
+            if (field.getType().isAssignableFrom(value.getClass())) {
+                //设置值
+                field.set(data, value);
+            } else {
+                //如值为double类型
+                if (value instanceof Double) {
+                    //对double类型兼容的类型处理
+                    if (field.getType() == short.class || field.getType() == Short.class)
+                        field.set(data, ((Double) value).shortValue());
+                    else if (field.getType() == int.class || field.getType() == Integer.class)
+                        field.set(data, ((Double) value).intValue());
+                    else if (field.getType() == long.class || field.getType() == Long.class)
+                        field.set(data, ((Double) value).longValue());
+                    else if (field.getType() == float.class || field.getType() == Float.class)
+                        field.set(data, ((Double) value).floatValue());
+                }
+            }
+        }
+    }
 }

+ 260 - 0
src/main/java/com/shkpr/service/alambizplugin/commtools/ExcelUtilsCopy.java

@@ -0,0 +1,260 @@
+package com.shkpr.service.alambizplugin.commtools;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.*;
+import org.springframework.util.StringUtils;
+
+import java.io.*;
+import java.text.DecimalFormat;
+import java.util.*;
+
+public class ExcelUtilsCopy {
+    public static class SheetObj{
+        private int index = 0; //sheet索引
+        private List<Map<String, Object>> rows2Col = new ArrayList<>();
+
+        public SheetObj() {
+        }
+
+        public SheetObj(int index, List<Map<String, Object>> rows2Col) {
+            this.index = index;
+            this.rows2Col = rows2Col;
+        }
+
+        public int getIndex() {
+            return index;
+        }
+
+        public void setIndex(int index) {
+            this.index = index;
+        }
+
+        public List<Map<String, Object>> getRows2Col() {
+            return rows2Col;
+        }
+
+        public void setRows2Col(List<Map<String, Object>> rows2Col) {
+            this.rows2Col = rows2Col;
+        }
+    }
+
+    public static List<SheetObj> parseExcelFile(String filePath){
+        List<SheetObj> arrRes = null;
+        if (StringUtils.isEmpty(filePath))
+            return arrRes;
+
+        Workbook wb = getExcelWorkObj(filePath);
+        if (wb == null)
+            return arrRes;
+
+        do {
+            int sheetsNum = wb.getNumberOfSheets();
+            if (sheetsNum <= 0)
+                break;
+            arrRes = new ArrayList<>();
+
+            for (int i = 0; i < sheetsNum; i++)
+                arrRes.add(new SheetObj(i, parseSheetObj(wb.getSheetAt(i))));
+        }while (false);
+
+        if (wb != null){
+            try {
+                wb.close();
+            }catch (Exception e){}
+        }
+        return arrRes;
+    }
+
+    public static List<SheetObj> parseExcelFile(InputStream is, String ext){
+        List<SheetObj> arrRes = null;
+        Workbook wb = getExcelWorkObj(is, ext);
+        if (wb == null)
+            return arrRes;
+
+        do {
+            int sheetsNum = wb.getNumberOfSheets();
+            if (sheetsNum <= 0)
+                break;
+            arrRes = new ArrayList<>();
+
+            for (int i = 0; i < sheetsNum; i++)
+                arrRes.add(new SheetObj(i, parseSheetObj(wb.getSheetAt(i))));
+        }while (false);
+
+        if (wb != null){
+            try {
+                wb.close();
+            }catch (Exception e){}
+        }
+        return arrRes;
+    }
+
+    private static Workbook getExcelWorkObj(InputStream is, String ext){
+        Workbook wb = null;
+        if (is != null && !StringUtils.isEmpty(ext)){
+            try {
+                if("xls".equalsIgnoreCase(ext)){
+                    wb = new HSSFWorkbook(is);
+                }else if("xlsx".equalsIgnoreCase(ext)){
+                    wb = new XSSFWorkbook(is);
+                }
+            } catch (FileNotFoundException e) {
+                e.printStackTrace();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return wb;
+    }
+
+    private static Workbook getExcelWorkObj(String filePath){
+        Workbook wb = null;
+        String ext = filePath.substring(filePath.lastIndexOf("."));
+        try {
+            InputStream is = new FileInputStream(filePath);
+            if(".xls".equalsIgnoreCase(ext)){
+                wb = new HSSFWorkbook(is);
+            }else if(".xlsx".equalsIgnoreCase(ext)){
+                wb = new XSSFWorkbook(is);
+            }
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return wb;
+    }
+
+    private static List<Map<String, Object>> parseSheetObj(Sheet sheet){
+        List<Map<String, Object>> rows2Col = new ArrayList<>();
+        if (sheet == null)
+            return rows2Col;
+
+        int rowsNum = sheet.getPhysicalNumberOfRows();
+        int colsNum = (rowsNum>0)?sheet.getRow(0).getPhysicalNumberOfCells():0;
+        if (rowsNum <= 1)
+            return rows2Col;
+
+        Row rowHead = sheet.getRow(0);
+        List<String> colsHeads = new ArrayList<>();
+        for (int j = 0; j < colsNum; j++){
+            Cell cell = (rowHead!=null)?rowHead.getCell(j):null;
+            String colHeadName = cell!=null?getCellValue(cell):String.format("col%d",j);
+            colsHeads.add(!StringUtils.isEmpty(colHeadName)?colHeadName:String.format("col%d",j));
+        }
+
+        for (int i = 1; i < rowsNum; i++){
+            Row row = sheet.getRow(i);
+            if (row == null)
+                continue;
+
+            Map<String, Object> oneRow2Cols = new HashMap<>();
+            for (int j = 0; j < colsNum; j++){
+                Cell cell = row.getCell(j);
+                oneRow2Cols.put(colsHeads.get(j), cell!=null?getCellValue(cell):"");
+            }
+            if (oneRow2Cols.size() > 0)
+                rows2Col.add(oneRow2Cols);
+        }
+        return rows2Col;
+    }
+
+    private static String getCellValue(Cell cell) {
+        String result = "";
+        if (cell == null)
+            return result;
+
+        try {
+            switch (cell.getCellTypeEnum()){
+                case NUMERIC:{
+                    if (DateUtil.isCellDateFormatted(cell)){
+                        result = TimeTool.convertDateObj2DateStr(cell.getDateCellValue(), cell.getCellStyle().getDataFormatString());
+                    }else if(String.valueOf(cell.getNumericCellValue()).contains(".")){
+                        DecimalFormat df = new DecimalFormat("#.####");
+                        result = df.format(cell.getNumericCellValue());
+                    }else
+                        result = String.valueOf(cell.getNumericCellValue());;
+                }
+                break;
+                case STRING:{
+                    result = cell.getRichStringCellValue().toString();
+                }
+                break;
+                case BOOLEAN:{
+                    result = String.valueOf(cell.getBooleanCellValue());
+                }
+                break;
+                case FORMULA:{
+                    result = String.valueOf(cell.getNumericCellValue());
+                }
+                break;
+                default:{
+                    result = "";
+                }
+                break;
+            }
+        }catch (Exception e){}
+        return result==null?"":result.trim();
+    }
+
+    /**
+     *
+     * @param rowsWithColsData
+     * @param outputStream
+     */
+    public static void writeExcel(List<List<Object>> rowsWithColsData, OutputStream outputStream, boolean hasHeader){
+        if (rowsWithColsData == null || rowsWithColsData.size() <= 0 || outputStream == null)
+            return;
+        XSSFWorkbook xssfWorkbook = new XSSFWorkbook();
+        XSSFSheet xssfSheet = xssfWorkbook.createSheet("sheet1");
+
+        XSSFCellStyle colHeaderStyle = null;
+        if (hasHeader){
+            colHeaderStyle = xssfWorkbook.createCellStyle();
+            XSSFFont colHeaderFont = xssfWorkbook.createFont();
+            colHeaderFont.setBold(true);
+            colHeaderStyle.setFont(colHeaderFont);
+        }
+
+        for (int i=0,j=rowsWithColsData.size();i<j;i++){
+            XSSFRow xssfRow = xssfSheet.createRow(i);
+            List<Object> columnData = rowsWithColsData.get(i);
+            if (columnData == null)
+                continue;
+
+            for (int m=0,n=columnData.size();m<n;m++){
+                XSSFCell xssfCell = xssfRow.createCell(m);
+                Object col = columnData.get(m);
+                if (i == 0 && colHeaderStyle != null)
+                    xssfCell.setCellStyle(colHeaderStyle);
+
+                if (col == null){
+                    xssfCell.setCellValue("");
+                }else {
+                    if (col instanceof String){
+                        xssfCell.setCellValue(new XSSFRichTextString((String)col));
+                    }else if (col instanceof Date){
+                        xssfCell.setCellValue((Date)col);
+                    }else if (col instanceof Boolean){
+                        xssfCell.setCellValue((Boolean)col);
+                    }else if (col instanceof Double){
+                        xssfCell.setCellValue((Double)col);
+                    }else
+                        xssfCell.setCellValue(new XSSFRichTextString(String.valueOf(col)));
+                }
+
+                if (i != 0 && i == j-1)
+                    xssfSheet.autoSizeColumn(m);
+            }
+        }
+
+        try {
+            xssfWorkbook.write(outputStream);
+            outputStream.flush();
+            outputStream.close();
+        }catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 76 - 0
src/main/java/com/shkpr/service/alambizplugin/commtools/GeomUtil.java

@@ -0,0 +1,76 @@
+package com.shkpr.service.alambizplugin.commtools;
+
+import org.locationtech.jts.geom.GeometryFactory;
+import org.locationtech.jts.geom.Point;
+import org.locationtech.jts.geom.PrecisionModel;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+/**
+ * 地理工具类
+ *
+ * @author 欧阳劲驰
+ * @since JDK1.8
+ */
+public class GeomUtil {
+    /**
+     * geom工厂
+     */
+    private static final GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), 4490);
+    /**
+     * 地球半径
+     */
+    private static final int EARTH_RADIUS = 6378137;
+
+    /**
+     * 将米转换为度
+     *
+     * @param degrees 度
+     * @return 对应的米
+     */
+    public static double convertDegreesToMeters(double degrees) {
+        return degrees * (Math.PI / 180) * EARTH_RADIUS;
+    }
+
+
+    /**
+     * 将米转换为度
+     *
+     * @param meters 米
+     * @return 对应的度
+     */
+    public static double convertMetersToDegrees(double meters) {
+        return meters / (Math.PI / 180 * EARTH_RADIUS);
+    }
+
+    /**
+     * 经纬度的度转十进制
+     * <p>如RMC(NMEA0183)协议报文:</p>
+     * <blockquote><pre>$GNRMC,072905.00,A,3640.46260,N,11707.54950,E,000.0,000.0,050119,OK*24</pre></blockquote>
+     * <p>则表示为:{@code [36.67438,117.12583]}</p>
+     *
+     * @param degrees      度
+     * @param minutesIndex 分索引,如 {@code  ddmm.mmmmm} 则为2
+     * @return 十进制表示
+     */
+    public static double convertDegreesToDecimal(String degrees, int minutesIndex) {
+        return Integer.parseInt(degrees.substring(0, minutesIndex)) +
+                //分除60保留8位
+                BigDecimal.valueOf(Float.parseFloat(degrees.substring(minutesIndex)))
+                        .divide(BigDecimal.valueOf(60), 8, RoundingMode.HALF_UP)
+                        .doubleValue();
+    }
+
+    /**
+     * 判断点1是否在点2距离范围内
+     *
+     * @param point1   点1
+     * @param point2   点2
+     * @param distance 距离(米)
+     * @return 判断状态
+     */
+    public static Boolean isWithinDistance(Point point1, Point point2, double distance) {
+        return point1.isWithinDistance(point2, convertMetersToDegrees(distance));
+    }
+}

+ 236 - 0
src/main/java/com/shkpr/service/alambizplugin/components/GisSurveyThirdImporter.java

@@ -0,0 +1,236 @@
+package com.shkpr.service.alambizplugin.components;
+
+import com.global.base.log.LogLevelFlag;
+import com.global.base.log.LogPrintMgr;
+import com.shkpr.service.alambizplugin.apiparam.GisSurveyThirdImportParams;
+import com.shkpr.service.alambizplugin.commtools.ExcelUtils;
+import com.shkpr.service.alambizplugin.components.checker.DuplicatePointsFinder;
+import com.shkpr.service.alambizplugin.components.checker.InvalidLinesFinder;
+import com.shkpr.service.alambizplugin.components.checker.InvalidPropertiesFinder;
+import com.shkpr.service.alambizplugin.constants.ExcelEnum;
+import com.shkpr.service.alambizplugin.constants.GisMetadataDefine;
+import com.shkpr.service.alambizplugin.constants.GisSurveyCheckStatusEnum;
+import com.shkpr.service.alambizplugin.constants.GisSurveyImportDefine;
+import com.shkpr.service.alambizplugin.constants.LogFlagBusiType;
+import com.shkpr.service.alambizplugin.dbdao.services.intef.GisMetadataLayerTemplateService;
+import com.shkpr.service.alambizplugin.dto.GisMetadataLayerTemplate;
+import com.shkpr.service.alambizplugin.dto.GisSurveyThirdImportElement;
+import com.shkpr.service.alambizplugin.dto.GisSurveyThirdImportResult;
+import com.shkpr.service.alambizplugin.dto.GisSurveyThirdImportResultDetail;
+import com.shkpr.service.alambizplugin.dto.GisSurveyThirdImportSubtask;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.AsyncResult;
+import org.springframework.stereotype.Component;
+import org.springframework.util.concurrent.ListenableFuture;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+
+/**
+ * 第三方导入执行器
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Component
+public class GisSurveyThirdImporter {
+    /**
+     * log
+     */
+    private final String mStrClassName;
+    private final String mBizType;
+
+    private final GisMetadataLayerTemplateService layerTemplateService;
+    private final DuplicatePointsFinder duplicatePointsFinder;
+    private final InvalidLinesFinder invalidLinesFinder;
+    private final InvalidPropertiesFinder invalidPropertiesFinder;
+
+    public GisSurveyThirdImporter(GisMetadataLayerTemplateService layerTemplateService, DuplicatePointsFinder duplicatePointsFinder, InvalidLinesFinder invalidLinesFinder, InvalidPropertiesFinder invalidPropertiesFinder) {
+        mStrClassName = "GisSurveyThirdImporter";
+        mBizType = LogFlagBusiType.BUSI_GIS_SURVEY.toStrValue();
+        this.layerTemplateService = layerTemplateService;
+        this.duplicatePointsFinder = duplicatePointsFinder;
+        this.invalidLinesFinder = invalidLinesFinder;
+        this.invalidPropertiesFinder = invalidPropertiesFinder;
+    }
+
+    /**
+     * 第三方导入任务
+     *
+     * @param params              系统检查参数
+     * @param inputStreams        文件输入流
+     * @param onStartSubtask      启动子任务
+     * @param onDeprecatedSubtask 弃用子任务(完成数据收集/取消)
+     * @return 系统检查返回
+     */
+    @Async
+    public ListenableFuture<GisSurveyThirdImportResult> thirdImportTask(GisSurveyThirdImportParams params, List<InputStream> inputStreams
+            , Consumer<GisSurveyThirdImportSubtask> onStartSubtask, Consumer<String> onDeprecatedSubtask) {
+        //构建返回
+        GisSurveyThirdImportResult result = GisSurveyThirdImportResult.fail(params);
+        //无效属性任务
+        ListenableFuture<GisSurveyThirdImportResultDetail<Map<String, List<GisSurveyThirdImportElement>>>> invalidPropertiesFuture = null;
+        //重复点号任务
+        ListenableFuture<GisSurveyThirdImportResultDetail<List<GisSurveyThirdImportElement>>> duplicatePointsFuture = null;
+        //无效线任务
+        ListenableFuture<GisSurveyThirdImportResultDetail<List<GisSurveyThirdImportElement>>> invalidLinesFuture = null;
+        //点集合
+        List<Map<String, String>> points = new ArrayList<>();
+        //线集合
+        List<Map<String, String>> lines = new ArrayList<>();
+        try {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName
+                    , String.format(
+                            "开始执行第三方导入;任务id: %s"
+                            , params.getJobId()
+                    )
+            );
+
+            //解析excel
+            parseExcel(inputStreams, points, lines);
+
+            //提取图层名
+            List<String> pointLayerNames = getLayerNames(points, GisSurveyImportDefine.POINT.LAYER);
+            List<String> listLayerNames = getLayerNames(lines, GisSurveyImportDefine.LINE.LAYER);
+            //图层模版
+            List<GisMetadataLayerTemplate> pointLayerTemplates = layerTemplateService.findByNatureAndNameIn(params.getNature(), pointLayerNames);
+            List<GisMetadataLayerTemplate> lineLayerTemplates = layerTemplateService.findByNatureAndNameIn(params.getNature(), listLayerNames);
+
+            //无效属性检查
+            invalidPropertiesFuture = invalidPropertiesFinder.findInvalidProperties(points, lines, pointLayerTemplates, lineLayerTemplates);
+            //重复点检查
+            duplicatePointsFuture = duplicatePointsFinder.findDuplicatePoints(points);
+            //无效线检查
+            invalidLinesFuture = invalidLinesFinder.finderInvalidLines(points, lines);
+
+            //返回子任务
+            onStartSubtask.accept(
+                    new GisSurveyThirdImportSubtask(invalidPropertiesFuture, duplicatePointsFuture, invalidLinesFuture)
+            );
+
+            //等待结果
+            GisSurveyThirdImportResultDetail<Map<String, List<GisSurveyThirdImportElement>>> invalidPropertiesResult = invalidPropertiesFuture.get();
+            //存入无效属性结果
+            result.setInvalidLinesResult(untarInvalidProperties(invalidPropertiesResult, GisSurveyImportDefine.RESULT.INVALID_LAYERS));
+            result.setMissingRequirementsResult(untarInvalidProperties(invalidPropertiesResult, GisSurveyImportDefine.RESULT.MISSING_REQUIREMENTS));
+            result.setInvalidTypesResult(untarInvalidProperties(invalidPropertiesResult, GisSurveyImportDefine.RESULT.INVALID_TYPES));
+            result.setOutRangesResult(untarInvalidProperties(invalidPropertiesResult, GisSurveyImportDefine.RESULT.OUT_RANGES));
+            //存入重复点结果
+            result.setDuplicatePointsResult(duplicatePointsFuture.get());
+            //存入无效线结果
+            result.setInvalidLinesResult(invalidLinesFuture.get());
+
+            //完成检查
+            result.setImportStatus(GisSurveyCheckStatusEnum.SUCCESS.getCode());
+            result.setCompleteTime(LocalDateTime.now());
+
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName
+                    , String.format(
+                            "结束执行第三方导入;任务id: %s, 用时(毫秒):%d",
+                            params.getJobId(),
+                            Duration.between(result.getRequestTime(), result.getCompleteTime()).toMillis()
+                    )
+            );
+
+            //弃用子任务
+            onDeprecatedSubtask.accept(params.getJobId());
+            return new AsyncResult<>(result);
+        } catch (InterruptedException | ExecutionException | IOException e) {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
+                    , String.format(
+                            "监测到中断或执行异常,开始清除子任务 任务id:%s",
+                            params.getJobId()
+                    )
+            );
+
+            //清除子任务
+            if (invalidPropertiesFuture != null) invalidPropertiesFuture.cancel(true);
+            if (duplicatePointsFuture != null) duplicatePointsFuture.cancel(true);
+            if (invalidLinesFuture != null) invalidLinesFuture.cancel(true);
+
+            //失败信息
+            result.setImportStatus(GisSurveyCheckStatusEnum.FAIL.getCode());
+            result.setCompleteTime(LocalDateTime.now());
+
+            //弃用子任务
+            onDeprecatedSubtask.accept(params.getJobId());
+            return new AsyncResult<>(result);
+        }
+    }
+
+    /**
+     * 解析excel
+     *
+     * @param inputStreams 输入流
+     * @param points       点集合
+     * @param lines        线集合
+     * @throws IOException io异常
+     */
+    private void parseExcel(List<InputStream> inputStreams, List<Map<String, String>> points, List<Map<String, String>> lines) throws IOException {
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, "开始执行解析excel   ======>");
+        long begin = System.currentTimeMillis();
+
+        //解析文件
+        for (InputStream inputStream : inputStreams) {
+            //解析excel
+            Map<String, List<Map<String, String>>> excelData = ExcelUtils.parseExcelFile(inputStream,
+                    ExcelEnum.XLSX, 0, 3);
+            //填入集合
+            if (excelData != null && excelData.containsKey(GisMetadataDefine.TYPE_KINE.POINT))
+                points.addAll(excelData.get(GisMetadataDefine.TYPE_KINE.POINT));
+            if (excelData != null && excelData.containsKey(GisMetadataDefine.TYPE_KINE.LINE))
+                lines.addAll(excelData.get(GisMetadataDefine.TYPE_KINE.LINE));
+            //释放流
+            inputStream.close();
+        }
+
+        long end = System.currentTimeMillis();
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName
+                , String.format(
+                        "结束执行执行解析excel,用时(毫秒):%d"
+                        , (end - begin)
+                )
+        );
+    }
+
+    /**
+     * 获取图层名称
+     *
+     * @param datas    数据
+     * @param layerKey 图层的key
+     * @return 图层名称集合
+     */
+    private List<String> getLayerNames(List<Map<String, String>> datas, String layerKey) {
+        //去重图层
+        return datas.parallelStream()
+                .filter(data -> data.get(layerKey) != null)
+                .map(data -> data.get(layerKey))
+                .distinct()
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * 解包无效属性
+     *
+     * @param invalidPropertiesResult 无效属性结果
+     * @param resultKey               结果key
+     * @return 具体结果
+     */
+    private GisSurveyThirdImportResultDetail<List<GisSurveyThirdImportElement>> untarInvalidProperties(
+            GisSurveyThirdImportResultDetail<Map<String, List<GisSurveyThirdImportElement>>> invalidPropertiesResult
+            , String resultKey) {
+        //获取结果
+        List<GisSurveyThirdImportElement> importElements = invalidPropertiesResult.getResults().get(resultKey);
+
+        return new GisSurveyThirdImportResultDetail<>(true, importElements);
+    }
+}

+ 47 - 0
src/main/java/com/shkpr/service/alambizplugin/components/checker/DuplicatePointsFinder.java

@@ -4,12 +4,16 @@ import com.global.base.log.LogLevelFlag;
 import com.global.base.log.LogPrintMgr;
 import com.shkpr.service.alambizplugin.commtools.BeanUtil;
 import com.shkpr.service.alambizplugin.components.GisSurveySystemCheckResultManager;
+import com.shkpr.service.alambizplugin.constants.GisMetadataDefine;
+import com.shkpr.service.alambizplugin.constants.GisSurveyImportDefine;
 import com.shkpr.service.alambizplugin.constants.GisSurveySystemCheckResultPath;
 import com.shkpr.service.alambizplugin.constants.LogFlagBusiType;
 import com.shkpr.service.alambizplugin.dto.GisSurveyLayerApplyPoint;
 import com.shkpr.service.alambizplugin.dto.GisSurveySystemCheckElement;
 import com.shkpr.service.alambizplugin.dto.GisSurveySystemCheckId;
 import com.shkpr.service.alambizplugin.dto.GisSurveySystemCheckResultDetail;
+import com.shkpr.service.alambizplugin.dto.GisSurveyThirdImportElement;
+import com.shkpr.service.alambizplugin.dto.GisSurveyThirdImportResultDetail;
 import com.shkpr.service.alambizplugin.dto.TypeDefine;
 import org.apache.commons.lang3.StringUtils;
 import org.locationtech.jts.geom.Coordinate;
@@ -26,6 +30,9 @@ import java.util.stream.Collectors;
 
 /**
  * 重复点寻找器
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
  */
 @Component
 public class DuplicatePointsFinder {
@@ -56,6 +63,46 @@ public class DuplicatePointsFinder {
 
     /**
      * 寻找重复点
+     * <p>根据 <strong>code</strong> 匹配</p>
+     *
+     * @param points 点集合
+     * @return 重复点
+     */
+    @Async
+    public ListenableFuture<GisSurveyThirdImportResultDetail<List<GisSurveyThirdImportElement>>> findDuplicatePoints(List<Map<String, String>> points) throws InterruptedException {
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, "开始执行寻找重复点   ======>");
+        long begin = System.currentTimeMillis();
+
+        //根据code度分组
+        Map<String, List<Map<String, String>>> keyToPoints = points.parallelStream()
+                //过滤类型为字符串
+                .filter(point ->
+                        point.get(GisSurveyImportDefine.POINT.NO) != null)
+                .collect(Collectors.groupingBy(point ->
+                                point.get(GisSurveyImportDefine.POINT.NO),
+                        Collectors.toList())
+                );
+        //响应中断
+        if (Thread.interrupted()) throw new InterruptedException();
+        //并行流寻找重复点号
+        List<GisSurveyThirdImportElement> groupElements = keyToPoints.entrySet().parallelStream()
+                //过滤组内大于1
+                .filter(group -> group.getValue().size() > 1)
+                .map(entry -> new GisSurveyThirdImportElement(GisMetadataDefine.TYPE_KINE.POINT, entry.getKey()))
+                .collect(Collectors.toList());
+
+        long end = System.currentTimeMillis();
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName
+                , String.format(
+                        "结束执行寻找重复点,用时(毫秒):%d"
+                        , (end - begin)
+                )
+        );
+        return new AsyncResult<>(new GisSurveyThirdImportResultDetail<>(true, groupElements));
+    }
+
+    /**
+     * 寻找重复点
      * <p>根据 <strong>精度</strong> 强匹配</p>
      *
      * @param points      点集合

+ 93 - 0
src/main/java/com/shkpr/service/alambizplugin/components/checker/InvalidLinesFinder.java

@@ -0,0 +1,93 @@
+package com.shkpr.service.alambizplugin.components.checker;
+
+import com.global.base.log.LogLevelFlag;
+import com.global.base.log.LogPrintMgr;
+import com.google.common.collect.Lists;
+import com.shkpr.service.alambizplugin.constants.GisSurveyImportDefine;
+import com.shkpr.service.alambizplugin.constants.LogFlagBusiType;
+import com.shkpr.service.alambizplugin.dto.GisSurveyThirdImportElement;
+import com.shkpr.service.alambizplugin.dto.GisSurveyThirdImportResultDetail;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.AsyncResult;
+import org.springframework.stereotype.Component;
+import org.springframework.util.concurrent.ListenableFuture;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.shkpr.service.alambizplugin.constants.GisSurveyImportDefine.LINE.DOWN_NO;
+import static com.shkpr.service.alambizplugin.constants.GisSurveyImportDefine.LINE.UP_NO;
+
+/**
+ * 无效线查找器
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Component
+public class InvalidLinesFinder {
+    /**
+     * log
+     */
+    private final String mStrClassName;
+    private final String mBizType;
+
+    public InvalidLinesFinder() {
+        mStrClassName = "InvalidLinesFinder";
+        mBizType = LogFlagBusiType.BUSI_GIS_SURVEY.toStrValue();
+    }
+
+    /**
+     * 寻找无效线
+     *
+     * @param points 点集合
+     * @param lines  线集合
+     * @return 线分组
+     */
+    @Async
+    public ListenableFuture<GisSurveyThirdImportResultDetail<List<GisSurveyThirdImportElement>>> finderInvalidLines(List<Map<String, String>> points
+            , List<Map<String, String>> lines) throws InterruptedException {
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, "开始执行寻找无效线   ======>");
+        long begin = System.currentTimeMillis();
+
+        //如点为空,则全是无效线
+        if (points.isEmpty()) return new AsyncResult<>(new GisSurveyThirdImportResultDetail<>(true,
+                lines.stream()
+                        //转code字符串
+                        .map(line -> GisSurveyThirdImportElement.create(line, GisSurveyImportDefine.LayerType.LINE))
+                        .collect(Collectors.toList())
+        ));
+        //如线为空,则无无效线
+        if (lines.isEmpty()) return new AsyncResult<>(new GisSurveyThirdImportResultDetail<>(
+                true, Lists.newArrayList()
+        ));
+
+        //点号集合
+        Set<String> nos = points.parallelStream()
+                .map(it -> it.get(GisSurveyImportDefine.POINT.NO))
+                .filter(Objects::nonNull)
+                .collect(Collectors.toSet());
+        //收集无效线
+        List<GisSurveyThirdImportElement> results = new ArrayList<>();
+        for (Map<String, String> line : lines) {
+            //响应中断
+            if (Thread.interrupted()) throw new InterruptedException();
+            //不包含上节点或下节点,则收集
+            if (!nos.contains(line.get(UP_NO)) || !nos.contains(line.get(DOWN_NO)))
+                results.add(GisSurveyThirdImportElement.create(line, GisSurveyImportDefine.LayerType.LINE));
+        }
+
+        long end = System.currentTimeMillis();
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName
+                , String.format(
+                        "结束执行寻找无效线,用时(毫秒):%d"
+                        , (end - begin)
+                )
+        );
+        return new AsyncResult<>(new GisSurveyThirdImportResultDetail<>(true, results));
+    }
+}

+ 228 - 0
src/main/java/com/shkpr/service/alambizplugin/components/checker/InvalidPropertiesFinder.java

@@ -0,0 +1,228 @@
+package com.shkpr.service.alambizplugin.components.checker;
+
+import com.global.base.log.LogLevelFlag;
+import com.global.base.log.LogPrintMgr;
+import com.shkpr.service.alambizplugin.commtools.GeomUtil;
+import com.shkpr.service.alambizplugin.constants.GisSurveyImportDefine;
+import com.shkpr.service.alambizplugin.constants.LogFlagBusiType;
+import com.shkpr.service.alambizplugin.dto.GisMetadataLayerTemplate;
+import com.shkpr.service.alambizplugin.dto.GisMetadataPropertyTemplate;
+import com.shkpr.service.alambizplugin.dto.GisSurveyThirdImportElement;
+import com.shkpr.service.alambizplugin.dto.GisSurveyThirdImportResultDetail;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.AsyncResult;
+import org.springframework.stereotype.Component;
+import org.springframework.util.concurrent.ListenableFuture;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * 无效属性查找器
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Component
+public class InvalidPropertiesFinder {
+    /**
+     * 中国经纬度范围
+     */
+    private static final Double MIN_LAT = GeomUtil.convertDegreesToDecimal("351", 1);
+    private static final Double MAX_LAT = GeomUtil.convertDegreesToDecimal("5333", 2);
+    private static final Double MIN_LNG = GeomUtil.convertDegreesToDecimal("7333", 2);
+    private static final Double MAX_LNG = GeomUtil.convertDegreesToDecimal("13505", 3);
+    /**
+     * log
+     */
+    private final String mStrClassName;
+    private final String mBizType;
+
+    public InvalidPropertiesFinder() {
+        mStrClassName = "InvalidPropertiesFinder";
+        mBizType = LogFlagBusiType.BUSI_GIS_SURVEY.toStrValue();
+    }
+
+    /**
+     * 寻找无效属性
+     *
+     * @param points              点集合
+     * @param lines               线集合
+     * @param pointLayerTemplates 点图层模版集合
+     * @param lineLayerTemplates  线图层模版集合
+     * @return 重复点
+     */
+    @Async
+    public ListenableFuture<GisSurveyThirdImportResultDetail<Map<String, List<GisSurveyThirdImportElement>>>> findInvalidProperties(
+            List<Map<String, String>> points, List<Map<String, String>> lines, List<GisMetadataLayerTemplate> pointLayerTemplates
+            , List<GisMetadataLayerTemplate> lineLayerTemplates) throws InterruptedException {
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, "开始执行寻找无效属性   ======>");
+        long begin = System.currentTimeMillis();
+
+        //无效图层结果
+        List<GisSurveyThirdImportElement> invalidLayersResult = new ArrayList<>();
+        //缺失必填结果
+        List<GisSurveyThirdImportElement> missingRequirementsResult = new ArrayList<>();
+        //无效类型结果
+        List<GisSurveyThirdImportElement> invalidTypesResult = new ArrayList<>();
+        //超出范围结果
+        List<GisSurveyThirdImportElement> outRangesResult = new ArrayList<>();
+        //检查点属性
+        for (Map<String, String> point : points) {
+            //响应中断
+            if (Thread.interrupted()) throw new InterruptedException();
+            //点号
+            String no = point.get(GisSurveyImportDefine.POINT.NO);
+            //如点号缺失直接返回必填不存在
+            if (StringUtils.isBlank(no)) {
+                missingRequirementsResult.add(GisSurveyThirdImportElement.create(point
+                        , GisSurveyImportDefine.POINT.NO
+                        , GisSurveyImportDefine.LayerType.POINT
+                ));
+                continue;
+            }
+            //过滤图层
+            GisMetadataLayerTemplate layerTemplate = pointLayerTemplates.stream()
+                    .filter(template -> Objects.equals(point.get(GisSurveyImportDefine.POINT.LAYER), template.getName()))
+                    .findFirst().orElse(null);
+            //图层不存在则加入无效图层结果
+            if (layerTemplate == null)
+                invalidLayersResult.add(GisSurveyThirdImportElement.create(point, GisSurveyImportDefine.LayerType.POINT));
+            else
+                //图层存在则检查图层
+                checkLayer(point, layerTemplate, missingRequirementsResult, invalidTypesResult, GisSurveyImportDefine.LayerType.POINT);
+            //检查坐标超出范围
+            if (checkOutRanges(point))
+                outRangesResult.add(GisSurveyThirdImportElement.create(point, GisSurveyImportDefine.LayerType.POINT));
+        }
+        //检查线属性
+        for (Map<String, String> line : lines) {
+            //响应中断
+            if (Thread.interrupted()) throw new InterruptedException();
+            //上下游点号
+            String upNo = line.get(GisSurveyImportDefine.LINE.UP_NO);
+            String downNo = line.get(GisSurveyImportDefine.LINE.DOWN_NO);
+            //如点号缺失直接返回必填不存在
+            if (StringUtils.isBlank(upNo)) {
+                missingRequirementsResult.add(GisSurveyThirdImportElement.create(line
+                        , GisSurveyImportDefine.LINE.UP_NO
+                        , GisSurveyImportDefine.LayerType.LINE
+                ));
+                continue;
+            }
+            if (StringUtils.isBlank(downNo)) {
+                missingRequirementsResult.add(GisSurveyThirdImportElement.create(line
+                        , GisSurveyImportDefine.LINE.DOWN_NO
+                        , GisSurveyImportDefine.LayerType.LINE
+                ));
+                continue;
+            }
+            //过滤图层
+            GisMetadataLayerTemplate layerTemplate = lineLayerTemplates.stream()
+                    .filter(template -> Objects.equals(template.getName(), line.get(GisSurveyImportDefine.LINE.LAYER)))
+                    .findFirst().orElse(null);
+            //图层不存在则加入无效图层结果
+            if (layerTemplate == null)
+                invalidLayersResult.add(GisSurveyThirdImportElement.create(line, GisSurveyImportDefine.LayerType.LINE));
+            else
+                //图层存在则检查图层
+                checkLayer(line, layerTemplate, missingRequirementsResult, invalidTypesResult, GisSurveyImportDefine.LayerType.LINE);
+            //检查坐标超出范围
+            if (checkOutRanges(line))
+                outRangesResult.add(GisSurveyThirdImportElement.create(line, GisSurveyImportDefine.LayerType.LINE));
+        }
+
+        long end = System.currentTimeMillis();
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName
+                , String.format(
+                        "结束执行寻找无效属性,用时(毫秒):%d"
+                        , (end - begin)
+                )
+        );
+
+        //构建结果
+        Map<String, List<GisSurveyThirdImportElement>> result = new HashMap<>();
+        result.put(GisSurveyImportDefine.RESULT.INVALID_LAYERS, invalidLayersResult);
+        result.put(GisSurveyImportDefine.RESULT.MISSING_REQUIREMENTS, missingRequirementsResult);
+        result.put(GisSurveyImportDefine.RESULT.INVALID_TYPES, invalidTypesResult);
+        result.put(GisSurveyImportDefine.RESULT.OUT_RANGES, outRangesResult);
+        return new AsyncResult<>(new GisSurveyThirdImportResultDetail<>(true, result));
+    }
+
+    /**
+     * 检查超出范围
+     *
+     * @param point 点
+     * @return 超出范围昨状态
+     */
+    public Boolean checkOutRanges(Map<String, String> point) {
+        //获取经纬度字段
+        String latStr = point.get(GisSurveyImportDefine.POINT.LAT);
+        String lngStr = point.get(GisSurveyImportDefine.POINT.LNG);
+        //检查是否字符串
+        if (latStr == null || lngStr == null) return true;
+        //检查是否可解析
+        if (!NumberUtils.isParsable(latStr) || !NumberUtils.isParsable(lngStr)) return true;
+        //解析
+        double lat = Double.parseDouble(latStr);
+        double lng = Double.parseDouble(lngStr);
+        //判断是否在范围
+        return MIN_LAT >= lat || lat >= MAX_LAT || MIN_LNG >= lng || lng >= MAX_LNG;
+    }
+
+    /**
+     * 检查图层
+     *
+     * @param data                      数据
+     * @param layerTemplate             图层模版
+     * @param missingRequirementsResult 缺少必填结果
+     * @param invalidTypesResult        无效类型结果
+     * @param layerType                 图层类型
+     */
+    public void checkLayer(Map<String, String> data, GisMetadataLayerTemplate layerTemplate
+            , List<GisSurveyThirdImportElement> missingRequirementsResult
+            , List<GisSurveyThirdImportElement> invalidTypesResult, GisSurveyImportDefine.LayerType layerType) {
+        //遍历图层属性模版
+        for (GisMetadataPropertyTemplate propertyTemplate : layerTemplate.getPropertyTemplates()) {
+            //排除非必填
+            if (propertyTemplate.getRequired() != 1)
+                continue;
+            //排除code
+            if (Objects.equals(GisSurveyImportDefine.TEMPLATE.CODE, propertyTemplate.getKey()))
+                continue;
+            //模版名称
+            String templateName = propertyTemplate.getName();
+            //点类型模版表头映射
+            if (layerType == GisSurveyImportDefine.LayerType.POINT)
+                switch (propertyTemplate.getKey()) {
+                    case GisSurveyImportDefine.TEMPLATE.LNG:
+                        templateName = GisSurveyImportDefine.POINT.LNG;
+                        break;
+                    case GisSurveyImportDefine.TEMPLATE.LAT:
+                        templateName = GisSurveyImportDefine.POINT.LAT;
+                        break;
+                }
+            //必填不存在则存入缺少必填
+            if (!data.containsKey(templateName))
+                missingRequirementsResult.add(GisSurveyThirdImportElement.create(data,
+                        templateName,
+                        layerType
+                ));
+            else if ((propertyTemplate.getType().equals("float") || propertyTemplate.getType().equals("int"))
+                    && !NumberUtils.isParsable(data.get(templateName)))
+                //存在且类型为数字则判断数字类型
+                invalidTypesResult.add(GisSurveyThirdImportElement.create(data,
+                        data.get(templateName),
+                        layerType
+                ));
+        }
+
+    }
+
+
+}

+ 2 - 0
src/main/java/com/shkpr/service/alambizplugin/constants/ApiURI.java

@@ -27,6 +27,8 @@ public class ApiURI {
     public static final String URI_XXX_SYS_CHECK = "sys-check";
     public static final String URI_XXX_SYS_CHECK_CANCEL = "sys-check-cancel";
     public static final String URI_XXX_SYS_CHECK_RESULTS = "sys-check-results";
+    public static final String URI_XXX_THIRD_IMPORT= "third-import";
+    public static final String URI_XXX_THIRD_IMPORT_CANCEL= "third-import-cancel";
 
     public static final String URI_ACCESS_TOKEN_CHECK = "/kpr-plugin/apply/access-token-check";
     public static final String URI_FILE_BUSI_XXX = "/files/**";

+ 22 - 0
src/main/java/com/shkpr/service/alambizplugin/constants/ExcelEnum.java

@@ -0,0 +1,22 @@
+package com.shkpr.service.alambizplugin.constants;
+
+/**
+ * excel枚举
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public enum ExcelEnum {
+    /**
+     * csv
+     */
+    CSV,
+    /**
+     * xls
+     */
+    XLS,
+    /**
+     * xlsx
+     */
+    XLSX
+}

+ 57 - 0
src/main/java/com/shkpr/service/alambizplugin/constants/GisSurveyImportDefine.java

@@ -0,0 +1,57 @@
+package com.shkpr.service.alambizplugin.constants;
+
+/**
+ * 第三方导入字典
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public interface GisSurveyImportDefine {
+    /**
+     * 图层 枚举
+     */
+    enum LayerType {
+        POINT,
+        LINE
+    }
+
+    /**
+     * 点
+     */
+    interface POINT {
+        String NO = "点号";
+        String LAYER = "点类型";
+        String LNG = "X坐标/经度";
+        String LAT = "Y坐标/纬度";
+    }
+
+    /**
+     * 线
+     */
+    interface LINE {
+        String UP_NO = "起点号";
+        String DOWN_NO = "终点号";
+        String LAYER = "线类型";
+    }
+
+    /**
+     * 模版
+     */
+    interface TEMPLATE {
+        String CODE = "code";
+        String LNG = "lng";
+        String LAT = "lat";
+        String UP_NO = "up_no";
+        String DOWN_NO = "down_no";
+    }
+
+    /**
+     * 结果
+     */
+    interface RESULT{
+        String INVALID_LAYERS = "invalidLayersResult";
+        String MISSING_REQUIREMENTS = "missingRequirementsResult";
+        String INVALID_TYPES = "invalidTypesResult";
+        String OUT_RANGES = "outRangesResult";
+    }
+}

+ 35 - 0
src/main/java/com/shkpr/service/alambizplugin/constants/GisSurveyImportStatusEnum.java

@@ -0,0 +1,35 @@
+package com.shkpr.service.alambizplugin.constants;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 第三方导入状态枚举
+ *
+ * @author 欧阳劲驰
+ * @serial 1.0.0
+ */
+@AllArgsConstructor
+@Getter
+public enum GisSurveyImportStatusEnum {
+    /**
+     * 进行中
+     */
+    IN_PROGRESS(0),
+    /**
+     * 成功
+     */
+    SUCCESS(1),
+    /**
+     * 失败
+     */
+    FAIL(2),
+    /**
+     * 不存在
+     */
+    NOT_EXISTS(3);
+    /**
+     * code
+     */
+    private final Integer code;
+}

+ 4 - 0
src/main/java/com/shkpr/service/alambizplugin/constants/ResponseCode.java

@@ -100,6 +100,10 @@ public enum ResponseCode {
     RESULT_SYSTEM_CHECK_CANCEL_FAILED(40002, "System check cancel failed."),
     RESULT_SYSTEM_CHECK_RESULT_NOT_FOUND(40003, "System check result not found."),
 
+    RESULT_THIRD_IMPORT_FAILED(40010, "Third import failed."),
+    RESULT_THIRD_IMPORT_NOT_FOUND(40011, "Third import not found."),
+    RESULT_THIRD_IMPORT_CANCEL_FAILED(40012, "Third import cancel failed."),
+
     BUSINESS_SYNC_FUN_FAILED(65529,"The Synch operation failed."),
     BUSINESS_DB_REQ_FAILED(65530,"The DB operation failed."),
     BUSINESS_API_ABOLISH(65531,"The Api has been abolished."),

+ 168 - 4
src/main/java/com/shkpr/service/alambizplugin/controller/ApiGisSurveyController.java

@@ -3,26 +3,36 @@ package com.shkpr.service.alambizplugin.controller;
 import com.global.base.log.LogLevelFlag;
 import com.global.base.log.LogPrintMgr;
 import com.shkpr.service.alambizplugin.apiparam.GisSurveyCheckParams;
+import com.shkpr.service.alambizplugin.apiparam.GisSurveyThirdImportParams;
 import com.shkpr.service.alambizplugin.bizservice.GisSurveySystemCheckBizService;
+import com.shkpr.service.alambizplugin.bizservice.GisSurveyThirdImportBizService;
 import com.shkpr.service.alambizplugin.commtools.CommTool;
 import com.shkpr.service.alambizplugin.constants.ApiURI;
 import com.shkpr.service.alambizplugin.constants.GisSurveyCheckStatusEnum;
+import com.shkpr.service.alambizplugin.constants.GisSurveyImportStatusEnum;
 import com.shkpr.service.alambizplugin.constants.LogFlagBusiType;
 import com.shkpr.service.alambizplugin.constants.ResponseCode;
 import com.shkpr.service.alambizplugin.controllerfilter.TokenAuthenticationService;
 import com.shkpr.service.alambizplugin.controllervalid.CommonParamValidSK;
 import com.shkpr.service.alambizplugin.dto.GisSurveySystemCheckResult;
+import com.shkpr.service.alambizplugin.dto.GisSurveyThirdImportResult;
 import com.shkpr.service.alambizplugin.dto.ResponseRes;
 import com.shkpr.service.alambizplugin.exception.SelfException;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.validation.BindingResult;
 import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestHeader;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
 
 import javax.servlet.http.HttpServletRequest;
+import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -34,16 +44,22 @@ public class ApiGisSurveyController {
     private final String mBizType;
     //计数器
     private final AtomicInteger mSeqSysCheckReq;
-    private final AtomicInteger mSeqSysCheckDelReq;
+    private final AtomicInteger mSeqSysCheckCancelReq;
+    private final AtomicInteger mSeqThirdImportReq;
+    private final AtomicInteger mSeqThirdImportCancelReq;
 
     private final GisSurveySystemCheckBizService systemCheckBizService;
+    private final GisSurveyThirdImportBizService thirdImportBizService;
 
-    public ApiGisSurveyController(GisSurveySystemCheckBizService systemCheckBizService) {
+    public ApiGisSurveyController(GisSurveySystemCheckBizService systemCheckBizService, GisSurveyThirdImportBizService thirdImportBizService) {
         mStrClassName = "ApiGisSurveyController";
         mBizType = LogFlagBusiType.BUSI_GIS_SURVEY.toStrValue();
         mSeqSysCheckReq = new AtomicInteger(0);
-        mSeqSysCheckDelReq = new AtomicInteger(0);
+        mSeqSysCheckCancelReq = new AtomicInteger(0);
+        mSeqThirdImportReq = new AtomicInteger(0);
+        mSeqThirdImportCancelReq = new AtomicInteger(0);
         this.systemCheckBizService = systemCheckBizService;
+        this.thirdImportBizService = thirdImportBizService;
     }
 
     /**
@@ -150,7 +166,7 @@ public class ApiGisSurveyController {
         }
         //begin
         long llReqBefore = System.currentTimeMillis();
-        String strRunSeq = String.format("%d-%d", llReqBefore, mSeqSysCheckDelReq.incrementAndGet());
+        String strRunSeq = String.format("%d-%d", llReqBefore, mSeqSysCheckCancelReq.incrementAndGet());
         LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, strUserId
                 , String.format("%s:%s seq:{%s} param:%s begin====>"
                         , strPlatform
@@ -185,4 +201,152 @@ public class ApiGisSurveyController {
                         , resResult.getTimestamp() - llReqBefore));
         return resResult;
     }
+
+
+    /**
+     * 执行第三方导入
+     *
+     * @param request       request
+     * @param strClientType 客户端类型
+     * @param strUserAgent  用户信息
+     * @param files         文件列表
+     * @param operator      操作人
+     * @param jobId         任务id
+     * @param nature        用水性质,supply/drain
+     * @param codeRule      点号规则
+     * @param ignoreFail    是否忽略失败
+     * @return 第三方导入结果
+     */
+    @PostMapping(value = ApiURI.URI_XXX_THIRD_IMPORT)
+    public ResponseRes<GisSurveyThirdImportResult> thirdImport(HttpServletRequest request
+            , @RequestHeader(value = ApiURI.HEADER_CLIENT_TYPE, required = false) String strClientType
+            , @RequestHeader(value = ApiURI.HEADER_USER_AGENT, required = false) String strUserAgent
+            , @RequestParam(value = "files", required = false) List<MultipartFile> files
+            , @RequestParam(value = "operator", required = false) String operator
+            , @RequestParam(value = "jobId", required = false) String jobId
+            , @RequestParam(value = "nature", required = false) String nature
+            , @RequestParam(value = "codeRule", required = false) String codeRule
+            , @RequestParam(value = "ignoreFail", required = false, defaultValue = "false") String ignoreFail) throws SelfException {
+        //入参校验
+        final String URI_PATH = request.getRequestURI();
+        final String strPlatform = CommTool.getPlatformByAgent(strClientType, strUserAgent);
+        final String strUserId = (String) request.getAttribute(TokenAuthenticationService.HEADER_USERID);
+        if (StringUtils.isAnyBlank(operator, jobId, nature) || CollectionUtils.isEmpty(files)) {
+            throw new SelfException(ResponseCode.STATUS_ERROR_PARAM_FORMAT.toStrCode()
+                    , String.format(ApiURI.EXCEPTION_FORMAT
+                    , strPlatform
+                    , URI_PATH
+                    , ResponseCode.STATUS_ERROR_PARAM_FORMAT.toStrMsg()));
+        }
+        //构建入参数
+        GisSurveyThirdImportParams params = new GisSurveyThirdImportParams(files, operator, jobId, nature, codeRule, Boolean.parseBoolean(ignoreFail));
+        //begin
+        long llReqBefore = System.currentTimeMillis();
+        String strRunSeq = String.format("%d-%d", llReqBefore, mSeqThirdImportReq.incrementAndGet());
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, strUserId
+                , String.format("%s:%s seq:{%s} param:%s begin====>"
+                        , strPlatform
+                        , URI_PATH
+                        , strRunSeq
+                        , params));
+        //构建result
+        ResponseRes<GisSurveyThirdImportResult> resResult = new ResponseRes<>();
+        resResult.setRescode(ResponseCode.RESULT_THIRD_IMPORT_FAILED.toStrCode());
+        resResult.setResmsg(ResponseCode.RESULT_THIRD_IMPORT_FAILED.toStrMsg());
+
+        //执行第三方导入
+        GisSurveyThirdImportResult result = thirdImportBizService.thirdImport(params);
+
+        //执行成功
+        if (result != null && !Objects.equals(result.getImportStatus(), GisSurveyImportStatusEnum.FAIL.getCode())) {
+            resResult.setRescode(ResponseCode.RESULT_NORMAL.toStrCode());
+            resResult.setResmsg(ResponseCode.RESULT_NORMAL.toStrMsg());
+            resResult.setResdata(result);
+        }
+        //执行失败
+        if (result != null && Objects.equals(result.getImportStatus(), GisSurveyImportStatusEnum.FAIL.getCode())) {
+            resResult.setResdata(result);
+        }
+        //结果为空
+        if (result == null) {
+            resResult.setRescode(ResponseCode.RESULT_THIRD_IMPORT_NOT_FOUND.toStrCode());
+            resResult.setResmsg(ResponseCode.RESULT_THIRD_IMPORT_NOT_FOUND.toStrMsg());
+        }
+
+        //end
+        resResult.setTimestamp(System.currentTimeMillis());
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, strUserId
+                , String.format("%s:%s seq:{%s} rescode:{%s} resmsg:{%s} time:{%d ms} end<===="
+                        , strPlatform
+                        , URI_PATH
+                        , strRunSeq
+                        , resResult.getRescode()
+                        , resResult.getResmsg()
+                        , resResult.getTimestamp() - llReqBefore));
+        return resResult;
+    }
+
+    /**
+     * 清除第三方导入
+     *
+     * @param request       request
+     * @param strClientType 客户端类型
+     * @param strUserAgent  用户信息
+     * @param jobId         任务id
+     * @return 清除状态
+     * @throws SelfException selfException
+     */
+    @GetMapping(value = ApiURI.URI_XXX_THIRD_IMPORT_CANCEL)
+    public ResponseRes<?> cancelImport(HttpServletRequest request
+            , @RequestHeader(value = ApiURI.HEADER_CLIENT_TYPE, required = false) String strClientType
+            , @RequestHeader(value = ApiURI.HEADER_USER_AGENT, required = false) String strUserAgent
+            , @RequestParam("jobId") String jobId) throws Exception {
+        //入参校验
+        final String URI_PATH = request.getRequestURI();
+        final String strPlatform = CommTool.getPlatformByAgent(strClientType, strUserAgent);
+        final String strUserId = (String) request.getAttribute(TokenAuthenticationService.HEADER_USERID);
+        if (StringUtils.isBlank(jobId)) {
+            throw new SelfException(ResponseCode.STATUS_ERROR_PARAM_FORMAT.toStrCode()
+                    , String.format(ApiURI.EXCEPTION_FORMAT
+                    , strPlatform
+                    , URI_PATH
+                    , ResponseCode.STATUS_ERROR_PARAM_FORMAT.toStrMsg()));
+        }
+        //begin
+        long llReqBefore = System.currentTimeMillis();
+        String strRunSeq = String.format("%d-%d", llReqBefore, mSeqThirdImportCancelReq.incrementAndGet());
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, strUserId
+                , String.format("%s:%s seq:{%s} param:%s begin====>"
+                        , strPlatform
+                        , URI_PATH
+                        , strRunSeq
+                        , jobId));
+        //构建result
+        ResponseRes<Boolean> resResult = new ResponseRes<>();
+        resResult.setRescode(ResponseCode.RESULT_THIRD_IMPORT_CANCEL_FAILED.toStrCode());
+        resResult.setResmsg(ResponseCode.RESULT_THIRD_IMPORT_CANCEL_FAILED.toStrMsg());
+        //清除检查
+        Integer cancelCheck = thirdImportBizService.cancelCheck(jobId);
+        //成功
+        if (Objects.equals(cancelCheck, GisSurveyCheckStatusEnum.SUCCESS.getCode())) {
+            resResult.setRescode(ResponseCode.RESULT_NORMAL.toStrCode());
+            resResult.setResmsg(ResponseCode.RESULT_NORMAL.toStrMsg());
+        }
+        //不存在
+        else if (Objects.equals(cancelCheck, GisSurveyCheckStatusEnum.NOT_EXISTS.getCode())) {
+            resResult.setRescode(ResponseCode.RESULT_THIRD_IMPORT_NOT_FOUND.toStrCode());
+            resResult.setResmsg(ResponseCode.RESULT_THIRD_IMPORT_NOT_FOUND.toStrMsg());
+        }
+        //end
+        resResult.setTimestamp(System.currentTimeMillis());
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, strUserId
+                , String.format("%s:%s seq:{%s} rescode:{%s} resmsg:{%s} time:{%d ms} end<===="
+                        , strPlatform
+                        , URI_PATH
+                        , strRunSeq
+                        , resResult.getRescode()
+                        , resResult.getResmsg()
+                        , resResult.getTimestamp() - llReqBefore));
+        return resResult;
+    }
 }

+ 2 - 0
src/main/java/com/shkpr/service/alambizplugin/controllerfilter/third/ApiJWTGisSurveyBizFilter.java

@@ -22,6 +22,8 @@ public class ApiJWTGisSurveyBizFilter extends JWTAuthenticationFilter {
         msMapURI2Method.put(String.format("%s/%s", ApiURI.URI_GIS_SURVEY_H, ApiURI.URI_XXX_SYS_CHECK), "POST");
         msMapURI2Method.put(String.format("%s/%s", ApiURI.URI_GIS_SURVEY_H, ApiURI.URI_XXX_SYS_CHECK_CANCEL), "POST");
         msMapURI2Method.put(String.format("%s/%s", ApiURI.URI_GIS_SURVEY_H, ApiURI.URI_XXX_SYS_CHECK_RESULTS), "GET");
+        msMapURI2Method.put(String.format("%s/%s", ApiURI.URI_GIS_SURVEY_H, ApiURI.URI_XXX_THIRD_IMPORT), "POST");
+        msMapURI2Method.put(String.format("%s/%s", ApiURI.URI_GIS_SURVEY_H, ApiURI.URI_XXX_THIRD_IMPORT_CANCEL), "GET");
     }
 
     public ApiJWTGisSurveyBizFilter(String url, AuthenticationManager authenticationManager){

+ 27 - 0
src/main/java/com/shkpr/service/alambizplugin/dbdao/mapper/GisMetadataLayerTemplateMapper.java

@@ -0,0 +1,27 @@
+package com.shkpr.service.alambizplugin.dbdao.mapper;
+
+import com.shkpr.service.alambizplugin.dto.GisMetadataLayerTemplate;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * gis元数据图层定义模板mapper
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Mapper
+public interface GisMetadataLayerTemplateMapper {
+
+    /**
+     * 根据用水类别和图层名集合查询
+     *
+     * @param nature 用水类别
+     * @param names  图层名集合
+     * @return 图层定义模版
+     */
+    List<GisMetadataLayerTemplate> findByNatureAndNameIn(@Param("nature") String nature, @Param("names") List<String> names);
+
+}

+ 14 - 0
src/main/java/com/shkpr/service/alambizplugin/dbdao/mapper/GisMetadataPropertyTemplateMapper.java

@@ -0,0 +1,14 @@
+package com.shkpr.service.alambizplugin.dbdao.mapper;
+
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * gis元数据图层属性定义模板mapper
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Mapper
+public interface GisMetadataPropertyTemplateMapper {
+
+}

+ 36 - 0
src/main/java/com/shkpr/service/alambizplugin/dbdao/services/GisMetadataLayerTemplateServiceImpl.java

@@ -0,0 +1,36 @@
+package com.shkpr.service.alambizplugin.dbdao.services;
+
+import com.shkpr.service.alambizplugin.dbdao.mapper.GisMetadataLayerTemplateMapper;
+import com.shkpr.service.alambizplugin.dbdao.services.intef.GisMetadataLayerTemplateService;
+import com.shkpr.service.alambizplugin.dto.GisMetadataLayerTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * gis元数据图层定义模板service实现
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Service
+public class GisMetadataLayerTemplateServiceImpl implements GisMetadataLayerTemplateService {
+    final
+    GisMetadataLayerTemplateMapper layerTemplateMapper;
+
+    public GisMetadataLayerTemplateServiceImpl(GisMetadataLayerTemplateMapper layerTemplateMapper) {
+        this.layerTemplateMapper = layerTemplateMapper;
+    }
+
+    /**
+     * 根据用水类别和图层名集合查询
+     *
+     * @param nature 用水类别
+     * @param names  图层名集合
+     * @return 图层定义模版
+     */
+    @Override
+    public List<GisMetadataLayerTemplate> findByNatureAndNameIn(String nature, List<String> names) {
+        return layerTemplateMapper.findByNatureAndNameIn(nature, names);
+    }
+}

+ 22 - 0
src/main/java/com/shkpr/service/alambizplugin/dbdao/services/intef/GisMetadataLayerTemplateService.java

@@ -0,0 +1,22 @@
+package com.shkpr.service.alambizplugin.dbdao.services.intef;
+
+import com.shkpr.service.alambizplugin.dto.GisMetadataLayerTemplate;
+
+import java.util.List;
+
+/**
+ * gis元数据图层定义模板service实现
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public interface GisMetadataLayerTemplateService {
+    /**
+     * 根据用水类别和图层名集合查询
+     *
+     * @param nature 用水类别
+     * @param names  图层名集合
+     * @return 图层定义模版
+     */
+    List<GisMetadataLayerTemplate> findByNatureAndNameIn(String nature, List<String> names);
+}

+ 77 - 0
src/main/java/com/shkpr/service/alambizplugin/dto/GisMetadataLayerTemplate.java

@@ -0,0 +1,77 @@
+package com.shkpr.service.alambizplugin.dto;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * gis元数据图层定义模板
+ */
+@Data
+public class GisMetadataLayerTemplate {
+    /**
+     * 主键
+     */
+    private Long id;
+
+    /**
+     * 用水类别
+     */
+    private String nature;
+
+    /**
+     * 图层标识符key
+     */
+    private String key;
+
+    /**
+     * 图层所属种类
+     */
+    private String kind;
+
+    /**
+     * 图层名称
+     */
+    private String name;
+
+    /**
+     * 相关图标
+     */
+    private String icon;
+
+    /**
+     * 相关图标颜色
+     */
+    private String color;
+
+    /**
+     * 状态:0--禁用;1--启用
+     */
+    private Short status;
+
+    /**
+     * 相关描述
+     */
+    private String remark;
+
+    /**
+     * 创建者
+     */
+    private String creator;
+
+    private String param1;
+
+    private String param2;
+
+    private LocalDateTime createTime;
+
+    private LocalDateTime updateTime;
+
+    private Short ordering;
+
+    /**
+     * 属性模版集合
+     */
+    private List<GisMetadataPropertyTemplate> propertyTemplates;
+}

+ 111 - 0
src/main/java/com/shkpr/service/alambizplugin/dto/GisMetadataPropertyTemplate.java

@@ -0,0 +1,111 @@
+package com.shkpr.service.alambizplugin.dto;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * gis元数据图层属性定义模板
+ */
+@Data
+public class GisMetadataPropertyTemplate {
+    /**
+     * 主键
+     */
+    private Long id;
+
+    /**
+     * 用水性质:supply/drain
+     */
+    private String nature;
+
+    /**
+     * 图层标识符key
+     */
+    private String layer;
+
+    /**
+     * 属性标识符key
+     */
+    private String key;
+
+    /**
+     * 属性名称
+     */
+    private String name;
+
+    /**
+     * 取值类型:string/float/int
+     */
+    private String type;
+
+    /**
+     * 取值范围列表
+     */
+    private String ranges;
+
+    /**
+     * 控件输入类型
+     */
+    private String widget;
+
+    /**
+     * 默认取值
+     */
+    private String defaults;
+
+    /**
+     * 是否必填:0--非必填;1--必填
+     */
+    private Short required;
+
+    /**
+     * 显示顺序
+     */
+    private Short ordering;
+
+    /**
+     * 数据来源
+     */
+    private String source;
+
+    /**
+     * 取值单位
+     */
+    private String unit;
+
+    /**
+     * 是否可编辑:0--不可编辑;1--可编辑
+     */
+    private Short editable;
+
+    /**
+     * 浮点数精度位数
+     */
+    private Short precisions;
+
+    /**
+     * 状态:0--禁用(隐藏);1--启用(正常)
+     */
+    private Short status;
+
+    /**
+     * 相关描述
+     */
+    private String remark;
+
+    /**
+     * 创建人
+     */
+    private String creator;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 82 - 0
src/main/java/com/shkpr/service/alambizplugin/dto/GisSurveyThirdImportElement.java

@@ -0,0 +1,82 @@
+package com.shkpr.service.alambizplugin.dto;
+
+import com.shkpr.service.alambizplugin.constants.GisMetadataDefine;
+import com.shkpr.service.alambizplugin.constants.GisSurveyImportDefine;
+import lombok.Data;
+
+import java.util.Map;
+
+/**
+ * 第三方导入元素dto
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+public class GisSurveyThirdImportElement {
+    /**
+     * 点号
+     */
+    private String no;
+    /**
+     * 上游点号
+     */
+    private String upNO;
+    /**
+     * 下游点号
+     */
+    private String downNO;
+    /**
+     * 元素分类:point--点;line--线;face--面
+     */
+    private String kind;
+    /**
+     * 图层名称
+     */
+    private String layerName;
+    /**
+     * 属性名称
+     */
+    private String propertyName;
+
+    public GisSurveyThirdImportElement(String kind, String no) {
+        this.kind = kind;
+        this.no = no;
+    }
+
+    public GisSurveyThirdImportElement(String kind, String no, String layerName, String propertyName) {
+        this.kind = kind;
+        this.no = no;
+        this.layerName = layerName;
+        this.propertyName = propertyName;
+    }
+
+    public GisSurveyThirdImportElement(String kind, String upNO, String downNO, String layerName, String propertyName) {
+        this.kind = kind;
+        this.upNO = upNO;
+        this.downNO = downNO;
+        this.layerName = layerName;
+        this.propertyName = propertyName;
+    }
+
+    public static GisSurveyThirdImportElement create(Map<String, String> data, GisSurveyImportDefine.LayerType layerType) {
+        return create(data, null, layerType);
+    }
+
+    public static GisSurveyThirdImportElement create(Map<String, String> data, String propertyName
+            , GisSurveyImportDefine.LayerType layerType) {
+        //点号
+        String no = data.get(GisSurveyImportDefine.POINT.NO);
+        String upNo = data.get(GisSurveyImportDefine.LINE.UP_NO);
+        String Down = data.get(GisSurveyImportDefine.LINE.DOWN_NO);
+        //根据类型创建
+        if (layerType == GisSurveyImportDefine.LayerType.POINT) {
+            return new GisSurveyThirdImportElement(GisMetadataDefine.TYPE_KINE.POINT, no
+                    , data.get(GisSurveyImportDefine.POINT.LAYER), propertyName);
+        } else if (layerType == GisSurveyImportDefine.LayerType.LINE) {
+            return new GisSurveyThirdImportElement(GisMetadataDefine.TYPE_KINE.LINE, upNo, Down
+                    , data.get(GisSurveyImportDefine.LINE.LAYER), propertyName);
+        }
+        return null;
+    }
+}

+ 124 - 0
src/main/java/com/shkpr/service/alambizplugin/dto/GisSurveyThirdImportResult.java

@@ -0,0 +1,124 @@
+package com.shkpr.service.alambizplugin.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.shkpr.service.alambizplugin.apiparam.GisSurveyThirdImportParams;
+import com.shkpr.service.alambizplugin.constants.GisSurveyImportStatusEnum;
+import lombok.Data;
+import org.springframework.beans.BeanUtils;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 第三方导入返回dto
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+public class GisSurveyThirdImportResult {
+    /**
+     * 检查状态:0:进行中,1:成功,2:失败,3:不存在
+     */
+    private Integer importStatus;
+
+    /**
+     * 任务id
+     */
+    private String jobId;
+    /**
+     * 当前操作人id
+     */
+    private String operator;
+    /**
+     * 请求导入时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh_CN", timezone = "Asia/Shanghai")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime requestTime;
+    /**
+     * 完成导入时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh_CN", timezone = "Asia/Shanghai")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime completeTime;
+
+    /**
+     * 无效图层结果
+     */
+    private GisSurveyThirdImportResultDetail<List<GisSurveyThirdImportElement>> invalidLayersResult = new GisSurveyThirdImportResultDetail<>();
+
+    /**
+     * 缺失必填结果
+     */
+    private GisSurveyThirdImportResultDetail<List<GisSurveyThirdImportElement>> missingRequirementsResult = new GisSurveyThirdImportResultDetail<>();
+
+    /**
+     * 无效类型结果
+     */
+    private GisSurveyThirdImportResultDetail<List<GisSurveyThirdImportElement>> invalidTypesResult = new GisSurveyThirdImportResultDetail<>();
+
+    /**
+     * 超出范围结果
+     */
+    private GisSurveyThirdImportResultDetail<List<GisSurveyThirdImportElement>> outRangesResult = new GisSurveyThirdImportResultDetail<>();
+
+    /**
+     * 重复点号结果
+     */
+    private GisSurveyThirdImportResultDetail<List<GisSurveyThirdImportElement>> duplicatePointsResult = new GisSurveyThirdImportResultDetail<>();
+
+    /**
+     * 无效线结果
+     */
+    private GisSurveyThirdImportResultDetail<List<GisSurveyThirdImportElement>> invalidLinesResult = new GisSurveyThirdImportResultDetail<>();
+
+    /**
+     * 进行中
+     */
+    public static GisSurveyThirdImportResult inProgress(GisSurveyThirdImportParams params, GisSurveyThirdImportSubtask subtask, LocalDateTime requestTime) {
+        GisSurveyThirdImportResult result = new GisSurveyThirdImportResult();
+        BeanUtils.copyProperties(params, result);
+
+        //设置子任务状态
+        if (subtask != null) {
+            if (subtask.getInvalidPropertiesFuture() != null) {
+                result.getInvalidLayersResult().setDone(subtask.getInvalidPropertiesFuture().isDone());
+                result.getMissingRequirementsResult().setDone(subtask.getInvalidPropertiesFuture().isDone());
+                result.getInvalidTypesResult().setDone(subtask.getInvalidPropertiesFuture().isDone());
+                result.getOutRangesResult().setDone(subtask.getInvalidPropertiesFuture().isDone());
+            }
+            if (subtask.getDuplicatePointsFuture() != null)
+                result.getDuplicatePointsResult().setDone(subtask.getDuplicatePointsFuture().isDone());
+            if (subtask.getInvalidLinesFuture() != null)
+                result.getInvalidLinesResult().setDone(subtask.getInvalidLinesFuture().isDone());
+        }
+
+        result.setImportStatus(GisSurveyImportStatusEnum.IN_PROGRESS.getCode());
+        result.setRequestTime(requestTime);
+        return result;
+    }
+
+    /**
+     * 成功
+     */
+    public static GisSurveyThirdImportResult success(GisSurveyThirdImportParams params) {
+        GisSurveyThirdImportResult result = new GisSurveyThirdImportResult();
+        BeanUtils.copyProperties(params, result);
+        result.setImportStatus(GisSurveyImportStatusEnum.SUCCESS.getCode());
+        result.setRequestTime(LocalDateTime.now());
+        return result;
+    }
+
+    /**
+     * 失败
+     */
+    public static GisSurveyThirdImportResult fail(GisSurveyThirdImportParams params) {
+        GisSurveyThirdImportResult result = new GisSurveyThirdImportResult();
+        BeanUtils.copyProperties(params, result);
+        result.setImportStatus(GisSurveyImportStatusEnum.FAIL.getCode());
+        result.setRequestTime(LocalDateTime.now());
+        return result;
+    }
+}

+ 27 - 0
src/main/java/com/shkpr/service/alambizplugin/dto/GisSurveyThirdImportResultDetail.java

@@ -0,0 +1,27 @@
+package com.shkpr.service.alambizplugin.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * 第三方导入结果详情
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+public class GisSurveyThirdImportResultDetail<T> {
+    /**
+     * 完成状态
+     */
+    private Boolean done;
+    /**
+     * 结果
+     */
+    private T results;
+}

+ 30 - 0
src/main/java/com/shkpr/service/alambizplugin/dto/GisSurveyThirdImportSubtask.java

@@ -0,0 +1,30 @@
+package com.shkpr.service.alambizplugin.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.util.concurrent.ListenableFuture;
+
+/**
+ * 第三方导入子任务
+ *
+ * @author 欧阳劲驰
+ * @since 0.0.1
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+public class GisSurveyThirdImportSubtask {
+    /**
+     * 无效属性任务
+     */
+    private ListenableFuture<? extends GisSurveyThirdImportResultDetail<?>> invalidPropertiesFuture;
+    /**
+     * 重复点号任务
+     */
+    private ListenableFuture<? extends GisSurveyThirdImportResultDetail<?>> duplicatePointsFuture;
+    /**
+     * 无效线任务
+     */
+    private ListenableFuture<? extends GisSurveyThirdImportResultDetail<?>> invalidLinesFuture;
+}

+ 19 - 2
src/main/java/com/shkpr/service/alambizplugin/globalmgr/ScheduleTaskMgr.java

@@ -4,7 +4,9 @@ import com.global.base.log.LogLevelFlag;
 import com.global.base.log.LogPrintMgr;
 import com.global.base.thread.ThreadPoolProxy;
 import com.shkpr.service.alambizplugin.bizservice.GisSurveySystemCheckBizService;
+import com.shkpr.service.alambizplugin.bizservice.GisSurveyThirdImportBizService;
 import com.shkpr.service.alambizplugin.commproperties.GisSurveySystemCheckProperties;
+import com.shkpr.service.alambizplugin.commproperties.GisSurveyThirdImportProperties;
 import com.shkpr.service.alambizplugin.commtools.TimeTool;
 import com.shkpr.service.alambizplugin.components.GisDynamicDataSource;
 import com.shkpr.service.alambizplugin.components.locks.AlarmOrderLockMgr;
@@ -22,17 +24,22 @@ import java.util.Map;
 import java.util.Set;
 
 @Component
-@EnableConfigurationProperties(GisSurveySystemCheckProperties.class)
+@EnableConfigurationProperties({GisSurveySystemCheckProperties.class,GisSurveyThirdImportProperties.class})
 public class ScheduleTaskMgr {
     private final String mStrClassName;
     private final GisSurveySystemCheckProperties systemCheckProperties;
+    private final GisSurveyThirdImportProperties thirdImportProperties;
     private final GisSurveySystemCheckBizService systemCheckBizService;
+    private final GisSurveyThirdImportBizService thirdImportBizService;
 
 
-    public ScheduleTaskMgr(GisSurveySystemCheckProperties systemCheckProperties, GisSurveySystemCheckBizService systemCheckBizService) {
+    public ScheduleTaskMgr(GisSurveySystemCheckProperties systemCheckProperties,GisSurveyThirdImportProperties thirdImportProperties
+            , GisSurveySystemCheckBizService systemCheckBizService,GisSurveyThirdImportBizService thirdImportBizService) {
         mStrClassName = this.getClass().getSimpleName();
         this.systemCheckProperties = systemCheckProperties;
+        this.thirdImportProperties = thirdImportProperties;
         this.systemCheckBizService = systemCheckBizService;
+        this.thirdImportBizService = thirdImportBizService;
     }
 
     @PostConstruct
@@ -55,6 +62,16 @@ public class ScheduleTaskMgr {
         if (systemCheckProperties.getTtl() != null) systemCheckBizService.expireResult(systemCheckProperties.getTtl());
     }
 
+    /**
+     * 第三方导入超时任务
+     */
+    @Scheduled(fixedRateString = "${third-import.ttl-check-interval}")
+    public void thirdImportTasksTtl() {
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, LogFlagBusiType.BUSI_GIS_SURVEY.toStrValue(), mStrClassName
+                , String.format("开始执行第三方导入超时任务 ttl:%s ======>", thirdImportProperties.getTtl()));
+        if (thirdImportProperties.getTtl() != null) thirdImportBizService.expireResult(thirdImportProperties.getTtl());
+    }
+
     @Scheduled(cron = "${cron.refresh.timer.clock}")
     public void taskRefreshTimeRes() {
         TimeTool.refreshUTCTimeRes();

+ 9 - 5
src/main/resources/application.properties

@@ -140,14 +140,18 @@ des.proxy.fdfs=http://116.63.130.83:9999
 
 #=============系统检查========================
 #超时时间
-system-check.ttl= 24h
+system-check.ttl=24h
 #检查周期(毫秒)
-system-check.ttl-check-interval= 60000
+system-check.ttl-check-interval=60000
 #资源路径
-system-check.resource-path= /home/kprCloud/alam_dma_kpr_plugin/sys-check-results/
+system-check.resource-path=/home/kprCloud/alam_dma_kpr_plugin/sys-check-results/
 #结果滞后时间
-system-check.result-lag-duration= 30m
-
+system-check.result-lag-duration=30m
+#=============第三方导入========================
+#超时时间
+third-import.ttl=24h
+#检查周期(毫秒)
+third-import.ttl-check-interval=60000
 
 
 

+ 93 - 0
src/main/resources/mapper/GisMetadataLayerTemplateMapper.xml

@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.shkpr.service.alambizplugin.dbdao.mapper.GisMetadataLayerTemplateMapper">
+    <resultMap id="BaseResultMap" type="com.shkpr.service.alambizplugin.dto.GisMetadataLayerTemplate">
+        <!--@Table k3_gis_metadata_layer_template-->
+        <id column="nature" jdbcType="VARCHAR" property="nature"/>
+        <id column="key" jdbcType="VARCHAR" property="key"/>
+        <result column="id" jdbcType="BIGINT" property="id"/>
+        <result column="kind" jdbcType="VARCHAR" property="kind"/>
+        <result column="name" jdbcType="VARCHAR" property="name"/>
+        <result column="icon" jdbcType="VARCHAR" property="icon"/>
+        <result column="color" jdbcType="VARCHAR" property="color"/>
+        <result column="status" jdbcType="SMALLINT" property="status"/>
+        <result column="remark" jdbcType="VARCHAR" property="remark"/>
+        <result column="creator" jdbcType="VARCHAR" property="creator"/>
+        <result column="param1" jdbcType="VARCHAR" property="param1"/>
+        <result column="param2" jdbcType="VARCHAR" property="param2"/>
+        <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
+        <result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
+        <result column="ordering" jdbcType="SMALLINT" property="ordering"/>
+        <collection property="propertyTemplates"
+                    ofType="com.shkpr.service.alambizplugin.dto.GisMetadataPropertyTemplate">
+            <id column="property_nature" jdbcType="VARCHAR" property="nature"/>
+            <id column="property_layer" jdbcType="VARCHAR" property="layer"/>
+            <id column="property_key" jdbcType="VARCHAR" property="key"/>
+            <result column="property_id" jdbcType="BIGINT" property="id"/>
+            <result column="property_name" jdbcType="VARCHAR" property="name"/>
+            <result column="property_type" jdbcType="VARCHAR" property="type"/>
+            <result column="property_ranges" jdbcType="VARCHAR" property="ranges"/>
+            <result column="property_widget" jdbcType="VARCHAR" property="widget"/>
+            <result column="property_defaults" jdbcType="VARCHAR" property="defaults"/>
+            <result column="property_required" jdbcType="SMALLINT" property="required"/>
+            <result column="property_ordering" jdbcType="SMALLINT" property="ordering"/>
+            <result column="property_source" jdbcType="VARCHAR" property="source"/>
+            <result column="property_unit" jdbcType="VARCHAR" property="unit"/>
+            <result column="property_editable" jdbcType="SMALLINT" property="editable"/>
+            <result column="property_precisions" jdbcType="SMALLINT" property="precisions"/>
+            <result column="property_status" jdbcType="SMALLINT" property="status"/>
+            <result column="property_remark" jdbcType="VARCHAR" property="remark"/>
+            <result column="property_creator" jdbcType="VARCHAR" property="creator"/>
+            <result column="property_create_time" jdbcType="TIMESTAMP" property="createTime"/>
+            <result column="property_update_time" jdbcType="TIMESTAMP" property="updateTime"/>
+        </collection>
+    </resultMap>
+
+    <select id="findByNatureAndNameIn" resultMap="BaseResultMap">
+        select mlt.id,
+        mlt.nature,
+        mlt.kind,
+        mlt.key,
+        mlt.name,
+        mlt.icon,
+        mlt.color,
+        mlt.status,
+        mlt.remark,
+        mlt.creator,
+        mlt.param1,
+        mlt.param2,
+        mlt.create_time,
+        mlt.update_time,
+        mlt.ordering,
+        mpt.id as property_id,
+        mpt.nature as property_nature,
+        mpt.layer as property_layer,
+        mpt.key as property_key,
+        mpt.name as property_name,
+        mpt.type as property_type,
+        mpt.ranges as property_ranges,
+        mpt.widget as property_widget,
+        mpt.defaults as property_defaults,
+        mpt.required as property_required,
+        mpt.ordering as property_ordering,
+        mpt.source as property_source,
+        mpt.unit as property_unit,
+        mpt.editable as property_editable,
+        mpt.precisions as property_precisions,
+        mpt.status as property_status,
+        mpt.remark as property_remark,
+        mpt.creator as property_creator,
+        mpt.create_time as property_create_time,
+        mpt.update_time as property_update_time
+        from k3_gis_metadata_layer_template mlt
+        left join k3_gis_metadata_property_template mpt
+        on mlt.nature = mpt.nature and mlt.key = mpt.layer and mpt.status = 1
+        where mlt.nature = #{nature,jdbcType=VARCHAR}
+        and mlt.status = 1
+        and mlt.name in
+        <foreach item="item" index="index" collection="names"
+                 open="(" separator="," close=")">
+            #{item,jdbcType=VARCHAR}
+        </foreach>
+    </select>
+</mapper>

+ 5 - 0
src/main/resources/mapper/GisMetadataPropertyTemplateMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.shkpr.service.alambizplugin.dbdao.mapper.GisMetadataPropertyTemplateMapper">
+
+</mapper>