Browse Source

fix conflict

lixing 3 years ago
parent
commit
ebf11b0033
51 changed files with 4590 additions and 61 deletions
  1. 0 2
      dmp-alarm/pom.xml
  2. 11 10
      dmp-alarm/src/main/resources/logback-spring.xml
  3. 1 1
      dmp-common/src/main/java/com/persagy/dmp/common/excel/ExcelUtils.java
  4. 12 11
      dmp-org/src/main/resources/logback-spring.xml
  5. 0 1
      dmp-rwd-datautils/pom.xml
  6. 1 1
      dmp-rwd-datautils/src/test/java/com/persagy/dmp/rwd/dic/ExcelUtils.java
  7. 1 1
      dmp-rwd-datautils/src/test/java/com/persagy/dmp/rwd/dic/ExcelUtilsForEdit.java
  8. 0 1
      dmp-rwd-edit/pom.xml
  9. 63 6
      dmp-rwd/pom.xml
  10. 59 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/config/DefaultAsycTaskConfig.java
  11. 75 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/constants/CommonConstant.java
  12. 64 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/constants/CommonObjectColumnEnum.java
  13. 54 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/constants/EquipObjectColumnEnum.java
  14. 62 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/constants/ErrorEnum.java
  15. 30 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/constants/GraphCodeEnum.java
  16. 36 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/constants/RelCodeEnum.java
  17. 54 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/constants/SystemObjectColumnEnum.java
  18. 108 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/controller/BatchHandleObjectController.java
  19. 2 1
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/entity/ObjectInstance.java
  20. 28 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/feign/DicClient.java
  21. 109 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/handler/BusinessException.java
  22. 71 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/handler/ResponseCode.java
  23. 152 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/handler/SpringHelper.java
  24. 284 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/handler/TypeConvertUtil.java
  25. 24 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/init/InitRunner.java
  26. 23 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/model/rwd/RelCodeDTO.java
  27. 19 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/model/rwd/RelDTO.java
  28. 91 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/model/rwd/UploadDTO.java
  29. 33 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/repository/FuncidDefMapper.java
  30. 3 8
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/repository/ObjectInstanceRepository.java
  31. 26 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/repository/ProjectDao.java
  32. 1 1
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/service/BaseService.java
  33. 38 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/service/BatchHandleObjectService.java
  34. 98 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/service/DownloadService.java
  35. 2 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/service/InitService.java
  36. 4 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/service/ObjectInstanceQueryService.java
  37. 1276 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/service/impl/BatchHandleObjectServiceImpl.java
  38. 119 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/util/FileUtil.java
  39. 55 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/validators/service/FileCheckService.java
  40. 438 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/validators/service/impl/AbstractFileCheckService.java
  41. 376 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/validators/service/impl/CommonFileCheckServiceImpl.java
  42. 271 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/validators/service/impl/EquipFileCheckServiceImpl.java
  43. 253 0
      dmp-rwd/src/main/java/com/persagy/dmp/rwd/validators/service/impl/SystemFileCheckServiceImpl.java
  44. 5 1
      dmp-rwd/src/main/resources/application.yml
  45. BIN
      dmp-rwd/src/main/resources/arthas.zip
  46. 6 1
      dmp-rwd/src/main/resources/bootstrap.yml
  47. 12 11
      dmp-rwd/src/main/resources/logback-spring.xml
  48. 60 0
      dmp-rwd/src/main/resources/mapper/FuncidDefMapper.xml
  49. 72 1
      dmp-rwd/src/main/resources/mapper/ProjectDao.xml
  50. BIN
      dmp-rwd/src/main/resources/template/ObjectInfoTemplate.xlsx
  51. 8 3
      pom.xml

+ 0 - 2
dmp-alarm/pom.xml

@@ -111,8 +111,6 @@
         <dependency>
             <groupId>cn.hutool</groupId>
             <artifactId>hutool-all</artifactId>
-            <version>5.4.3</version>
-            <scope>compile</scope>
         </dependency>
     </dependencies>
 

+ 11 - 10
dmp-alarm/src/main/resources/logback-spring.xml

@@ -4,6 +4,7 @@
     <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
     <property name="log_pattern" value="%-30thread %d{yyyyMMdd HH:mm:ss.SSS} %-5level %logger{140} - %msg%n"/>
     <property name="app_name" value="alarm"/>
+    <springProperty name="LOG_LEVEL" scope="context" source="persagy.dmp.alarm.log.level" defaultValue="INFO"/>
     <springProperty scope="context" name="log_path" source="persagy.log.path"/>
     <property name="log_file" value="${log_path}/${app_name}"/>
     <property name="rabbit_log_file" value="${log_path}/${app_name}/rabbit/"/>
@@ -36,32 +37,32 @@
         </encoder>
     </appender>
 
-    <logger name="org.hibernate" level="INFO"/>
-    <logger name="org.springframework" level="INFO"/>
-    <logger name="com.netflix" level="WARN"/>
-    <logger name="org.apache.http" level="INFO"/>
+    <logger name="org.hibernate" level="${LOG_LEVEL}"/>
+    <logger name="org.springframework" level="${LOG_LEVEL}"/>
+    <logger name="com.netflix" level="${LOG_LEVEL}"/>
+    <logger name="org.apache.http" level="${LOG_LEVEL}"/>
     <logger name="com.persagy.dmp.alarm.jms.RabbitmqConfig" level="ERROR">
         <appender-ref ref="rabbitmq"/>
     </logger>
 
     <springProfile name="dev">
-        <logger name="org.hibernate.SQL" level="DEBUG"/>
-        <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE"/>
+        <logger name="org.hibernate.SQL" level="${LOG_LEVEL}"/>
+        <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="${LOG_LEVEL}"/>
         <root level="info">
             <appender-ref ref="stdout"/>
         </root>
     </springProfile>
 
     <springProfile name="test">
-        <logger name="org.hibernate.SQL" level="DEBUG"/>
-        <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE"/>
-        <root level="info">
+        <logger name="org.hibernate.SQL" level="${LOG_LEVEL}"/>
+        <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="${LOG_LEVEL}"/>
+        <root level="${LOG_LEVEL}">
             <appender-ref ref="file"/>
         </root>
     </springProfile>
 
     <springProfile name="prod">
-        <root level="info">
+        <root level="${LOG_LEVEL}">
             <appender-ref ref="file"/>
         </root>
     </springProfile>

+ 1 - 1
dmp-common/src/main/java/com/persagy/dmp/common/excel/ExcelUtils.java

@@ -11,7 +11,7 @@ import java.util.*;
 public class ExcelUtils {
 
     public static Object parseCell(Cell cell, String type) {
-        CellType cellType = cell.getCellTypeEnum();
+        CellType cellType = cell.getCellType();
         if ("string".equalsIgnoreCase(type)) {
             if (cellType == CellType.STRING) {
                 return cell.getStringCellValue();

+ 12 - 11
dmp-org/src/main/resources/logback-spring.xml

@@ -3,6 +3,7 @@
 
     <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
     <property name="log_pattern" value="%-30thread %d{yyyyMMdd HH:mm:ss.SSS} %-5level %logger{140} - %msg%n"/>
+    <springProperty name="LOG_LEVEL" scope="context" source="persagy.dmp.org.log.level" defaultValue="INFO"/>
     <property name="app_name" value="org"/>
     <springProperty scope="context" name="log_path" source="persagy.log.path"/>
     <property name="log_file" value="${log_path}/${app_name}"/>
@@ -25,30 +26,30 @@
         </encoder>
     </appender>
 
-    <logger name="org.hibernate" level="INFO"/>
-    <logger name="org.springframework" level="INFO"/>
-    <logger name="com.netflix" level="INFO"/>
-    <logger name="org.apache.http" level="INFO"/>
+    <logger name="org.hibernate" level="${LOG_LEVEL}"/>
+    <logger name="org.springframework" level="${LOG_LEVEL}"/>
+    <logger name="com.netflix" level="${LOG_LEVEL}"/>
+    <logger name="org.apache.http" level="${LOG_LEVEL}"/>
 
     <springProfile name="dev">
-        <logger name="org.hibernate.SQL" level="DEBUG"/>
-        <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE"/>
-        <root level="INFO">
+        <logger name="org.hibernate.SQL" level="${LOG_LEVEL}"/>
+        <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="${LOG_LEVEL}"/>
+        <root level="${LOG_LEVEL}">
             <appender-ref ref="stdout"/>
         </root>
     </springProfile>
 
     <springProfile name="test">
-        <logger name="org.hibernate.SQL" level="DEBUG"/>
-        <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE"/>
-        <root level="INFO">
+        <logger name="org.hibernate.SQL" level="${LOG_LEVEL}"/>
+        <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="${LOG_LEVEL}"/>
+        <root level="${LOG_LEVEL}">
             <appender-ref ref="file"/>
             <appender-ref ref="stdout"/>
         </root>
     </springProfile>
 
     <springProfile name="prod">
-        <root level="info">
+        <root level="${LOG_LEVEL}">
             <appender-ref ref="file"/>
         </root>
     </springProfile>

+ 0 - 1
dmp-rwd-datautils/pom.xml

@@ -69,7 +69,6 @@
         <dependency>
             <groupId>cn.hutool</groupId>
             <artifactId>hutool-all</artifactId>
-            <version>5.7.2</version>
         </dependency>
     </dependencies>
 </project>

+ 1 - 1
dmp-rwd-datautils/src/test/java/com/persagy/dmp/rwd/dic/ExcelUtils.java

@@ -25,7 +25,7 @@ public class ExcelUtils {
         if (cell == null) {
             return null;
         }
-        CellType cellType = cell.getCellTypeEnum();
+        CellType cellType = cell.getCellType();
         if ("string".equalsIgnoreCase(type)) {
             if (cellType == CellType.STRING) {
                 String val = cell.getStringCellValue();

+ 1 - 1
dmp-rwd-datautils/src/test/java/com/persagy/dmp/rwd/dic/ExcelUtilsForEdit.java

@@ -39,7 +39,7 @@ public class ExcelUtilsForEdit {
         if (cell == null) {
             return null;
         }
-        CellType cellType = cell.getCellTypeEnum();
+        CellType cellType = cell.getCellType();
         if ("string".equalsIgnoreCase(type)) {
             if (cellType == CellType.STRING) {
                 String val = cell.getStringCellValue();

+ 0 - 1
dmp-rwd-edit/pom.xml

@@ -101,7 +101,6 @@
         <dependency>
             <groupId>cn.hutool</groupId>
             <artifactId>hutool-all</artifactId>
-            <version>5.7.2</version>
         </dependency>
         <dependency>
             <groupId>commons-lang</groupId>

+ 63 - 6
dmp-rwd/pom.xml

@@ -21,11 +21,31 @@
             <groupId>com.persagy</groupId>
             <artifactId>dmp-common</artifactId>
             <version>4.0.0</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.poi</groupId>
+                    <artifactId>poi</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.poi</groupId>
+                    <artifactId>poi-ooxml</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>com.persagy</groupId>
             <artifactId>dmp-rwd-funcid-parser</artifactId>
             <version>4.0.0</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.poi</groupId>
+                    <artifactId>poi</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.poi</groupId>
+                    <artifactId>poi-ooxml</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
@@ -49,7 +69,6 @@
         <dependency>
             <groupId>cn.hutool</groupId>
             <artifactId>hutool-all</artifactId>
-            <version>5.7.2</version>
         </dependency>
         <dependency>
             <groupId>com.alibaba</groupId>
@@ -57,8 +76,33 @@
             <version>1.1.22</version>
         </dependency>
         <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>5.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi</artifactId>
+            <version>5.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml-lite</artifactId>
+            <version>5.0.0</version>
+        </dependency>
+        <dependency>
             <groupId>com.querydsl</groupId>
             <artifactId>querydsl-apt</artifactId>
+            <exclusions>
+                <exclusion>
+                    <artifactId>javassist</artifactId>
+                    <groupId>org.javassist</groupId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>guava</artifactId>
+                    <groupId>com.google.guava</groupId>
+                </exclusion>
+            </exclusions>
             <!--<exclusions>
                 <exclusion>
                     <artifactId>guava</artifactId>
@@ -98,15 +142,20 @@
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>-->
-        <dependency>
-            <groupId>cn.hutool</groupId>
-            <artifactId>hutool-all</artifactId>
-            <version>5.5.8</version>
-        </dependency>
         <!-- 注册中心 -->
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
+            <exclusions>
+                <exclusion>
+                    <artifactId>bcpkix-jdk15on</artifactId>
+                    <groupId>org.bouncycastle</groupId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>guava</artifactId>
+                    <groupId>com.google.guava</groupId>
+                </exclusion>
+            </exclusions>
             <!--<exclusions>
                 <exclusion>
                     <artifactId>guava</artifactId>
@@ -129,6 +178,12 @@
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-openfeign</artifactId>
+            <exclusions>
+                <exclusion>
+                    <artifactId>HdrHistogram</artifactId>
+                    <groupId>org.hdrhistogram</groupId>
+                </exclusion>
+            </exclusions>
             <!--<exclusions>
                 <exclusion>
                     <artifactId>HdrHistogram</artifactId>
@@ -195,6 +250,8 @@
                                     <directory>src/main/resources/</directory>
                                     <includes>
                                         <include>**/*.yml</include>
+                                        <include>**/arthas-boot.jar</include>
+                                        <include>**/arthas.zip</include>
                                     </includes>
                                 </resource>
                             </resources>

+ 59 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/config/DefaultAsycTaskConfig.java

@@ -0,0 +1,59 @@
+package com.persagy.dmp.rwd.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * 
+ * @description 
+ * @author zhangqiankun
+ * @since 2020年10月21日:	上午9:51:48
+ */
+@Setter
+@Getter
+@EnableAsync(proxyTargetClass = true)
+public class DefaultAsycTaskConfig {
+    /**
+     *  线程池维护线程的最小数量.
+     */
+    @Value("${asyc-task.corePoolSize:10}")
+    private int corePoolSize;
+    /**
+     *  线程池维护线程的最大数量
+     */
+    @Value("${asyc-task.maxPoolSize:200}")
+    private int maxPoolSize;
+    /**
+     *  队列最大长度
+     */
+    @Value("${asyc-task.queueCapacity:10}")
+    private int queueCapacity;
+    /**
+     *  线程池前缀
+     */
+    @Value("${asyc-task.threadNamePrefix:integrated-executor-}")
+    private String threadNamePrefix;
+
+    @Bean
+    public ThreadPoolTaskExecutor taskExecutor() {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        executor.setCorePoolSize(corePoolSize);
+        executor.setMaxPoolSize(maxPoolSize);
+        executor.setQueueCapacity(queueCapacity);
+        executor.setThreadNamePrefix(threadNamePrefix);
+        /*
+           rejection-policy:当pool已经达到max size的时候,如何处理新任务
+           CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
+        */
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+        executor.initialize();
+        return executor;
+    }
+}

+ 75 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/constants/CommonConstant.java

@@ -0,0 +1,75 @@
+package com.persagy.dmp.rwd.constants;
+/***
+ * Description: 通用常量类
+ * @author : lijie
+ * @date :2021/4/27 17:13
+ * Update By lijie 2021/4/27 17:13
+ */
+public class CommonConstant {
+    /**uploadFlag,响应头的key:1-成功,0-失败*/
+    //public static final String UPLOAD_FLAG = "uploadFlag";
+    public static final String UPLOAD_FLAG = "successFlag";
+    /**Excel文件的文件后缀*/
+    public static final String EXCEL_SUFFIX = "xlsx";
+    /**响应头:Access-Control-Expose-Headers*/
+    public static final String REPONSE_HEAD_ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
+    /**响应头:Content-disposition*/
+    public static final String REPONSE_HEAD_CONTENT_DISPOSITION = "Content-disposition";
+    /**响应头:Content-Type*/
+    public static final String REPONSE_HEAD_CONTENT_TYPE = "Content-Type";
+    /**响应头:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet*/
+    public static final String REPONSE_HEAD_CONTENT_TYPE_SHEET = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
+    /**响应头:attachment;filename=*/
+    public static final String REPONSE_HEAD_CONTENT_DISPOSITION_ATTACHMENT = "attachment;filename=";
+    /**系统类型-windows*/
+    public static final String SYSTEM_TYPE_WINDOWS = "windows";
+    /**系统类型-linux/unix*/
+    public static final String SYSTEM_TYPE_LINUX = "linux/unix";
+    /**系统类型-mac*/
+    public static final String SYSTEM_TYPE_MAC = "mac";
+    /**自定义请求头-os-type*/
+    public static final String OS_TYPE = "os-type";
+    /**手机号的正则表达式*/
+    public static final String PHONE_NUM_REGEX = "^$|^[0-9-]{11,13}$";
+    /**邮箱的正则表达式*/
+    public static final String MAIL_REGEX = "^.+@.+(\\..+)+$";
+    /**内容仅包含的正则表达式*/
+    public static final String CONTENT_ILLEGAL_REGEX = "^[0-9A-Za-z]{1,}$";
+    /**内容长度为20的限制*/
+    public static final String CONTENT_LENGTH_20_REGEX = "^$|^.{0,20}$";
+    /**内容长度为50的限制*/
+    public static final String CONTENT_LENGTH_50_REGEX = "^$|^.{0,50}$";
+    /**内容长度为50的限制*/
+    public static final String CONTENT_CHINA_AND_ENGLISH_REGEX = "^[a-zA-Z\u4e00-\u9fa5]{1,20}$";
+    /**生日的正则表达式*/
+    public static final String BIRTHDAY_REGEX = "^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$";
+    /**成功标记,1-成功*/
+    public static final String SUCCESS_FLAG_ONE="1";
+    /**成功标记,0-失败*/
+    public static final String SUCCESS_FLAG_ZERO="0";
+    /**账号id*/
+    public static final String USER_ID="userId";
+    /**文件名称*/
+    public static final String DTO_FILE="file";
+    /**批量导入物理世界对象错误提示文件名称*/
+    public static final String UPLOAD_ERR_FILE_NAME="批量导入物理世界对象错误提示文件.txt";
+    /**物理世界对象表模板*/
+    public static final String RWD_OBJECT_TABLE_NAME_FORMAT="rwd_object_{}%";
+    /**物理世界关系表模板*/
+    public static final String RWD_RELATION_TABLE_NAME_FORMAT="rwd_relation_{}%";
+    /**第几行模板*/
+    public static final String REL_COL_FORMAT="{}Sheet表中第{}行,";
+    /**第几行第几列模板*/
+    public static final String REL_ROW_COL_FORMAT="{}Sheet表中第{}行第{}列,";
+    /**多个字符串模板*/
+    public static final String THREE_FORMAT ="{}{}{}";
+    /**第几行第几列模板*/
+    public static final String GRAPH_ID_FORMAT="Gt{}001";
+    /**基础对象录入*/
+    public static final String COMMON_SHEET_NAME="基础对象录入";
+    /**设备对象录入*/
+    public static final String EQUIP_SHEET_NAME="设备对象录入";
+    /**空间对象录入*/
+    public static final String SYSTEM_SHEET_NAME ="系统对象录入";
+
+}

+ 64 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/constants/CommonObjectColumnEnum.java

@@ -0,0 +1,64 @@
+package com.persagy.dmp.rwd.constants;
+
+
+/***
+ * Description: 导入SOP文件表头
+ * @author : lijie
+ * @date :2021/3/4 10:58
+ * Update By lijie 2021/3/4 10:58
+ */
+public enum CommonObjectColumnEnum {
+
+	/**项目id**/
+	PROJECT_ID(0,"项目id*","项目id"),
+	/**建筑本地编码**/
+	BUILD_LOCAL_ID(1,"建筑本地编码*","建筑本地编码"),
+	/**建筑本地名称**/
+	BUILD_LOCAL_NAME(2,"建筑本地名称*","建筑本地名称"),
+	/**建筑功能类型**/
+	BUILD_FUNC_TYPE(3,"建筑功能类型*","建筑功能类型"),
+	/**楼层本地编码**/
+	FLOOR_LOCAL_ID(4,"楼层本地编码*","楼层本地编码"),
+	/**楼层本地名称**/
+	FLOOR_LOCAL_NAME(5,"楼层本地名称*","楼层本地名称"),
+	/**楼层编码**/
+	FLOOR_IDENTITY(6,"楼层编码*","楼层编码"),
+	/**空间本地编码**/
+	SPACE_LOCAL_ID(7,"空间本地编码*","空间本地编码"),
+	/**空间名称**/
+	SPACE_LOCAL_NAME(8,"空间名称*","空间名称"),
+	/**空间分区**/
+	SPACE_ZONE(9,"空间分区*","空间分区"),
+	/**空间功能类型**/
+	SPACE_FUNC_TYPE(10,"空间功能类型*","空间功能类型");
+
+	/**在上传标准文件中的列索引号*/
+	private Integer index;
+
+	/**描述*/
+	private String name;
+	/**真实行含义名称*/
+	private String realName;
+
+	public Integer getIndex() {
+		return index;
+	}
+
+	public String getName() {
+		return this.name;
+	}
+	public String getRealName() {
+		return this.realName;
+	}
+
+	CommonObjectColumnEnum(Integer index, String name,String realName) {
+		this.name = name;
+		this.index = index;
+		this.realName = realName;
+	}
+
+	@Override
+	public String toString() {
+		return this.index+"_"+this.name;
+	}
+}

+ 54 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/constants/EquipObjectColumnEnum.java

@@ -0,0 +1,54 @@
+package com.persagy.dmp.rwd.constants;
+
+
+/***
+ * Description: 导入SOP文件表头
+ * @author : lijie
+ * @date :2021/3/4 10:58
+ * Update By lijie 2021/3/4 10:58
+ */
+public enum EquipObjectColumnEnum {
+
+	/**项目id**/
+	PROJECT_ID(1,"项目id*","项目id"),
+	/**空间本地编码**/
+	SPACE_LOCAL_ID(2,"空间本地编码*","空间本地编码"),
+	/**空间与设备关系**/
+	SPACE_EQUIP_REL(3,"空间与设备关系*","空间与设备关系"),
+	/**设备本地编码**/
+	EQUIP_LOCAL_ID(4,"设备本地编码*","设备本地编码"),
+	/**设备名称**/
+	EQUIP_LOCAL_NAME(5,"设备名称*","设备名称"),
+	/**有效状态**/
+	VALID(6,"有效状态*","有效状态");
+
+	/**在上传标准文件中的列索引号*/
+	private Integer index;
+
+	/**描述*/
+	private String name;
+	/**真实名称*/
+	private String relName;
+
+	public Integer getIndex() {
+		return index;
+	}
+
+	public String getName() {
+		return this.name;
+	}
+	public String getRelName() {
+		return this.relName;
+	}
+
+	EquipObjectColumnEnum(Integer index, String name,String relName) {
+		this.name = name;
+		this.index = index;
+		this.relName = relName;
+	}
+
+	@Override
+	public String toString() {
+		return this.index+"_"+this.name;
+	}
+}

+ 62 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/constants/ErrorEnum.java

@@ -0,0 +1,62 @@
+package com.persagy.dmp.rwd.constants;
+
+
+/***
+ * Description: 导入标准错误提示码
+ * @author : lijie
+ * @date :2021/3/4 10:58
+ * Update By lijie 2021/3/4 10:58
+ */
+public enum ErrorEnum {
+
+	/**
+	 *内容错误
+	 */
+	CONTENT_ERROR("内容错误"),
+	/**
+	 *信息点名称错误
+	 */
+	INFO_NAME_NOT_EXIST_ERROR("信息点名称错误"),
+	/**
+	 *存在多个
+	 */
+	REPEAT_ERROR("存在多个"),
+	/**
+	 *不存在
+	 */
+	NO_EXIST_ERROR("不存在"),
+	/**
+	 *不能为空
+	 */
+	CONTENT_BLANK_ERROR("不能为空"),
+	/**
+	 *仅可输入数字、字母
+	 */
+	CONTENT_ILLEGAL_ERROR("仅可输入数字、字母"),
+	/**
+	 *仅可输入汉字、字母
+	 */
+	CONTENT_ILLEGAL_CHINA_ERROR("仅可输入汉字、字母"),
+	/**
+	 *非模板文件,请上传正确的模板文件
+	 */
+	FILE_ERROR("非模板文件,请上传正确的模板文件");
+
+	/**
+	 * 描述
+	 */
+	private String desc;
+
+	public String getDesc() {
+		return this.desc;
+	}
+
+	ErrorEnum(String desc) {
+		this.desc = desc;
+	}
+
+	@Override
+	public String toString() {
+		return this.desc;
+	}
+}

+ 30 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/constants/GraphCodeEnum.java

@@ -0,0 +1,30 @@
+package com.persagy.dmp.rwd.constants;
+
+import lombok.Getter;
+
+/**
+ * 对象类型
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Getter
+public enum GraphCodeEnum {
+    /** 建筑从属关系 */
+    ARCH_SUBSET("ArchSubset", "建筑从属关系"),
+    /** 区域服务关系 */
+    ARCH_FOR_ARCH("ArchForArch", "区域服务关系"),
+    /** 机电类所在区域关系 */
+    MECH_IN_ARCH("MechInArch", "机电类所在区域关系"),
+    /** 机电类服务区域关系 */
+    MECH_FOR_ARCH("MechForArch", "机电类服务区域关系"),
+    /** 机电从属关系 */
+    MECH_SUBSET("MechSubset", "机电从属关系");
+
+    private String index;
+    private String name;
+
+    GraphCodeEnum(String index, String name) {
+        this.index = index;
+        this.name = name;
+    }
+}

+ 36 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/constants/RelCodeEnum.java

@@ -0,0 +1,36 @@
+package com.persagy.dmp.rwd.constants;
+
+import lombok.Getter;
+
+/**
+ * 对象类型
+ * @author Charlie Yu
+ * @date 2021-06-25
+ */
+@Getter
+public enum RelCodeEnum {
+    /** 对象类型 */
+    BD_2_FL("Bd2Fl", "建筑下的楼层"),
+    BD_2_SH("Bd2Sh", "建筑下的竖井"),
+    BD_2_SP("Bd2Sp", "建筑下的业务空间"),
+    FL_2_SP("Fl2Sp", "楼层下的业务空间"),
+    SH_2_SP("Sh2Sp", "竖井下的业务空间"),
+    SY_2_BD("Sy2Bd", "系统所在建筑"),
+    SY_2_FL("Sy2Fl", "系统所在楼层"),
+    SY_2_SH("Sy2Sh", "系统所在竖井"),
+    SY_2_SP("Sy2Sp", "系统所在空间"),
+    EQ_2_BD("Eq2Bd", "设备所在建筑"),
+    EQ_2_FL("Eq2Fl", "设备所在楼层"),
+    EQ_2_SH("Eq2Sh", "设备所在竖井"),
+    EQ_2_SP("Eq2Sp", "设备所在空间"),
+    SY_2_EQ("Sy2Eq", "系统下的设备"),
+    EQ_2_EC("Eq2Ec", "设备下的部件");
+
+    private String index;
+    private String name;
+
+    RelCodeEnum(String index, String name) {
+        this.index = index;
+        this.name = name;
+    }
+}

+ 54 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/constants/SystemObjectColumnEnum.java

@@ -0,0 +1,54 @@
+package com.persagy.dmp.rwd.constants;
+
+
+/***
+ * Description: 导入SOP文件表头
+ * @author : lijie
+ * @date :2021/3/4 10:58
+ * Update By lijie 2021/3/4 10:58
+ */
+public enum SystemObjectColumnEnum {
+
+	/**项目id**/
+	PROJECT_ID(1,"项目id*","项目id"),
+	/**建筑本地编码**/
+	BUILD_LOCAL_ID(2,"建筑本地编码*","建筑本地编码"),
+	/**建筑与系统关系**/
+	BUILD_EQUIP_REL(3,"建筑与系统关系*","建筑与系统关系"),
+	/**系统本地编码**/
+	SYSTEM_LOCAL_ID(4,"系统本地编码*","系统本地编码"),
+	/**系统名称**/
+	SYSTEM_LOCAL_NAME(5,"系统名称*","系统名称"),
+	/**有效状态**/
+	VALID(6,"有效状态*","有效状态");
+
+	/**在上传标准文件中的列索引号*/
+	private Integer index;
+
+	/**描述*/
+	private String name;
+	/**真实名称*/
+	private String relName;
+
+	public Integer getIndex() {
+		return index;
+	}
+
+	public String getName() {
+		return this.name;
+	}
+	public String getRelName() {
+		return this.relName;
+	}
+
+	SystemObjectColumnEnum(Integer index, String name,String relName) {
+		this.name = name;
+		this.index = index;
+		this.relName = relName;
+	}
+
+	@Override
+	public String toString() {
+		return this.index+"_"+this.name;
+	}
+}

+ 108 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/controller/BatchHandleObjectController.java

@@ -0,0 +1,108 @@
+package com.persagy.dmp.rwd.controller;
+
+import cn.hutool.core.lang.TypeReference;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import com.persagy.dmp.config.DmpParameterStorage;
+import com.persagy.dmp.rwd.constants.CommonConstant;
+import com.persagy.dmp.rwd.entity.ObjectInstance;
+import com.persagy.dmp.rwd.entity.RelationInstance;
+import com.persagy.dmp.rwd.handler.BusinessException;
+import com.persagy.dmp.rwd.handler.ResponseCode;
+import com.persagy.dmp.rwd.handler.SpringHelper;
+import com.persagy.dmp.rwd.model.rwd.RelDTO;
+import com.persagy.dmp.rwd.repository.ProjectDao;
+import com.persagy.dmp.rwd.service.BatchHandleObjectService;
+import com.persagy.dmp.rwd.util.FileUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.*;
+
+@RestController
+@RequestMapping("/rwd/instance/object/")
+@RequiredArgsConstructor
+@Slf4j
+public class BatchHandleObjectController {
+
+    private final BatchHandleObjectService batchHandleObjectService;
+    /***
+     * Description: 下载模板接口
+     * @param response : 响应对象
+     * @return : void  
+     * @author : lijie
+     * @date :2021/9/22 9:54
+     * Update By lijie 2021/9/22 9:54
+     */
+    @PostMapping("downloadObjectTemplateFile")
+    public void downloadObjectTemplateFile(HttpServletResponse response) throws IOException {
+        String groupCode = DmpParameterStorage.getGroupCode();
+        if (StrUtil.isBlank(groupCode)) {
+            throw new BusinessException(ResponseCode.A0402.getCode(),"缺少集团编码");
+        }
+        batchHandleObjectService.downloadObjectTemplateFile(response,groupCode);
+    }
+    /***
+     * Description: 上传模板接口
+     * @param file : 文件对象
+     * @param request : 请求参数
+     * @param response : 响应参数
+     * return : void
+     * @author : lijie
+     * date :2021/9/24 10:10
+     * Update By lijie 2021/9/24 10:10
+     */
+    @PostMapping("uploadObjectTemplateFile")
+    public void uploadObjectTemplateFile(@RequestParam(CommonConstant.DTO_FILE) MultipartFile file,
+                                          HttpServletRequest request,
+                                          HttpServletResponse response){
+        String groupCode = DmpParameterStorage.getGroupCode();
+        if (StrUtil.isBlank(groupCode)) {
+            throw new BusinessException(ResponseCode.A0402.getCode(),"缺少集团编码");
+        }
+        try {
+            if (file.isEmpty()){
+                throw new BusinessException(ResponseCode.A0400.getCode(),"文件不能为空");
+            }
+            String originalFilename = file.getOriginalFilename();
+            if (StrUtil.isBlank(originalFilename)){
+                throw new BusinessException(ResponseCode.A0400.getCode(),"文件名称不能为空");
+            }
+            if (!originalFilename.endsWith(CommonConstant.EXCEL_SUFFIX)){
+                throw new BusinessException(ResponseCode.A0400.getCode(),"文件后缀名不符合,应该为xlsx");
+            }
+            batchHandleObjectService.uploadObjectTemplateFile(file,request,response,groupCode);
+        }catch (Exception exr){
+            log.error("上传文件失败",exr);
+            List<String> errorList = new ArrayList<>();
+            errorList.add(exr.getMessage());
+            FileUtil.writeErrorContentToResponse(errorList,response,request,CommonConstant.UPLOAD_ERR_FILE_NAME);
+        }
+    }
+    /***
+     * Description: 测试查询表名称列表
+     * return : void
+     * @author : lijie
+     * date :2021/9/24 10:10
+     * Update By lijie 2021/9/24 10:10
+     * @return
+     */
+    @PostMapping("testQueryTableNames")
+    public List<RelationInstance> testQueryTableNames(@RequestBody Map<String,Object> param){
+        String groupCode = DmpParameterStorage.getGroupCode();
+        if (StrUtil.isBlank(groupCode)) {
+            throw new BusinessException(ResponseCode.A0402.getCode(),"缺少集团编码");
+        }
+        ProjectDao projectDao = SpringHelper.getBean(ProjectDao.class);
+        return projectDao.queryObjRelBySpaceIdsAndProjectId(MapUtil.get(param,"rels", new TypeReference<List<RelDTO>>(){},new ArrayList<>()),groupCode);
+    }
+
+
+
+
+}

+ 2 - 1
dmp-rwd/src/main/java/com/persagy/dmp/rwd/entity/ObjectInstance.java

@@ -45,7 +45,8 @@ public class ObjectInstance {
 	private Integer grouping;
 
 	@Type(type = "json")
-	@TableField(value = "infos",typeHandler = JsonTypeHandlerFactory.ObjectNodeHandler.class)
+	//@TableField(value = "infos",typeHandler = JsonTypeHandlerFactory.ObjectNodeHandler.class)
+	@TableField(value = "infos",typeHandler = JacksonTypeHandler.class)
 	private ObjectNode infos;
 
 	@Type(type = "json")

+ 28 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/feign/DicClient.java

@@ -0,0 +1,28 @@
+package com.persagy.dmp.rwd.feign;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.persagy.common.criteria.JacksonCriteria;
+import com.persagy.common.web.MapResponse;
+import com.persagy.common.web.PagedResponse;
+import com.persagy.dmp.rwd.model.GroupModel;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.Map;
+
+/***
+ * Description: 字典服务Client
+ * @author : lijie
+ * @date :2021/9/23 15:03
+ * Update By lijie 2021/9/23 15:03
+ */
+@FeignClient(name = "dmp-dic",path = "/dic/dt/data/",url = "${persagy.dmp.dic.service:}")
+public interface DicClient {
+
+	@PostMapping("query")
+	PagedResponse<JsonNode> query(@RequestParam(name = "userId") String userId,
+								  @RequestParam(name = "groupCode") String groupCode,
+								  @RequestBody JacksonCriteria criteria);
+}

+ 109 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/handler/BusinessException.java

@@ -0,0 +1,109 @@
+package com.persagy.dmp.rwd.handler;
+
+
+/**
+ * @description 
+ * @author zhangqiankun
+ * @since 2020年8月26日:	下午5:17:08
+ */
+public class BusinessException extends RuntimeException {
+	private static final long serialVersionUID = -3325873096967595156L;
+
+	/** 异常编码 */
+	private String errorCode;
+    /** 异常描述 */
+    private String errorDesc;
+    /** 响应content中的数据,可加可不加 */
+    private Object respJson;
+
+    public BusinessException() {
+        super();
+    }
+
+    public BusinessException(Throwable e) {
+        super(e);
+    }
+
+    public BusinessException(String message, Throwable e) {
+        super(message, e);
+    }
+
+    /**
+     * @param errorDesc
+     */
+    public BusinessException(String errorDesc) {
+    	super(errorDesc);
+        this.errorCode = ResponseCode.B0001.getCode();
+        this.errorDesc = errorDesc;
+    }
+    
+    /**
+     * 业务异常错误码和错误描述构造器
+     *
+     * @param errorCode
+     * @param errorDesc
+     */
+    public BusinessException(String errorCode, String errorDesc) {
+    	super(errorDesc);
+        this.errorCode = errorCode;
+        this.errorDesc = errorDesc;
+    }
+    
+    public BusinessException(String errorCode, String errorDesc, Object respJson) {
+    	super(errorDesc);
+        this.errorCode = errorCode;
+        this.errorDesc = errorDesc;
+        this.respJson = respJson;
+    }
+
+    /**
+     * 业务异常信息、错误码和错误描述构造器
+     *
+     * @param message 后台日志看
+     * @param errorCode 错误码
+     * @param errorDesc	给前端看
+     */
+    public BusinessException(String message, String errorCode, String errorDesc, Object respJson) {
+        super(message);
+        this.errorCode = errorCode;
+        this.errorDesc = errorDesc;
+        this.respJson = respJson;
+    }
+
+    public BusinessException(Throwable cause, String errorCode, String errorDesc) {
+        super(cause);
+        this.errorCode = errorCode;
+        this.errorDesc = errorDesc;
+    }
+
+    public BusinessException(String message, Throwable cause, String errorCode, String errorDesc) {
+        super(message, cause);
+        this.errorCode = errorCode;
+        this.errorDesc = errorDesc;
+    }
+
+    public String getErrorCode() {
+        return errorCode;
+    }
+
+    public void setErrorCode(String errorCode) {
+        this.errorCode = errorCode;
+    }
+
+    public String getErrorDesc() {
+        return errorDesc;
+    }
+
+    public void setErrorDesc(String errorDesc) {
+        this.errorDesc = errorDesc;
+    }
+
+	public Object getRespJson() {
+		return respJson;
+	}
+
+	public void setRespJson(Object respJson) {
+		this.respJson = respJson;
+	}
+    
+}

+ 71 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/handler/ResponseCode.java

@@ -0,0 +1,71 @@
+package com.persagy.dmp.rwd.handler;
+
+/**
+ * @description 
+ * @author zhangqiankun
+ * @since 2020年8月26日:	下午5:17:08
+ */
+public enum ResponseCode {
+    /** 通用返回值 */
+	A00000("00000", "success"),
+    A10000("10000", "failure"),
+    A0001("A0001", "用户端错误"),
+    A0100("A0100", "用户注册错误"),
+    A0135("A0135", "Method Not Allowed"),
+    A0136("A0136", "Unsupported Media Type"),
+    A0137("A0137", "Not Acceptable"),
+    A0151("A0151", "手机格式校验失败"),
+	A0152("A0152", "地址格式校验失败"),
+	A0153("A0153", "邮箱格式校验失败"),
+    A0154("A0154", "账号名称重复"),
+    A0155("A0155", "员工编号重复"),
+    A0156("A0156", "手机号重复"),
+    A0157("A0157", "邮箱重复"),
+    A0201("A0201", "用户账户不存在"),
+    A0202("A0202", "用户账户被冻结"),
+    A0203("A0203", "用户账户已作废"),
+    A0210("A0210", "用户名/密码错误"),
+	A0220("A0220", "用户身份校验失败"),
+	A0301("A0301", "访问未授权"),
+	A0302("A0302", "正在授权中"),
+	A0303("A0303", "拒绝授权申请"),
+	A0311("A0311", "授权已过期"),
+	A0324("A0324", "网关访问受限"),
+	A0340("A0340", "签名异常"),
+	A0400("A0400", "用户请求参数错误"),
+	A0402("A0402", "无效的用户输入"),
+	A0422("A0422", "地址不在服务范围"),
+	A0427("A0427", "请求JSON 解析失败"),
+    B0001("B0001", "系统执行出错"),
+    B0300("B0300", "系统资源异常"),
+    C0001("C0001", "调用第三方服务出错"),
+    C0100("C0100", "中间件服务出错"),
+    C0110("C0110", "RPC服务出错"),
+    C0134("C0134", "不支持的数据格式"),
+    C0320("C0320", "数据不存在"),
+    C0341("C0341", "主键冲突"),
+	Z9999("Z9999", "系统繁忙");
+	
+    private String code;
+    
+    private String desc;
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    private ResponseCode(String code, String desc) {
+        this.desc = desc;
+        this.code = code;
+    }
+
+    @Override
+    public String toString() {
+        return this.code + "_" + this.desc;
+    }
+
+}

+ 152 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/handler/SpringHelper.java

@@ -0,0 +1,152 @@
+package com.persagy.dmp.rwd.handler;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import org.springframework.context.ApplicationContext;
+
+import java.util.Map;
+
+/**
+ * Spring助手
+ * @author Charlie Yu
+ * @version 1.0 2021-03-02
+ */
+public class SpringHelper {
+
+    /**
+     * spring上下文
+     * @return spring上下文
+     */
+    public static ApplicationContext getContext(){
+        return SpringUtil.getApplicationContext();
+    }
+
+    /**
+     * 根据类名搜索相应的bean对象
+     * @param <T> 类模板标识返回值类型
+     * @param clazz 模板类
+     * @return bean对象
+     */
+    public static <T>T getBean(Class<T> clazz){
+        return SpringUtil.getBean(clazz);
+    }
+
+    /**
+     * 根据类型取得所有
+     * @param type 接口类
+     * @return 取得所有的实现bean
+     */
+    public static <T> Map<String, T> getBeansOfType(Class<T> type){
+        return SpringUtil.getBeansOfType(type);
+    }
+
+    /**
+     * 根据bean名称和bean类型搜索相应的bean对象
+     * @param <T> 类模板标识返回值类型
+     * @param beanName bean名称
+     * @param clazz 模板类
+     * @return bean对象
+     */
+    public static <T>T getBean(String beanName,Class<T> clazz){
+        return SpringUtil.getBean(beanName, clazz);
+    }
+
+    /**
+     * 根据bean名称搜索相应的bean对象
+     * @param beanName bean名称
+     * @return bean对象
+     */
+    public static <T>T getBean(String beanName){
+        return SpringUtil.getBean(beanName);
+    }
+
+    /**
+     * 根据配置名称取得字符串配置值(配置名形式为nodeName.nodeName)
+     * @param key 配置名称
+     * @return 指定配置字符串值
+     */
+    public static String getString(String key) {
+        return SpringUtil.getProperty(key);
+    }
+
+    /**
+     * 根据配置名称取得字符串配置值,如果配置值为空使用指定的默认值
+     * @param key         配置名称
+     * @param defaultValue 指定默认值
+     * @return 最终配置值
+     */
+    public static String getString(String key, String defaultValue) {
+        String value = getString(key);
+        return StrUtil.isBlank(value) ? defaultValue : value;
+    }
+
+    /**
+     * 根据配置名称取得整型配置值,如果配置值为空使用指定的默认值
+     * @param key         配置名称
+     * @param defaultValue 默认整型值
+     * @return 最终配置值
+     */
+    public static int getInt(String key, int defaultValue) {
+        String value = getString(key);
+        if (StrUtil.isEmpty(value)) {
+            return defaultValue;
+        }
+        return TypeConvertUtil.parseInt(value);
+    }
+    /**
+     * 根据配置名称取得布尔配置值,如果配置值为空使用指定的默认值
+     * @param key         配置名称
+     * @param defaultValue 默认布尔值
+     * @return 最终配置值
+     */
+    public static boolean getBoolean(String key, boolean defaultValue) {
+        String value = getString(key);
+        if (StrUtil.isEmpty(value)) {
+            return defaultValue;
+        }
+        return TypeConvertUtil.parseBoolean(value);
+    }
+
+    /**
+     * 根据配置名称取得长整型配置值,如果配置值为空使用指定的默认值
+     * @param key         配置名称
+     * @param defaultValue 默认长整型值
+     * @return 最终配置值
+     */
+    public static long getLong(String key, long defaultValue) {
+        String value = getString(key);
+        if (StrUtil.isEmpty(value)) {
+            return defaultValue;
+        }
+        return TypeConvertUtil.parseLong(value);
+    }
+
+    /**
+     * 根据配置名称取得浮点型配置值,如果配置值为空使用指定的默认值
+     * @param key         配置名称
+     * @param defaultValue 默认浮点型值
+     * @return 最终配置值
+     */
+    public static float getFloat(String key, float defaultValue) {
+        String value = getString(key);
+        if (StrUtil.isEmpty(value)) {
+            return defaultValue;
+        }
+        return TypeConvertUtil.parseFloat(value);
+    }
+
+    /**
+     * 根据配置名称取得双浮点型配置值,如果配置值为空使用指定的默认值
+     * @param key         配置名称
+     * @param defaultValue 默认双浮点型值
+     * @return 最终配置值
+     */
+    public static double getDouble(String key, double defaultValue) {
+        String value = getString(key);
+        if (StrUtil.isEmpty(value)) {
+            return defaultValue;
+        }
+        return TypeConvertUtil.parseDouble(value);
+    }
+
+}

+ 284 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/handler/TypeConvertUtil.java

@@ -0,0 +1,284 @@
+package com.persagy.dmp.rwd.handler;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.math.BigDecimal;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * 数据类型转换器
+ * @author Charlie Yu
+ * @version 1.0 2021-03-03
+ */
+@Slf4j
+public class TypeConvertUtil {
+
+    /**
+     * 私有构造方法,防止实例化
+     */
+    private TypeConvertUtil() {
+
+    }
+
+    /**
+     * 将Object对象解析成字符串类型
+     * @param obj 需要转换的对象
+     * @return 字符串
+     */
+    public static final String parseString(Object obj) {
+        if (obj == null) {
+            return null;
+        }
+        return obj.toString();
+    }
+
+    /**
+     * 将对象解析成字节类型
+     * @param obj 需要转换的对象
+     * @return 字节值
+     */
+    public static final byte parseByte(Object obj) {
+        if (obj == null) {
+            return 0;
+        }
+        if (obj instanceof Number) {
+            return ((Number) obj).byteValue();
+        }
+        if (obj instanceof Boolean) {
+            return (byte) (((Boolean) obj).booleanValue() ? 1 : 0);
+        }
+        String s;
+        if ("".equals(s = obj.toString())) {
+            return 0;
+        } else {
+            return Byte.parseByte(s);
+        }
+    }
+
+    /**
+     * 将对象解析成字节类型
+     * @param obj 需要转换的对象
+     * @return 字节值
+     */
+    public static final short parseShort(Object obj) {
+        if (obj == null) {
+            return 0;
+        }
+        if (obj instanceof Number) {
+            return ((Number) obj).shortValue();
+        }
+        if (obj instanceof Boolean) {
+            return (short) (((Boolean) obj).booleanValue() ? 1 : 0);
+        }
+        String s;
+        if ("".equals(s = obj.toString())) {
+            return 0;
+        } else {
+            return Short.parseShort(s);
+        }
+    }
+
+    /**
+     * 将对象解析成整数类型
+     * @param obj 需转换的对象
+     * @return 整数值
+     */
+    public static final int parseInt(Object obj) {
+        if (obj == null) {
+            return 0;
+        }
+        if (obj instanceof Number) {
+            return ((Number) obj).intValue();
+        }
+        if (obj instanceof Boolean) {
+            return !((Boolean) obj).booleanValue() ? 0 : 1;
+        }
+        String s;
+        if ("".equals(s = obj.toString())) {
+            return 0;
+        } else {
+            return Integer.parseInt(s);
+        }
+    }
+
+    /**
+     * 将对象解析成长整类型
+     * @param obj 需转换的对象
+     * @return 长整数值
+     */
+    public static final long parseLong(Object obj) {
+        if (obj == null) {
+            return 0;
+        }
+        if (obj instanceof Number) {
+            return ((Number) obj).longValue();
+        }
+        if (obj instanceof Boolean) {
+            return !((Boolean) obj).booleanValue() ? 0L : 1L;
+        }
+        if (obj instanceof Date) {
+            return ((Date) obj).getTime();
+        }
+        String s;
+        if ("".equals(s = obj.toString())) {
+            return 0;
+        } else {
+            return Long.parseLong(s);
+        }
+    }
+
+    /**
+     * 将对象解析成布尔类型数据
+     * @param obj 需转换的对象
+     * @return 布尔值
+     */
+    public static final boolean parseBoolean(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (obj instanceof Boolean) {
+            return ((Boolean) obj).booleanValue();
+        } else {
+            String s = obj.toString();
+            return "true".equalsIgnoreCase(s) || "1".equals(s) || "Y".equalsIgnoreCase(s) || "YES".equalsIgnoreCase(s);
+        }
+    }
+
+    /**
+     * 将对象解析成浮点型数据
+     * @param obj 需转换的对象
+     * @return 浮点数值
+     */
+    public static final float parseFloat(Object obj) {
+        if (obj == null) {
+            return 0.0f;
+        }
+        if (obj instanceof Number) {
+            return ((Number) obj).floatValue();
+        }
+        if (obj instanceof Boolean) {
+            return !((Boolean) obj).booleanValue() ? 0.0F : 1.0F;
+        }
+        String s;
+        if ("".equals(s = obj.toString())) {
+            return 0.0f;
+        } else {
+            return Float.parseFloat(s);
+        }
+    }
+
+    /**
+     * 将对象解析成双浮点型数据
+     * @param obj 需转换的对象
+     * @return 双浮点值
+     */
+    public static final double parseDouble(Object obj) {
+        if (obj == null) {
+            return 0.0d;
+        }
+        if (obj instanceof Number) {
+            return ((Number) obj).doubleValue();
+        }
+        if (obj instanceof Boolean) {
+            return !((Boolean) obj).booleanValue() ? 0.0D : 1.0D;
+        }
+        String s;
+        if ("".equals(s = obj.toString())) {
+            return 0.0d;
+        } else {
+            return Double.parseDouble(s);
+        }
+    }
+
+    /**
+     * 解析对象成大数字类型数据
+     * @param obj 需要转换的对象
+     * @return 大数字对象
+     */
+    public static final BigDecimal parseBigDecimal(Object obj) {
+        if (obj == null) {
+            return BigDecimal.valueOf(0L);
+        }
+        if (obj instanceof BigDecimal) {
+            return (BigDecimal) obj;
+        }
+        if (obj instanceof Number) {
+            return BigDecimal.valueOf(((Number) obj).doubleValue());
+        }
+        if (obj instanceof Boolean) {
+            return BigDecimal.valueOf(((Boolean) obj).booleanValue() ? 1L : 0L);
+        }
+        String s;
+        if ("".equals(s = obj.toString())) {
+            return BigDecimal.valueOf(0L);
+        } else {
+            return new BigDecimal(s);
+        }
+    }
+
+    /**
+     * 解析对象成日期数据类型
+     *
+     * @param obj 需转换的对象
+     * @return 日期对象
+     */
+    public static Date parseDate(Object obj) {
+        if (obj == null) {
+            return null;
+        }
+        if (obj instanceof Date) {
+            return (Date) obj;
+        }
+        if (obj instanceof Number) {
+            return new Date(((Number) obj).longValue());
+        }
+        String objString = String.valueOf(obj);
+        if (StrUtil.isBlank(objString)) {
+            return null;
+        }
+        if (isNumeric(objString)) {
+            long time = Long.parseLong(objString);
+            return new Date(time);
+        }
+        int len = objString.length();
+        if (len >= 19) {
+            return null;
+        }
+        boolean isDate = objString.indexOf("-") > 0;
+        boolean isTime = objString.indexOf(":") > 0;
+        try {
+            if (isDate && isTime) {
+                return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(objString);
+            }
+            if (isDate) {
+                return new SimpleDateFormat("yyyy-MM-dd").parse(objString);
+            }
+            if (isTime) {
+                return new SimpleDateFormat("HH:mm:ss").parse(objString);
+            }
+        } catch (ParseException e) {
+            log.error("TypeConvert parse: Date parse error", e);
+        }
+        return null;
+    }
+
+    /**
+     * 判断字符串是否是有效的数组
+     * @param s 需要判断的字符串
+     * @return 布尔值
+     */
+    public static boolean isNumeric(String s) {
+        int length = s.length();
+        for (int i = 0; i < length; i++) {
+            char c = s.charAt(i);
+            boolean isNumberChar = (c < '0' || c > '9') && c != '.' && (i != 0 || c != '-');
+            if (isNumberChar) {
+                return false;
+            }
+        }
+        return true;
+    }
+}

+ 24 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/init/InitRunner.java

@@ -0,0 +1,24 @@
+package com.persagy.dmp.rwd.init;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
+
+@Component
+public class InitRunner implements CommandLineRunner {
+
+    @Autowired
+    private Environment environment;
+
+    @Override
+    public void run(String... args) throws Exception {
+        System.out.println("spring.datasource.druid.filter.wall.config.multi-statement-allow:"
+                +environment.getProperty("spring.datasource.druid.filter.wall.config.multi-statement-allow"));
+        System.out.println("spring.datasource.druid.filter.wall.config.none-base-statement-allow:"
+                +environment.getProperty("spring.datasource.druid.filter.wall.config.none-base-statement-allow"));
+        System.out.println("spring.datasource.druid.filters:"+environment.getProperty("spring.datasource.druid.filters"));
+        System.out.println("spring.datasource.druid.filter.wall.enabled:"+environment.getProperty("spring.datasource.druid.filter.wall.enabled"));
+    }
+}

+ 23 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/model/rwd/RelCodeDTO.java

@@ -0,0 +1,23 @@
+package com.persagy.dmp.rwd.model.rwd;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class RelCodeDTO {
+    /**边类型名称*/
+    private String relCodeName;
+    /**边类型编码*/
+    private String relCode;
+    /**图类型编码*/
+    private String graphCode;
+    /**图类型名称*/
+    private String graphName;
+
+
+}

+ 19 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/model/rwd/RelDTO.java

@@ -0,0 +1,19 @@
+package com.persagy.dmp.rwd.model.rwd;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Set;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class RelDTO {
+
+    private String projectId;
+    private Set<String> spaceIds;
+
+}

+ 91 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/model/rwd/UploadDTO.java

@@ -0,0 +1,91 @@
+package com.persagy.dmp.rwd.model.rwd;
+
+import com.persagy.dmp.rwd.entity.ObjectInstance;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/***
+ * Description: 存储上传物理世界对象的数据
+ * @author : lijie
+ * date :2021/9/26 12:06
+ * Update By lijie 2021/9/26 12:06
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class UploadDTO {
+
+    /**基础对象录入列表*/
+    private List<List<Object>> commonObjectUploadData;
+    /**设备对象录入列表*/
+    private List<List<Object>> equipObjectUploadData;
+    /**系统对象录入列表*/
+    private List<List<Object>> systemObjectUploadData;
+    /**系统对象信息点列表*/
+    private List<List<Object>> systemObjectInfosListList;
+    /**设备对象信息点列表*/
+    private List<List<Object>> equipObjectInfosListList;
+    /**建筑功能类型列表*/
+    private List<List<Object>> buildingFuncTypesListList;
+    /**楼层编码列表*/
+    private List<List<Object>> floorIdentitiesListList;
+    /**空间分区列表*/
+    private List<List<Object>> spaceZonesListList;
+    /**空间功能类型列表*/
+    private List<List<Object>> spaceFuncTypesListList;
+    /**专业系统设备类型列表*/
+    private List<List<Object>> objectClazzListList;
+    /**关系类型列表*/
+    private List<List<Object>> relCodesListList;
+    /**{系统信息点名称:系统信息点code}映射*/
+    private Map<String,String> systemObjectInfosMap;
+    /**{设备信息点名称:设备信息点code}映射*/
+    private Map<String,String> equipObjectInfosMap;
+    /**{建筑功能类型名称:建筑功能类型code}映射*/
+    private Map<String,String> buildingFuncTypesMap;
+    /**{楼层编码名称:楼层编码code}映射*/
+    private Map<String,String> floorIdentitiesMap;
+    /**{空间分区名称:空间分区code}映射*/
+    private Map<String,String> spaceZonesMap;
+    /**{空间功能类型名称:空间功能类型code}映射*/
+    private Map<String,String> spaceFuncTypesMap;
+    /**{专业系统设备类型名称:专业系统设备类型code}映射*/
+    private Map<String,String> objectClazzMap;
+    /**{关系类型名称:关系类型DTO}映射*/
+    private Map<String,RelCodeDTO> relCodesMap;
+    /**集团编码*/
+    private String groupCode;
+    /**账号id*/
+    private String userId;
+    /**应用id*/
+    private String appId;
+    /**{项目id:项目对象}映射*/
+    private Map<String, ObjectInstance> projectMap;
+    /**{建筑本地编码:{项目id:[建筑对象A,建筑对象B]}}映射*/
+    private Map<String, Map<String,List<ObjectInstance>>> buildMap;
+    /**{楼层本地编码:{项目id:[楼层对象A,楼层对象B]}}映射*/
+    private Map<String, Map<String,List<ObjectInstance>>> floorMap;
+    /**{空间本地编码:{项目id:[空间对象A,空间对象B]}}映射*/
+    private Map<String, Map<String,List<ObjectInstance>>> spaceMap;
+    /**{设备本地编码:{项目id:[设备对象A,设备对象B]}}映射*/
+    private Map<String, Map<String,List<ObjectInstance>>> equipMap;
+    /**{系统本地编码:{项目id:[系统对象A,系统对象B]}}映射*/
+    private Map<String, Map<String,List<ObjectInstance>>> systemMap;
+    /**{"空间id":"楼层id"}映射*/
+    private Map<String, String> spaceFloorMap;
+    /**{"楼层id":"建筑id"}映射*/
+    private Map<String, String> floorBuildMap;
+
+
+
+
+
+
+}

+ 33 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/repository/FuncidDefMapper.java

@@ -0,0 +1,33 @@
+package com.persagy.dmp.rwd.repository;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.common.web.ListResponse;
+import com.persagy.dmp.rwd.entity.FuncidDef;
+import com.persagy.dmp.rwd.model.FuncidDefModel;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Set;
+
+/***
+ * Description: 功能点定义Mapper
+ * @author : lijie
+ * @date :2021/9/27 11:31
+ * Update By lijie 2021/9/27 11:31
+ */
+@Repository
+@Mapper
+public interface FuncidDefMapper extends BaseMapper<FuncidDef> {
+
+    /***
+     * Description: 根据classCode和集团编码查询系统和设备的信息点
+     * @param classCodeSet : classCode的集合
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/23 18:14
+     * Update By lijie 2021/9/23 18:14
+     */
+    List<FuncidDef> queryFuncidByClassCodesAndGroupCode(@Param("classCodes") Set<String> classCodeSet,@Param("groupCode") String groupCode);
+}

+ 3 - 8
dmp-rwd/src/main/java/com/persagy/dmp/rwd/repository/ObjectInstanceRepository.java

@@ -5,16 +5,11 @@ import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.data.querydsl.QuerydslPredicateExecutor;
 
-import java.util.List;
+import java.util.Set;
 
 public interface ObjectInstanceRepository extends JpaRepository<ObjectInstance, String>, QuerydslPredicateExecutor<ObjectInstance>{
-    @Query(nativeQuery=true,value = "USE mysql;")
-    void selectUseDatabase();
-    @Query(nativeQuery=true,value = "SET SESSION group_concat_max_len = 65535;")
-    void setSessionConcatMaxLen();
-    @Query(nativeQuery=true,value = "SELECT REPLACE(GROUP_CONCAT(CONCAT(\"(SELECT * FROM \",table_name,\" WHERE class_code='project') UNION\")),\",\",\" \") "
-            + "from mysql.innodb_table_stats where table_name like '%rwd_object_wd%'")
-    String queryAllProjectTableNames();
+    @Query(nativeQuery=true,value = "SHOW TABLES LIKE ?")
+    Set<String> queryAllProjectTableNames(String queryKeyword);
 
 }
 

+ 26 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/repository/ProjectDao.java

@@ -3,11 +3,14 @@ package com.persagy.dmp.rwd.repository;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.persagy.dmp.rwd.entity.ObjectInstance;
+import com.persagy.dmp.rwd.entity.RelationInstance;
+import com.persagy.dmp.rwd.model.rwd.RelDTO;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 import org.springframework.stereotype.Repository;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * 数据库操作dao
@@ -36,4 +39,27 @@ public interface ProjectDao  extends BaseMapper<ObjectInstance> {
      * Update By lijie 2021/6/30 22:31
      */
     List<ObjectInstance> queryAllProjects(@Param("querySql") String querySql);
+    /***
+     * Description: 根据项目id集合和本地编码id集合查询物理世界对象
+     * @param validTableNames : 有效表名称列表
+     * @param transferProjectIds : 项目id集合
+     * @param localIds : 本地编码集合
+     * @return : java.util.List<com.persagy.dmp.rwd.entity.ObjectInstance>
+     * @author : lijie
+     * @date :2021/9/24 23:15
+     * Update By lijie 2021/9/24 23:15
+     */
+    List<ObjectInstance> queryRwdObjectsMultiTablesAndLocalIds(@Param("tableNames") Set<String> validTableNames,
+                                                               @Param("projectIds") Set<String> transferProjectIds,
+                                                               @Param("localIds") Set<String> localIds);
+    /***
+     * Description: 根据空间id查询其所属的楼层和建筑关系
+     * @param relDTOS : 关系列表
+     * @param groupCode : 集团编码
+     * @return : java.util.List<com.persagy.dmp.rwd.entity.RelationInstance>
+     * @author : lijie
+     * @date :2021/9/27 22:56
+     * Update By lijie 2021/9/27 22:56
+     */
+    List<RelationInstance> queryObjRelBySpaceIdsAndProjectId(@Param("rels") List<RelDTO> relDTOS,@Param("groupCode") String groupCode);
 }

+ 1 - 1
dmp-rwd/src/main/java/com/persagy/dmp/rwd/service/BaseService.java

@@ -70,7 +70,7 @@ public class BaseService {
     @Autowired
     protected SchemaProjectRepository schemaProjectRepository;
 
-    protected void setSharding(String groupCode, String projectId){
+    public void setSharding(String groupCode, String projectId){
         JpaSqlExecuteContext.init(groupCode, projectId);
     }
 

+ 38 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/service/BatchHandleObjectService.java

@@ -0,0 +1,38 @@
+package com.persagy.dmp.rwd.service;
+
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/***
+ * Description: 对象的上传下载逻辑处理类
+ * @author : lijie
+ * @date :2021/9/22 9:55
+ * Update By lijie 2021/9/22 9:55
+ */
+public interface BatchHandleObjectService {
+
+    /***
+     * Description: 下载模板接口
+     * @param response : 响应对象
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/22 9:54
+     * Update By lijie 2021/9/22 9:54
+     */
+    void downloadObjectTemplateFile(HttpServletResponse response,String groupCode) throws IOException;
+    /***
+     * Description: 上传模板接口
+     * @param file : 文件对象
+     * @param request : 请求参数
+     * @param response : 响应参数
+     * @param groupCode : 集团编码
+     * return : void
+     * @author : lijie
+     * date :2021/9/24 10:10
+     * Update By lijie 2021/9/24 10:10
+     */
+    void uploadObjectTemplateFile(MultipartFile file, HttpServletRequest request, HttpServletResponse response,String groupCode) throws IOException;
+}

+ 98 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/service/DownloadService.java

@@ -0,0 +1,98 @@
+package com.persagy.dmp.rwd.service;
+
+import com.persagy.dmp.rwd.constants.CommonConstant;
+import com.persagy.dmp.rwd.util.FileUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.springframework.core.io.Resource;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLEncoder;
+
+/***
+ * Description: 下载Excel的公共逻辑抽象类
+ * @author : lijie
+ * @date :2021/4/28 17:22
+ * Update By lijie 2021/4/28 17:22
+ */
+@Slf4j
+public abstract class DownloadService {
+
+    private static final String CONFIG_PATH_PREFIX="file:./config";
+    private static final String CLASS_PATH_PREFIX="classpath:.";
+
+    /***
+     * Description: 公共下载方法的壳子
+     * @return : void
+     * @author : lijie
+     * @date :2021/4/28 16:55
+     * Update By lijie 2021/4/28 16:55
+     */
+    public void downloadFile() throws IOException {
+        String filePath = getFilePath();
+        Resource[] resolverResources = FileUtil.getResource(CONFIG_PATH_PREFIX+filePath, CLASS_PATH_PREFIX+filePath);
+        if (resolverResources.length<=0){
+            return;
+        }
+        Resource resolverResource = resolverResources[0];
+        String filename = resolverResource.getFilename();
+        InputStream inputStream = resolverResource.getInputStream();
+        Workbook workbook = null;
+        HttpServletResponse response = getHttpServletResponse();
+        try {
+            workbook = WorkbookFactory.create(inputStream);
+            handleWorkbook(workbook);
+            // 为文件命名
+            response.setHeader(CommonConstant.REPONSE_HEAD_CONTENT_DISPOSITION,
+                    CommonConstant.REPONSE_HEAD_CONTENT_DISPOSITION_ATTACHMENT + URLEncoder.encode(filename, "UTF-8"));
+            response.addHeader(CommonConstant.REPONSE_HEAD_CONTENT_TYPE, CommonConstant.REPONSE_HEAD_CONTENT_TYPE_SHEET);
+            response.addHeader(CommonConstant.UPLOAD_FLAG, CommonConstant.SUCCESS_FLAG_ONE);
+            workbook.write(response.getOutputStream());
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            response.addHeader(CommonConstant.UPLOAD_FLAG,CommonConstant.SUCCESS_FLAG_ZERO);
+        } finally {
+            try {
+                inputStream.close();
+            } catch (IOException ignored) {
+                log.error("关闭文件流失败");
+            }
+            if (workbook != null) {
+                try {
+                    workbook.close();
+                } catch (IOException ignored) {
+                    log.error("关闭工作簿失败");
+                }
+            }
+        }
+    }
+    /***
+     * Description: 核心处理业务逻辑的方法
+     * @param workbook : 工作簿
+     * @return : void
+     * @author : lijie
+     * @date :2021/4/28 17:20
+     * Update By lijie 2021/4/28 17:20
+     */
+    protected abstract void handleWorkbook(Workbook workbook) throws InterruptedException;
+    /***
+     * Description: 获取文件路径
+     * @return : java.lang.String
+     * @author : lijie
+     * @date :2021/4/28 17:21
+     * Update By lijie 2021/4/28 17:21
+     */
+    protected abstract String getFilePath();
+    /***
+     * Description: 获取响应对象
+     * @return : javax.servlet.http.HttpServletResponse
+     * @author : lijie
+     * @date :2021/4/28 17:21
+     * Update By lijie 2021/4/28 17:21
+     */
+    protected abstract HttpServletResponse getHttpServletResponse();
+
+}

+ 2 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/service/InitService.java

@@ -202,6 +202,8 @@ public class InitService extends BaseService {
 		sql.append("   `note` text,                                                               \n");
 		sql.append("   `sub_flag` int(11) DEFAULT NULL,                                           \n");
 		sql.append("   `weak_point` int(11) DEFAULT NULL,                                         \n");
+		sql.append("   `alias_first_tag` varchar(40) DEFAULT NULL,                                \n");
+		sql.append("   `alias_second_tag` varchar(40) DEFAULT NULL,                               \n");
 		sql.append("   PRIMARY KEY (`id`),                                                        \n");
 		sql.append("   KEY `class_code` (`class_code`,`code`),                                    \n");
 		sql.append("   KEY `class_code_2` (`class_code`,`orig_code`)                              \n");

+ 4 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/service/ObjectInstanceQueryService.java

@@ -463,4 +463,8 @@ public class ObjectInstanceQueryService extends BaseService {
         analysisQueryResult(projects,criteria,result);
         return result;
     }
+
+
+
+
 }

File diff suppressed because it is too large
+ 1276 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/service/impl/BatchHandleObjectServiceImpl.java


+ 119 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/util/FileUtil.java

@@ -0,0 +1,119 @@
+package com.persagy.dmp.rwd.util;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.useragent.OS;
+import cn.hutool.http.useragent.UserAgent;
+import cn.hutool.http.useragent.UserAgentUtil;
+import com.persagy.dmp.rwd.constants.CommonConstant;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.List;
+
+/***
+ * Description: 文件处理公共类
+ * @author : lijie
+ * @date :2021/4/28 16:38
+ * Update By lijie 2021/4/28 16:38
+ */
+@Slf4j
+public class FileUtil {
+
+    /***
+     * Description: 获取资源文件方法
+     * @param configFilePath : 配置文件路径
+     * @param classpathFilePath : 本地路径
+     * @return : org.springframework.core.io.Resource[]
+     * @author : lijie
+     * @date :2021/3/1 14:25
+     * Update By lijie 2021/3/1 14:25
+     */
+    public static Resource[] getResource(String configFilePath, String classpathFilePath) throws IOException {
+        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
+        Resource[] resolverResources = resolver.getResources(configFilePath);
+        if (resolverResources.length > 0) {
+            boolean exist = true;
+            for (Resource resource : resolverResources) {
+                if (!resource.exists()) {
+                    exist = false;
+                    break;
+                }
+            }
+            if(exist) {
+                return resolverResources;
+            }
+        }
+        return resolver.getResources(classpathFilePath);
+    }
+
+    /***
+     * Description: 写错误提示语到文件中
+     * @param errorList : 错误提示语列表
+     * @param response : 响应体对象
+     * @author : lijie
+     * @date :2021/3/4 15:33
+     * Update By lijie 2021/3/4 15:33
+     */
+    public static void writeErrorContentToResponse(List<String> errorList,
+                                                   HttpServletResponse response,
+                                                   HttpServletRequest request, String errorFileName){
+        try {
+            ServletOutputStream outputStream = response.getOutputStream();
+            String lineSeparator = getSystemLineSeparator(request);
+            for (String error : errorList) {
+                outputStream.write(error.getBytes());
+                outputStream.write(lineSeparator.getBytes());
+            }
+            // 为文件命名
+            response.setHeader(CommonConstant.REPONSE_HEAD_CONTENT_DISPOSITION,
+                    "attachment;filename=" + URLEncoder.encode(errorFileName, "UTF-8"));
+            response.addHeader(CommonConstant.REPONSE_HEAD_CONTENT_TYPE, "text/plain");
+            response.addHeader(CommonConstant.UPLOAD_FLAG, CommonConstant.SUCCESS_FLAG_ZERO);
+            response.addHeader(CommonConstant.REPONSE_HEAD_ACCESS_CONTROL_EXPOSE_HEADERS,CommonConstant.UPLOAD_FLAG);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+        }
+    }
+
+    /***
+     * Description: 获得请求的换行符
+     * @param request : 请求体
+     * @return : void
+     * @author : lijie
+     * @date :2021/3/13 10:57
+     * Update By lijie 2021/3/13 10:57
+     */
+    private static String getSystemLineSeparator(HttpServletRequest request) {
+        String userAgent = request.getHeader(CommonConstant.OS_TYPE);
+        if (StrUtil.isBlank(userAgent)){
+            return System.lineSeparator();
+        }
+        UserAgent agent = UserAgentUtil.parse(userAgent);
+        OS os = agent.getOs();
+        if (null==os){
+            return System.lineSeparator();
+        }
+        String osStr = agent.getOs().toString().toLowerCase();
+        if (StrUtil.isBlank(osStr)){
+            return System.lineSeparator();
+        }
+        if (osStr.contains(CommonConstant.SYSTEM_TYPE_WINDOWS)){
+            return "\r\n";
+        }
+        if (osStr.contains(CommonConstant.SYSTEM_TYPE_LINUX)){
+            return "\r";
+        }
+        if (osStr.contains(CommonConstant.SYSTEM_TYPE_MAC)){
+            return "\n";
+        }
+        return System.lineSeparator();
+    }
+
+}

+ 55 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/validators/service/FileCheckService.java

@@ -0,0 +1,55 @@
+package com.persagy.dmp.rwd.validators.service;
+
+import com.persagy.dmp.rwd.model.rwd.UploadDTO;
+
+import java.util.List;
+import java.util.Map;
+
+/***
+ * Description: 文件校验逻辑处理类
+ * @author : lijie
+ * @date :2021/9/24 15:42
+ * Update By lijie 2021/9/24 15:42
+ */
+public interface FileCheckService {
+    /***
+     * Description: 校验文件的正确性
+     * @param lists : 数据列表
+     * @param dynamicMap : 动态表头映射
+     * @return : java.util.List<java.lang.String>
+     * @author : lijie
+     * @date :2021/3/15 11:51
+     * Update By lijie 2021/3/15 11:51
+     */
+    void checkFileIsValid(List<String> errorList, List<List<Object>> lists, Map<String,String> dynamicMap);
+
+    /***
+     * Description: 校验数据的正确性
+     * @param errorList : 错误列表
+     * @param uploadDTO : 整体上传数据
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/26 15:01
+     * Update By lijie 2021/9/26 15:01
+     */
+    void checkDataIsValid(List<String> errorList, UploadDTO uploadDTO);
+    /***
+     * Description: 批量处理物理世界对象数据
+     * @param uploadDTO : 整体上传数据
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/26 15:22
+     * Update By lijie 2021/9/26 15:22
+     */
+    void batchHandleUploadDatas(UploadDTO uploadDTO);
+    /***
+     * Description: 校验空间数据是否存在
+     * @param errorList : 错误列表
+     * @param uploadDTO : 上传数据
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/27 22:33
+     * Update By lijie 2021/9/27 22:33
+     */
+    void secondCheckSpaceDataIsValid(List<String> errorList, UploadDTO uploadDTO);
+}

+ 438 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/validators/service/impl/AbstractFileCheckService.java

@@ -0,0 +1,438 @@
+package com.persagy.dmp.rwd.validators.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.text.CharSequenceUtil;
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.persagy.dmp.rwd.constants.CommonConstant;
+import com.persagy.dmp.rwd.constants.CommonObjectColumnEnum;
+import com.persagy.dmp.rwd.constants.ErrorEnum;
+import com.persagy.dmp.rwd.entity.ObjectInstance;
+import com.persagy.dmp.rwd.entity.RelationInstance;
+import com.persagy.dmp.rwd.handler.SpringHelper;
+import com.persagy.dmp.rwd.model.rwd.UploadDTO;
+import com.persagy.dmp.rwd.repository.ObjectInstanceRepository;
+import com.persagy.dmp.rwd.repository.RelationInstanceRepository;
+import com.persagy.dmp.rwd.service.BaseService;
+import com.persagy.dmp.rwd.validators.service.FileCheckService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+
+/***
+ * Description: 文件检测抽象逻辑类(模板模式)
+ * 该抽象类一共处理三个上传的业务功能:
+ * 1.校验文件的合法性,见{@link AbstractFileCheckService#checkFileIsValid(List, List, Map)}
+ * 2.校验文件数据的合法性,见{@link AbstractFileCheckService#checkDataIsValid(List, UploadDTO)}
+ * 3.批量保存物理世界数据,见{@link AbstractFileCheckService#batchHandleUploadDatas(UploadDTO)}
+ * @author : lijie
+ * @date :2021/9/24 15:51
+ * Update By lijie 2021/9/24 15:51
+ */
+@Component
+@RequiredArgsConstructor
+public abstract class AbstractFileCheckService implements FileCheckService {
+
+    /***
+     * Description: 校验文件的正确性
+     * @param lists : 数据列表
+     * @return : java.util.List<java.lang.String>
+     * @author : lijie
+     * @date :2021/3/15 11:51
+     * Update By lijie 2021/3/15 11:51
+     */
+    @Override
+    public void checkFileIsValid(List<String> errorList, List<List<Object>> lists, Map<String,String> dynamicMap) {
+        // 1.通过钩子获得行头索引
+        int excelHeadIndex = getExcelHeadIndex();
+        String excelSheetName = getExcelSheetName();
+        if (lists.size() < excelHeadIndex){
+            errorList.add(excelSheetName+ErrorEnum.FILE_ERROR.getDesc());
+            return;
+        }
+        // 2.获的行头行的数据
+        List<Object> rows = lists.get(excelHeadIndex);
+        if (CollUtil.isEmpty(rows)){
+            errorList.add(excelSheetName+ErrorEnum.FILE_ERROR.getDesc());
+            return;
+        }
+        // 3.获得不可变行头的映射
+        Map<Integer,String> persistentHeadMap = getPersistentHeadMap();
+        if (rows.size()<persistentHeadMap.size()){
+            errorList.add(excelSheetName+ErrorEnum.FILE_ERROR.getDesc());
+            return;
+        }
+        // 4.校验不可变行头
+        int excelColumnOffset = getExcelColumnOffset();
+        int size = persistentHeadMap.size()+excelColumnOffset;
+        for (int i=excelColumnOffset;i<size;i++){
+            String columnName = persistentHeadMap.get(i);
+            if (StrUtil.isBlank(columnName)){
+                errorList.add(excelSheetName+ErrorEnum.FILE_ERROR.getDesc());
+                return;
+            }
+            String realName = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(rows.get(i)));
+            if (StrUtil.isBlank(realName) || !realName.contains(columnName)){
+                errorList.add(excelSheetName+ErrorEnum.FILE_ERROR.getDesc());
+                return;
+            }
+        }
+        if (dynamicMap.size()<=0){
+            return;
+        }
+        // 5.校验动态行头
+        int dynamicSize = persistentHeadMap.size()+excelColumnOffset;
+        for (int i = dynamicSize; i < rows.size(); i++) {
+            String realCol=excelSheetName+"Sheet表:第"+(excelHeadIndex+1)+"行第"+(i+1)+"列,";
+            String tempStr = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(rows.get(i)));
+            if (StrUtil.isNotBlank(tempStr) && !dynamicMap.containsKey(tempStr)){
+                errorList.add(realCol+ErrorEnum.INFO_NAME_NOT_EXIST_ERROR);
+            }
+        }
+    }
+    /***
+     * Description: 获得行的偏移量
+     * @return : java.lang.Integer
+     * @author : lijie
+     * @date :2021/9/27 15:31
+     * Update By lijie 2021/9/27 15:31
+     */
+    protected Integer getExcelColumnOffset(){return 0;};
+
+    /***
+     * Description: 校验数据的正确性
+     * @param errorList : 错误列表
+     * @param uploadDTO : 整体上传数据
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/26 15:01
+     * Update By lijie 2021/9/26 15:01
+     */
+    @Override
+    public void checkDataIsValid(List<String> errorList, UploadDTO uploadDTO) {}
+    /***
+     * Description: 批量处理物理世界对象数据
+     * @param uploadDTO : 整体上传数据
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/26 15:22
+     * Update By lijie 2021/9/26 15:22
+     */
+    @Override
+    public void batchHandleUploadDatas(UploadDTO uploadDTO) {}
+    /***
+     * Description: 校验空间数据是否存在
+     * @param errorList : 错误列表
+     * @param uploadDTO : 上传数据
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/27 22:33
+     * Update By lijie 2021/9/27 22:33
+     */
+    @Override
+    public void secondCheckSpaceDataIsValid(List<String> errorList, UploadDTO uploadDTO) {}
+
+    /***
+     * Description: 获得所在excel名称
+     * @return : java.lang.String
+     * @author : lijie
+     * @date :2021/9/24 16:53
+     * Update By lijie 2021/9/24 16:53
+     */
+    protected abstract String getExcelSheetName();
+
+    /***
+     * Description: 获得不可变行头的映射
+     * @return : java.util.Map<java.lang.String,java.lang.String>
+     * @author : lijie
+     * @date :2021/9/24 16:09
+     * Update By lijie 2021/9/24 16:09
+     */
+    protected abstract Map<Integer, String> getPersistentHeadMap();
+
+    /***
+     * Description: 获得excel行头索引
+     * @return : java.lang.Integer
+     * @author : lijie
+     * @date :2021/9/24 15:59
+     * Update By lijie 2021/9/24 15:59
+     */
+    protected abstract Integer getExcelHeadIndex();
+
+    /***
+     * Description: 校验本地编码是否存在
+     * @param errorList : 错误列表
+     * @param localId : 本地编码
+     * @param projectId : 项目id
+     * @param objectMap : 对象映射
+     * @param relCol : 真实行前缀
+     * @param realName : 真实名称
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/25 0:35
+     * Update By lijie 2021/9/25 0:35
+     */
+    protected final void checkLocalIdExists(List<String> errorList, String localId, String projectId,
+                                            Map<String, Map<String, List<ObjectInstance>>> objectMap, String relCol,
+                                            String realName) {
+        // 1.校验是否为空
+        checkContentBlank(errorList,localId,relCol,realName);
+        // 2.校验是否重复
+        if (StrUtil.isNotBlank(localId) && StrUtil.isNotBlank(projectId)){
+            Map<String, List<ObjectInstance>> projectMap = objectMap.getOrDefault(localId, new HashMap<>());
+            List<ObjectInstance> instances = projectMap.getOrDefault(projectId, new ArrayList<>());
+            if (instances.size()>1){
+                errorList.add(StrUtil.format(CommonConstant.THREE_FORMAT,relCol, realName,ErrorEnum.REPEAT_ERROR.getDesc()));
+            }
+        }
+    }
+    /***
+     * Description: 校验内容为空
+     * @param errorList : 错误列表
+     * @param content : 校验内容
+     * @param relCol : 真实列名称
+     * @param realName : 真实名称
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/25 0:38
+     * Update By lijie 2021/9/25 0:38
+     */
+    protected final void checkContentBlank(List<String> errorList, String content, String relCol, String realName) {
+        if (StrUtil.isNotBlank(content)){
+            return;
+        }
+        errorList.add(StrUtil.format(CommonConstant.THREE_FORMAT,relCol, realName,ErrorEnum.CONTENT_BLANK_ERROR.getDesc()));
+    }
+
+    /***
+     * Description: 校验项目是否为空且存在
+     * @param errorList : 错误列表
+     * @param projectId : 项目id
+     * @param projectMap : 项目映射
+     * @param relCol : 真实行
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/25 1:37
+     * Update By lijie 2021/9/25 1:37
+     */
+    protected final void checkProjectValid(List<String> errorList, String projectId, Map<String, ObjectInstance> projectMap,String relCol) {
+        checkContentBlank(errorList,projectId,relCol, CommonObjectColumnEnum.PROJECT_ID.getRealName());
+        if (StrUtil.isNotBlank(projectId) && !projectMap.containsKey(projectId)){
+            errorList.add(StrUtil.format(CommonConstant.THREE_FORMAT, relCol, CommonObjectColumnEnum.PROJECT_ID.getRealName(),ErrorEnum.NO_EXIST_ERROR.getDesc()));
+        }
+    }
+
+    /***
+     * Description: 校验信息点code是否正确
+     * @param errorList : 错误列表
+     * @param infosNameList : 信息点名称列表
+     * @param infosCodeList : 信息点code列表
+     * @param objectInfosMap : 对象信息点映射
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/25 1:20
+     * Update By lijie 2021/9/25 1:20
+     */
+    protected final void checkObjectInfoValid(List<String> errorList, List<Object> infosNameList, List<Object> infosCodeList,
+                                              Map<String, String> objectInfosMap,String sheetName) {
+        int colStartIndex=7;
+        if (CollUtil.isEmpty(infosNameList) || infosNameList.size()<=colStartIndex){
+            return;
+        }
+        int nameIndex=6;
+        int codeIndex=3;
+        for (int i = colStartIndex; i < infosNameList.size(); i++) {
+            String nameRelCol = StrUtil.format(CommonConstant.REL_ROW_COL_FORMAT,sheetName,nameIndex+1,i+1);
+            String codeRelCol = StrUtil.format(CommonConstant.REL_ROW_COL_FORMAT,sheetName,codeIndex+1,i+1);
+            String name = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(infosNameList.get(i)));
+            String code = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(infosCodeList.get(i)));
+            if (StrUtil.isNotBlank(name)){
+                checkContentBlank(errorList,code,codeRelCol,"信息点code");
+            }
+            // checkContentBlank(errorList,name,nameRelCol,"信息点名称");
+            if (StrUtil.isNotBlank(name) && !objectInfosMap.containsKey(name)){
+                errorList.add(StrUtil.format(CommonConstant.THREE_FORMAT,nameRelCol, "信息点名称",ErrorEnum.NO_EXIST_ERROR.getDesc()));
+            }
+            if (StrUtil.isNotBlank(name) && StrUtil.isNotBlank(code) && !objectInfosMap.containsValue(code)){
+                errorList.add(StrUtil.format(CommonConstant.THREE_FORMAT,codeRelCol, "信息点code",ErrorEnum.NO_EXIST_ERROR.getDesc()));
+            }
+        }
+    }
+
+    /***
+     * Description: 通用更新对象实例
+     * @param localName : 本地名称
+     * @param uploadDTO : 上传数据对象
+     * @param projectId : 项目id
+     * @param existInsMap : 已存在对象实例映射
+     * @param instanceMap : 更新对象映射
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/26 22:43
+     * Update By lijie 2021/9/26 22:43
+     */
+    protected final void commonUpdateObjectInstance(String localId, String localName, UploadDTO uploadDTO, String projectId,
+                                            Map<String, Map<String, List<ObjectInstance>>> existInsMap,
+                                            Map<String, List<ObjectInstance>> instanceMap, ObjectNode infos,Boolean valid) {
+        ObjectInstance objectInstance = existInsMap.getOrDefault(localId, new HashMap<>())
+                .getOrDefault(projectId,new ArrayList<>()).get(0);
+        ObjectNode srcInfos = objectInstance.getInfos();
+        if (null==srcInfos){
+            objectInstance.setInfos(infos);
+        }else {
+            srcInfos.setAll(infos);
+            objectInstance.setInfos(srcInfos);
+        }
+        objectInstance.setUpdateApp(uploadDTO.getAppId());
+        objectInstance.setUpdateUser(uploadDTO.getUserId());
+        objectInstance.setLocalName(localName);
+        objectInstance.setInfos(infos);
+        objectInstance.setUpdateTime(new Date());
+        if (null!=valid){
+            objectInstance.setValid(BooleanUtil.toInt(valid));
+        }
+        List<ObjectInstance> instances = instanceMap.getOrDefault(projectId, new ArrayList<>());
+        instances.add(objectInstance);
+        instanceMap.put(projectId,instances);
+    }
+
+    /***
+     * Description: 通用更新数据
+     * @param instanceMap : 实例映射
+     * @param relationMap : 关系映射
+     * @param uploadDTO : 上传数据
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/26 23:27
+     * Update By lijie 2021/9/26 23:27
+     */
+    protected final void commonUpdateInstances(Map<String, List<ObjectInstance>> instanceMap,
+                                       Map<String, List<RelationInstance>> relationMap, UploadDTO uploadDTO) {
+        Set<Map.Entry<String, List<ObjectInstance>>> entries = instanceMap.entrySet();
+        for (Map.Entry<String, List<ObjectInstance>> entry : entries) {
+            String projectId = entry.getKey();
+            SpringHelper.getBean("baseService",BaseService.class).setSharding(uploadDTO.getGroupCode(),projectId);
+            if (CollUtil.isNotEmpty(entry.getValue())){
+                SpringHelper.getBean(ObjectInstanceRepository.class).saveAll(entry.getValue());
+            }
+            List<RelationInstance> relationInstances = relationMap.get(entry.getKey());
+            if (CollUtil.isNotEmpty(relationInstances)){
+                SpringHelper.getBean(RelationInstanceRepository.class).saveAll(relationInstances);
+            }
+        }
+    }
+
+    /***
+     * Description: 通用的创建对象实例的方法
+     * @param idPrefix : id的前缀
+     * @param localId : 本地编码
+     * @param localName : 本地名称
+     * @param projectId : 项目id
+     * @param uploadDTO : 上传数据对象
+     * @param objType : 对象分类
+     * @param classCode : 对象类型
+     * @param infos : 信息点
+     * @param instanceMap : 实例映射
+     * @param existInstanceMap : 已经存在的实例映射
+     * @return : com.persagy.dmp.rwd.entity.ObjectInstance
+     * @author : lijie
+     * @date :2021/9/26 22:34
+     * Update By lijie 2021/9/26 22:34
+     */
+    protected final ObjectInstance commonCreateObjectInstance(String idPrefix, String localId, String localName,
+                                                      String projectId, UploadDTO uploadDTO, String objType,
+                                                      String classCode, ObjectNode infos,
+                                                      Map<String, List<ObjectInstance>> instanceMap,
+                                                      Map<String, Map<String, List<ObjectInstance>>> existInstanceMap,
+                                                              Boolean valid) {
+        ObjectInstance objectInstance = new ObjectInstance();
+        objectInstance.setId(StrUtil.format(CommonConstant.THREE_FORMAT,idPrefix, projectId.substring(2), IdWorker.getIdStr()));
+        objectInstance.setName(localName);
+        objectInstance.setLocalId(localId);
+        objectInstance.setLocalName(localName);
+        objectInstance.setGroupCode(uploadDTO.getGroupCode());
+        objectInstance.setProjectId(projectId);
+        objectInstance.setObjType(objType);
+        objectInstance.setClassCode(classCode);
+        objectInstance.setGrouping(1);
+        objectInstance.setValid(BooleanUtil.toInt(valid));
+        objectInstance.setInfos(infos);
+        objectInstance.setVirtualInfoCodes(new ArrayList<>());
+        objectInstance.setCreateApp(uploadDTO.getAppId());
+        objectInstance.setUpdateApp(uploadDTO.getAppId());
+        objectInstance.setCreateUser(uploadDTO.getUserId());
+        objectInstance.setUpdateUser(uploadDTO.getUserId());
+        List<ObjectInstance> instances = instanceMap.getOrDefault(projectId, new ArrayList<>());
+        instances.add(objectInstance);
+        instanceMap.put(projectId,instances);
+        Map<String, List<ObjectInstance>> projectInsMap = existInstanceMap.getOrDefault(localId, new HashMap<>());
+        List<ObjectInstance> insList = projectInsMap.getOrDefault(projectId, new ArrayList<>());
+        insList.add(objectInstance);
+        projectInsMap.put(projectId,insList);
+        existInstanceMap.put(localId,projectInsMap);
+        return objectInstance;
+    }
+
+    /***
+     * Description: 通用的创建关系实例的方法
+     * @param projectId : 项目id
+     * @param uploadDTO : 上传的数据
+     * @return : com.persagy.dmp.rwd.entity.RelationInstance
+     * @author : lijie
+     * @date :2021/9/26 22:24
+     * Update By lijie 2021/9/26 22:24
+     */
+    protected final RelationInstance commmonCreateRelationInstance(String projectId, UploadDTO uploadDTO,String graphCode,
+                                                           String relCode,String fromId,String toId,String relVal) {
+        RelationInstance relationInstance = new RelationInstance();
+        relationInstance.setId(IdWorker.getIdStr());
+        relationInstance.setGroupCode(uploadDTO.getGroupCode());
+        relationInstance.setProjectId(projectId);
+        relationInstance.setGraphId(StrUtil.format(CommonConstant.GRAPH_ID_FORMAT, graphCode));
+        relationInstance.setGraphCode(graphCode);
+        relationInstance.setRelCode(relCode);
+        relationInstance.setObjFrom(fromId);
+        relationInstance.setRelValue(relVal);
+        relationInstance.setObjTo(toId);
+        relationInstance.setStatus(1);
+        relationInstance.setCreateUser(uploadDTO.getUserId());
+        relationInstance.setUpdateUser(uploadDTO.getUserId());
+        relationInstance.setCreateApp(uploadDTO.getAppId());
+        relationInstance.setUpdateApp(uploadDTO.getAppId());
+        return relationInstance;
+    }
+
+    /***
+     * Description: 通用创建对象
+     * @param infoCodeList : 信息点列表
+     * @param datas : 数据列表
+     * @return : com.fasterxml.jackson.databind.node.ObjectNode
+     * @author : lijie
+     * @date :2021/9/26 23:31
+     * Update By lijie 2021/9/26 23:31
+     */
+    protected final ObjectNode commonCreateInfos(List<Object> infoCodeList, List<Object> datas) {
+        int startIndex=7;
+        ObjectNode infos = SpringHelper.getBean(ObjectMapper.class).createObjectNode();
+        if (infoCodeList.size()<=startIndex || datas.size()<=startIndex){
+            return infos;
+        }
+        for (int i = startIndex; i < infoCodeList.size(); i++) {
+            String infoCode = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(infoCodeList.get(i)));
+            if (StrUtil.isBlank(infoCode)){
+                continue;
+            }
+            if (infos.has(infoCode) && StrUtil.isNotBlank(infos.get(infoCode).asText())){
+                continue;
+            }
+            String dataStr = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(datas.get(i)));
+            infos.put(infoCode,dataStr);
+        }
+        return infos;
+    }
+
+}

+ 376 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/validators/service/impl/CommonFileCheckServiceImpl.java

@@ -0,0 +1,376 @@
+package com.persagy.dmp.rwd.validators.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.text.CharSequenceUtil;
+import cn.hutool.core.util.EnumUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.persagy.common.json.JacksonMapper;
+import com.persagy.dmp.rwd.constants.*;
+import com.persagy.dmp.rwd.entity.ObjectInstance;
+import com.persagy.dmp.rwd.entity.RelationInstance;
+import com.persagy.dmp.rwd.enums.ObjType;
+import com.persagy.dmp.rwd.handler.SpringHelper;
+import com.persagy.dmp.rwd.model.rwd.UploadDTO;
+import com.persagy.dmp.rwd.repository.ObjectInstanceRepository;
+import com.persagy.dmp.rwd.repository.RelationInstanceRepository;
+import com.persagy.dmp.rwd.service.BaseService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class CommonFileCheckServiceImpl extends AbstractFileCheckService {
+
+    /***
+     * Description: 校验数据的正确性
+     * @param errorList : 错误列表
+     * @param uploadDTO : 整体上传数据
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/26 15:01
+     * Update By lijie 2021/9/26 15:01
+     */
+    @Override
+    public void checkDataIsValid(List<String> errorList, UploadDTO uploadDTO) {
+        int startRowIndex=3;
+        List<List<Object>> commonObjectUploadData = uploadDTO.getCommonObjectUploadData();
+        if (commonObjectUploadData.size()<=startRowIndex){
+            return;
+        }
+        Map<String, ObjectInstance> projectMap = uploadDTO.getProjectMap();
+        Map<String, Map<String, List<ObjectInstance>>> buildMap = uploadDTO.getBuildMap();
+        Map<String, String> buildingFuncTypesMap = uploadDTO.getBuildingFuncTypesMap();
+        Map<String, Map<String, List<ObjectInstance>>> floorMap = uploadDTO.getFloorMap();
+        Map<String, String> floorIdentitiesMap = uploadDTO.getFloorIdentitiesMap();
+        Map<String, String> spaceZonesMap = uploadDTO.getSpaceZonesMap();
+        Map<String, String> spaceFuncTypesMap = uploadDTO.getSpaceFuncTypesMap();
+        Map<String, Map<String, List<ObjectInstance>>> spaceMap = uploadDTO.getSpaceMap();
+        Map<String,String> floorBuildLocalIdMap = new HashMap<>();
+        Map<String, String> spaceFloorIdMap = new HashMap<>();
+        int objSize = commonObjectUploadData.size();
+        for (int i = startRowIndex; i < objSize; i++) {
+            String relCol = StrUtil.format(CommonConstant.REL_COL_FORMAT,CommonConstant.COMMON_SHEET_NAME,i+1);
+            List<Object> datas = commonObjectUploadData.get(i);
+            // 1.项目id:必填,是否存在
+            String projectId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,0)));
+            checkProjectValid(errorList,projectId,projectMap,relCol);
+            // 2.建筑本地编码:必填,是否在项目下有重复
+            String buildLocalId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,1)));
+            checkLocalIdExists(errorList,buildLocalId,projectId,buildMap,relCol,CommonObjectColumnEnum.BUILD_LOCAL_ID.getRealName());
+            // 3.建筑本地名称:必填
+            checkContentBlank(errorList,CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,2))),relCol,CommonObjectColumnEnum.BUILD_LOCAL_NAME.getRealName());
+            // 4.建筑功能类型:必填,是否存在
+            String buildFuncType = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,3)));
+            checkContentBlank(errorList,buildFuncType,relCol,CommonObjectColumnEnum.BUILD_FUNC_TYPE.getRealName());
+            if (StrUtil.isNotBlank(buildFuncType) && !buildingFuncTypesMap.containsKey(buildFuncType)){
+                errorList.add(StrUtil.format(CommonConstant.THREE_FORMAT,relCol, CommonObjectColumnEnum.BUILD_FUNC_TYPE.getRealName(),ErrorEnum.NO_EXIST_ERROR.getDesc()));
+            }
+            // 5.楼层本地编码:必填,是否在项目下有重复
+            String floorLocalId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,4)));
+            checkLocalIdExists(errorList,floorLocalId,projectId,floorMap,relCol,CommonObjectColumnEnum.FLOOR_LOCAL_ID.getRealName());
+            checkLocalIdRepeated(floorLocalId,buildLocalId,projectId,floorBuildLocalIdMap,relCol,CommonObjectColumnEnum.FLOOR_LOCAL_ID.getRealName(),errorList);
+            // 6.楼层本地名称:必填
+            checkContentBlank(errorList,CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,5))),relCol,CommonObjectColumnEnum.FLOOR_LOCAL_NAME.getRealName());
+            // 7.楼层编码:必填,是否存在
+            String floorIdentity = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,6)));
+            checkContentBlank(errorList,floorIdentity,relCol,CommonObjectColumnEnum.FLOOR_IDENTITY.getRealName());
+            if (StrUtil.isNotBlank(floorIdentity) && !floorIdentitiesMap.containsKey(floorIdentity)){
+                errorList.add(StrUtil.format(CommonConstant.THREE_FORMAT,relCol, CommonObjectColumnEnum.FLOOR_IDENTITY.getRealName(), ErrorEnum.NO_EXIST_ERROR.getDesc()));
+            }
+            // 8.空间本地编码:必填,是否在项目下有重复
+            String spaceLocalId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas, 7)));
+            checkLocalIdExists(errorList,spaceLocalId,
+                    projectId,spaceMap,relCol,CommonObjectColumnEnum.SPACE_LOCAL_ID.getRealName());
+            checkLocalIdRepeated(spaceLocalId,floorLocalId,projectId,spaceFloorIdMap,relCol,CommonObjectColumnEnum.SPACE_LOCAL_ID.getRealName(),errorList);
+            // 9.空间名称:必填
+            checkContentBlank(errorList,CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,8))),
+                    relCol,CommonObjectColumnEnum.SPACE_LOCAL_NAME.getRealName());
+            // 10.空间分区:必填,是否存在
+            String spaceZone = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,9)));
+            checkContentBlank(errorList,spaceZone,relCol,CommonObjectColumnEnum.SPACE_ZONE.getRealName());
+            if (StrUtil.isNotBlank(spaceZone) && !spaceZonesMap.containsKey(spaceZone)){
+                errorList.add(StrUtil.format(CommonConstant.THREE_FORMAT,relCol, CommonObjectColumnEnum.SPACE_ZONE.getRealName(),ErrorEnum.NO_EXIST_ERROR.getDesc()));
+            }
+            // 11.空间功能类型:必填,是否存在
+            String spaceFuncType = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,10)));
+            checkContentBlank(errorList,spaceFuncType,relCol,CommonObjectColumnEnum.SPACE_FUNC_TYPE.getRealName());
+            if (StrUtil.isNotBlank(spaceFuncType) && !spaceFuncTypesMap.containsKey(spaceFuncType)){
+                errorList.add(StrUtil.format(CommonConstant.THREE_FORMAT,relCol, CommonObjectColumnEnum.SPACE_FUNC_TYPE.getRealName(),ErrorEnum.NO_EXIST_ERROR.getDesc()));
+            }
+        }
+    }
+    /***
+     * Description: 校验楼层本地编码或空间本地编码是否重复
+     * @param sonLocalId : 子级本地编码
+     * @param parentLocalId : 父级本地编码
+     * @param projectId : 项目id
+     * @param localIdMap : 本地编码_项目id与父级本地编码的映射
+     * @param relCol : 关系字段
+     * @param realName : 关系名称
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/27 21:20
+     * Update By lijie 2021/9/27 21:20
+     */
+    private void checkLocalIdRepeated(String sonLocalId, String parentLocalId, String projectId,
+                                      Map<String, String> localIdMap, String relCol, String realName,List<String> errorList) {
+        if (StrUtil.isNotBlank(sonLocalId)
+                && StrUtil.isNotBlank(parentLocalId)
+                && StrUtil.isNotBlank(projectId)){
+            // 判断楼层本地编码对应的建筑本地编码是否一致
+            String otherParentLocalId = localIdMap.getOrDefault(StrUtil.format("{}_{}", sonLocalId, projectId), "");
+            if (StrUtil.isNotBlank(otherParentLocalId)
+                    && !otherParentLocalId.equals(parentLocalId)){
+                errorList.add(StrUtil.format("{}{}{}{}{}",
+                        relCol,realName,"在",parentLocalId,"下已存在"));
+            }else {
+                localIdMap.put(StrUtil.format("{}_{}", sonLocalId, projectId),parentLocalId);
+            }
+        }
+
+
+    }
+
+    /***
+     * Description: 批量处理物理世界对象数据
+     * @param uploadDTO : 整体上传数据
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/26 15:22
+     * Update By lijie 2021/9/26 15:22
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void batchHandleUploadDatas(UploadDTO uploadDTO) {
+        int startRowIndex=3;
+        List<List<Object>> commonObjectUploadData = uploadDTO.getCommonObjectUploadData();
+        if (commonObjectUploadData.size()<=startRowIndex){
+            return;
+        }
+        List<Object> infosData = commonObjectUploadData.get(1);
+        int objSize = commonObjectUploadData.size();
+        Map<String,List<ObjectInstance>> instanceMap = new HashMap<>();
+        Map<String,List<RelationInstance>> relationMap = new HashMap<>();
+        for (int i = startRowIndex; i < objSize; i++) {
+            List<Object> datas = commonObjectUploadData.get(i);
+            // 1.项目id:必填,是否存在
+            String projectId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(datas.get(0)));
+            // 2.建筑本地编码:必填,是否在项目下有重复
+            String buildLocalId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(datas.get(1)));
+            // 3.建筑本地名称:必填
+            String buildLocalName = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(datas.get(2)));
+            // 4.建筑功能类型:必填,是否存在
+            String buildFuncType = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(datas.get(3)));
+            String buildFuncTypeInfo = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(infosData.get(3)));
+            String buildingId = handleBuildObject(projectId, buildLocalId, buildLocalName, buildFuncType,
+                    instanceMap, relationMap, buildFuncTypeInfo, uploadDTO);
+            // 5.楼层本地编码:必填,是否在项目下有重复
+            String floorLocalId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(datas.get(4)));
+            // 6.楼层本地名称:必填
+            String floorLocalName = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(datas.get(5)));
+            // 7.楼层编码:必填,是否存在
+            String floorIdentity = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(datas.get(6)));
+            String floorIdentityInfoCode = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(infosData.get(6)));
+            String floorId = handleFloorObject(projectId,floorLocalId,floorLocalName,floorIdentity,floorIdentityInfoCode,
+                    buildingId,instanceMap,relationMap,uploadDTO);
+            // 8.空间本地编码:必填,是否在项目下有重复
+            String spaceLocalId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(datas.get(7)));
+            // 9.空间名称:必填
+            String spaceLocalName = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(datas.get(8)));
+            // 10.空间分区:必填,是否存在
+            String spaceZone = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(datas.get(9)));
+            // 11.空间功能类型:必填,是否存在
+            String spaceFuncType = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(datas.get(10)));
+            String spaceFuncTypeInfo = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(infosData.get(10)));
+            handleSpaceObject(projectId,spaceLocalId,spaceLocalName,spaceZone,spaceFuncType,buildingId,floorId,
+                    instanceMap,relationMap,uploadDTO,spaceFuncTypeInfo);
+        }
+        commonUpdateInstances(instanceMap,relationMap,uploadDTO);
+    }
+
+
+    /***
+     * Description: 获得excel的sheet名称
+     * @return : java.lang.String
+     * @author : lijie
+     * @date :2021/9/24 16:54
+     * Update By lijie 2021/9/24 16:54
+     */
+    @Override
+    protected String getExcelSheetName() {
+        return "基础对象录入";
+    }
+
+    /***
+     * Description: 获得不可变行头的映射
+     * @return : java.util.Map<java.lang.String,java.lang.String>
+     * @author : lijie
+     * @date :2021/9/24 16:09
+     * Update By lijie 2021/9/24 16:09
+     */
+    @Override
+    protected Map<Integer, String> getPersistentHeadMap() {
+        List<CommonObjectColumnEnum> list = CollUtil.list(false, EnumUtil.getEnumMap(CommonObjectColumnEnum.class).values());
+        return list.stream()
+                .collect(Collectors.toMap(CommonObjectColumnEnum::getIndex, CommonObjectColumnEnum::getName, (k1, k2) -> k1));
+    }
+
+    /***
+     * Description: 获得excel行头索引
+     * @return : java.lang.Integer
+     * @author : lijie
+     * @date :2021/9/24 15:59
+     * Update By lijie 2021/9/24 15:59
+     */
+    @Override
+    protected Integer getExcelHeadIndex() {
+        return 2;
+    }
+
+    /***
+     * Description: 处理空间对象
+     * @param projectId : 项目id
+     * @param spaceLocalId : 空间本地编码
+     * @param spaceLocalName : 空间本地名称
+     * @param spaceZone : 空间分区
+     * @param spaceFuncType : 空间功能类型
+     * @param buildingId : 建筑id
+     * @param floorId : 楼层id
+     * @param instanceMap : 实例映射
+     * @param relationMap : 关系映射
+     * @param uploadDTO : 上传数据
+     * @param spaceFuncTypeInfo : 空间功能类型信息点code
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/26 22:53
+     * Update By lijie 2021/9/26 22:53
+     */
+    private void handleSpaceObject(String projectId, String spaceLocalId, String spaceLocalName, String spaceZone,
+                                   String spaceFuncType, String buildingId, String floorId,
+                                   Map<String, List<ObjectInstance>> instanceMap,
+                                   Map<String, List<RelationInstance>> relationMap,
+                                   UploadDTO uploadDTO,
+                                   String spaceFuncTypeInfo) {
+        Map<String, String> spaceZonesMap = uploadDTO.getSpaceZonesMap();
+        Map<String, String> spaceFuncTypesMap = uploadDTO.getSpaceFuncTypesMap();
+        Map<String, Map<String, List<ObjectInstance>>> spaceMap = uploadDTO.getSpaceMap();
+        if (spaceMap.containsKey(spaceLocalId)
+                && spaceMap.getOrDefault(spaceLocalId,new HashMap<>()).containsKey(projectId)){
+            // 更新对象
+            ObjectNode infos = SpringHelper.getBean(ObjectMapper.class)
+                    .createObjectNode()
+                    .put(spaceFuncTypeInfo, spaceFuncTypesMap.get(spaceFuncType));
+            commonUpdateObjectInstance(spaceLocalId,spaceLocalName,uploadDTO,projectId, spaceMap,instanceMap, infos,null);
+            return;
+        }
+        // 新增对象
+        ObjectNode infos = SpringHelper.getBean(ObjectMapper.class).createObjectNode();
+        infos.put(spaceFuncTypeInfo,spaceFuncTypesMap.get(spaceFuncType));
+        ObjectInstance objectInstance = commonCreateObjectInstance("Sp",spaceLocalId,
+                spaceLocalName,projectId,uploadDTO,ObjType.space.name(),spaceZonesMap.get(spaceZone),
+                infos,instanceMap,spaceMap,Boolean.TRUE);
+        // 新增关系
+        List<RelationInstance> rels = relationMap.getOrDefault(projectId, new ArrayList<>());
+        rels.add(commmonCreateRelationInstance(projectId,uploadDTO,GraphCodeEnum.ARCH_SUBSET.getIndex(),
+                RelCodeEnum.BD_2_SP.getIndex(),buildingId,objectInstance.getId(),spaceZonesMap.get(spaceZone)));
+        rels.add(commmonCreateRelationInstance(projectId,uploadDTO,GraphCodeEnum.ARCH_SUBSET.getIndex(),
+                RelCodeEnum.FL_2_SP.getIndex(),floorId,objectInstance.getId(),spaceZonesMap.get(spaceZone)));
+        relationMap.put(projectId,rels);
+    }
+
+    /***
+     * Description: 处理楼层对象
+     * @param projectId : 项目id
+     * @param floorLocalId : 楼层本地编码
+     * @param floorLocalName : 楼层本地名称
+     * @param floorIdentity : 楼层编码
+     * @param floorIdentityInfoCode : 楼层编码信息点
+     * @param buildingId : 建筑id
+     * @param instanceMap : 实例映射
+     * @param relationMap : 关系映射
+     * @param uploadDTO : 上传数据对象
+     * @return : java.lang.String
+     * @author : lijie
+     * @date :2021/9/26 22:10
+     * Update By lijie 2021/9/26 22:10
+     */
+    private String handleFloorObject(String projectId, String floorLocalId, String floorLocalName,
+                                     String floorIdentity, String floorIdentityInfoCode, String buildingId,
+                                     Map<String, List<ObjectInstance>> instanceMap,
+                                     Map<String, List<RelationInstance>> relationMap,
+                                     UploadDTO uploadDTO) {
+        Map<String, String> floorIdentitiesMap = uploadDTO.getFloorIdentitiesMap();
+        Map<String, Map<String, List<ObjectInstance>>> floorMap = uploadDTO.getFloorMap();
+        if (floorMap.containsKey(floorLocalId)
+                && floorMap.getOrDefault(floorLocalId,new HashMap<>()).containsKey(projectId)){
+            // 更新对象
+            ObjectInstance floor = floorMap.getOrDefault(floorLocalId, new HashMap<>())
+                    .getOrDefault(projectId,new ArrayList<>()).get(0);
+            ObjectNode infos = SpringHelper.getBean(ObjectMapper.class)
+                    .createObjectNode()
+                    .put(floorIdentityInfoCode,floorIdentitiesMap.get(floorIdentity));
+            commonUpdateObjectInstance(floorLocalId, floorLocalName,uploadDTO,projectId, floorMap,instanceMap,infos,null);
+            return floor.getId();
+        }
+        // 新增对象
+        ObjectNode infos = SpringHelper.getBean(ObjectMapper.class).createObjectNode();
+        infos.put(floorIdentityInfoCode,floorIdentitiesMap.get(floorIdentity));
+        ObjectInstance objectInstance = commonCreateObjectInstance("Fl",floorLocalId,floorLocalName,projectId,
+                uploadDTO,ObjType.floor.name(),ObjType.floor.name(),infos,instanceMap,floorMap,Boolean.TRUE);
+        // 新增关系
+        List<RelationInstance> rels = relationMap.getOrDefault(projectId, new ArrayList<>());
+        rels.add(commmonCreateRelationInstance(projectId,uploadDTO,GraphCodeEnum.ARCH_SUBSET.getIndex(),
+                RelCodeEnum.BD_2_FL.getIndex(),buildingId,objectInstance.getId(),null));
+        relationMap.put(projectId,rels);
+        return objectInstance.getId();
+    }
+
+    /***
+     * Description: 处理建筑对象
+     * @param projectId : 项目id
+     * @param buildLocalId : 建筑本地编码
+     * @param buildLocalName : 建筑本地名称
+     * @param buildFuncType : 建筑功能类型
+     * @param instanceMap : 更新实例映射
+     * @param relationMap : 关系实例映射
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/26 18:52
+     * Update By lijie 2021/9/26 18:52
+     */
+    private String handleBuildObject(String projectId, String buildLocalId, String buildLocalName, String buildFuncType,
+                                     Map<String, List<ObjectInstance>> instanceMap,
+                                     Map<String, List<RelationInstance>> relationMap,
+                                     String buildFuncTypeInfo,UploadDTO uploadDTO) {
+        Map<String, Map<String, List<ObjectInstance>>> buildMap = uploadDTO.getBuildMap();
+        Map<String, String> buildingFuncTypesMap = uploadDTO.getBuildingFuncTypesMap();
+        if (buildMap.containsKey(buildLocalId)
+                && buildMap.getOrDefault(buildLocalId,new HashMap<>()).containsKey(projectId)){
+            // 更新建筑
+            ObjectInstance building = buildMap.getOrDefault(buildLocalId, new HashMap<>())
+                    .getOrDefault(projectId,new ArrayList<>()).get(0);
+            ObjectNode infos = SpringHelper.getBean(ObjectMapper.class)
+                    .createObjectNode()
+                    .put(buildFuncTypeInfo,buildingFuncTypesMap.get(buildFuncType));
+            commonUpdateObjectInstance(buildLocalId, buildLocalName,uploadDTO,projectId, buildMap,instanceMap,infos,null);
+            return building.getId();
+        }
+        // 新增建筑
+        ObjectNode infos = SpringHelper.getBean(ObjectMapper.class).createObjectNode();
+        infos.put(buildFuncTypeInfo,buildingFuncTypesMap.get(buildFuncType));
+        ObjectInstance objectInstance = commonCreateObjectInstance("Bd",buildLocalId,buildLocalName,projectId,
+                uploadDTO,ObjType.building.name(),ObjType.building.name(),infos,instanceMap,buildMap,Boolean.TRUE);
+        return objectInstance.getId();
+    }
+
+}

+ 271 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/validators/service/impl/EquipFileCheckServiceImpl.java

@@ -0,0 +1,271 @@
+package com.persagy.dmp.rwd.validators.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.text.CharSequenceUtil;
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.core.util.EnumUtil;
+import cn.hutool.core.util.StrUtil;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.persagy.dmp.rwd.constants.*;
+import com.persagy.dmp.rwd.entity.ObjectInstance;
+import com.persagy.dmp.rwd.entity.RelationInstance;
+import com.persagy.dmp.rwd.enums.ObjType;
+import com.persagy.dmp.rwd.handler.SpringHelper;
+import com.persagy.dmp.rwd.model.rwd.RelCodeDTO;
+import com.persagy.dmp.rwd.model.rwd.UploadDTO;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class EquipFileCheckServiceImpl extends AbstractFileCheckService {
+
+    @Override
+    public void checkDataIsValid(List<String> errorList, UploadDTO uploadDTO) {
+        int startRowIndex = 7;
+        List<List<Object>> equipObjectUploadData = uploadDTO.getEquipObjectUploadData();
+        if (equipObjectUploadData.size()<=startRowIndex){
+            return;
+        }
+        Map<String, String> objectClazzMap = uploadDTO.getObjectClazzMap();
+        Map<String, String> equipObjectInfosMap = uploadDTO.getEquipObjectInfosMap();
+        Map<String, Map<String, List<ObjectInstance>>> equipMap = uploadDTO.getEquipMap();
+        Map<String, ObjectInstance> projectMap = uploadDTO.getProjectMap();
+        // 1.校验设备类型必填
+        List<Object> clazzRow = equipObjectUploadData.get(2);
+        String relClazzCol = StrUtil.format(CommonConstant.REL_COL_FORMAT,CommonConstant.EQUIP_SHEET_NAME,3);
+        // 1.1 专业名称
+        String domainName = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(clazzRow.get(1)));
+        checkContentBlank(errorList,domainName,relClazzCol, "专业");
+        if (StrUtil.isNotBlank(domainName) && !objectClazzMap.containsKey(domainName.substring(0,domainName.lastIndexOf(StrUtil.UNDERLINE)))){
+            errorList.add(StrUtil.format(CommonConstant.THREE_FORMAT,relClazzCol, "专业",ErrorEnum.NO_EXIST_ERROR.getDesc()));
+        }
+        // 1.2 系统类型名称
+        String systemName = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(clazzRow.get(2)));
+        checkContentBlank(errorList,systemName,relClazzCol, "系统类");
+        if (StrUtil.isNotBlank(systemName) && !objectClazzMap.containsKey(systemName.substring(0,systemName.lastIndexOf(StrUtil.UNDERLINE)))){
+            errorList.add(StrUtil.format(CommonConstant.THREE_FORMAT,relClazzCol, "系统类",ErrorEnum.NO_EXIST_ERROR.getDesc()));
+        }
+        // 1.3 设备类型名称
+        String equipName = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(clazzRow.get(3)));
+        checkContentBlank(errorList,equipName,relClazzCol, "设备类型");
+        if (StrUtil.isNotBlank(equipName) && !objectClazzMap.containsKey(equipName.substring(0,equipName.lastIndexOf(StrUtil.UNDERLINE)))){
+            errorList.add(StrUtil.format(CommonConstant.THREE_FORMAT,relClazzCol, "设备类型", ErrorEnum.NO_EXIST_ERROR.getDesc()));
+        }
+        // 2.校验信息点code是否正确
+        checkObjectInfoValid(errorList,equipObjectUploadData.get(6),equipObjectUploadData.get(3),
+                equipObjectInfosMap,CommonConstant.EQUIP_SHEET_NAME);
+        // 3.校验必填项
+        int equipSize = equipObjectUploadData.size();
+        for (int i = startRowIndex; i < equipSize; i++) {
+            String relCol = StrUtil.format(CommonConstant.REL_COL_FORMAT,CommonConstant.EQUIP_SHEET_NAME,i+1);
+            List<Object> datas = equipObjectUploadData.get(i);
+            // 1.项目id:必填,是否存在
+            String projectId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,1)));
+            checkProjectValid(errorList,projectId,projectMap,relCol);
+            // 2.空间本地编码:必填
+            checkContentBlank(errorList,CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,2))),relCol,
+                    EquipObjectColumnEnum.SPACE_LOCAL_ID.getRelName());
+            // 3.空间与设备关系:必填
+            checkContentBlank(errorList,CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,3))),relCol,
+                    EquipObjectColumnEnum.SPACE_EQUIP_REL.getRelName());
+            // 4.设备本地编码:必填,唯一
+            checkLocalIdExists(errorList,CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,4))),projectId,
+                    equipMap,relCol,EquipObjectColumnEnum.EQUIP_LOCAL_ID.getRelName());
+            // 5.设备名称:必填
+            checkContentBlank(errorList,CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,5))),relCol,
+                    EquipObjectColumnEnum.EQUIP_LOCAL_NAME.getRelName());
+            // 6.有效状态:必填
+            checkContentBlank(errorList,CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,6))),relCol,
+                    EquipObjectColumnEnum.VALID.getRelName());
+        }
+    }
+
+    /***
+     * Description: 批量处理物理世界对象数据
+     * @param uploadDTO : 整体上传数据
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/26 15:22
+     * Update By lijie 2021/9/26 15:22
+     */
+    @Override
+    public void batchHandleUploadDatas(UploadDTO uploadDTO) {
+        int startRowIndex = 7;
+        List<List<Object>> equipObjectUploadData = uploadDTO.getEquipObjectUploadData();
+        if (equipObjectUploadData.size()<=startRowIndex){
+            return;
+        }
+        Map<String, String> objectClazzMap = uploadDTO.getObjectClazzMap();
+        Map<String, Map<String, List<ObjectInstance>>> equipMap = uploadDTO.getEquipMap();
+        // 1.校验设备类型必填
+        List<Object> clazzRow = equipObjectUploadData.get(2);
+        // 1.1 设备类型名称
+        String equipTypeName = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(clazzRow.get(3)));
+        // 1.2 获得设备类型code
+        String classCode = objectClazzMap.get(equipTypeName);
+        Map<String, Map<String, List<ObjectInstance>>> spaceMap = uploadDTO.getSpaceMap();
+        Map<String, String> spaceFloorMap = MapUtil.defaultIfEmpty(uploadDTO.getSpaceFloorMap(), new HashMap<>());
+        Map<String, String> floorBuildMap = MapUtil.defaultIfEmpty(uploadDTO.getFloorBuildMap(), new HashMap<>());
+        Map<String, RelCodeDTO> relCodesMap = uploadDTO.getRelCodesMap();
+        int equipSize = equipObjectUploadData.size();
+        Map<String,List<ObjectInstance>> instanceMap = new HashMap<>();
+        Map<String,List<RelationInstance>> relationMap = new HashMap<>();
+        List<Object> infoCodeList = equipObjectUploadData.get(3);
+        for (int i = startRowIndex; i < equipSize; i++) {
+            List<Object> datas = equipObjectUploadData.get(i);
+            // 1.项目id
+            String projectId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,1)));
+            // 2.空间本地编码
+            String spaceLocalId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,2)));
+            // 3.空间与设备关系:必填
+            String relCodeStr = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,3)));
+            // 4.设备本地编码
+            String equipLocalId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,4)));
+            // 5.设备本地名称
+            String equipLocalName = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,5)));
+            // 6.有效状态
+            String validStr = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,6)));
+            Boolean valid = StrUtil.isBlank(validStr)?null:BooleanUtil.toBoolean(validStr);
+            // 7.判断设备是否存在
+            ObjectNode infos = commonCreateInfos(infoCodeList,datas);
+            if (equipMap.containsKey(equipLocalId)
+                    && equipMap.getOrDefault(equipLocalId,new HashMap<>()).containsKey(projectId)){
+                // 更新设备
+                commonUpdateObjectInstance(equipLocalId,equipLocalName,uploadDTO,projectId, equipMap,instanceMap,infos, valid);
+                continue;
+            }
+            // 新增设备
+            ObjectInstance objectInstance = commonCreateObjectInstance("Eq", equipLocalId, equipLocalName,
+                    projectId, uploadDTO, ObjType.equipment.name(), classCode, infos, instanceMap, equipMap, valid);
+            // 新增空间关系
+            List<ObjectInstance> spaces = spaceMap.getOrDefault(spaceLocalId, new HashMap<>()).getOrDefault(projectId, new ArrayList<>());
+            RelCodeDTO relCodeDTO = relCodesMap.get(relCodeStr);
+            if (CollUtil.isEmpty(spaces) || null==relCodeDTO){
+                continue;
+            }
+            for (ObjectInstance space : spaces) {
+                List<RelationInstance> rels = relationMap.getOrDefault(projectId, new ArrayList<>());
+                rels.add(commmonCreateRelationInstance(projectId,uploadDTO, relCodeDTO.getGraphCode(),
+                        relCodeDTO.getRelCode(),objectInstance.getId(),space.getId(),space.getClassCode()));
+                String floorId = spaceFloorMap.getOrDefault(space.getId(), "");
+                if (StrUtil.isNotBlank(floorId)
+                        && GraphCodeEnum.MECH_IN_ARCH.getIndex().equals(relCodeDTO.getGraphCode())){
+                    rels.add(commmonCreateRelationInstance(projectId,uploadDTO, GraphCodeEnum.MECH_IN_ARCH.getIndex(),
+                            RelCodeEnum.EQ_2_FL.getIndex(),objectInstance.getId(),floorId,null));
+                    if (floorBuildMap.containsKey(floorId)
+                            && StrUtil.isNotBlank(floorBuildMap.get(floorId))){
+                        rels.add(commmonCreateRelationInstance(projectId,uploadDTO, GraphCodeEnum.MECH_IN_ARCH.getIndex(),
+                                RelCodeEnum.EQ_2_BD.getIndex(),objectInstance.getId(),floorBuildMap.get(floorId),null));
+                    }
+                }
+                if (StrUtil.isNotBlank(floorId)
+                        && GraphCodeEnum.MECH_FOR_ARCH.getIndex().equals(relCodeDTO.getGraphCode())){
+                    rels.add(commmonCreateRelationInstance(projectId,uploadDTO, GraphCodeEnum.MECH_FOR_ARCH.getIndex(),
+                            RelCodeEnum.EQ_2_FL.getIndex(),objectInstance.getId(),floorId,null));
+                    if (floorBuildMap.containsKey(floorId)
+                            && StrUtil.isNotBlank(floorBuildMap.get(floorId))){
+                        rels.add(commmonCreateRelationInstance(projectId,uploadDTO, GraphCodeEnum.MECH_FOR_ARCH.getIndex(),
+                                RelCodeEnum.EQ_2_BD.getIndex(),objectInstance.getId(),floorBuildMap.get(floorId),null));
+                    }
+                }
+                relationMap.put(projectId,rels);
+            }
+        }
+        commonUpdateInstances(instanceMap,relationMap,uploadDTO);
+    }
+    /***
+     * Description: 校验空间数据是否存在
+     * @param errorList : 错误列表
+     * @param uploadDTO : 上传数据
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/27 22:33
+     * Update By lijie 2021/9/27 22:33
+     */
+    @Override
+    public void secondCheckSpaceDataIsValid(List<String> errorList, UploadDTO uploadDTO) {
+        int startRowIndex = 7;
+        List<List<Object>> equipObjectUploadData = uploadDTO.getEquipObjectUploadData();
+        if (equipObjectUploadData.size()<=startRowIndex){
+            return;
+        }
+        Map<String, Map<String, List<ObjectInstance>>> spaceMap = uploadDTO.getSpaceMap();
+        Map<String, ObjectInstance> projectMap = uploadDTO.getProjectMap();
+        // 3.校验必填项
+        int equipSize = equipObjectUploadData.size();
+        for (int i = startRowIndex; i < equipSize; i++) {
+            String relCol = StrUtil.format(CommonConstant.REL_COL_FORMAT,CommonConstant.EQUIP_SHEET_NAME,i+1);
+            List<Object> datas = equipObjectUploadData.get(i);
+            // 1.项目id:必填,是否存在
+            String projectId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,1)));
+            // 2.空间本地编码:必填
+            String spaceLocalId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas, 2)));
+            if (!spaceMap.containsKey(spaceLocalId)
+                    || !spaceMap.getOrDefault(spaceLocalId,new HashMap<>()).containsKey(projectId)){
+                // 空间对象不存在
+                errorList.add(StrUtil.format("{}{}{}{}{}",relCol,
+                        EquipObjectColumnEnum.SPACE_LOCAL_ID.getRelName(),"在项目",projectId,"下不存在"));
+            }
+        }
+    }
+
+    /***
+     * Description: 获得excel的sheet名称
+     * @return : java.lang.String
+     * @author : lijie
+     * @date :2021/9/24 16:54
+     * Update By lijie 2021/9/24 16:54
+     */
+    @Override
+    protected String getExcelSheetName() {
+        return "设备对象录入";
+    }
+
+    /***
+     * Description: 获得不可变行头的映射
+     * @return : java.util.Map<java.lang.String,java.lang.String>
+     * @author : lijie
+     * @date :2021/9/24 16:09
+     * Update By lijie 2021/9/24 16:09
+     */
+    @Override
+    protected Map<Integer, String> getPersistentHeadMap() {
+        List<EquipObjectColumnEnum> list = CollUtil.list(false, EnumUtil.getEnumMap(EquipObjectColumnEnum.class).values());
+        return list.stream()
+                .collect(Collectors.toMap(EquipObjectColumnEnum::getIndex, EquipObjectColumnEnum::getName, (k1, k2) -> k1));
+    }
+
+    /***
+     * Description: 获得excel行头索引
+     * @return : java.lang.Integer
+     * @author : lijie
+     * @date :2021/9/24 15:59
+     * Update By lijie 2021/9/24 15:59
+     */
+    @Override
+    protected Integer getExcelHeadIndex() {
+        return 6;
+    }
+    /***
+     * Description: 获得列偏移量
+     * @return : java.lang.Integer
+     * @author : lijie
+     * @date :2021/9/27 15:32
+     * Update By lijie 2021/9/27 15:32
+     */
+    @Override
+    protected Integer getExcelColumnOffset() {
+        return 1;
+    }
+}

+ 253 - 0
dmp-rwd/src/main/java/com/persagy/dmp/rwd/validators/service/impl/SystemFileCheckServiceImpl.java

@@ -0,0 +1,253 @@
+package com.persagy.dmp.rwd.validators.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.text.CharSequenceUtil;
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.core.util.EnumUtil;
+import cn.hutool.core.util.StrUtil;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.persagy.dmp.rwd.constants.CommonConstant;
+import com.persagy.dmp.rwd.constants.EquipObjectColumnEnum;
+import com.persagy.dmp.rwd.constants.ErrorEnum;
+import com.persagy.dmp.rwd.constants.SystemObjectColumnEnum;
+import com.persagy.dmp.rwd.entity.ObjectInstance;
+import com.persagy.dmp.rwd.entity.RelationInstance;
+import com.persagy.dmp.rwd.enums.ObjType;
+import com.persagy.dmp.rwd.model.rwd.RelCodeDTO;
+import com.persagy.dmp.rwd.model.rwd.UploadDTO;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class SystemFileCheckServiceImpl extends AbstractFileCheckService {
+
+    /***
+     * Description: 校验数据的正确性
+     * @param errorList : 错误列表
+     * @param uploadDTO : 整体上传数据
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/26 15:01
+     * Update By lijie 2021/9/26 15:01
+     */
+    @Override
+    public void checkDataIsValid(List<String> errorList, UploadDTO uploadDTO) {
+        int startRowIndex = 7;
+        List<List<Object>> systemObjectUploadData = uploadDTO.getSystemObjectUploadData();
+        if (systemObjectUploadData.size()<=startRowIndex){
+            return;
+        }
+        Map<String, String> objectClazzMap = uploadDTO.getObjectClazzMap();
+        Map<String, String> systemObjectInfosMap = uploadDTO.getSystemObjectInfosMap();
+        Map<String, Map<String, List<ObjectInstance>>> systemMap = uploadDTO.getSystemMap();
+        Map<String, ObjectInstance> projectMap = uploadDTO.getProjectMap();
+        // 1.校验设备类型必填
+        List<Object> clazzRow = systemObjectUploadData.get(2);
+        String relClazzCol = StrUtil.format(CommonConstant.REL_COL_FORMAT,CommonConstant.SYSTEM_SHEET_NAME,3);
+        // 1.1 专业名称
+        String domainName = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(clazzRow.get(1)));
+        checkContentBlank(errorList,domainName,relClazzCol, "专业");
+        if (StrUtil.isNotBlank(domainName) && !objectClazzMap.containsKey(domainName)){
+            errorList.add(StrUtil.format(CommonConstant.THREE_FORMAT,relClazzCol, "专业",ErrorEnum.NO_EXIST_ERROR.getDesc()));
+        }
+        // 1.2 系统类型名称
+        String systemName = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(clazzRow.get(2)));
+        checkContentBlank(errorList,systemName,relClazzCol, "系统类");
+        if (StrUtil.isNotBlank(systemName) && !objectClazzMap.containsKey(systemName)){
+            errorList.add(StrUtil.format(CommonConstant.THREE_FORMAT,relClazzCol, "系统类", ErrorEnum.NO_EXIST_ERROR.getDesc()));
+        }
+        // 2.校验信息点code是否正确
+        checkObjectInfoValid(errorList,systemObjectUploadData.get(6),systemObjectUploadData.get(3),
+                systemObjectInfosMap, CommonConstant.SYSTEM_SHEET_NAME);
+        // 3.校验必填项
+        int equipSize = systemObjectUploadData.size();
+        for (int i = startRowIndex; i < equipSize; i++) {
+            String relCol = StrUtil.format(CommonConstant.REL_COL_FORMAT,CommonConstant.SYSTEM_SHEET_NAME,i+1);
+            List<Object> datas = systemObjectUploadData.get(i);
+            // 1.项目id:必填,是否存在
+            String projectId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,1)));
+            checkProjectValid(errorList,projectId,projectMap,relCol);
+            // 2.建筑本地编码:必填
+            checkContentBlank(errorList,CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,2))),relCol,
+                    SystemObjectColumnEnum.BUILD_LOCAL_ID.getRelName());
+            // 3.建筑与系统关系:必填
+            checkContentBlank(errorList,CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,3))),relCol,
+                    SystemObjectColumnEnum.BUILD_EQUIP_REL.getRelName());
+            // 4.系统本地编码:必填,唯一
+            checkLocalIdExists(errorList,CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,4))),projectId,
+                    systemMap,relCol,SystemObjectColumnEnum.SYSTEM_LOCAL_ID.getRelName());
+            // 5.系统名称:必填
+            checkContentBlank(errorList,CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,5))),relCol,
+                    SystemObjectColumnEnum.SYSTEM_LOCAL_NAME.getRelName());
+            // 6.系统状态:必填
+            checkContentBlank(errorList,CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,6))),relCol,
+                    SystemObjectColumnEnum.VALID.getRelName());
+        }
+    }
+
+    /***
+     * Description: 批量处理物理世界对象数据
+     * @param uploadDTO : 整体上传数据
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/26 15:22
+     * Update By lijie 2021/9/26 15:22
+     */
+    @Override
+    public void batchHandleUploadDatas(UploadDTO uploadDTO) {
+        int startRowIndex = 7;
+        List<List<Object>> systemObjectUploadData = uploadDTO.getSystemObjectUploadData();
+        if (systemObjectUploadData.size()<=startRowIndex){
+            return;
+        }
+        Map<String, String> objectClazzMap = uploadDTO.getObjectClazzMap();
+        Map<String, Map<String, List<ObjectInstance>>> spaceMap = uploadDTO.getSpaceMap();
+        // 1.校验设备类型必填
+        List<Object> clazzRow = systemObjectUploadData.get(2);
+        // 1.1 系统类型名称
+        String systemName = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(clazzRow.get(2)));
+        // 1.2 获得系统类型code
+        String classCode = objectClazzMap.get(systemName);
+        Map<String, Map<String, List<ObjectInstance>>> buildMap = uploadDTO.getBuildMap();
+        Map<String, RelCodeDTO> relCodesMap = uploadDTO.getRelCodesMap();
+        int equipSize = systemObjectUploadData.size();
+        Map<String,List<ObjectInstance>> instanceMap = new HashMap<>();
+        Map<String,List<RelationInstance>> relationMap = new HashMap<>();
+        List<Object> infoCodeList = systemObjectUploadData.get(3);
+        for (int i = startRowIndex; i < equipSize; i++) {
+            List<Object> datas = systemObjectUploadData.get(i);
+            // 1.项目id
+            String projectId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,1)));
+            // 2.建筑本地编码
+            String buildLocalId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,2)));
+            // 3.建筑与系统关系
+            String relCodeStr = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,3)));
+            // 4.系统本地编码
+            String systemLocalId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,4)));
+            // 5.系统本地名称
+            String systemLocalName = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,5)));
+            // 6.有效状态
+            String validStr = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,6)));
+            Boolean valid = StrUtil.isBlank(validStr)?null: BooleanUtil.toBoolean(validStr);
+            // 7.判断设备是否存在
+            ObjectNode infos = commonCreateInfos(infoCodeList,datas);
+            if (spaceMap.containsKey(systemLocalId)
+                    && spaceMap.getOrDefault(systemLocalId,new HashMap<>()).containsKey(projectId)){
+                // 更新系统
+                commonUpdateObjectInstance(systemLocalId,systemLocalName,uploadDTO,projectId, spaceMap,instanceMap,infos, valid);
+                continue;
+            }
+            // 新增系统
+            ObjectInstance objectInstance = commonCreateObjectInstance("Sy", systemLocalId, systemLocalName,
+                    projectId, uploadDTO, ObjType.system.name(), classCode, infos, instanceMap, spaceMap, valid);
+            // 新增建筑与系统关系
+            List<ObjectInstance> buildings = buildMap.getOrDefault(buildLocalId, new HashMap<>()).getOrDefault(projectId, new ArrayList<>());
+            RelCodeDTO relCodeDTO = relCodesMap.get(relCodeStr);
+            if (CollUtil.isEmpty(buildings) || null==relCodeDTO){
+                continue;
+            }
+            for (ObjectInstance building : buildings) {
+                List<RelationInstance> rels = relationMap.getOrDefault(projectId, new ArrayList<>());
+                rels.add(commmonCreateRelationInstance(projectId,uploadDTO, relCodeDTO.getGraphCode(),
+                        relCodeDTO.getRelCode(),objectInstance.getId(),building.getId(),null));
+                relationMap.put(projectId,rels);
+            }
+        }
+        commonUpdateInstances(instanceMap,relationMap,uploadDTO);
+    }
+
+    /***
+     * Description: 校验空间数据是否存在
+     * @param errorList : 错误列表
+     * @param uploadDTO : 上传数据
+     * @return : void
+     * @author : lijie
+     * @date :2021/9/27 22:33
+     * Update By lijie 2021/9/27 22:33
+     */
+    @Override
+    public void secondCheckSpaceDataIsValid(List<String> errorList, UploadDTO uploadDTO) {
+        int startRowIndex = 7;
+        List<List<Object>> systemObjectUploadData = uploadDTO.getSystemObjectUploadData();
+        if (systemObjectUploadData.size()<=startRowIndex){
+            return;
+        }
+        Map<String, Map<String, List<ObjectInstance>>> buildMap = uploadDTO.getBuildMap();
+        // 3.校验必填项
+        int systemSize = systemObjectUploadData.size();
+        for (int i = startRowIndex; i < systemSize; i++) {
+            String relCol = StrUtil.format(CommonConstant.REL_COL_FORMAT,CommonConstant.SYSTEM_SHEET_NAME,i+1);
+            List<Object> datas = systemObjectUploadData.get(i);
+            // 1.项目id:必填,是否存在
+            String projectId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas,1)));
+            // 2.建筑本地编码:必填
+            String buildLocalId = CharSequenceUtil.trimToEmpty(StrUtil.utf8Str(CollUtil.get(datas, 2)));
+            if (!buildMap.containsKey(buildLocalId)
+                    || !buildMap.getOrDefault(buildLocalId,new HashMap<>()).containsKey(projectId)){
+                // 空间对象不存在
+                errorList.add(StrUtil.format("{}{}{}{}{}",relCol,
+                        SystemObjectColumnEnum.BUILD_LOCAL_ID.getRelName(),"在项目",projectId,"下不存在"));
+            }
+        }
+    }
+
+    /***
+     * Description: 获得excel的sheet名称
+     * @return : java.lang.String
+     * @author : lijie
+     * @date :2021/9/24 16:54
+     * Update By lijie 2021/9/24 16:54
+     */
+    @Override
+    protected String getExcelSheetName() {
+        return "系统对象录入";
+    }
+
+    /***
+     * Description: 获得不可变行头的映射
+     * @return : java.util.Map<java.lang.String,java.lang.String>
+     * @author : lijie
+     * @date :2021/9/24 16:09
+     * Update By lijie 2021/9/24 16:09
+     */
+    @Override
+    protected Map<Integer, String> getPersistentHeadMap() {
+        List<SystemObjectColumnEnum> list = CollUtil.list(false, EnumUtil.getEnumMap(SystemObjectColumnEnum.class).values());
+        return list.stream()
+                .collect(Collectors.toMap(SystemObjectColumnEnum::getIndex, SystemObjectColumnEnum::getName, (k1, k2) -> k1));
+    }
+
+    /***
+     * Description: 获得excel行头索引
+     * @return : java.lang.Integer
+     * @author : lijie
+     * @date :2021/9/24 15:59
+     * Update By lijie 2021/9/24 15:59
+     */
+    @Override
+    protected Integer getExcelHeadIndex() {
+        return 6;
+    }
+
+    /***
+     * Description: 获得列偏移量
+     * @return : java.lang.Integer
+     * @author : lijie
+     * @date :2021/9/27 15:32
+     * Update By lijie 2021/9/27 15:32
+     */
+    @Override
+    protected Integer getExcelColumnOffset() {
+        return 1;
+    }
+
+}

+ 5 - 1
dmp-rwd/src/main/resources/application.yml

@@ -6,4 +6,8 @@ spring:
         session_factory:
           statement_inspector: com.persagy.dmp.rwd.sharding.JpaSqlStatementInspector
     hibernate:
-      ddl-auto: none
+      ddl-auto: none
+  servlet:
+    multipart:
+      max-file-size: 20MB
+      max-request-size: 20MB

BIN
dmp-rwd/src/main/resources/arthas.zip


+ 6 - 1
dmp-rwd/src/main/resources/bootstrap.yml

@@ -6,4 +6,9 @@ spring:
   cloud:
     config:
       profile: dev
-      uri: http://localhost:9932
+      uri: http://localhost:9932
+persagy:
+  dmp:
+    rwd:
+      log:
+        level: ${PERSAGY_DMP_RWD_LOG_LEVEL:INFO}

+ 12 - 11
dmp-rwd/src/main/resources/logback-spring.xml

@@ -3,6 +3,7 @@
 
     <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
     <property name="log_pattern" value="%-30thread %d{yyyyMMdd HH:mm:ss.SSS} %-5level %logger{140} - %msg%n"/>
+    <springProperty name="LOG_LEVEL" scope="context" source="persagy.dmp.rwd.log.level" defaultValue="INFO"/>
     <property name="app_name" value="rwd"/>
     <springProperty scope="context" name="log_path" source="persagy.log.path"/>
     <property name="log_file" value="${log_path}/${app_name}"/>
@@ -25,29 +26,29 @@
         </encoder>
     </appender>
 
-    <logger name="org.hibernate" level="INFO"/>
-    <logger name="org.springframework" level="INFO"/>
-    <logger name="com.netflix" level="INFO"/>
-    <logger name="org.apache.http" level="INFO"/>
+    <logger name="org.hibernate" level="${LOG_LEVEL}"/>
+    <logger name="org.springframework" level="${LOG_LEVEL}"/>
+    <logger name="com.netflix" level="${LOG_LEVEL}"/>
+    <logger name="org.apache.http" level="${LOG_LEVEL}"/>
 
     <springProfile name="dev">
-        <logger name="org.hibernate.SQL" level="DEBUG"/>
-        <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE"/>
-        <root level="INFO">
+        <logger name="org.hibernate.SQL" level="${LOG_LEVEL}"/>
+        <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="${LOG_LEVEL}"/>
+        <root level="${LOG_LEVEL}">
             <appender-ref ref="stdout"/>
         </root>
     </springProfile>
 
     <springProfile name="test">
-        <logger name="org.hibernate.SQL" level="DEBUG"/>
-        <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE"/>
-        <root level="info">
+        <logger name="org.hibernate.SQL" level="${LOG_LEVEL}"/>
+        <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="${LOG_LEVEL}"/>
+        <root level="${LOG_LEVEL}">
             <appender-ref ref="file"/>
         </root>
     </springProfile>
 
     <springProfile name="prod">
-        <root level="info">
+        <root level="${LOG_LEVEL}">
             <appender-ref ref="file"/>
         </root>
     </springProfile>

+ 60 - 0
dmp-rwd/src/main/resources/mapper/FuncidDefMapper.xml

@@ -0,0 +1,60 @@
+<?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.persagy.dmp.rwd.repository.FuncidDefMapper">
+	<resultMap id="BaseResultMap" type="com.persagy.dmp.rwd.entity.FuncidDef">
+		<id property="id" column="id" jdbcType="VARCHAR"/>
+		<result property="name" column="name" jdbcType="VARCHAR"/>
+		<result property="code" column="code" jdbcType="VARCHAR"/>
+		<result property="origCode" column="orig_code" jdbcType="VARCHAR"/>
+		<result property="aliasCode" column="alias_code" jdbcType="VARCHAR"/>
+		<result property="aliasName" column="alias_name" jdbcType="VARCHAR"/>
+		<result property="classCode" column="class_code" jdbcType="VARCHAR"/>
+		<result property="type" column="type" jdbcType="VARCHAR"/>
+		<result property="groupCode" column="group_code" jdbcType="VARCHAR"/>
+		<result property="projectId" column="project_id" jdbcType="VARCHAR"/>
+		<result property="category" column="category" jdbcType="VARCHAR"/>
+		<result property="firstTag" column="first_tag" jdbcType="VARCHAR"/>
+		<result property="secondTag" column="second_tag" jdbcType="VARCHAR"/>
+		<result property="priority" column="priority" jdbcType="VARCHAR"/>
+		<result property="inputMode" column="input_mode" jdbcType="VARCHAR"/>
+		<result property="unit" column="unit" jdbcType="VARCHAR"/>
+		<result property="dataType" column="data_type" jdbcType="VARCHAR"/>
+		<result property="origDataType" column="orig_data_type" jdbcType="VARCHAR"/>
+		<result property="isMultiple" column="is_multiple" jdbcType="INTEGER"/>
+		<result property="isRegion" column="is_region" jdbcType="INTEGER"/>
+		<result property="formater" column="formater" jdbcType="VARCHAR"/>
+		<result property="dataSource" column="data_source" jdbcType="JAVA_OBJECT" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
+		<result property="note" column="note" jdbcType="VARCHAR"/>
+		<result property="subFlag" column="sub_flag" jdbcType="INTEGER"/>
+		<result property="weakPoint" column="weak_point" jdbcType="INTEGER"/>
+		<result property="aliasFirstTag" column="alias_first_tag" jdbcType="VARCHAR"/>
+		<result property="aliasSecondTag" column="alias_second_tag" jdbcType="VARCHAR"/>
+	</resultMap>
+	<select id="queryFuncidByClassCodesAndGroupCode" resultType="com.persagy.dmp.rwd.entity.FuncidDef">
+		SELECT
+			*
+		FROM
+			rwd_def_funcid_${groupCode}
+		WHERE 1=1
+		<if test="null!=classCodes and classCodes.size()>0">
+			<foreach collection="classCodes" item="classCode" open=" AND class_code IN(" close=")" separator=",">
+				#{classCode}
+			</foreach>
+		</if>
+		UNION
+		SELECT
+			*
+		FROM
+			rwd_def_funcid
+		WHERE 1=1
+		<if test="null!=classCodes and classCodes.size()>0">
+			<foreach collection="classCodes" item="classCode" open=" AND class_code IN(" close=")" separator=",">
+				#{classCode}
+			</foreach>
+		</if>
+		  AND CONCAT(class_code, '_', `code`) NOT IN ( SELECT CONCAT( class_code, '_', `code`) FROM rwd_def_funcid_${groupCode});
+	</select>
+
+
+</mapper>

+ 72 - 1
dmp-rwd/src/main/resources/mapper/ProjectDao.xml

@@ -1,8 +1,28 @@
 <?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.persagy.dmp.rwd.repository.ProjectDao">
+	<resultMap id="BaseResultMap" type="com.persagy.dmp.rwd.entity.ObjectInstance">
+		<id property="id" column="id" jdbcType="VARCHAR"/>
+		<result property="name" column="name" jdbcType="VARCHAR"/>
+		<result property="localId" column="local_id" jdbcType="VARCHAR"/>
+		<result property="localName" column="local_name" jdbcType="VARCHAR"/>
+		<result property="groupCode" column="group_code" jdbcType="VARCHAR"/>
+		<result property="projectId" column="project_id" jdbcType="VARCHAR"/>
+		<result property="objType" column="obj_type" jdbcType="VARCHAR"/>
+		<result property="classCode" column="class_code" jdbcType="VARCHAR"/>
+		<result property="grouping" column="grouping" jdbcType="INTEGER"/>
+		<result property="infos" column="infos" jdbcType="JAVA_OBJECT" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
+		<result property="virtualInfoCodes" column="virtual_codes" jdbcType="VARCHAR" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
+		<result property="createApp" column="create_app" jdbcType="VARCHAR"/>
+		<result property="updateApp" column="update_app" jdbcType="VARCHAR"/>
+		<result property="createUser" column="create_user" jdbcType="VARCHAR"/>
+		<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
+		<result property="updateUser" column="update_user" jdbcType="VARCHAR"/>
+		<result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
+		<result property="valid" column="valid" jdbcType="INTEGER"/>
+	</resultMap>
+
 	<select id="queryRwdObjectTableNamesByGroupCode" parameterType="hashmap" resultType="string">
 		USE INFORMATION_SCHEMA;
 		SET SESSION group_concat_max_len = 65535;
@@ -17,5 +37,56 @@
 	<select id="queryAllProjects" parameterType="string" resultType="com.persagy.dmp.rwd.entity.ObjectInstance">
 		${querySql}
 	</select>
+	<select id="queryRwdObjectsMultiTablesAndLocalIds" resultMap="BaseResultMap">
+		<if test="null!=tableNames and tableNames.size()>0">
+			<foreach collection="tableNames" separator=" UNION " item="tableName">
+				SELECT * FROM ${tableName} WHERE 1=1 AND(
+				<if test="null!=projectIds and projectIds.size()>0">
+					<foreach collection="projectIds" item="projectId" open="id IN(" close=")" separator=",">
+						#{projectId}
+					</foreach>
+				</if>
+				<if test="null!=projectIds and projectIds.size()>0 and null!=localIds and localIds.size()>0">
+					OR
+				</if>
+				<if test="null!=localIds and localIds.size()>0">
+					<foreach collection="localIds" item="localId" open="local_id IN(" close=")" separator=",">
+						#{localId}
+					</foreach>
+				</if>
+				)
+			</foreach>
+			;
+		</if>
+	</select>
+	<select id="queryObjRelBySpaceIdsAndProjectId" resultType="com.persagy.dmp.rwd.entity.RelationInstance">
+		<foreach collection="rels" item="rel" separator=" UNION ">
+			SELECT
+			*
+			FROM
+			rwd_relation_${groupCode}_${rel.projectId}
+			WHERE graph_code='ArchSubset'
+			AND rel_code = 'Fl2Sp'
+			<foreach collection="rel.spaceIds" item="spaceId" open="AND obj_to IN (" close=")" separator=",">
+				#{spaceId}
+			</foreach>
+			UNION
+			SELECT
+			*
+			FROM
+			rwd_relation_${groupCode}_${rel.projectId}
+			WHERE
+			graph_code = 'ArchSubset'
+			AND rel_code = 'Bd2Fl'
+			AND obj_to IN(
+			    SELECT obj_from
+			    FROM rwd_relation_${groupCode}_${rel.projectId}
+			    WHERE graph_code = 'ArchSubset'
+			    AND rel_code = 'Fl2Sp'
+			<foreach collection="rel.spaceIds" item="spaceId" open="AND obj_to IN (" close=")" separator=",">
+				#{spaceId}
+			</foreach>)
+		</foreach>
+	</select>
 
 </mapper>

BIN
dmp-rwd/src/main/resources/template/ObjectInfoTemplate.xlsx


+ 8 - 3
pom.xml

@@ -127,7 +127,7 @@
             <dependency>
                 <groupId>org.apache.poi</groupId>
                 <artifactId>poi</artifactId>
-                <version>3.17</version>
+                <version>5.0.0</version>
                 <exclusions>
                     <exclusion>
                         <groupId>commons-logging</groupId>
@@ -138,12 +138,12 @@
             <dependency>
                 <groupId>org.apache.poi</groupId>
                 <artifactId>poi-ooxml</artifactId>
-                <version>3.17</version>
+                <version>5.0.0</version>
             </dependency>
             <dependency>
                 <groupId>org.apache.poi</groupId>
                 <artifactId>poi-ooxml-schemas</artifactId>
-                <version>3.17</version>
+                <version>4.1.2</version>
             </dependency>
             <dependency>
                 <groupId>org.slf4j</groupId>
@@ -160,6 +160,11 @@
                 <artifactId>spring-boot-starter-amqp</artifactId>
                 <version>${springboot.version}</version>
             </dependency>
+            <dependency>
+                <groupId>cn.hutool</groupId>
+                <artifactId>hutool-all</artifactId>
+                <version>5.7.2</version>
+            </dependency>
         </dependencies>
 
     </dependencyManagement>