瀏覽代碼

Merge branch 'develop' of http://192.168.20.45/Sky/ROBOT-APP into develop

wzz 2 年之前
父節點
當前提交
309416d5bf
共有 57 個文件被更改,包括 5520 次插入1 次删除
  1. 33 0
      code/AppDownload/.gitignore
  2. 二進制
      code/AppDownload/.mvn/wrapper/maven-wrapper.jar
  3. 2 0
      code/AppDownload/.mvn/wrapper/maven-wrapper.properties
  4. 140 0
      code/AppDownload/logs/pmp
  5. 二進制
      code/AppDownload/logs/pmp.2022-02-23.0.gz
  6. 331 0
      code/AppDownload/mvnw
  7. 188 0
      code/AppDownload/mvnw.cmd
  8. 74 0
      code/AppDownload/pom.xml
  9. 13 0
      code/AppDownload/src/main/java/com/sw/appcloudv1/Appcloudv1Application.java
  10. 52 0
      code/AppDownload/src/main/java/com/sw/appcloudv1/Utils/ShortUrlUtils.java
  11. 38 0
      code/AppDownload/src/main/java/com/sw/appcloudv1/controller/AppDownloadController.java
  12. 35 0
      code/AppDownload/src/main/java/com/sw/appcloudv1/controller/ShortUrlController.java
  13. 113 0
      code/AppDownload/src/main/java/com/sw/appcloudv1/entities/ResultData.java
  14. 9 0
      code/AppDownload/src/main/java/com/sw/appcloudv1/service/AppDownloadService.java
  15. 171 0
      code/AppDownload/src/main/java/com/sw/appcloudv1/service/AppDownloadServiceImpl.java
  16. 8 0
      code/AppDownload/src/main/java/com/sw/appcloudv1/service/ShortUrlService.java
  17. 42 0
      code/AppDownload/src/main/java/com/sw/appcloudv1/service/ShortUrlServiceImpl.java
  18. 25 0
      code/AppDownload/src/main/resources/application.properties
  19. 13 0
      code/AppDownload/src/test/java/com/sw/appcloudv1/Appcloudv1ApplicationTests.java
  20. 7 1
      code/readme.md
  21. 33 0
      code/robot2ips/.gitignore
  22. 二進制
      code/robot2ips/IPS监测点清单.xls
  23. 316 0
      code/robot2ips/mvnw
  24. 188 0
      code/robot2ips/mvnw.cmd
  25. 245 0
      code/robot2ips/pom.xml
  26. 2 0
      code/robot2ips/readme.md
  27. 13 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/Robot2ipsApplication.java
  28. 28 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/aspect/ExcelHeader.java
  29. 73 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/beans/dto/CheckDataDTO.java
  30. 27 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/beans/dto/IPSPointDTO.java
  31. 33 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/beans/dto/RobotDTO.java
  32. 20 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/beans/vo/IPSResp.java
  33. 32 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/beans/vo/RecordData.java
  34. 64 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/beans/vo/RecordTaskPoint.java
  35. 14 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/common/RedisKey.java
  36. 25 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/config/CommandLineRunnerImpl.java
  37. 17 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/config/MybatisPlusConfig.java
  38. 68 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/config/RedisConfig.java
  39. 31 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/dao/UploadMapper.java
  40. 11 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/service/CheckDataService.java
  41. 165 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/service/impl/CheckDataServiceImpl.java
  42. 26 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/task/UploadIPSTask.java
  43. 207 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/util/Base64Util.java
  44. 518 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/util/DateUtil.java
  45. 613 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/util/ExcelUtil.java
  46. 354 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/util/FileUtil.java
  47. 125 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/util/HttpUtils.java
  48. 44 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/util/ListSplitUtil.java
  49. 32 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/util/MyBeanUtil.java
  50. 43 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/util/PageInfoUtil.java
  51. 553 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/util/RedisUtils.java
  52. 81 0
      code/robot2ips/src/main/java/com/sunwin/robot2ips/util/TimeUtil.java
  53. 54 0
      code/robot2ips/src/main/resources/application-prod.properties
  54. 54 0
      code/robot2ips/src/main/resources/application-test.properties
  55. 51 0
      code/robot2ips/src/main/resources/application.properties
  56. 53 0
      code/robot2ips/src/main/resources/mapper/UploadMapper.xml
  57. 13 0
      code/robot2ips/src/test/java/com/sunwin/robot2ips/Robot2ipsApplicationTests.java

+ 33 - 0
code/AppDownload/.gitignore

@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/

二進制
code/AppDownload/.mvn/wrapper/maven-wrapper.jar


+ 2 - 0
code/AppDownload/.mvn/wrapper/maven-wrapper.properties

@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar

+ 140 - 0
code/AppDownload/logs/pmp

@@ -0,0 +1,140 @@
+2022-02-24 10:17:51.035 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Starting Appcloudv1Application using Java 1.8.0_181 on DESKTOP-FQ8NNTE with PID 92204 (E:\ProjectIndex\appcloudv1\target\classes started by SUNWIN in E:\ProjectIndex\appcloudv1)
+2022-02-24 10:17:51.050 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- No active profile set, falling back to default profiles: default
+2022-02-24 10:17:52.646 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Started Appcloudv1Application in 1.985 seconds (JVM running for 3.737)
+2022-02-24 10:18:10.851 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Starting Appcloudv1Application using Java 1.8.0_181 on DESKTOP-FQ8NNTE with PID 99932 (E:\ProjectIndex\appcloudv1\target\classes started by SUNWIN in E:\ProjectIndex\appcloudv1)
+2022-02-24 10:18:10.853 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- No active profile set, falling back to default profiles: default
+2022-02-24 10:18:11.798 [restartedMain] WARN  org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext- Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'shortUrlServiceImpl': Invocation of init method failed; nested exception is java.lang.NullPointerException
+2022-02-24 10:18:11.840 [restartedMain] ERROR org.springframework.boot.SpringApplication- Application run failed
+org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'shortUrlServiceImpl': Invocation of init method failed; nested exception is java.lang.NullPointerException
+	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:160)
+	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:440)
+	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1796)
+	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620)
+	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
+	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
+	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
+	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
+	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
+	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953)
+	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
+	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
+	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
+	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:732)
+	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:414)
+	at org.springframework.boot.SpringApplication.run(SpringApplication.java:302)
+	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303)
+	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292)
+	at com.sw.appcloudv1.Appcloudv1Application.main(Appcloudv1Application.java:10)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
+	at java.lang.reflect.Method.invoke(Method.java:498)
+	at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
+Caused by: java.lang.NullPointerException: null
+	at com.sw.appcloudv1.service.ShortUrlServiceImpl.createShortUrl(ShortUrlServiceImpl.java:30)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
+	at java.lang.reflect.Method.invoke(Method.java:498)
+	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389)
+	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333)
+	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157)
+	... 23 common frames omitted
+2022-02-24 10:18:22.539 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Starting Appcloudv1Application using Java 1.8.0_181 on DESKTOP-FQ8NNTE with PID 97644 (E:\ProjectIndex\appcloudv1\target\classes started by SUNWIN in E:\ProjectIndex\appcloudv1)
+2022-02-24 10:18:22.539 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- No active profile set, falling back to default profiles: default
+2022-02-24 10:18:39.090 [restartedMain] WARN  org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext- Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'shortUrlServiceImpl': Invocation of init method failed; nested exception is java.lang.NullPointerException
+2022-02-24 10:18:42.691 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Starting Appcloudv1Application using Java 1.8.0_181 on DESKTOP-FQ8NNTE with PID 100068 (E:\ProjectIndex\appcloudv1\target\classes started by SUNWIN in E:\ProjectIndex\appcloudv1)
+2022-02-24 10:18:42.691 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- No active profile set, falling back to default profiles: default
+2022-02-24 10:18:57.893 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Started Appcloudv1Application in 15.505 seconds (JVM running for 16.223)
+2022-02-24 10:19:13.045 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Starting Appcloudv1Application using Java 1.8.0_181 on DESKTOP-FQ8NNTE with PID 99836 (E:\ProjectIndex\appcloudv1\target\classes started by SUNWIN in E:\ProjectIndex\appcloudv1)
+2022-02-24 10:19:13.045 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- No active profile set, falling back to default profiles: default
+2022-02-24 10:19:32.470 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Started Appcloudv1Application in 19.727 seconds (JVM running for 20.541)
+2022-02-24 10:19:34.841 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Starting Appcloudv1Application using Java 1.8.0_181 on DESKTOP-FQ8NNTE with PID 90412 (E:\ProjectIndex\appcloudv1\target\classes started by SUNWIN in E:\ProjectIndex\appcloudv1)
+2022-02-24 10:19:34.842 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- No active profile set, falling back to default profiles: default
+2022-02-24 10:19:42.332 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Started Appcloudv1Application in 7.789 seconds (JVM running for 8.401)
+2022-02-24 10:19:46.220 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Starting Appcloudv1Application using Java 1.8.0_181 on DESKTOP-FQ8NNTE with PID 74064 (E:\ProjectIndex\appcloudv1\target\classes started by SUNWIN in E:\ProjectIndex\appcloudv1)
+2022-02-24 10:19:46.220 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- No active profile set, falling back to default profiles: default
+2022-02-24 10:19:59.332 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Started Appcloudv1Application in 13.402 seconds (JVM running for 14.03)
+2022-02-24 10:24:06.929 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Starting Appcloudv1Application using Java 1.8.0_181 on DESKTOP-FQ8NNTE with PID 95692 (E:\ProjectIndex\appcloudv1\target\classes started by SUNWIN in E:\ProjectIndex\appcloudv1)
+2022-02-24 10:24:06.933 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- No active profile set, falling back to default profiles: default
+2022-02-24 10:24:08.186 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Started Appcloudv1Application in 1.588 seconds (JVM running for 2.229)
+2022-02-24 10:25:08.346 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Starting Appcloudv1Application using Java 1.8.0_181 on DESKTOP-FQ8NNTE with PID 100124 (E:\ProjectIndex\appcloudv1\target\classes started by SUNWIN in E:\ProjectIndex\appcloudv1)
+2022-02-24 10:25:08.346 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- No active profile set, falling back to default profiles: default
+2022-02-24 10:25:09.423 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Started Appcloudv1Application in 1.39 seconds (JVM running for 2.105)
+2022-02-24 10:25:20.134 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Starting Appcloudv1Application using Java 1.8.0_181 on DESKTOP-FQ8NNTE with PID 85432 (E:\ProjectIndex\appcloudv1\target\classes started by SUNWIN in E:\ProjectIndex\appcloudv1)
+2022-02-24 10:25:20.150 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- No active profile set, falling back to default profiles: default
+2022-02-24 10:25:21.189 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Started Appcloudv1Application in 1.332 seconds (JVM running for 1.955)
+2022-02-24 10:26:30.083 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Starting Appcloudv1Application using Java 1.8.0_181 on DESKTOP-FQ8NNTE with PID 37768 (E:\ProjectIndex\appcloudv1\target\classes started by SUNWIN in E:\ProjectIndex\appcloudv1)
+2022-02-24 10:26:30.090 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- No active profile set, falling back to default profiles: default
+2022-02-24 10:26:31.093 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Started Appcloudv1Application in 1.343 seconds (JVM running for 2.06)
+2022-02-24 10:30:25.738 [http-nio-8081-exec-1] ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet]- Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
+java.lang.NullPointerException: null
+	at com.sw.appcloudv1.controller.AppDownloadController.deCode(AppDownloadController.java:55)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
+	at java.lang.reflect.Method.invoke(Method.java:498)
+	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
+	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
+	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
+	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
+	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
+	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
+	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
+	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
+	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
+	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
+	at javax.servlet.http.HttpServlet.service(HttpServlet.java:655)
+	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
+	at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
+	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
+	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
+	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
+	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
+	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
+	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
+	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
+	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
+	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
+	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
+	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
+	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
+	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
+	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
+	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
+	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
+	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
+	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
+	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
+	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
+	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
+	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
+	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
+	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
+	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
+	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
+	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
+	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732)
+	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
+	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
+	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
+	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
+	at java.lang.Thread.run(Thread.java:748)
+2022-02-24 10:31:23.487 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Starting Appcloudv1Application using Java 1.8.0_181 on DESKTOP-FQ8NNTE with PID 85344 (E:\ProjectIndex\appcloudv1\target\classes started by SUNWIN in E:\ProjectIndex\appcloudv1)
+2022-02-24 10:31:23.488 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- No active profile set, falling back to default profiles: default
+2022-02-24 10:31:24.501 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Started Appcloudv1Application in 1.357 seconds (JVM running for 2.139)
+2022-02-24 10:34:06.360 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Starting Appcloudv1Application using Java 1.8.0_181 on DESKTOP-FQ8NNTE with PID 86864 (E:\ProjectIndex\appcloudv1\target\classes started by SUNWIN in E:\ProjectIndex\appcloudv1)
+2022-02-24 10:34:06.360 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- No active profile set, falling back to default profiles: default
+2022-02-24 10:34:07.401 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Started Appcloudv1Application in 1.348 seconds (JVM running for 2.01)
+2022-02-24 10:36:22.657 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Starting Appcloudv1Application using Java 1.8.0_181 on DESKTOP-FQ8NNTE with PID 99924 (E:\ProjectIndex\appcloudv1\target\classes started by SUNWIN in E:\ProjectIndex\appcloudv1)
+2022-02-24 10:36:22.657 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- No active profile set, falling back to default profiles: default
+2022-02-24 10:36:35.168 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Started Appcloudv1Application in 12.823 seconds (JVM running for 13.461)
+2022-02-24 10:37:14.663 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Starting Appcloudv1Application using Java 1.8.0_181 on DESKTOP-FQ8NNTE with PID 63384 (E:\ProjectIndex\appcloudv1\target\classes started by SUNWIN in E:\ProjectIndex\appcloudv1)
+2022-02-24 10:37:14.679 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- No active profile set, falling back to default profiles: default
+2022-02-24 10:37:15.757 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Started Appcloudv1Application in 1.386 seconds (JVM running for 2.065)
+2022-02-24 10:38:05.611 [main] INFO  com.sw.appcloudv1.Appcloudv1ApplicationTests- Starting Appcloudv1ApplicationTests using Java 1.8.0_181 on DESKTOP-FQ8NNTE with PID 100764 (started by SUNWIN in E:\ProjectIndex\appcloudv1)
+2022-02-24 10:38:05.611 [main] INFO  com.sw.appcloudv1.Appcloudv1ApplicationTests- No active profile set, falling back to default profiles: default
+2022-02-24 10:38:06.758 [main] INFO  com.sw.appcloudv1.Appcloudv1ApplicationTests- Started Appcloudv1ApplicationTests in 1.359 seconds (JVM running for 2.164)
+2022-06-09 14:08:59.362 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Starting Appcloudv1Application using Java 1.8.0_181 on DESKTOP-FQ8NNTE with PID 9108 (E:\ProjectIndex\appcloudv1\code\AppDownload\target\classes started by SUNWIN in E:\ProjectIndex\appcloudv1\code\AppDownload)
+2022-06-09 14:08:59.363 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- No active profile set, falling back to default profiles: default
+2022-06-09 14:09:01.107 [restartedMain] INFO  com.sw.appcloudv1.Appcloudv1Application- Started Appcloudv1Application in 2.384 seconds (JVM running for 3.352)

二進制
code/AppDownload/logs/pmp.2022-02-23.0.gz


+ 331 - 0
code/AppDownload/mvnw

@@ -0,0 +1,331 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#    https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+#   JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+#   M2_HOME - location of maven2's installed home dir
+#   MAVEN_OPTS - parameters passed to the Java VM when running Maven
+#     e.g. to debug Maven itself, use
+#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ]; then
+
+  if [ -f /usr/local/etc/mavenrc ]; then
+    . /usr/local/etc/mavenrc
+  fi
+
+  if [ -f /etc/mavenrc ]; then
+    . /etc/mavenrc
+  fi
+
+  if [ -f "$HOME/.mavenrc" ]; then
+    . "$HOME/.mavenrc"
+  fi
+
+fi
+
+# OS specific support.  $var _must_ be set to either true or false.
+cygwin=false
+darwin=false
+mingw=false
+case "$(uname)" in
+CYGWIN*) cygwin=true ;;
+MINGW*) mingw=true ;;
+Darwin*)
+  darwin=true
+  # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+  # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+  if [ -z "$JAVA_HOME" ]; then
+    if [ -x "/usr/libexec/java_home" ]; then
+      export JAVA_HOME="$(/usr/libexec/java_home)"
+    else
+      export JAVA_HOME="/Library/Java/Home"
+    fi
+  fi
+  ;;
+esac
+
+if [ -z "$JAVA_HOME" ]; then
+  if [ -r /etc/gentoo-release ]; then
+    JAVA_HOME=$(java-config --jre-home)
+  fi
+fi
+
+if [ -z "$M2_HOME" ]; then
+  ## resolve links - $0 may be a link to maven's home
+  PRG="$0"
+
+  # need this for relative symlinks
+  while [ -h "$PRG" ]; do
+    ls=$(ls -ld "$PRG")
+    link=$(expr "$ls" : '.*-> \(.*\)$')
+    if expr "$link" : '/.*' >/dev/null; then
+      PRG="$link"
+    else
+      PRG="$(dirname "$PRG")/$link"
+    fi
+  done
+
+  saveddir=$(pwd)
+
+  M2_HOME=$(dirname "$PRG")/..
+
+  # make it fully qualified
+  M2_HOME=$(cd "$M2_HOME" && pwd)
+
+  cd "$saveddir"
+  # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME=$(cygpath --unix "$M2_HOME")
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME="$( (
+      cd "$M2_HOME"
+      pwd
+    ))"
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME="$( (
+      cd "$JAVA_HOME"
+      pwd
+    ))"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+  javaExecutable="$(which javac)"
+  if [ -n "$javaExecutable" ] && ! [ "$(expr \"$javaExecutable\" : '\([^ ]*\)')" = "no" ]; then
+    # readlink(1) is not available as standard on Solaris 10.
+    readLink=$(which readlink)
+    if [ ! $(expr "$readLink" : '\([^ ]*\)') = "no" ]; then
+      if $darwin; then
+        javaHome="$(dirname \"$javaExecutable\")"
+        javaExecutable="$(cd \"$javaHome\" && pwd -P)/javac"
+      else
+        javaExecutable="$(readlink -f \"$javaExecutable\")"
+      fi
+      javaHome="$(dirname \"$javaExecutable\")"
+      javaHome=$(expr "$javaHome" : '\(.*\)/bin')
+      JAVA_HOME="$javaHome"
+      export JAVA_HOME
+    fi
+  fi
+fi
+
+if [ -z "$JAVACMD" ]; then
+  if [ -n "$JAVA_HOME" ]; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ]; then
+      # IBM's JDK on AIX uses strange locations for the executables
+      JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+      JAVACMD="$JAVA_HOME/bin/java"
+    fi
+  else
+    JAVACMD="$(
+      \unset -f command
+      \command -v java
+    )"
+  fi
+fi
+
+if [ ! -x "$JAVACMD" ]; then
+  echo "Error: JAVA_HOME is not defined correctly." >&2
+  echo "  We cannot execute $JAVACMD" >&2
+  exit 1
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+  echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+  if [ -z "$1" ]; then
+    echo "Path not specified to find_maven_basedir"
+    return 1
+  fi
+
+  basedir="$1"
+  wdir="$1"
+  while [ "$wdir" != '/' ]; do
+    if [ -d "$wdir"/.mvn ]; then
+      basedir=$wdir
+      break
+    fi
+    # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+    if [ -d "${wdir}" ]; then
+      wdir=$(
+        cd "$wdir/.."
+        pwd
+      )
+    fi
+    # end of workaround
+  done
+  echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+  if [ -f "$1" ]; then
+    echo "$(tr -s '\n' ' ' <"$1")"
+  fi
+}
+
+BASE_DIR=$(find_maven_basedir "$(pwd)")
+if [ -z "$BASE_DIR" ]; then
+  exit 1
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+  if [ "$MVNW_VERBOSE" = true ]; then
+    echo "Found .mvn/wrapper/maven-wrapper.jar"
+  fi
+else
+  if [ "$MVNW_VERBOSE" = true ]; then
+    echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+  fi
+  if [ -n "$MVNW_REPOURL" ]; then
+    jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
+  else
+    jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
+  fi
+  while IFS="=" read key value; do
+    case "$key" in wrapperUrl)
+      jarUrl="$value"
+      break
+      ;;
+    esac
+  done <"$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+  if [ "$MVNW_VERBOSE" = true ]; then
+    echo "Downloading from: $jarUrl"
+  fi
+  wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+  if $cygwin; then
+    wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
+  fi
+
+  if command -v wget >/dev/null; then
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Found wget ... using wget"
+    fi
+    if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+      wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+    else
+      wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+    fi
+  elif command -v curl >/dev/null; then
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Found curl ... using curl"
+    fi
+    if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+      curl -o "$wrapperJarPath" "$jarUrl" -f
+    else
+      curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+    fi
+
+  else
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Falling back to using Java to download"
+    fi
+    javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+    # For Cygwin, switch paths to Windows format before running javac
+    if $cygwin; then
+      javaClass=$(cygpath --path --windows "$javaClass")
+    fi
+    if [ -e "$javaClass" ]; then
+      if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo " - Compiling MavenWrapperDownloader.java ..."
+        fi
+        # Compiling the Java class
+        ("$JAVA_HOME/bin/javac" "$javaClass")
+      fi
+      if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+        # Running the downloader
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo " - Running MavenWrapperDownloader.java ..."
+        fi
+        ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+      fi
+    fi
+  fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+  echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME=$(cygpath --path --windows "$M2_HOME")
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
+  [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+    MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+  $MAVEN_OPTS \
+  $MAVEN_DEBUG_OPTS \
+  -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+  "-Dmaven.home=${M2_HOME}" \
+  "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

+ 188 - 0
code/AppDownload/mvnw.cmd

@@ -0,0 +1,188 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements.  See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership.  The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License.  You may obtain a copy of the License at
+@REM
+@REM    https://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied.  See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM     e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on"  echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
+
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+    IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Found %WRAPPER_JAR%
+    )
+) else (
+    if not "%MVNW_REPOURL%" == "" (
+        SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
+    )
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Couldn't find %WRAPPER_JAR%, downloading it ...
+        echo Downloading from: %DOWNLOAD_URL%
+    )
+
+    powershell -Command "&{"^
+		"$webclient = new-object System.Net.WebClient;"^
+		"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+		"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+		"}"^
+		"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+		"}"
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Finished downloading %WRAPPER_JAR%
+    )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% ^
+  %JVM_CONFIG_MAVEN_PROPS% ^
+  %MAVEN_OPTS% ^
+  %MAVEN_DEBUG_OPTS% ^
+  -classpath %WRAPPER_JAR% ^
+  "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
+  %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
+if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%"=="on" pause
+
+if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
+
+cmd /C exit /B %ERROR_CODE%

+ 74 - 0
code/AppDownload/pom.xml

@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.6.3</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <groupId>com.sw</groupId>
+    <artifactId>appcloudv1</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>appcloudv1</name>
+    <description>Demo project for Spring Boot</description>
+    <properties>
+        <java.version>1.8</java.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <scope>runtime</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+            <version>1.10</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                        </exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <version>3.1.0</version>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 13 - 0
code/AppDownload/src/main/java/com/sw/appcloudv1/Appcloudv1Application.java

@@ -0,0 +1,13 @@
+package com.sw.appcloudv1;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Appcloudv1Application {
+
+    public static void main(String[] args) {
+        SpringApplication.run(Appcloudv1Application.class, args);
+    }
+
+}

+ 52 - 0
code/AppDownload/src/main/java/com/sw/appcloudv1/Utils/ShortUrlUtils.java

@@ -0,0 +1,52 @@
+package com.sw.appcloudv1.Utils;
+
+import org.apache.commons.codec.digest.DigestUtils;
+
+/**
+ * 短连接算法
+ * Created by shiwn on 2022/2/24 10:07
+ */
+public class ShortUrlUtils {
+    //  26小写字母 + 26大写字母 + 10个数字 = 62
+    public static final String[] chars = new String[]{"a", "b", "c", "d", "e", "f", "g", "h",
+            "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
+            "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
+            "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H",
+            "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
+            "U", "V", "W", "X", "Y", "Z"};
+
+    /**
+     * 短连接算法
+     */
+    public static String[] shortUrl(String url) {
+        //  对传入网址进行 MD5 加密
+        String sMD5EncryptResult = DigestUtils.md5Hex(url);
+        //  md5处理后是32位
+        String hex = sMD5EncryptResult;
+        //  切割为4组,每组8个字符, 32 = 4 *  8
+        String[] resUrl = new String[4];
+
+        for (int i = 0; i < 4; i++) {
+            //  取出8位字符串,md5 32位,按照8位一组字符,被切割为4组
+            String sTempSubString = hex.substring(i * 8, i * 8 + 8);
+
+            //  把加密字符按照8位一组16进制与 0x3FFFFFFF 进行位与运算
+            //  这里需要使用 long 型来转换,因为 Inteper .parseInt() 只能处理 31 位 , 首位为符号位 , 如果不用 long ,则会越界
+            long lHexLong = 0x3FFFFFFF & Long.parseLong(sTempSubString, 16);
+
+            String outChars = "";
+            for (int j = 0; j < 6; j++) {
+                //  0x0000003D它的10进制是61,61代表最上面定义的chars数组长度62的0到61的坐标。
+                //  0x0000003D & lHexLong进行位与运算,就是格式化为6位,即保证了index绝对是61以内的值
+                long index = 0x0000003D & lHexLong;
+                //  按照下标index把从chars数组取得的字符逐个相加
+                outChars += chars[(int) index];
+                //  每次循环按位移5位,因为30位的二进制,分6次循环,即每次右移5位
+                lHexLong = lHexLong >> 5;
+            }
+            // 把字符串存入对应索引的输出数组,会产生一组6位字符串
+            resUrl[i] = outChars;
+        }
+        return resUrl;
+    }
+}

+ 38 - 0
code/AppDownload/src/main/java/com/sw/appcloudv1/controller/AppDownloadController.java

@@ -0,0 +1,38 @@
+package com.sw.appcloudv1.controller;
+
+import com.sw.appcloudv1.entities.ResultData;
+import com.sw.appcloudv1.service.AppDownloadService;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * app下载\更新\查询版本
+ */
+@RestController
+@RequestMapping("appDown")
+public class AppDownloadController {
+    @Resource
+    private AppDownloadService appDownloadService;
+
+    /**
+     * @Description: 下载app
+     * @Param: [response,  projectId:项目id]
+     * @Return:
+     */
+    @GetMapping("/download")
+    public void download(HttpServletResponse response, Integer projectId) {
+        appDownloadService.download(response, projectId);
+    }
+
+    /**
+     * @Description: 查询最新的版本号
+     * @Param: [projectId]
+     * @Return:
+     */
+    @GetMapping("/getNewVersion")
+    public ResultData getNewVersion(Integer projectId) {
+        return ResultData.success(appDownloadService.getNewVersion(projectId));
+    }
+}

+ 35 - 0
code/AppDownload/src/main/java/com/sw/appcloudv1/controller/ShortUrlController.java

@@ -0,0 +1,35 @@
+package com.sw.appcloudv1.controller;
+
+import com.sw.appcloudv1.service.ShortUrlService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Created by shiwn on 2022/2/24 10:33
+ */
+@RestController
+public class ShortUrlController {
+    @Resource
+    private ShortUrlService shortUrlService;
+    @Resource
+    private HttpServletResponse httpServletResponse;
+
+    @GetMapping(value = "/deCode/{shortUrlKey}")
+    public void deCode(@PathVariable String shortUrlKey) {
+        String url = shortUrlService.getLongUrl(shortUrlKey);
+        if (url == null) {
+            return;
+        }
+        try {
+            //重定向到原始的url
+            httpServletResponse.sendRedirect(url);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 113 - 0
code/AppDownload/src/main/java/com/sw/appcloudv1/entities/ResultData.java

@@ -0,0 +1,113 @@
+package com.sw.appcloudv1.entities;
+
+/**
+ * Created by shiwn on 2022/2/23 16:15
+ */
+public class ResultData<T> {
+    /**
+     * 默认:0成功,1失败,205结果为null,500系统异常
+     */
+    private Integer code;
+    private String msg;
+    private T data;
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public T getData() {
+        return data;
+    }
+
+    public void setData(T data) {
+        this.data = data;
+    }
+
+    public ResultData() {
+        this.code = 0;
+        this.msg = "操作成功";
+    }
+
+    public ResultData(Integer code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public ResultData(Integer code, T obj) {
+        this.code = code;
+        this.data = obj;
+    }
+
+    private ResultData(T data) {
+        this.code = 0;
+        this.msg = "操作成功";
+        this.data = data;
+    }
+
+
+    /**
+     * 操作成功,无返回数据
+     *
+     * @return 0
+     */
+    public static ResultData success() {
+        return new ResultData();
+    }
+
+    /**
+     * @Description: 操作执行成功,并判断返回值
+     * @Param: [data]
+     * @Author: shiwn
+     * @Date: 2020/8/3 15:56
+     */
+    public static ResultData success(Object data) {
+        //  判断空值
+        if (data != null) {
+            return new ResultData(data);
+        } else {
+            return ResultData.emptyData();
+        }
+    }
+
+
+    /**
+     * 操作失败
+     *
+     * @param code code
+     * @param msg  操作信息
+     * @return ResultData
+     */
+    public static ResultData fail(Integer code, String msg) {
+        return new ResultData(code, msg);
+    }
+
+    /**
+     * @Description: 操作成功,但返回值为null
+     * @Param: [data]
+     * @Author: shiwn
+     * @Date: 2020/8/3 15:57
+     */
+    public static ResultData emptyData() {
+        return new ResultData(205, "查询结果为空");
+    }
+
+    public static ResultData fail(String msg) {
+        return new ResultData(1, msg);
+    }
+
+    public static ResultData fail() {
+        return new ResultData(1, "操作失败");
+    }
+}

+ 9 - 0
code/AppDownload/src/main/java/com/sw/appcloudv1/service/AppDownloadService.java

@@ -0,0 +1,9 @@
+package com.sw.appcloudv1.service;
+
+import javax.servlet.http.HttpServletResponse;
+
+public interface AppDownloadService {
+    void download(HttpServletResponse response, Integer projectId);
+
+    String getNewVersion(Integer projectId);
+}

+ 171 - 0
code/AppDownload/src/main/java/com/sw/appcloudv1/service/AppDownloadServiceImpl.java

@@ -0,0 +1,171 @@
+package com.sw.appcloudv1.service;
+
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+@Slf4j
+public class AppDownloadServiceImpl implements AppDownloadService {
+    private static final Logger logger = LoggerFactory.getLogger(AppDownloadServiceImpl.class);
+
+    /**
+     * app完整包地址
+     */
+    @Value("${app.file.path}")
+    private String filePath;
+
+    /**
+     * app更新包地址
+     */
+    @Value("${app.update.path}")
+    private String updatePath;
+
+    /**
+     * @Description: 下载文件
+     * @Param: [response, version:版本号, projectId:项目id]
+     * @Return:
+     */
+    @Override
+    public void download(HttpServletResponse response, Integer projectId) {
+        projectId = projectId == null ? 1 : projectId;
+        //  获取目录下的全部文件名
+        List<String> listFileNames = getFileNames(filePath);
+        if (listFileNames.size() == 0) {
+            return;
+        }
+        //  获取最新版本文件名
+        String newFile = getNewFileName(listFileNames, projectId);
+        if (newFile == null) {
+            return;
+        }
+        //  下载文件
+        download(response, newFile, filePath);
+    }
+
+    /**
+     * @Description: 获取最新的版本号
+     * @Param: [projectId]
+     * @Return:
+     */
+    @Override
+    public String getNewVersion(Integer projectId) {
+        projectId = projectId == null ? 1 : projectId;
+        //  获取目录下的全部文件名
+        List<String> listFileNames = getFileNames(filePath);
+        if (listFileNames.size() == 0) {
+            return null;
+        }
+        //  获取最新版本文件名
+        String newFile = getNewFileName(listFileNames, projectId);
+        if (newFile == null) {
+            return null;
+        }
+        //  返回
+        return newFile.substring(0, newFile.lastIndexOf("."));
+    }
+
+    /**
+     * @Description: 流文件下载
+     * @Param: [response, newFile:最新版本的文件名, path:文件目录]
+     * @Return:
+     */
+    private void download(HttpServletResponse response, String newFile, String path) {
+        InputStream fis = null;
+        try {
+            path = path + "/" + newFile;
+            File file = new File(path);
+            // 取得文件的后缀名。
+            String ext = newFile.substring(newFile.lastIndexOf(".") + 1).toUpperCase();
+            // 以流的形式下载文件。
+            fis = new BufferedInputStream(new FileInputStream(path));
+            byte[] buffer = new byte[fis.available()];
+            fis.read(buffer);
+            fis.close();
+            // 清空response
+            response.reset();
+            // 设置response的Header
+            response.addHeader("Content-Disposition", "attachment;filename=" + new String(newFile.getBytes()));
+            response.addHeader("Content-Length", "" + file.length());
+            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
+            response.setContentType("application/octet-stream");
+            toClient.write(buffer);
+            toClient.flush();
+            toClient.close();
+            logger.info("下载app文件成功!");
+        } catch (IOException ex) {
+            ex.printStackTrace();
+            logger.info("下载app文件失败!");
+        } finally {
+            if (fis != null) {
+                try {
+                    fis.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                    logger.info("关闭文件流失败!");
+                }
+            }
+        }
+    }
+
+    /**
+     * @Description: 获取最新版本的文件名
+     * @Return:
+     */
+    private String getNewFileName(List<String> listFileNames, Integer projectId) {
+        String newFile = null;
+        Integer maxVersionId = 1;
+        for (String fileName : listFileNames) {
+            Integer pid = Integer.parseInt(fileName.substring(9, 11));
+            //  判断项目id
+            if (pid.equals(projectId)) {
+                if (newFile == null) {
+                    newFile = fileName;
+                } else {
+                    //  获取最新版本号
+                    Integer versionId = Integer.parseInt(fileName.substring(12, 14));
+                    if (versionId > maxVersionId) {
+                        maxVersionId = versionId;
+                        newFile = fileName;
+                    }
+                }
+            }
+        }
+        return newFile;
+    }
+
+    /**
+     * @Description: 获取目录下的全部文件名
+     * @Return:
+     */
+    private List<String> getFileNames(String path) {
+        //  目录下的文件名
+        List<String> listFileNames = new ArrayList<>();
+        //  判断是否存在目录
+        File dir = new File(path);
+        if (!dir.exists() || !dir.isDirectory()) {
+            return new ArrayList<>();
+        }
+        //  读取目录下的所有目录文件信息
+        String[] files = dir.list();
+        //  循环,添加文件名或回调自身
+        for (int i = 0; i < files.length; i++) {
+            File file = new File(dir, files[i]);
+            //  如果文件
+            if (file.isFile()) {
+                //  添加文件全路径名
+//                listFileNames.add(dir + "\\" + file.getName());
+//                listFileNames.add(file.getName().substring(0, file.getName().lastIndexOf(".")));
+                listFileNames.add(file.getName());
+            }
+        }
+        return listFileNames;
+    }
+}

+ 8 - 0
code/AppDownload/src/main/java/com/sw/appcloudv1/service/ShortUrlService.java

@@ -0,0 +1,8 @@
+package com.sw.appcloudv1.service;
+
+/**
+ * Created by shiwn on 2022/2/24 10:11
+ */
+public interface ShortUrlService {
+    String getLongUrl(String shortUrlKey);
+}

+ 42 - 0
code/AppDownload/src/main/java/com/sw/appcloudv1/service/ShortUrlServiceImpl.java

@@ -0,0 +1,42 @@
+package com.sw.appcloudv1.service;
+
+import com.sw.appcloudv1.Utils.ShortUrlUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by shiwn on 2022/2/24 10:11
+ */
+@Service
+public class ShortUrlServiceImpl implements ShortUrlService {
+
+    private static Map map = new HashMap();
+
+    @Value("${app.url}")
+    private String appUrl;
+
+    @Override
+    public String getLongUrl(String shortUrlKey) {
+        return map.get(shortUrlKey).toString();
+    }
+
+    /**
+     * @Description: 长链接转短链接保存到map中
+     * @Return:
+     */
+    @PostConstruct
+    public void createShortUrl() {
+        String[] urls = appUrl.split(",");
+        for (String longUrl : urls) {
+            String[] shortUrls = ShortUrlUtils.shortUrl(longUrl);
+            for (String shortUrl : shortUrls) {
+                map.put(shortUrl, longUrl);
+            }
+        }
+        System.out.println(map);
+    }
+}

+ 25 - 0
code/AppDownload/src/main/resources/application.properties

@@ -0,0 +1,25 @@
+server.port=8081
+
+app.file.path=E:/AppFile/file
+app.update.path=E:/AppFile/update
+
+app.url=http://112.26.142.150:9000/appDown/download?projectId=1
+
+spring.application.name=app-cloud-v1
+
+# ========================logging 日志相关的配置=====================
+#系统默认,全局root配置的日志形式,可以注释掉
+logging.level.root=warn
+#开发人员自己设置的包结构,对那个package进行什么级别的日志监控
+logging.level.com.sw.appcloudv1=info
+#开发人员自定义日志路径和日志名称
+logging.file.name=./logs/pmp
+#%d{HH:mm:ss.SSS}――日志输出时间
+#%thread――输出日志的进程名字,这在Web应用以及异步任务处理中很有用
+#%-5level――日志级别,并且使用5个字符靠左对齐
+#%logger- ――日志输出者的名字
+#%msg――日志消息
+#%n――平台的换行符
+#logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger- %msg%n
+logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger- %msg%n 
+logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger- %msg%n

+ 13 - 0
code/AppDownload/src/test/java/com/sw/appcloudv1/Appcloudv1ApplicationTests.java

@@ -0,0 +1,13 @@
+package com.sw.appcloudv1;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class Appcloudv1ApplicationTests {
+
+    @Test
+    void contextLoads() {
+    }
+
+}

+ 7 - 1
code/readme.md

@@ -1 +1,7 @@
-APP代码放此目录下
+APP代码\其他应用程序 放此目录下
+
+HBX---巡检系统安卓手机APP代码
+
+AppDownload---APP更新服务代码
+
+robot2ips ---IPS系统对接插件代码(目前仅用于宁德2期)

+ 33 - 0
code/robot2ips/.gitignore

@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/

二進制
code/robot2ips/IPS监测点清单.xls


+ 316 - 0
code/robot2ips/mvnw

@@ -0,0 +1,316 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#    https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+#   JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+#   M2_HOME - location of maven2's installed home dir
+#   MAVEN_OPTS - parameters passed to the Java VM when running Maven
+#     e.g. to debug Maven itself, use
+#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+  if [ -f /usr/local/etc/mavenrc ] ; then
+    . /usr/local/etc/mavenrc
+  fi
+
+  if [ -f /etc/mavenrc ] ; then
+    . /etc/mavenrc
+  fi
+
+  if [ -f "$HOME/.mavenrc" ] ; then
+    . "$HOME/.mavenrc"
+  fi
+
+fi
+
+# OS specific support.  $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+  CYGWIN*) cygwin=true ;;
+  MINGW*) mingw=true;;
+  Darwin*) darwin=true
+    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+    if [ -z "$JAVA_HOME" ]; then
+      if [ -x "/usr/libexec/java_home" ]; then
+        export JAVA_HOME="`/usr/libexec/java_home`"
+      else
+        export JAVA_HOME="/Library/Java/Home"
+      fi
+    fi
+    ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+  if [ -r /etc/gentoo-release ] ; then
+    JAVA_HOME=`java-config --jre-home`
+  fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+  ## resolve links - $0 may be a link to maven's home
+  PRG="$0"
+
+  # need this for relative symlinks
+  while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+      PRG="$link"
+    else
+      PRG="`dirname "$PRG"`/$link"
+    fi
+  done
+
+  saveddir=`pwd`
+
+  M2_HOME=`dirname "$PRG"`/..
+
+  # make it fully qualified
+  M2_HOME=`cd "$M2_HOME" && pwd`
+
+  cd "$saveddir"
+  # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME=`cygpath --unix "$M2_HOME"`
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME="`(cd "$M2_HOME"; pwd)`"
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+  javaExecutable="`which javac`"
+  if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+    # readlink(1) is not available as standard on Solaris 10.
+    readLink=`which readlink`
+    if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+      if $darwin ; then
+        javaHome="`dirname \"$javaExecutable\"`"
+        javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+      else
+        javaExecutable="`readlink -f \"$javaExecutable\"`"
+      fi
+      javaHome="`dirname \"$javaExecutable\"`"
+      javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+      JAVA_HOME="$javaHome"
+      export JAVA_HOME
+    fi
+  fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+  if [ -n "$JAVA_HOME"  ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+      # IBM's JDK on AIX uses strange locations for the executables
+      JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+      JAVACMD="$JAVA_HOME/bin/java"
+    fi
+  else
+    JAVACMD="`\\unset -f command; \\command -v java`"
+  fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+  echo "Error: JAVA_HOME is not defined correctly." >&2
+  echo "  We cannot execute $JAVACMD" >&2
+  exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+  echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+  if [ -z "$1" ]
+  then
+    echo "Path not specified to find_maven_basedir"
+    return 1
+  fi
+
+  basedir="$1"
+  wdir="$1"
+  while [ "$wdir" != '/' ] ; do
+    if [ -d "$wdir"/.mvn ] ; then
+      basedir=$wdir
+      break
+    fi
+    # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+    if [ -d "${wdir}" ]; then
+      wdir=`cd "$wdir/.."; pwd`
+    fi
+    # end of workaround
+  done
+  echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+  if [ -f "$1" ]; then
+    echo "$(tr -s '\n' ' ' < "$1")"
+  fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+  exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Found .mvn/wrapper/maven-wrapper.jar"
+    fi
+else
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+    fi
+    if [ -n "$MVNW_REPOURL" ]; then
+      jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
+    else
+      jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
+    fi
+    while IFS="=" read key value; do
+      case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+      esac
+    done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Downloading from: $jarUrl"
+    fi
+    wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+    if $cygwin; then
+      wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+    fi
+
+    if command -v wget > /dev/null; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Found wget ... using wget"
+        fi
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+        else
+            wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+        fi
+    elif command -v curl > /dev/null; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Found curl ... using curl"
+        fi
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            curl -o "$wrapperJarPath" "$jarUrl" -f
+        else
+            curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+        fi
+
+    else
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Falling back to using Java to download"
+        fi
+        javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+        # For Cygwin, switch paths to Windows format before running javac
+        if $cygwin; then
+          javaClass=`cygpath --path --windows "$javaClass"`
+        fi
+        if [ -e "$javaClass" ]; then
+            if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+                if [ "$MVNW_VERBOSE" = true ]; then
+                  echo " - Compiling MavenWrapperDownloader.java ..."
+                fi
+                # Compiling the Java class
+                ("$JAVA_HOME/bin/javac" "$javaClass")
+            fi
+            if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+                # Running the downloader
+                if [ "$MVNW_VERBOSE" = true ]; then
+                  echo " - Running MavenWrapperDownloader.java ..."
+                fi
+                ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+            fi
+        fi
+    fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+  echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME=`cygpath --path --windows "$M2_HOME"`
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+  [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+    MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+  $MAVEN_OPTS \
+  $MAVEN_DEBUG_OPTS \
+  -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+  "-Dmaven.home=${M2_HOME}" \
+  "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

+ 188 - 0
code/robot2ips/mvnw.cmd

@@ -0,0 +1,188 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements.  See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership.  The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License.  You may obtain a copy of the License at
+@REM
+@REM    https://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied.  See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM     e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on"  echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
+
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+    IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Found %WRAPPER_JAR%
+    )
+) else (
+    if not "%MVNW_REPOURL%" == "" (
+        SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
+    )
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Couldn't find %WRAPPER_JAR%, downloading it ...
+        echo Downloading from: %DOWNLOAD_URL%
+    )
+
+    powershell -Command "&{"^
+		"$webclient = new-object System.Net.WebClient;"^
+		"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+		"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+		"}"^
+		"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+		"}"
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Finished downloading %WRAPPER_JAR%
+    )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% ^
+  %JVM_CONFIG_MAVEN_PROPS% ^
+  %MAVEN_OPTS% ^
+  %MAVEN_DEBUG_OPTS% ^
+  -classpath %WRAPPER_JAR% ^
+  "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
+  %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
+if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%"=="on" pause
+
+if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
+
+cmd /C exit /B %ERROR_CODE%

+ 245 - 0
code/robot2ips/pom.xml

@@ -0,0 +1,245 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.4.5</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <groupId>com.sunwin</groupId>
+    <artifactId>robot2ips</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>robot2ips</name>
+    <description>upload robot check data to ips system</description>
+    <properties>
+        <java.version>1.8</java.version>
+    </properties>
+    <dependencies>
+        <!--        thymeleaf-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-thymeleaf</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>2.1.4</version>
+        </dependency>
+        <!--        lombok-->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- mybatis启动器-->
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>2.1.1</version>
+        </dependency>
+        <!--mybatis分页插件-->
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+            <version>1.2.5</version>
+        </dependency>
+        <!--        mybatis-plus-->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>3.2.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-generator</artifactId>
+            <version>3.2.0</version>
+        </dependency>
+        <!-- 数据库驱动-->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+        <!--数据库连接池-->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid</artifactId>
+            <version>1.1.8</version>
+        </dependency>
+        <!--        Redis依赖-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+
+        <!--swagger用于定义API文档  -->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>2.9.2</version>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>2.9.2</version>
+        </dependency>
+        <!--bootstrap ui下的swagger-->
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>swagger-bootstrap-ui</artifactId>
+            <version>1.9.6</version>
+        </dependency>
+
+        <!--json处理-->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.31</version>
+        </dependency>
+
+        <!--日志框架,SpringBoot默认的日志系统logback-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-logging</artifactId>
+        </dependency>
+
+        <!--        Apache commons io-->
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.8.0</version>
+        </dependency>
+
+        <!-- redis依赖commons-pool 这个依赖一定要添加 -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+        </dependency>
+
+        <!-- 工具包-->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.4</version>
+        </dependency>
+
+        <!--        最新http协议工具包-->
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.5.13</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <!-- 切面-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.aspectj</groupId>
+            <artifactId>aspectjweaver</artifactId>
+            <version>1.9.4</version>
+        </dependency>
+
+        <!--poi-->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi</artifactId>
+            <version>3.17</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.directory.studio</groupId>
+            <artifactId>org.apache.commons.io</artifactId>
+            <version>2.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>3.17</version>
+        </dependency>
+
+        <!--ftp文件上传下载-->
+        <dependency>
+            <groupId>commons-net</groupId>
+            <artifactId>commons-net</artifactId>
+            <version>3.1</version>
+        </dependency>
+
+        <!--        Netty-->
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty</artifactId>
+            <version>3.10.6.Final</version>
+        </dependency>
+
+        <!-- DOM操作 -->
+        <dependency>
+            <groupId>dom4j</groupId>
+            <artifactId>dom4j</artifactId>
+            <version>1.6.1</version>
+        </dependency>
+        <!--hutool工具类-->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.0.7</version>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <!-- 自动导入本地jar包 -->
+                    <includeSystemScope>true</includeSystemScope>
+                    <fork>true</fork>
+                    <excludes>
+                        <exclude>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                        </exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <!--修改版本-->
+                <version>3.1.0</version>
+            </plugin>
+
+
+            <!-- 解决webSocket打包冲突问题 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 2 - 0
code/robot2ips/readme.md

@@ -0,0 +1,2 @@
+此程序为宁德核电开发.
+向IPS系统同步巡检数据

+ 13 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/Robot2ipsApplication.java

@@ -0,0 +1,13 @@
+package com.sunwin.robot2ips;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Robot2ipsApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(Robot2ipsApplication.class, args);
+    }
+
+}

+ 28 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/aspect/ExcelHeader.java

@@ -0,0 +1,28 @@
+package com.sunwin.robot2ips.aspect;
+
+import java.lang.annotation.*;
+
+/**
+ * @author machao
+ * @version 1.0
+ * @description: TODO
+ * @date 2021/10/9 14:35
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ExcelHeader {
+
+    /**
+     * 表头
+     * @return
+     */
+    String value() default "";
+
+    /**
+     * 列索引
+     * @return
+     */
+    int columnIndex() default 0;
+
+}

+ 73 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/beans/dto/CheckDataDTO.java

@@ -0,0 +1,73 @@
+package com.sunwin.robot2ips.beans.dto;
+
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+/**
+ * 巡检数据
+ * Created by shiwn on 2021/6/3 15:25
+ */
+@Data
+@Accessors(chain = true)
+@TableName("check_data")
+public class CheckDataDTO {
+    private Long id;
+    private Integer robotId;
+    private Integer taskId;
+    private Long pointId;
+    private String pointName;
+    private Integer runTimes;
+
+    private String image;
+    private String infrared;
+    /**
+     * 视频
+     */
+    private String video;
+    /**
+     * 音频
+     */
+    private String audio;
+    /**
+     * 音频/局放图谱
+     */
+    private String spectrum;
+
+    private Date time;
+    private String result;
+    /**
+     * 异常标识,0-正常,1-异常
+     */
+    private Integer flag;
+    /**
+     * 告警等级,正常0、预警1、一般2、严重3、危急4
+     */
+    private Integer alarmLevel;
+    /**
+     * 识别状态,0-识别正确,1-识别错误
+     */
+    private Integer validityStatus;
+    private Integer identifyType;
+    private String auditResult;
+    private Date auditTime;
+    private Integer auditUserId;
+
+    /***
+     * 巡检点参照值,非表字段
+     */
+    @TableField(exist = false)
+    private String parameter;
+    /***
+     * 巡检点上级设备id,非表字段
+     */
+    @TableField(exist = false)
+    private Integer deviceId;
+
+    @TableField(exist = false)
+    private String taskName;
+}

+ 27 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/beans/dto/IPSPointDTO.java

@@ -0,0 +1,27 @@
+package com.sunwin.robot2ips.beans.dto;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.sunwin.robot2ips.aspect.ExcelHeader;
+import lombok.Data;
+
+/**
+ * ips与Robot点位关系导入实体
+ *
+ * @author machao
+ * @since 2022/6/7 13:47
+ **/
+@Data
+@TableName("ips_sw_point_link")
+public class IPSPointDTO {
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    @ExcelHeader(value = "监测点", columnIndex = 3)
+    private String monitoringPoint;
+
+    @ExcelHeader(value = "备注", columnIndex = 23)
+    private Long pointId;
+}

+ 33 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/beans/dto/RobotDTO.java

@@ -0,0 +1,33 @@
+package com.sunwin.robot2ips.beans.dto;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @Description: 机器人信息
+ * @Author: shiwn
+ * @Date: 2021/5/18 15:58
+ */
+@Data
+@Accessors(chain = true)
+@TableName("robot")
+public class RobotDTO {
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+    private String robotName;
+    private String robotNo;
+    private Integer type;
+    private String modelName;
+    private String ip;
+    private Integer port;
+    private Integer channelHd;
+    private Integer channelIr;
+    private Integer status;
+    private Integer selected;
+    private Integer company;
+    private String scene;
+    private String domainName;
+}

+ 20 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/beans/vo/IPSResp.java

@@ -0,0 +1,20 @@
+package com.sunwin.robot2ips.beans.vo;
+
+import lombok.Data;
+
+@Data
+public class IPSResp {
+    private String keyToken;
+    private String method;
+    private String isSuccessed = "1";
+    private String note = "成功";
+    private String errorCode;
+    private String errorDesc;
+    private String isNoticePreTaskFinishState;
+    private String noticeContent;
+    private String data;
+    private String exception;
+    private String NodeId;
+    private String NextNodeId;
+    private String PathId;
+}

+ 32 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/beans/vo/RecordData.java

@@ -0,0 +1,32 @@
+package com.sunwin.robot2ips.beans.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 上传IPS请求对象
+ *
+ * @author machao
+ * @since 2022/6/6 17:03
+ **/
+@Data
+public class RecordData {
+    /**
+     * 机器名称
+     */
+    private String robotName;
+    /**
+     * 机器编码
+     */
+    private String robotCode;
+    /**
+     * 公司编码(宁德NDNP)
+     */
+    private String companyId = "NDNP";
+    /**
+     * 测点列表
+     */
+    private List<RecordTaskPoint> recordTaskPoints;
+
+}

+ 64 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/beans/vo/RecordTaskPoint.java

@@ -0,0 +1,64 @@
+package com.sunwin.robot2ips.beans.vo;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import java.util.Date;
+
+
+/**
+ * 上传测点对象
+ *
+ * @author machao
+ * @since 2022/6/6 17:00
+ **/
+@Data
+public class RecordTaskPoint {
+
+    /**
+     * 测点id(唯一标识 uuid)
+     */
+    private String resultId;
+
+    /**
+     * 测点描述(巡检点名称)
+     */
+    private String remark;
+    /**
+     * 巡检值
+     */
+    private String resultValue;
+    /**
+     * 巡检来源1是手机版、2是电脑板(填1)
+     */
+    private String dataSource;
+    /**
+     * 测点编码
+     */
+    private String pointCode;
+    /**
+     * 任务的实际完成时间
+     */
+    private Date recordCompleteDate;
+    /**
+     * 巡检日期yyyy-MM-ddHH:mm:ss
+     */
+    private Date updateTime;
+    /**
+     * 计划开始时间
+     */
+    private Date recordPlanStartDate;
+    /**
+     * 计划完成时间
+     */
+    private Date recordPlanCompleteDate;
+    /**
+     * 任务的开始时间
+     */
+    private Date recordStartDate;
+
+    @JSONField(serialize = false)
+    private Integer robotId;
+}

+ 14 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/common/RedisKey.java

@@ -0,0 +1,14 @@
+package com.sunwin.robot2ips.common;
+
+public class RedisKey {
+
+    /**
+     * 最近一次上传时间
+     **/
+    public static final String UPLOAD_IPS_LAST_ID = "upload_ips_last_id";
+    /**
+     * 全部机器人列表
+     **/
+    public static final String ROBOT_LIST = "robot_list";
+
+}

+ 25 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/config/CommandLineRunnerImpl.java

@@ -0,0 +1,25 @@
+package com.sunwin.robot2ips.config;
+
+import com.sunwin.robot2ips.service.CheckDataService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+/**
+ * 项目启动会更新IPS与机器人点位绑定关系表
+ *
+ * @author machao
+ * @since 2022/6/8 10:09
+ **/
+@Component
+@Order(value = 2)
+public class CommandLineRunnerImpl implements CommandLineRunner {
+    @Autowired
+    CheckDataService checkDataService;
+
+    @Override
+    public void run(String... args) throws Exception {
+        checkDataService.bindIPSAndRobotPoint();
+    }
+}

+ 17 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/config/MybatisPlusConfig.java

@@ -0,0 +1,17 @@
+package com.sunwin.robot2ips.config;
+
+import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * MybatisPlus分页配置
+ * Created by shiwn on 2021/5/10 16:43
+ */
+@Configuration
+public class MybatisPlusConfig {
+    @Bean
+    public PaginationInterceptor paginationInterceptor() {
+        return new PaginationInterceptor();
+    }
+}

+ 68 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/config/RedisConfig.java

@@ -0,0 +1,68 @@
+package com.sunwin.robot2ips.config;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import java.net.UnknownHostException;
+
+/**
+ * Redis配置类
+ * Created by shiwn on 2021/5/11 10:41
+ */
+@Configuration
+public class RedisConfig {
+
+    @Bean
+    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
+        RedisTemplate<String, Object> template = new RedisTemplate<>();
+        template.setConnectionFactory(redisConnectionFactory);
+        setRedisTemplate(template);
+        template.afterPropertiesSet();
+        return template;
+    }
+
+    /**
+     * @Description: 序列化
+     * @Param: [template] 
+     * @Author: shiwn 
+     * @Date: 2021/5/11 11:28
+     */ 
+    private void setRedisTemplate(RedisTemplate<String, Object> template) {
+        // Json序列化配置
+        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
+
+        ObjectMapper objectMapper = new ObjectMapper();
+        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        // 解决jackson2无法反序列化LocalDateTime的问题
+        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+        objectMapper.registerModule(new JavaTimeModule());
+
+        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
+        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
+
+        // String 的序列化
+        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
+        // key采用String的序列化方式
+        template.setKeySerializer(stringRedisSerializer);
+        // hash的key也采用String的序列化方式
+        template.setHashKeySerializer(stringRedisSerializer);
+        // value序列化方式采用jackson
+        template.setValueSerializer(jackson2JsonRedisSerializer);
+        // hash的value序列化方式采用jackson
+        template.setHashValueSerializer(jackson2JsonRedisSerializer);
+        // 设置值(value)的序列化采用FastJsonRedisSerializer。
+        // 设置键(key)的序列化采用StringRedisSerializer。
+        template.afterPropertiesSet();
+    }
+}

+ 31 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/dao/UploadMapper.java

@@ -0,0 +1,31 @@
+package com.sunwin.robot2ips.dao;
+
+import com.sunwin.robot2ips.beans.dto.IPSPointDTO;
+import com.sunwin.robot2ips.beans.dto.RobotDTO;
+import com.sunwin.robot2ips.beans.vo.RecordTaskPoint;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Component
+@Mapper
+public interface UploadMapper {
+    /**
+     * 根据起止时间查询巡检数据
+     *
+     * @param startDate
+     * @param endDate
+     * @return java.util.List<com.sunwin.robot2ips.beans.dto.CheckDataDTO>
+     * @author machao
+     * @date 2022/6/6 17:21
+     **/
+    List<RecordTaskPoint> queryDataByDate(@Param("startDate") String startDate, @Param("endDate") String endDate);
+
+    List<RobotDTO> selectRobots();
+
+    void insertBindLink(@Param("list") List<IPSPointDTO> IPSPoints);
+
+    List<RecordTaskPoint> queryDataAfterId(@Param("lastDataId") Long lastDataId, @Param("count") Integer count);
+}

+ 11 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/service/CheckDataService.java

@@ -0,0 +1,11 @@
+package com.sunwin.robot2ips.service;
+
+import org.springframework.stereotype.Service;
+
+
+@Service
+public interface CheckDataService {
+    void uploadCheckData();
+
+    void bindIPSAndRobotPoint();
+}

+ 165 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/service/impl/CheckDataServiceImpl.java

@@ -0,0 +1,165 @@
+package com.sunwin.robot2ips.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.sunwin.robot2ips.beans.dto.CheckDataDTO;
+import com.sunwin.robot2ips.beans.dto.IPSPointDTO;
+import com.sunwin.robot2ips.beans.dto.RobotDTO;
+import com.sunwin.robot2ips.beans.vo.IPSResp;
+import com.sunwin.robot2ips.beans.vo.RecordData;
+import com.sunwin.robot2ips.beans.vo.RecordTaskPoint;
+import com.sunwin.robot2ips.common.RedisKey;
+import com.sunwin.robot2ips.dao.UploadMapper;
+import com.sunwin.robot2ips.service.CheckDataService;
+import com.sunwin.robot2ips.util.DateUtil;
+import com.sunwin.robot2ips.util.ExcelUtil;
+import com.sunwin.robot2ips.util.HttpUtils;
+import com.sunwin.robot2ips.util.RedisUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Component
+public class CheckDataServiceImpl implements CheckDataService {
+    private static final Logger logger = LoggerFactory.getLogger(CheckDataServiceImpl.class);
+
+    @Autowired
+    RedisUtils redisUtils;
+
+    @Autowired
+    UploadMapper uploadMapper;
+
+    @Value("${ips.connect.url}")
+    private String url;
+
+    @Value("${ips.point.fileName}")
+    private String fileName;
+    @Value("${ips.query.count}")
+    private Integer count;
+
+    /**
+     * 查询巡检数据并上传至IPS系统
+     *
+     * @param
+     * @return void
+     * @author machao
+     * @date 2022/6/6 17:06
+     **/
+    @Override
+    public void uploadCheckData() {
+        //获取机器人信息
+        List<RobotDTO> robots = uploadMapper.selectRobots();
+        if (CollectionUtils.isEmpty(robots)) {
+            logger.info("threadName={} robot list is null skip this sync", Thread.currentThread().getName());
+            return;
+        }
+        Map<Integer, List<RobotDTO>> robotMap = robots.stream().collect(Collectors.groupingBy(RobotDTO::getId));
+        //从redis中获取最新一次上传id (若为首次上传 查询当前最近的30条记录上传)
+        Long lastDataId = (Long) redisUtils.get(RedisKey.UPLOAD_IPS_LAST_ID);
+        logger.info(" last data id ={} ", lastDataId);
+
+        //根据lastDataId查询基于上次上传后的30条巡检数据
+        List<RecordTaskPoint> checkDataList = uploadMapper.queryDataAfterId(lastDataId,count);
+        if (CollectionUtils.isEmpty(checkDataList)) {
+            logger.info("no new data ");
+            return;
+        }
+        //获取当前时间并更新redis最近上传的最新id(若上传失败则回滚!)
+        redisUtils.set(RedisKey.UPLOAD_IPS_LAST_ID, Long.valueOf(checkDataList.get(0).getResultId()));
+        //将巡检数据按照robotId分组
+        Map<Integer, List<RecordTaskPoint>> robotCheckData = checkDataList.stream().collect(Collectors.groupingBy(RecordTaskPoint::getRobotId));
+        //初始化上传集合
+        List<RecordData> uploadResult = new ArrayList<>();
+        //根据机器人拆分巡检数据
+        for (Integer key : robotCheckData.keySet()) {
+            List<RobotDTO> robot = robotMap.get(key);
+            if (CollectionUtils.isEmpty(robot)) {
+                continue;
+            }
+            RobotDTO robotDTO = robot.get(0);
+            RecordData recordData = new RecordData();
+            recordData.setRobotCode(robotDTO.getId().toString());
+            recordData.setRobotName(robotDTO.getRobotName());
+            //获取机器人对应的巡检数据进行组装
+            List<RecordTaskPoint> checkDataArray = robotCheckData.get(key);
+            //初始化集合
+            List<RecordTaskPoint> recordTaskPoints = new ArrayList<>();
+            //遍历设置时间
+            for (RecordTaskPoint recordTaskPoint : checkDataArray) {
+                //取巡检数据的巡检时间的年月日作为任务日期
+                String yyyyMMdd = DateUtil.parseToString(recordTaskPoint.getUpdateTime(), DateUtil.DateFormat_yyyy_MM_dd);
+                Date start = DateUtil.strToDate(yyyyMMdd + " 00:00:00");
+                Date end = DateUtil.strToDate(yyyyMMdd + " 23:59:59");
+                //任务时间写死识别日期的00:00-23:59
+                recordTaskPoint.setRecordPlanStartDate(start);
+                recordTaskPoint.setRecordCompleteDate(end);
+                recordTaskPoint.setRecordPlanCompleteDate(end);
+                recordTaskPoint.setRecordStartDate(start);
+                recordTaskPoints.add(recordTaskPoint);
+            }
+            recordData.setRecordTaskPoints(recordTaskPoints);
+            uploadResult.add(recordData);
+        }
+        //初始化失败的最小id 集合
+        ArrayList<Long> minIds = new ArrayList<>();
+        //根据机器人拆分组装后遍历上传
+        for (RecordData recordData : uploadResult) {
+            //HttpPost
+            String resp = HttpUtils.HttpPostWithJson(url, JSONObject.toJSONString(recordData));
+            //上传成功
+            if (!StringUtils.isEmpty(resp)) {
+                IPSResp ipsResp = JSONObject.parseObject(resp, IPSResp.class);
+                if (ipsResp.getIsSuccessed().equals("1")) {
+                    continue;
+                }
+            }
+            //失败即全部重新上传
+            redisUtils.set(RedisKey.UPLOAD_IPS_LAST_ID, lastDataId);
+        }
+
+    }
+
+
+    /**
+     * 绑定IPS与机器人巡检点关系
+     *
+     * @param
+     * @return void
+     * @author machao
+     * @date 2022/6/8 9:13
+     **/
+    @Override
+    public void bindIPSAndRobotPoint() {
+        String absolutePath = new File("").getAbsolutePath() + "\\" + fileName;
+        File file = new File(absolutePath);
+        InputStream fileInputStream = null;
+        try {
+            fileInputStream = new FileInputStream(file);
+            List<IPSPointDTO> importList = (List<IPSPointDTO>) ExcelUtil.read(fileInputStream, IPSPointDTO.class, file.getName());
+            if (CollectionUtils.isEmpty(importList)) {
+                return;
+            }
+            Iterator<IPSPointDTO> iterator = importList.iterator();
+            while (iterator.hasNext()) {
+                IPSPointDTO next = iterator.next();
+                if (next.getPointId() == null) {
+                    iterator.remove();
+                }
+            }
+            //入库
+            uploadMapper.insertBindLink(importList);
+        } catch (Exception e) {
+            logger.error("bind link error msg={}", e.getMessage());
+        }
+    }
+
+}

+ 26 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/task/UploadIPSTask.java

@@ -0,0 +1,26 @@
+package com.sunwin.robot2ips.task;
+
+import com.sunwin.robot2ips.service.CheckDataService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+/**
+ * 定时上传巡检数据至IPS系统
+ *
+ * @author machao
+ * @since 2022/6/6 16:48
+ **/
+@Component
+@EnableScheduling
+public class UploadIPSTask {
+    @Autowired
+    CheckDataService checkDataService;
+
+    @Scheduled(fixedRate = 10000)
+    public void autoUploadCheckData() {
+
+        checkDataService.uploadCheckData();
+    }
+}

+ 207 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/util/Base64Util.java

@@ -0,0 +1,207 @@
+package com.sunwin.robot2ips.util;
+
+import sun.misc.BASE64Decoder;
+import sun.misc.BASE64Encoder;
+
+import java.io.*;
+
+/**
+ * @author 作者:Sky
+ * @name Base64.java
+ * @time 时间:2017-12-24 下午09:11:35
+ * @description 描述:图片base64转码器
+ */
+public class Base64Util {
+
+    /**
+     * 图片转化成base64字符串
+     */
+    public static String imageBase64(String imgPath) {//将图片文件转化为字节数组字符串,并对其进行Base64编码处理
+        //String imgFile = "D:\\tupian\\a.jpg";//待处理的图片
+        InputStream in = null;
+        byte[] data = null;
+        //读取图片字节数组
+        try {
+            in = new FileInputStream(imgPath);
+            data = new byte[in.available()];
+            in.read(data);
+            in.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        //对字节数组Base64编码
+        BASE64Encoder encoder = new BASE64Encoder();
+        return encoder.encode(data);//返回Base64编码过的字节数组字符串
+    }
+
+    /**
+     * 图片流转化成base64字符串
+     */
+    public static String imageBase64(InputStream in) {
+        byte[] data = null;
+        //读取图片字节数组
+        try {
+            data = new byte[in.available()];
+            in.read(data);
+            in.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        //对字节数组Base64编码
+        BASE64Encoder encoder = new BASE64Encoder();
+        return encoder.encode(data);//返回Base64编码过的字节数组字符串
+    }
+
+    public static byte[] getBase64ByteCode(String imgPath) {
+        InputStream in = null;
+        byte[] data = null;
+        //读取图片字节数组
+        try {
+            in = new FileInputStream(imgPath);
+            data = new byte[in.available()];
+            in.read(data);
+            in.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return data;
+    }
+
+    public static byte[] getByteByBase64Code(String base64Code) {
+        BASE64Decoder decoder = new BASE64Decoder();
+        try {
+            return decoder.decodeBuffer(base64Code);
+        } catch (IOException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    public static String byteImageCodeToStr(byte[] data) {
+        //对字节数组Base64编码
+        BASE64Encoder encoder = new BASE64Encoder();
+        return encoder.encode(data);//返回Base64编码过的字节数组字符串
+    }
+
+    /**
+     * base64字符串转化成图片
+     */
+    public static boolean generateImage(String imgCode, String imgPath) {   //对字节数组字符串进行Base64解码并生成图片
+        if (imgCode == null) //图像数据为空
+            return false;
+        BASE64Decoder decoder = new BASE64Decoder();
+        try {
+            //Base64解码
+            byte[] b = decoder.decodeBuffer(imgCode);
+            for (int i = 0; i < b.length; ++i) {
+                if (b[i] < 0) {//调整异常数据
+                    b[i] += 256;
+                }
+            }
+            //生成jpeg图片
+            //String imgFilePath = "C:\\Users\\sunwin\\Desktop\\dong2.jpg";//新生成的图片
+            OutputStream out = new FileOutputStream(imgPath);
+            out.write(b);
+            out.flush();
+            out.close();
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    /**
+     * 用图片二进制码生成图片
+     */
+    public static boolean generateImage(byte[] b, String imgPath) {
+        if (b == null) //图像数据为空
+            return false;
+        try {
+            for (int i = 0; i < b.length; ++i) {
+                if (b[i] < 0) {//调整异常数据
+                    b[i] += 256;
+                }
+            }
+            //生成图片
+            OutputStream out = new FileOutputStream(imgPath);
+            out.write(b);
+            out.flush();
+            out.close();
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    /**
+     * @Description: 使用Base64对字符串进行解码
+     * @Param: [s]
+     * @Author: shiwn
+     * @Date: 2020/6/16 15:42
+     */
+    public static String getFromBASE64(String s) {
+        byte[] b = null;
+        String result = null;
+        if (s != null) {
+            BASE64Decoder decoder = new BASE64Decoder();
+            try {
+                b = decoder.decodeBuffer(s);
+                result = new String(b, "utf-8");
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 计算图片大小
+     *
+     * @param: base64编码
+     * @return:
+     * @author machao
+     * @date: 2021/9/9 15:38
+     */
+    public static Integer imageSize(String image) {
+        String str = image;
+        if (image.contains("data:image/png;base64,")) {
+            // 1.需要计算文件流大小,首先把头部的data:image/png;base64,(注意有逗号)去掉。
+            str = image.substring(22);
+        }
+        //2.找到等号,把等号也去掉
+        Integer equalIndex = str.indexOf("=");
+        if (str.indexOf("=") > 0) {
+            str = str.substring(0, equalIndex);
+        }
+        //3.原来的字符流大小,单位为字节
+        Integer strLength = str.length();
+        //4.计算后得到的文件流大小,单位为字节
+        Integer size = strLength - (strLength / 8) * 2;
+        return size;
+    }
+
+
+
+    /**
+     * 本地文件(图片、excel等)转换成Base64字符串
+     *
+     * @param imgPath
+     */
+    public static String convertFileToBase64(String imgPath) {
+        byte[] data = null;
+        // 读取图片字节数组
+        try {
+            InputStream in = new FileInputStream(imgPath);
+            System.out.println("文件大小(字节)="+in.available());
+            data = new byte[in.available()];
+            in.read(data);
+            in.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        // 对字节数组进行Base64编码,得到Base64编码的字符串
+        BASE64Encoder encoder = new BASE64Encoder();
+        String base64Str = encoder.encode(data);
+        return base64Str;
+    }
+}

+ 518 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/util/DateUtil.java

@@ -0,0 +1,518 @@
+package com.sunwin.robot2ips.util;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.DayOfWeek;
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * 日期时间工具方法
+ * <p>
+ * Created by shiyanfei on 2018-01-09.
+ */
+public class DateUtil {
+
+    /**
+     * 格式 2015-08-07
+     */
+    //public static final String DateFormat_yyyyMMdd = "yyyy-MM-dd";
+    /**
+     * 格式 15:25:30
+     */
+    public static final String DateFormat_HHmmss = "HH:mm:ss";
+
+    /**
+     * 格式 15:25
+     */
+    public static final String DateFormat_HHmm = "HH:mm";
+
+    /**
+     * 格式 2015-08
+     */
+    public static final String DateFormat_yyyyMM = "yyyy-MM";
+
+    /**
+     * 格式 2015-08
+     */
+    public static final String DateFormat_yyyy_MM_dd = "yyyy-MM-dd";
+
+    /**
+     * 格式 2015-08-05 23
+     */
+    public static final String DateFormat_yyyy_MM_dd_HH = "yyyy-MM-dd HH";
+
+    /**
+     * 格式 2015-08-07 11:44:18
+     */
+    public static final String DateFormat_yyyyMMddHHmmss = "yyyy-MM-dd HH:mm:ss";
+
+    /**
+     * 格式 2015-08-07 11:44:18:591
+     */
+    public static final String DateFormat_yyyyMMddHHmmssSSS = "yyyy-MM-dd HH:mm:ss.SSS";
+
+    /**
+     * 格式 20200115
+     */
+    public static final String DateFormat_yyyyMMdd = "yyyyMMdd";
+
+    /**
+     * 格式 150807114418
+     */
+    public static final String DateFormat_yyMMddHHmmss = "yyMMddHHmmss";
+
+    /**
+     * 格式 20140416142030
+     */
+    public static final String DateFormat_TimeStemp_yyyyMMddHHmmss = "yyyyMMddHHmmss";
+
+    /**
+     * 格式 142030
+     */
+    public static final String DateFormat_TimeStemp_HHmmss = "HHmmss";
+
+    /**
+     * 格式 20150807114418591
+     */
+    public static final String DateFormat_TimeStemp = "yyyyMMddHHmmssSSS";
+
+    /**
+     * 格式 2015-08-13T16:49:02.039+0800
+     */
+    public static final String DateFormat_yyyyMMddTHHmmssSSSZ = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
+
+    /**
+     * 格式 2015-11-09T00:00:08.000+08:00
+     */
+    public static final String DateFormat_yyyyMMddTHHmmssSSSXXX = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
+
+
+    /**
+     * 日期转化为字符串
+     *
+     * @param format
+     * @return
+     */
+    public static String parseToString(Date date, String format) {
+        if (date != null) {
+            DateFormat df = new SimpleDateFormat(format);
+            String strDate = df.format(date);
+            return strDate;
+        } else {
+            return "-";
+        }
+    }
+
+    /**
+     * 格式化日期
+     */
+    public static Date getFormatDate(Date date, String format) {
+        try {
+            SimpleDateFormat sdf = new SimpleDateFormat(format);
+            String strDate = sdf.format(date);
+            Date newDate = sdf.parse(strDate);
+            return newDate;
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public static long compareDate(Date date1, Date date2) {
+        long l = date2.getTime() - date1.getTime();
+        return l / (1000 * 60);
+    }
+
+    /**
+     * 将字符串转为时间戳
+     *
+     * @param time
+     * @return
+     */
+    public static Long getTime(String time) {
+        try {
+            String re_time = null;
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            Date d = sdf.parse(time);
+            long l = d.getTime();
+            re_time = String.valueOf(l);
+            return Long.parseLong(re_time);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /**
+     * 将时间戳转为字符串
+     *
+     * @param time
+     * @return
+     */
+    public static String getStrTime(String time) {
+        String re_StrTime = null;
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        long lcc_time = Long.valueOf(time);
+        re_StrTime = sdf.format(new Date(lcc_time));
+        return re_StrTime;
+    }
+
+    /**
+     * 将时间戳转为字符串
+     *
+     * @param time
+     * @return
+     */
+    public static String getStrDate(Long time, String format) {
+        String re_StrTime = null;
+        SimpleDateFormat sdf = new SimpleDateFormat(format);
+        long lcc_time = Long.valueOf(time);
+        re_StrTime = sdf.format(new Date(lcc_time));
+        return re_StrTime;
+    }
+
+    /**
+     * 将时间戳转为字符串
+     *
+     * @param time
+     * @return
+     */
+    public static Date getLongDate(Long time, String format) {
+
+        SimpleDateFormat sdf = new SimpleDateFormat(format);
+        long lcc_time = Long.valueOf(time);
+        String re_StrTime = sdf.format(new Date(lcc_time));
+
+        Date parse = null;
+        try {
+            parse = sdf.parse(re_StrTime);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return parse;
+    }
+
+    /**
+     * String转date
+     *
+     * @param dateStr
+     * @return
+     */
+    public static Date strToDate(String dateStr) {
+        try {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            return sdf.parse(dateStr);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * @Description: string 转 date
+     * @Param: [dateStr, format]
+     * @Author: shiwn
+     * @Date: 2021/1/27 14:47
+     */
+    public static Date strToDate(String dateStr, String format) {
+        try {
+            SimpleDateFormat sdf = new SimpleDateFormat(format);
+            return sdf.parse(dateStr);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * @Description: 获取某年某月有多少天
+     * @Param: [year:年份, month:月份]
+     * @Author: shiwn
+     * @Date: 2020/1/20 11:09
+     */
+    public static int getDayByYearMonth(int year, int month) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(year, month, 0);
+        return calendar.get(Calendar.DAY_OF_MONTH);
+    }
+
+    /**
+     * @Description: 根据输入的参数生成固定时间
+     * @Param: [year:年份, month:月份, day:日期, time:时间]
+     * @Author: shiwn
+     * @Date: 2020/1/20 15:48
+     */
+    public static Date buildDate(String year, String month, String day, String time) {
+        if (time == null) {
+            time = "00:00:01";
+        }
+        if (day == null) {
+            day = "01";
+        }
+        //  判断日期是否满足条件
+        int maxDay = getMaxDayOfMonth(Integer.parseInt(year), Integer.parseInt(month));
+        if (maxDay < Integer.parseInt(day)) {
+            return null;
+        }
+        try {
+            day = formatDay(day);
+            String dateStr = year + "-" + month + "-" + day + " " + time;
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            Date date = sdf.parse(dateStr);
+            return date;
+        } catch (ParseException e) {
+            return null;
+        }
+    }
+
+    /**
+     * @Description: 获取每月有多少天
+     * @Param: [year:年份, month:月份]
+     * @Author: shiwn
+     * @Date: 2020/1/22 11:43
+     */
+    public static int getMaxDayOfMonth(int year, int month) {
+        //  获取每月有多少天
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.YEAR, year);
+        //  java月份从0开始
+        calendar.set(Calendar.MONTH, month - 1);
+        return calendar.getActualMaximum(Calendar.DATE);
+    }
+
+    /**
+     * @Description: 获取该月有几周
+     * @Param: [year:年份, month:月份]
+     * @Author: shiwn
+     * @Date: 2020/1/22 10:49
+     */
+    public static int getMonthWeek(int year, int month) {
+        Calendar c = Calendar.getInstance();
+        c.set(Calendar.YEAR, year);
+        //  java月份从0开始
+        c.set(Calendar.MONTH, month - 1);
+        return c.getActualMaximum(Calendar.WEEK_OF_MONTH);
+    }
+
+    /**
+     * @Description: 返回DayOfWeek格式的星期几
+     * @Param: [weekDay:星期几]
+     * @Author: shiwn
+     * @Date: 2020/1/22 11:13
+     */
+    public static DayOfWeek getWeekDay(int weekDay) {
+        switch (weekDay) {
+            case 0:
+                return DayOfWeek.SUNDAY;
+            case 1:
+                return DayOfWeek.MONDAY;
+            case 2:
+                return DayOfWeek.TUESDAY;
+            case 3:
+                return DayOfWeek.WEDNESDAY;
+            case 4:
+                return DayOfWeek.THURSDAY;
+            case 5:
+                return DayOfWeek.FRIDAY;
+            case 6:
+                return DayOfWeek.SATURDAY;
+            default:
+                return null;
+        }
+    }
+
+
+    /**
+     * @Description: 日期的天数加减计算
+     * @Param: [date:时间, days:间隔天数]
+     * @Author: shiwn
+     * @Date: 2021/1/21 15:24
+     */
+    public static Date getDateByDays(Date date, Integer days) {
+        Calendar calendar = Calendar.getInstance();
+        //设置起时间
+        calendar.setTime(date);
+        calendar.add(Calendar.DATE, days);
+        return calendar.getTime();
+    }
+
+    /**
+     * @Description: 计算两个时间点的间隔天数
+     * @Param: [start, end]
+     * @Author: shiwn
+     * @Date: 2021/1/25 14:21
+     */
+    public static Integer getDayInterval(Date start, Date end) {
+        final long nd = 1000 * 24 * 60 * 60;
+        Date startDay = new Date(start.getTime() - start.getTime() % nd);
+        Date endDay = new Date(end.getTime() - end.getTime() % nd);
+        return (int) ((endDay.getTime() - startDay.getTime()) / nd);
+    }
+
+    /**
+     * @Description: 计算两个时间点的间隔秒数
+     * @Param: [start, end]
+     * @Author: shiwn
+     * @Date: 2021/1/25 15:54
+     */
+    public static Integer getSecondInterval(Date start, Date end) {
+        final long nd = 1000;
+        long diff = end.getTime() - start.getTime();
+        return (int) (diff / nd);
+    }
+
+    /**
+     * @Description: 计算两个时间点的间隔分钟数
+     * @Param: [start, end]
+     * @Author: shiwn
+     * @Date: 2021/1/25 15:54
+     */
+    public static Integer getMinuteInterval(Date start, Date end) {
+        final Float nd = 60000F;
+        Float diff = Float.valueOf(end.getTime() - start.getTime());
+        return (int) Math.ceil(diff / nd);
+    }
+
+
+    /**
+     * @Description: 获取本周的开始日期
+     * @Author: shiwn
+     * @Date: 2021/1/28 10:35
+     */
+    public static Date getBeginDateOfWeek() {
+        Date date = new Date();
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
+        if (dayOfWeek == 1) {
+            dayOfWeek += 7;
+        }
+        calendar.add(Calendar.DATE, 2 - dayOfWeek);
+        return calendar.getTime();
+    }
+
+    /**
+     * @Description: 获取本周的结束日期
+     * @Author: shiwn
+     * @Date: 2021/1/28 10:53
+     */
+    public static Date getEndDateOfWeek() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(getBeginDateOfWeek());
+        calendar.add(Calendar.DAY_OF_WEEK, 6);
+        return calendar.getTime();
+    }
+
+    /**
+     * @Description: 将 字符串格式的时间戳 转为 时间格式的字符串
+     * @Param: [timeStamp]
+     * @Author: shiwn
+     * @Date: 2021/1/14 17:16
+     */
+    public static String getStringByTimeStamp(String timeStamp) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String sd = sdf.format(new Date(Long.parseLong(String.valueOf(timeStamp))));
+        return sd;
+    }
+
+    /**
+     * @description: 当前日期年数加减计算
+     * @author machao
+     * @date: 2021/5/14 10:00
+     */
+    public static String getYearTime(Integer year) {
+
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Calendar c = Calendar.getInstance();
+        //过去一年
+        c.setTime(new Date());
+        c.add(Calendar.YEAR, year);
+        Date y = c.getTime();
+        return format.format(y);
+    }
+
+    /**
+     * @Description: 获取昨天的开始时间
+     * @Date: 2021/12/6 10:41
+     * @Author: shiwn
+     * @Return:
+     */
+    public static Date getYesterdayStartTime() {
+        Calendar c = Calendar.getInstance();
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+        c.set(Calendar.MILLISECOND, 1);
+        c.add(Calendar.DATE, -1);
+        return c.getTime();
+    }
+
+    /**
+     * @Description: 获取昨天的结束时间
+     * @Date: 2021/12/6 10:41
+     * @Author: shiwn
+     * @Return:
+     */
+    public static Date getYesterdayEndTime() {
+        Calendar c = Calendar.getInstance();
+        c.set(Calendar.HOUR_OF_DAY, 23);
+        c.set(Calendar.MINUTE, 59);
+        c.set(Calendar.SECOND, 59);
+        c.set(Calendar.MILLISECOND, 999);
+        c.add(Calendar.DATE, -1);
+        return c.getTime();
+    }
+
+    /**
+     * @Description: 获取上月的开始时间
+     * @Date: 2021/12/6 10:43
+     * @Author: shiwn
+     * @Return:
+     */
+    public static Date getLastMonthdayStartTime() {
+        Calendar c = Calendar.getInstance();
+        c.add(Calendar.MONTH, -1);
+        c.set(Calendar.DATE, 1);
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+        c.set(Calendar.MILLISECOND, 1);
+        return c.getTime();
+    }
+
+    /**
+     * @Description: 获取上月的开始时间
+     * @Date: 2021/12/6 11:12
+     * @Author: shiwn
+     * @Return:
+     */
+    public static Date getLastMonthdayEndTime() {
+        Calendar c = Calendar.getInstance();
+        c.set(Calendar.DATE, 1);
+        c.add(Calendar.MONTH, -1);
+        //  取上月结束日期
+        int lastMonthMaxDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);
+        //  设置
+        c.set(Calendar.DATE, lastMonthMaxDay);
+        c.set(Calendar.HOUR_OF_DAY, 23);
+        c.set(Calendar.MINUTE, 59);
+        c.set(Calendar.SECOND, 59);
+        c.set(Calendar.MILLISECOND, 999);
+        return c.getTime();
+    }
+
+    // ———————————————————————— 以下为私有方法  ————————————————————————
+
+    /**
+     * @Description: 日期格式化,如:1转为01
+     * @Param: [day:日期]
+     * @Author: shiwn
+     * @Date: 2020/1/20 15:53
+     */
+    private static String formatDay(String day) {
+        if (day.length() == 1) {
+            day = "0" + day;
+        }
+        return day;
+    }
+}

+ 613 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/util/ExcelUtil.java

@@ -0,0 +1,613 @@
+package com.sunwin.robot2ips.util;
+
+
+import cn.hutool.core.bean.BeanUtil;
+import com.sunwin.robot2ips.aspect.ExcelHeader;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.poi.hssf.usermodel.*;
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.ss.usermodel.DateUtil;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.CollectionUtils;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+import java.net.URLEncoder;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+
+/**
+ * 导入导出excel工具类
+ *
+ * @author machao
+ * @version 1.0
+ * @date 2021/5/13 14:16
+ */
+public class ExcelUtil {
+    private static final Logger logger = LoggerFactory.getLogger(ExcelUtil.class);
+    HttpServletResponse response;
+    // 文件名
+    private String fileName;
+    //文件保存路径
+    private String fileDir;
+    //sheet名
+    private String sheetName;
+    //表头字体
+    private String titleFontType = "Arial Unicode MS";
+    //表头背景色
+    private String titleBackColor = "C1FBEE";
+    //表头字号
+    private short titleFontSize = 12;
+    //添加自动筛选的列 如 A:M
+    private String address = "";
+    //正文字体
+    private String contentFontType = "Arial Unicode MS";
+    //正文字号
+    private short contentFontSize = 12;
+    //Float类型数据小数位
+    private String floatDecimal = "0.00";
+    //Double类型数据小数位
+    private String doubleDecimal = "0.00";
+    //设置列的公式
+    private String colFormula[] = null;
+
+    DecimalFormat floatDecimalFormat = new DecimalFormat(floatDecimal);
+    DecimalFormat doubleDecimalFormat = new DecimalFormat(doubleDecimal);
+
+    private HSSFWorkbook workbook = null;
+
+    public ExcelUtil() {
+
+    }
+
+    public ExcelUtil(String fileDir, String sheetName) {
+        this.fileDir = fileDir;
+        this.sheetName = sheetName;
+        workbook = new HSSFWorkbook();
+    }
+
+    public ExcelUtil(HttpServletResponse response, String fileName, String sheetName) {
+        this.fileName = fileName;
+        this.response = response;
+        this.sheetName = sheetName;
+        workbook = new HSSFWorkbook();
+    }
+
+    /**
+     * 设置表头字体.
+     *
+     * @param titleFontType
+     */
+    public void setTitleFontType(String titleFontType) {
+        this.titleFontType = titleFontType;
+    }
+
+    /**
+     * 设置表头背景色.
+     *
+     * @param titleBackColor 十六进制
+     */
+    public void setTitleBackColor(String titleBackColor) {
+        this.titleBackColor = titleBackColor;
+    }
+
+    /**
+     * 设置表头字体大小.
+     *
+     * @param titleFontSize
+     */
+    public void setTitleFontSize(short titleFontSize) {
+        this.titleFontSize = titleFontSize;
+    }
+
+    /**
+     * 设置表头自动筛选栏位,如A:AC.
+     *
+     * @param address
+     */
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    /**
+     * 设置正文字体.
+     *
+     * @param contentFontType
+     */
+    public void setContentFontType(String contentFontType) {
+        this.contentFontType = contentFontType;
+    }
+
+    /**
+     * 设置正文字号.
+     *
+     * @param contentFontSize
+     */
+    public void setContentFontSize(short contentFontSize) {
+        this.contentFontSize = contentFontSize;
+    }
+
+    /**
+     * 设置float类型数据小数位 默认.00
+     *
+     * @param doubleDecimal 如 ".00"
+     */
+    public void setDoubleDecimal(String doubleDecimal) {
+        this.doubleDecimal = doubleDecimal;
+    }
+
+    /**
+     * 设置doubel类型数据小数位 默认.00
+     *
+     * @param floatDecimalFormat 如 ".00
+     */
+    public void setFloatDecimalFormat(DecimalFormat floatDecimalFormat) {
+        this.floatDecimalFormat = floatDecimalFormat;
+    }
+
+    /**
+     * 设置列的公式
+     *
+     * @param colFormula 存储i-1列的公式 涉及到的行号使用@替换 如A@+B@
+     */
+    public void setColFormula(String[] colFormula) {
+        this.colFormula = colFormula;
+    }
+
+    /**
+     * 写excel.
+     * xls方式
+     *
+     * @param titleColumn 对应bean的属性名
+     * @param titleName   excel要导出的列名
+     * @param dataList    数据
+     */
+    public void writeExcel(String titleColumn[], String titleName[], List<?> dataList) {
+        //添加Worksheet(不添加sheet时生成的xls文件打开时会报错)
+        Sheet sheet = workbook.createSheet(this.sheetName);
+        //新建文件
+        OutputStream out = null;
+        try {
+            if (fileDir != null) {
+                //有文件路径
+                out = new FileOutputStream(fileDir);
+            } else {
+                //否则,直接写到输出流中
+                out = response.getOutputStream();
+                fileName = fileName + ".xls";
+                response.setContentType("application/msexcel;charset=UTF-8");
+                response.setHeader("Content-Disposition", "attachment; filename="
+                        + URLEncoder.encode(fileName, "UTF-8"));
+            }
+
+            //写入excel的表头
+            Row titleNameRow = workbook.getSheet(sheetName).createRow(0);
+            //设置样式
+            CellStyle titleStyle = workbook.createCellStyle();
+            titleStyle = (HSSFCellStyle) setFontAndBorder(titleStyle, titleFontType, (short) titleFontSize);
+            titleStyle = (HSSFCellStyle) setColor(titleStyle, titleBackColor, (short) 10);
+
+            for (int i = 0; i < titleName.length; i++) {
+                sheet.setColumnWidth(i, 20 * 256);    //设置宽度
+                Cell cell = titleNameRow.createCell(i);
+                cell.setCellStyle(titleStyle);
+                cell.setCellValue(titleName[i].toString());
+            }
+
+            //为表头添加自动筛选
+            if (!"".equals(address)) {
+                CellRangeAddress c = (CellRangeAddress) CellRangeAddress.valueOf(address);
+                sheet.setAutoFilter(c);
+            }
+
+            //通过反射获取数据并写入到excel中
+            if (dataList != null && dataList.size() > 0) {
+                //设置样式
+                HSSFCellStyle dataStyle = workbook.createCellStyle();
+                titleStyle = (HSSFCellStyle) setFontAndBorder(titleStyle, contentFontType, (short) contentFontSize);
+
+                if (titleColumn.length > 0) {
+                    for (int rowIndex = 1; rowIndex <= dataList.size(); rowIndex++) {
+                        Object obj = dataList.get(rowIndex - 1);     //获得该对象
+                        Class clsss = obj.getClass();     //获得该对对象的class实例
+                        Row dataRow = workbook.getSheet(sheetName).createRow(rowIndex);
+                        for (int columnIndex = 0; columnIndex < titleColumn.length; columnIndex++) {
+                            String title = titleColumn[columnIndex].toString().trim();
+                            if (!"".equals(title)) {  //字段不为空
+                                //使首字母大写
+                                String UTitle = Character.toUpperCase(title.charAt(0)) + title.substring(1, title.length());
+                                String methodName = "get" + UTitle;
+
+                                // 设置要执行的方法
+                                Method method = clsss.getDeclaredMethod(methodName);
+
+                                //获取返回类型
+                                String returnType = method.getReturnType().getName();
+                                Object object = method.invoke(obj);
+                                String data = method.invoke(obj) == null ? "" : object.toString();
+                                Cell cell = dataRow.createCell(columnIndex);
+                                if (data != null && !"".equals(data)) {
+                                    if ("int".equals(returnType)) {
+                                        cell.setCellValue(Integer.parseInt(data));
+                                    } else if ("long".equals(returnType)) {
+                                        cell.setCellValue(Long.parseLong(data));
+                                    } else if ("float".equals(returnType)) {
+                                        cell.setCellValue(floatDecimalFormat.format(Float.parseFloat(data)));
+                                    } else if ("double".equals(returnType)) {
+                                        cell.setCellValue(doubleDecimalFormat.format(Double.parseDouble(data)));
+                                    } else if (Date.class.getName().equals(returnType)) {
+                                        cell.setCellValue(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(object));
+                                    } else {
+                                        cell.setCellValue(data);
+                                    }
+                                }
+                            } else {   //字段为空 检查该列是否是公式
+                                if (colFormula != null) {
+                                    String sixBuf = colFormula[columnIndex].replace("@", (rowIndex + 1) + "");
+                                    Cell cell = dataRow.createCell(columnIndex);
+                                    cell.setCellFormula(sixBuf);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            workbook.write(out);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (out != null) {
+                try {
+                    out.close();
+                } catch (IOException e) {
+                    logger.debug("导出写Excel异常");
+                }
+            }
+        }
+    }
+
+
+    /**
+     * xlsx方式
+     *
+     * @param response
+     * @param fileName
+     * @param titleColumn
+     * @param titleName
+     * @param dataList
+     */
+    public void writeBigExcel(HttpServletResponse response, String fileName, String titleColumn[],
+                              String titleName[], List<?> dataList) {
+        try {
+            SXSSFWorkbook workbook = new SXSSFWorkbook(100);
+            OutputStream out = response.getOutputStream();
+            String lastFileName = fileName + ".xlsx";
+            response.setContentType("application/msexcel;charset=UTF-8");
+            response.setHeader("Content-Disposition", "attachment; filename="
+                    + URLEncoder.encode(lastFileName, "UTF-8"));
+            int k = 0;
+            int rowIndex;
+            Sheet sheet = workbook.createSheet(fileName + (k + 1));
+            //写入excel的表头
+            Row titleNameRow = workbook.getSheet(fileName + (k + 1)).createRow(0);
+            for (int i = 0; i < titleName.length; i++) {
+                sheet.setColumnWidth(i, 20 * 256);    //设置宽度
+                Cell cell = titleNameRow.createCell(i);
+                cell.setCellValue(titleName[i]);
+            }
+            //写入到excel中
+            if (dataList != null && dataList.size() > 0) {
+                if (titleColumn.length > 0) {
+                    for (int index = 0; index < dataList.size(); index++) {
+                        //每个sheet3W条数据
+                        if (index != 0 && (index) % 30000 == 0) {
+                            k = k + 1;
+                            sheet = workbook.createSheet(fileName + (k + 1));
+                            //写入excel的表头
+                            titleNameRow = workbook.getSheet(fileName + (k + 1)).createRow(0);
+                            for (int i = 0; i < titleName.length; i++) {
+                                sheet.setColumnWidth(i, 20 * 256);    //设置宽度
+                                Cell cell = titleNameRow.createCell(i);
+                                cell.setCellValue(titleName[i]);
+                            }
+                        }
+                        if (index < 30000) {
+                            rowIndex = index + 1;
+                        } else {
+                            rowIndex = index - 30000 * ((index) / 30000) + 1;
+                        }
+                        Object obj = dataList.get(index);
+                        Class clazz = obj.getClass();
+                        Row dataRow = workbook.getSheet(fileName + (k + 1)).createRow(rowIndex);
+                        for (int columnIndex = 0; columnIndex < titleColumn.length; columnIndex++) {
+                            String title = titleColumn[columnIndex].trim();
+                            if (!"".equals(title)) {
+                                // 获取返回类型
+                                String UTitle = Character.toUpperCase(title.charAt(0)) + title.substring(1, title.length());
+                                String methodName = "get" + UTitle;
+                                Method method = clazz.getDeclaredMethod(methodName);
+                                String returnType = method.getReturnType().getName();
+                                Object object = method.invoke(obj);
+                                String data = method.invoke(obj) == null ? "" : object.toString();
+                                Cell cell = dataRow.createCell(columnIndex);
+                                if (data != null && !"".equals(data)) {
+                                    if ("int".equals(returnType)) {
+                                        cell.setCellValue(Integer.parseInt(data));
+                                    } else if ("long".equals(returnType)) {
+                                        cell.setCellValue(Long.parseLong(data));
+                                    } else if ("float".equals(returnType)) {
+                                        cell.setCellValue(new DecimalFormat("0.00").format(Float.parseFloat(data)));
+                                    } else if ("double".equals(returnType)) {
+                                        cell.setCellValue(new DecimalFormat("0.00").format(Double.parseDouble(data)));
+                                    } else if (Date.class.getName().equals(returnType)) {
+                                        cell.setCellValue(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(object));
+                                    } else {
+                                        cell.setCellValue(data);
+                                    }
+                                } else {   //字段为空 检查该列是否是公式
+                                    if (colFormula != null) {
+                                        String sixBuf = colFormula[columnIndex].replace("@", (rowIndex + 1) + "");
+                                        cell = dataRow.createCell(columnIndex);
+                                        cell.setCellFormula(sixBuf);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            workbook.write(out);
+            out.flush();
+            out.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 将16进制的颜色代码写入样式中来设置颜色
+     *
+     * @param style 保证style统一
+     * @param color 颜色:66FFDD
+     * @param index 索引 8-64 使用时不可重复
+     * @return
+     */
+    public CellStyle setColor(CellStyle style, String color, short index) {
+        if ("".equals(color)) {
+            //转为RGB码
+            int r = Integer.parseInt((color.substring(0, 2)), 16);   //转为16进制
+            int g = Integer.parseInt((color.substring(2, 4)), 16);
+            int b = Integer.parseInt((color.substring(4, 6)), 16);
+            //自定义cell颜色
+            HSSFPalette palette = workbook.getCustomPalette();
+            palette.setColorAtIndex((short) index, (byte) r, (byte) g, (byte) b);
+
+            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+            style.setFillForegroundColor(index);
+        }
+        return style;
+    }
+
+    /**
+     * 设置字体并加外边框
+     *
+     * @param style 样式
+     * @param style 字体名
+     * @param style 大小
+     * @return
+     */
+    public CellStyle setFontAndBorder(CellStyle style, String fontName, short size) {
+        HSSFFont font = workbook.createFont();
+        font.setFontHeightInPoints(size);
+        font.setFontName(fontName);
+        font.setBold(true);//是否加粗
+        style.setFont(font);
+        style.setBorderBottom(BorderStyle.THIN); //下边框
+        style.setBorderLeft(BorderStyle.THIN);//左边框
+        style.setBorderTop(BorderStyle.THIN);//上边框
+        style.setBorderRight(BorderStyle.THIN);//右边框
+        style.setFillForegroundColor(HSSFColor.RED.index);// 设置背景色
+        return style;
+    }
+
+
+
+    /*------------------------------------导入---------------------------------------*/
+
+    /**
+     * 是否是2003的excel,返回true是2003
+     *
+     * @param filePath
+     * @return
+     */
+    public static boolean isExcel2003(String filePath) {
+        return filePath.matches("^.+\\.(?i)(xls)$");
+    }
+
+    /**
+     * 是否是2007的excel,返回true是2007
+     *
+     * @param filePath
+     * @return
+     */
+    public static boolean isExcel2007(String filePath) {
+        return filePath.matches("^.+\\.(?i)(xlsx)$");
+    }
+
+
+    /**
+     * 读取excel
+     *
+     * @param: in 输入流 ,clazz
+     * @return:
+     * @author machao
+     * @date: 2021/10/25 8:59
+     */
+    public static List<? extends Object> read(InputStream in, Class clazz, String fileName) {
+        List<Field> fields = gatherAnnotationFields(clazz);
+        if (CollectionUtils.isEmpty(fields)) {
+            return null;
+        }
+        //获取sheet
+        Workbook wb = null;
+        try {
+            if (isExcel2003(fileName)) {
+                wb = new HSSFWorkbook(in);
+            } else {
+                wb = new XSSFWorkbook(in);
+            }
+        } catch (IOException e) {
+            logger.error("IO error msg ={}", e.getMessage());
+        }
+        Sheet importSheet = wb.getSheetAt(0);
+        List rList = null;
+        try {
+            rList = readContent(clazz, fields, importSheet);
+        } catch (Exception e) {
+            logger.error("read content error msg ={}", e.getMessage());
+        }
+        return rList;
+    }
+
+    private static List<Object> readContent(Class clazz, List<Field> fields, Sheet importSheet) throws IllegalAccessException, InstantiationException {
+        Object o = null;
+        List<Object> rsList = new ArrayList<>();
+        Object value = null;
+        int firstRowNum = importSheet.getFirstRowNum();
+        int lastRowNum = importSheet.getLastRowNum();
+        //第一行为表头,拿到表头对应的列值
+        Row row = importSheet.getRow(firstRowNum);
+
+        /**
+         * 根据sheet获取对应的行列值,和表头对应的列值映射
+         */
+        int firstCellNum = row.getFirstCellNum();
+        int lastCellNum = row.getLastCellNum();
+        Map<String, Integer> title_to_index = new HashMap<>();
+        for (int i = firstCellNum; i < lastCellNum; i++) {
+            title_to_index.put(row.getCell(i).getStringCellValue(), i);
+        }
+
+
+        for (int i = (firstRowNum + 1); i <= lastRowNum; i++) {
+            o = clazz.newInstance();
+            row = importSheet.getRow(i);
+            Cell cell = null;
+            for (Field field : fields) {
+                //根据注解中的title,取到表格中该列所对应的的值
+                Integer column = title_to_index.get(field.getAnnotation(ExcelHeader.class).value());
+                if (column == null) {
+                    continue;
+                }
+                cell = row.getCell(column);
+                value = getCellValue(cell);
+                if (null != value && StringUtils.isNotBlank(value.toString())) {
+                    BeanUtil.setProperty(o, field.getName(), value);
+                }
+            }
+            rsList.add(o);
+        }
+        return rsList;
+    }
+
+
+    /**
+     * 根据自定义注解,获取所要导入表格的sheet名称和需要导入的字段名称
+     *
+     * @param clazz
+     * @throws Exception
+     */
+    private static List<Field> gatherAnnotationFields(Class clazz) {
+
+        List<Field> fields = new ArrayList<>();
+
+        // 得到所有定义字段
+        Field[] allFields = FieldUtils.getAllFields(clazz);
+        // 得到所有field并存放到一个list中
+        for (Field field : allFields) {
+            if (field.isAnnotationPresent(ExcelHeader.class)) {
+                fields.add(field);
+            }
+        }
+        if (fields.isEmpty()) {
+            return null;
+        }
+        return fields;
+    }
+
+    private static Object getCellValue(Cell cell) {
+        if (cell == null) {
+            return "";
+        }
+        Object obj = null;
+        switch (cell.getCellTypeEnum()) {
+            case BOOLEAN:
+                obj = cell.getBooleanCellValue();
+                break;
+            case ERROR:
+                obj = cell.getErrorCellValue();
+                break;
+            case FORMULA:
+                try {
+                    obj = String.valueOf(cell.getStringCellValue());
+                } catch (IllegalStateException e) {
+                    obj = numericToBigDecimal(cell);
+                }
+                break;
+            case NUMERIC:
+                obj = getNumericValue(cell);
+                break;
+            case STRING:
+                String value = String.valueOf(cell.getStringCellValue());
+                value = value.replace(" ", "");
+                value = value.replace("\n", "");
+                value = value.replace("\t", "");
+                obj = value;
+                break;
+            default:
+                break;
+        }
+        return obj;
+    }
+
+    private static Object getNumericValue(Cell cell) {
+        // 处理日期格式、时间格式
+        if (HSSFDateUtil.isCellDateFormatted(cell)) {
+            return cell.getDateCellValue();
+        } else if (cell.getCellStyle().getDataFormat() == 58) {
+            // 处理自定义日期格式:m月d日(通过判断单元格的格式id解决,id的值是58)
+            double value = cell.getNumericCellValue();
+            return DateUtil.getJavaDate(value);
+        } else {
+            return numericToBigDecimal(cell);
+        }
+    }
+
+    private static Object numericToBigDecimal(Cell cell) {
+        String valueOf = String.valueOf(cell.getNumericCellValue());
+        BigDecimal bd = new BigDecimal(valueOf);
+        Long l = bd.setScale(0, BigDecimal.ROUND_UP).longValue();
+        if (new BigDecimal(l).compareTo(bd) == 0) {
+            return l;
+        }
+
+        return bd;
+    }
+
+
+}
+

+ 354 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/util/FileUtil.java

@@ -0,0 +1,354 @@
+package com.sunwin.robot2ips.util;
+
+import org.apache.commons.io.FileUtils;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @name FileUtil.java
+ * @author 作者:Sky
+ * @time 时间:2017-12-22 下午01:39:15
+ * @description 
+ * 描述:文件读取 工具
+ *
+ */
+public class FileUtil {
+	
+	/**
+	 * @name getFileNameList
+	 * 作者:Sky
+	 * 时间:2017-12-22 下午01:39:36
+	 * 描述:得到文件夹下所有文件名
+	 * @param path 物理路径
+	 * @return List<String>
+	 */
+	public static List<String> getFileNameList(String path) {
+		List<String> list = new ArrayList<String>();
+		try {
+			File file = new File(path);
+			String[] filelist = file.list();
+			for (int i = 0; i < filelist.length; i++) {
+				list.add(filelist[i]);
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return list;
+	}
+	/**
+	 * @name getFileList
+	 * 作者:Sky
+	 * 时间:2017-12-22 下午02:01:43
+	 * 描述:得到文件夹下所有文件名,包括目录名
+	 * @param path
+	 * @return String
+	 */
+	public static List<String> getFileList(String path) {
+		List<String> list = new ArrayList<String>();
+		try {
+			File file = new File(path);
+			String[] filelist = file.list();
+			for (int i = 0; i < filelist.length; i++) {
+				list.add(path + filelist[i]);
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return list;
+	}
+	/**
+	 * @name getAll
+	 * 作者:Sky
+	 * 时间:2017-12-22 下午01:40:35
+	 * 描述:读取指定目录下的所有文件及文件夹
+	 * @param path 物理路径
+	 * @return List<File>
+	 */
+	public static List<File> getAll(String path){
+		File[] fileArray = new File(path).listFiles();
+		return Arrays.asList(fileArray);
+	}
+	/**
+	 * @name getDirectory
+	 * 作者:Sky
+	 * 时间:2017-12-22 下午01:42:05
+	 * 描述:读取指定目录下的所有文件夹,不含文件
+	 * @param path 物理路径
+	 * @return List<File>
+	 */
+	public static List<File> getDirectory(String path){
+		File[] fileArray = new File(path).listFiles();
+		List<File> fileList = new ArrayList<File>();
+		for (File file : fileArray) {
+			if(file.isDirectory()){
+				fileList.add(file);
+			}
+		}
+		return fileList;
+	}
+	/**
+	 * @name getFile
+	 * 作者:Sky
+	 * 时间:2017-12-22 下午01:42:46
+	 * 描述:读取指定目录下的所有文件,不含目录
+	 * @param path 物理路径
+	 * @return List<File>
+	 */
+	public static List<File> getFile(String path){
+		File[] fileArray = new File(path).listFiles();
+		List<File> fileList = new ArrayList<File>();
+		for (File file : fileArray) {
+			if(file.isFile()){
+				fileList.add(file);
+			}
+		}
+		return fileList;
+	}
+	/**
+	 * @name readFileByLine
+	 * 作者:Sky
+	 * 时间:2017-12-22 下午02:12:27
+	 * 描述:按行读文件
+	 * @param file
+	 * @return List<String>
+	 */
+	public static List<String> readFileByLine(String file) {
+		List<String> res = new ArrayList<String>();
+		try {
+			FileReader conFile = new FileReader(file);
+			BufferedReader readConf = new BufferedReader(conFile);
+			String line;
+			while (null != (line = readConf.readLine())) {
+				//#注释不读取
+				if (!line.startsWith("#")) {
+					res.add(line);
+				}
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return res;
+	}
+	/**
+	 * @name readFile
+	 * 作者:Sky
+	 * 时间:2017-12-22 下午02:12:45
+	 * 描述:读取文件内容
+	 * @param file
+	 * @return String
+	 */
+	public static String readFile(String file) {
+		String res = new String();
+		try {
+			FileReader conFile = new FileReader(file);
+			BufferedReader readConf = new BufferedReader(conFile);
+			String line;
+			while (null != (line = readConf.readLine())) {
+				 {
+					res+=line+"\n\r";
+				}
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return res;
+	}
+	/**
+	 * @name removeFile
+	 * 作者:Sky
+	 * 时间:2017-12-22 下午02:15:05
+	 * 描述:删除文件
+	 * @param path
+	 */
+	public static void deleteFile(String path){
+		File file = new File(path);
+		if(file.exists()){ 
+            if(file.isFile()){
+            	file.delete(); 
+            }else if(file.isDirectory()){
+	             File files[] = file.listFiles(); 
+	             for(int i=0;i<files.length;i++){ 
+	            	 files[i].delete(); 
+	             }
+            }
+            file.delete(); 
+       }else{ 
+          System.out.println("该目录为空或文件不存在!"+'\n'); 
+       } 
+   }
+	/**
+	 * @name deleteEmptyDir
+	 * 作者:Sky
+	 * 时间:2017-12-22 下午02:47:40
+	 * 描述:删除文件夹
+	 * @param path
+	 */
+	public static  void deleteEmptyDir(String path){
+		File file = new File(path);
+		file.delete();
+	}
+	
+    /**
+     * 递归删除目录下的所有文件及子目录下所有文件
+     * @param dir 将要删除的文件目录
+     */
+	public static void deleteDir(File dir) {
+		File[] files = dir.listFiles();
+		for (File file : files) {
+			//如果是目录,继续遍历
+			if(file.isDirectory()){
+				deleteDir(file);
+			}else{
+				//如果不是目录,就删除文件
+				file.delete();
+			}
+		}
+		//删除目录
+		dir.delete();
+    }
+	
+	 /**
+     * 情况文件夹
+     * @param path 将要删除的文件
+     */
+	public static void clearDir(String path) {
+		File dir = new File(path);
+		if(dir.exists()){ 
+			File[] files = dir.listFiles();
+			for (File file : files) {
+				//如果是目录,继续遍历
+				if(file.isDirectory()){
+					deleteDir(file);
+				}else{
+					//如果不是目录,就删除文件
+					file.delete();
+				}
+			}
+		}
+    }
+	
+	/**
+     * 复制文件
+     * @param fromFile
+     * @param toFile
+     * <br/>
+     * 2016年12月19日  下午3:31:50
+     * @throws IOException 
+     */
+    public static void copyFile(File fromFile,File toFile) throws IOException{
+    	//方式一
+//    	FileInputStream ins = new FileInputStream(fromFile);
+//        FileOutputStream out = new FileOutputStream(toFile);
+//        byte[] b = new byte[1024];
+//        int n=0;
+//        while((n=ins.read(b))!=-1){
+//            out.write(b, 0, n);
+//        }
+//        
+//        ins.close();
+//        out.close();
+    	//方式二
+    	 FileUtils.copyFile(fromFile, toFile);
+    }
+	
+	/**
+	 * @name mkdir
+	 * 作者:Sky
+	 * 时间:2017-12-22 下午02:47:16
+	 * 描述:创建文件夹 
+	 * @param path
+	 * @return boolean
+	 */
+	public static  boolean mkdir(String path){
+		File file = new File(path);
+		return file.mkdir();
+	}
+	/**
+	 * @name createNewFile
+	 * 作者:Sky
+	 * 时间:2017-12-22 下午02:53:56
+	 * 描述:创建文件
+	 * @param path
+	 * @return boolean
+	 */
+	public static boolean createNewFile(String path){
+		try {
+			return new File(path).createNewFile();
+		} catch (IOException e) {
+			e.printStackTrace();
+			return false;
+		}
+	}
+	
+	/**
+	 * @name writeFile
+	 * 作者:Sky
+	 * 时间:2017-12-26 上午11:33:44
+	 * 描述:写文件
+	 * @param path
+	 * @param content
+	 */
+	public static void writeFile(String path,String content){
+		try {
+			FileWriter writer = new FileWriter(path);
+			writer.write(content);
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+
+	public static void writeFile(String path,byte[] bt){
+		try {
+			FileWriter writer = new FileWriter(path);
+			for (int i = 0; i < bt.length; i++) {
+				byte b = bt[i];
+				writer.write(b+"");
+			}
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+
+	//追加原文件最后写入文件
+	public static void writeFileAppend(String path,String content){
+		try {
+			File file = new File(path);
+			if(!file.exists()){
+				file.createNewFile();
+			}
+			FileWriter writer = new FileWriter(path,true);
+			writer.write(content);
+			writer.write("\r\n"); //换行符
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+	
+	 // 判断文件是否存在
+    public static boolean fileExist(File file) {
+    	return file.exists();
+    }
+
+    // 判断文件夹是否存在
+    public static boolean dirExists(File file) {
+        if (file.exists()) {
+            if (file.isDirectory()) {
+            	return true;
+            } else {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    //取文件名后缀
+	public static String getFileExtName(File file) {
+		String fileName = file.getName();
+		return fileName.substring(fileName.lastIndexOf("."));
+	}
+
+}

+ 125 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/util/HttpUtils.java

@@ -0,0 +1,125 @@
+package com.sunwin.robot2ips.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.BasicResponseHandler;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+public class HttpUtils {
+
+    private static final String ENCODING = "UTF-8";
+
+
+    public static String post(String url, Map<String, String> paramsMap) {
+        CloseableHttpClient client = HttpClients.createDefault();
+        String responseText = "";
+        CloseableHttpResponse response = null;
+        try {
+            HttpPost method = new HttpPost(url);
+            if (paramsMap != null) {
+                List<NameValuePair> paramList = new ArrayList<NameValuePair>();
+                for (Map.Entry<String, String> param : paramsMap.entrySet()) {
+                    NameValuePair pair = new BasicNameValuePair(param.getKey(), param.getValue());
+                    paramList.add(pair);
+                }
+                method.setEntity(new UrlEncodedFormEntity(paramList, ENCODING));
+            }
+            response = client.execute(method);
+            HttpEntity entity = response.getEntity();
+            if (entity != null) {
+                responseText = EntityUtils.toString(entity);
+            }
+        } catch (Exception e) {
+            log.error("http request failed", e);
+        } finally {
+            try {
+                response.close();
+            } catch (Exception e) {
+                log.error("", e);
+            }
+        }
+        return responseText;
+    }
+
+    public static String get(String url, Map<String, String> paramsMap) {
+        CloseableHttpClient client = HttpClients.createDefault();
+        String responseText = "";
+        CloseableHttpResponse response = null;
+        try {
+            String getUrl = url + "?";
+            if (paramsMap != null) {
+                for (Map.Entry<String, String> param : paramsMap.entrySet()) {
+                    getUrl += param.getKey() + "=" + URLEncoder.encode(param.getValue(), ENCODING) + "&";
+                }
+            }
+            HttpGet method = new HttpGet(getUrl);
+            response = client.execute(method);
+            HttpEntity entity = response.getEntity();
+            if (entity != null) {
+                responseText = EntityUtils.toString(entity);
+            }
+        } catch (Exception e) {
+            log.error("http request failed", e);
+        } finally {
+            try {
+                response.close();
+            } catch (Exception e) {
+                log.error("", e);
+            }
+        }
+        return responseText;
+    }
+
+    //post请求参数为json格式
+    public static String HttpPostWithJson(String url, String json) {
+        String returnValue = "";
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        ResponseHandler<String> responseHandler = new BasicResponseHandler();
+        try {
+            //第一步:创建HttpClient对象
+            httpClient = HttpClients.createDefault();
+
+            //第二步:创建httpPost对象
+            HttpPost httpPost = new HttpPost(url);
+
+            //第三步:给httpPost设置JSON格式的参数
+            StringEntity requestEntity = new StringEntity(json, "utf-8");
+            requestEntity.setContentEncoding("UTF-8");
+            httpPost.setHeader("Content-type", "application/json");
+            httpPost.setEntity(requestEntity);
+            //第四步:发送HttpPost请求,获取返回值
+            returnValue = httpClient.execute(httpPost, responseHandler); //调接口获取返回值时,必须用此方法
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                httpClient.close();
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+        //第五步:处理返回值
+        return returnValue;
+    }
+
+
+}

+ 44 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/util/ListSplitUtil.java

@@ -0,0 +1,44 @@
+package com.sunwin.robot2ips.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author machao
+ * @version 1.0
+ * @description: TODO
+ * @date 2021/7/5 11:01
+ */
+public class ListSplitUtil<T> {
+
+
+    /**
+     * list切割
+     *
+     * @param source 需要切割的list
+     * @param n      切割的list的数量单位
+     * @param <T>
+     * @return
+     */
+    public <T> List<List<T>> fixedGrouping(List<T> source, int n) {
+        if (null == source || source.size() == 0 || n <= 0) {
+            return null;
+        }
+        List<List<T>> result = new ArrayList<>();
+        int remainder = source.size() % n;
+        int size = (source.size() / n);
+        for (int i = 0; i < size; i++) {
+            List<T> subset;
+            subset = source.subList(i * n, (i + 1) * n);
+            result.add(subset);
+        }
+        if (remainder > 0) {
+            List<T> subset;
+            subset = source.subList(size * n, size * n + remainder);
+            result.add(subset);
+        }
+        return result;
+    }
+
+
+}

+ 32 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/util/MyBeanUtil.java

@@ -0,0 +1,32 @@
+package com.sunwin.robot2ips.util;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.BeanWrapper;
+import org.springframework.beans.BeanWrapperImpl;
+
+import java.beans.FeatureDescriptor;
+import java.util.stream.Stream;
+
+/**
+ * @author machao
+ * @version 1.0
+ * @description: TODO
+ * @date 2021/10/8 11:02
+ */
+public class MyBeanUtil {
+
+    public static String[] getNullPropertyNames(Object source) {
+        final BeanWrapper wrappedSource = new BeanWrapperImpl(source);
+        return Stream.of(wrappedSource.getPropertyDescriptors())
+                .map(FeatureDescriptor::getName)
+                .filter(propertyName -> wrappedSource.getPropertyValue(propertyName) == null)
+                .toArray(String[]::new);
+    }
+
+    /**
+     * 拷贝对象,忽略值为null的字段
+     */
+    public static void copyPropertiesIgnoreNull(Object src, Object target) {
+        BeanUtils.copyProperties(src, target, getNullPropertyNames(src));
+    }
+}

+ 43 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/util/PageInfoUtil.java

@@ -0,0 +1,43 @@
+package com.sunwin.robot2ips.util;
+
+import com.github.pagehelper.PageInfo;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description: 自定义分页类(解决pageHelper返回结果需要封装出错问题)
+ * @Author: shiwn
+ * @Date: 2020/3/13 13:40
+ */
+public class PageInfoUtil {
+    /**
+     * @Description: 包装PageHelper对象对象
+     * @Param: [pageOrg]
+     * @Author: shiwn
+     * @Date: 2020/3/13 14:03
+     */
+    public static PageInfo<Map> PageInfoMap(PageInfo pageOrg, List list) {
+        PageInfo<Map> pageInfo = new PageInfo<>();
+        pageInfo.setPageNum(pageOrg.getPageNum());
+        pageInfo.setPageSize(pageOrg.getPageSize());
+        pageInfo.setSize(pageOrg.getSize());
+        pageInfo.setStartRow(pageOrg.getStartRow());
+        pageInfo.setEndRow(pageOrg.getEndRow());
+
+        pageInfo.setPages(pageOrg.getPages());
+        pageInfo.setPrePage(pageOrg.getPrePage());
+        pageInfo.setNextPage(pageOrg.getNextPage());
+
+        pageInfo.setIsFirstPage(pageOrg.isIsFirstPage());
+        pageInfo.setIsLastPage(pageOrg.isIsLastPage());
+
+        pageInfo.setNavigateFirstPage(pageOrg.getNavigateFirstPage());
+        pageInfo.setNavigateLastPage(pageOrg.getNavigateLastPage());
+
+
+        pageInfo.setTotal(pageOrg.getTotal());
+        pageInfo.setList(list);
+        return pageInfo;
+    }
+}

+ 553 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/util/RedisUtils.java

@@ -0,0 +1,553 @@
+package com.sunwin.robot2ips.util;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * redis 工具类
+ * Created by shiwn on 2021/5/11 10:48
+ */
+@Component
+public class RedisUtils {
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+    // =============================common===========================
+
+    /**
+     * @Description: 指定缓存失效时间
+     * @Param: [key:键,  expireTime:失效时间(秒)]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:29
+     */
+    public boolean expire(String key, long expireTime) {
+        try {
+            if (expireTime > 0) {
+                redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * @Description: 根据key 获取过期时间
+     * @Param: [key:键]
+     * @Author: shiwn
+     * @Return: 时间(秒),返回0代表为永久有效
+     * @Date: 2021/5/11 10:54
+     */
+    public long getExpire(String key) {
+        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
+    }
+
+    /**
+     * @Description: 判断key是否存在
+     * @Param: [key:键]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:31
+     */
+    public boolean hasKey(String key) {
+        try {
+            return redisTemplate.hasKey(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * @Description: 删除缓存
+     * @Param: [key:键,可以传一个值或多个]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:32
+     */
+    @SuppressWarnings("unchecked")
+    public void del(String... key) {
+        if (key != null && key.length > 0) {
+            if (key.length == 1) {
+                redisTemplate.delete(key[0]);
+            } else {
+                redisTemplate.delete(CollectionUtils.arrayToList(key));
+            }
+        }
+    }
+
+    // ============================String=============================
+
+    /**
+     * @Description: 获取缓存值
+     * @Param: [key]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:38
+     */
+    public Object get(String key) {
+        return key == null ? null : redisTemplate.opsForValue().get(key);
+    }
+
+    /**
+     * @Description: 写入缓存
+     * @Param: [key, value]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:38
+     */
+    public boolean set(String key, Object value) {
+        try {
+            redisTemplate.opsForValue().set(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * @Description: 写入缓存,并设置时效时间
+     * @Param: [key:键, value:值, expireTime:失效时间(秒)]
+     * @Author: shiwn
+     * @Date: 2021/5/11 10:52
+     */
+    public boolean set(final String key, Object value, Long expireTime) {
+        try {
+            if (expireTime > 0) {
+                redisTemplate.opsForValue().set(key, value, expireTime, TimeUnit.SECONDS);
+                return true;
+            }
+            return false;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * @Description: 缓存值递增
+     * @Param: [key:键, delta:递增值,要增加几(大于0)]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:40
+     */
+    public long incr(String key, long delta) {
+        if (delta < 0) {
+            throw new RuntimeException("递增因子必须大于0");
+        }
+        return redisTemplate.opsForValue().increment(key, delta);
+    }
+
+    /**
+     * @Description: 缓存值递减
+     * @Param: [key:键, delta:递增值,要减少几(小于0)]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:41
+     */
+    public long decr(String key, long delta) {
+        if (delta < 0) {
+            throw new RuntimeException("递减因子必须大于0");
+        }
+        return redisTemplate.opsForValue().increment(key, -delta);
+    }
+
+    // ================================Map=================================
+
+    /**
+     * @Description: HashGet
+     * @Param: [key:键(不能为null), item:项(不能为null)]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:43
+     */
+    public Object hGet(String key, String item) {
+        return redisTemplate.opsForHash().get(key, item);
+    }
+
+    /**
+     * @Description: 获取hashKey对应的所有键值
+     * @Param: [key:键]
+     * @Return 对应的多个键值
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:44
+     */
+    public Map<Object, Object> hmGet(String key) {
+        return redisTemplate.opsForHash().entries(key);
+    }
+
+    /**
+     * @Description: HashSet
+     * @Param: [key, map]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:47
+     */
+    public boolean hmSet(String key, Map<String, Object> map) {
+        try {
+            redisTemplate.opsForHash().putAll(key, map);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * @Description: HashSet,并设置失效时间
+     * @Param: [key, map, time:失效时间(秒)]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:48
+     */
+    public boolean hmSet(String key, Map<String, Object> map, long time) {
+        try {
+            redisTemplate.opsForHash().putAll(key, map);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * @Description: 向一张hash表中放入数据, 如果不存在将创建
+     * @Param: [key:键, item:项, value:值]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:49
+     */
+    public boolean hSet(String key, String item, Object value) {
+        try {
+            redisTemplate.opsForHash().put(key, item, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * @Description: 向一张hash表中放入数据, 如果不存在将创建,并设置失效时间。
+     * 如果已存在的hash表有失效时间,这里将会替换原有的时间
+     * @Param: [key, item, value, time:失效时间(秒)]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:50
+     */
+    public boolean hSet(String key, String item, Object value, long time) {
+        try {
+            redisTemplate.opsForHash().put(key, item, value);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * @Description: 删除hash表中的值
+     * @Param: [key:键, item:项(一个或多个,不能为null)]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:51
+     */
+    public void hDel(String key, Object... item) {
+        redisTemplate.opsForHash().delete(key, item);
+    }
+
+    /**
+     * @Description: 判断hash表中是否有该项的值
+     * @Param: [key:键, item:项]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:52
+     */
+    public boolean hHasKey(String key, String item) {
+        return redisTemplate.opsForHash().hasKey(key, item);
+    }
+
+    /**
+     * @Description: hash递增
+     * 如果不存在,就会创建一个 并把新增后的值返回
+     * @Param: [key:键, item:项, by:要增加几(大于0)]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:52
+     */
+    public double hIncr(String key, String item, double by) {
+        return redisTemplate.opsForHash().increment(key, item, by);
+    }
+
+    /**
+     * @Description: hash递减
+     * 如果不存在,就会创建一个 并把新增后的值返回
+     * @Param: [key:键, item:项, by:要减少记(小于0)]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:53
+     */
+    public double hDecr(String key, String item, double by) {
+        return redisTemplate.opsForHash().increment(key, item, -by);
+    }
+
+
+    // ============================set=============================
+
+    /**
+     * @Description: 根据key获取Set中的所有值
+     * @Param: [key]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:54
+     */
+    public Set<Object> sGet(String key) {
+        try {
+            return redisTemplate.opsForSet().members(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * @Description: 根据value从一个set中查询, 是否存在
+     * @Param: [key, value]
+     * @Author: shiwn
+     * @Date: 2021/5/11 11:55
+     */
+    public boolean sHasKey(String key, Object value) {
+        try {
+            return redisTemplate.opsForSet().isMember(key, value);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * @Description: 将数据放入set缓存
+     * @Param: [key, values:值(一个或多个)]
+     * @Author: shiwn
+     * @Date: 2021/5/11 14:21
+     */
+    public long sSet(String key, Object... values) {
+        try {
+            return redisTemplate.opsForSet().add(key, values);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * @Description: 将set数据放入缓存,并设置失效时间
+     * @Param: [key, time:失效时间(秒), values:值(一个或多个)]
+     * @Author: shiwn
+     * @Date: 2021/5/11 14:21
+     */
+    public long sSet(String key, long time, Object... values) {
+        try {
+            Long count = redisTemplate.opsForSet().add(key, values);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return count;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * @Description: 获取set缓存的长度
+     * @Param: [key]
+     * @Author: shiwn
+     * @Date: 2021/5/11 14:22
+     */
+    public long sGetSize(String key) {
+        try {
+            return redisTemplate.opsForSet().size(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * @Description: 移除值为value的
+     * @Param: [key, values:值(一个或多个)]
+     * @Return 移除的个数
+     * @Author: shiwn
+     * @Date: 2021/5/11 14:23
+     */
+    public long sRemove(String key, Object... values) {
+        try {
+            Long count = redisTemplate.opsForSet().remove(key, values);
+            return count;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+
+    // ===============================list=================================
+
+    /**
+     * @Description: 将list放入缓存
+     * @Param: [key, value]
+     * @Author: shiwn
+     * @Date: 2021/5/11 14:26
+     */
+    public boolean lSet(String key, Object value) {
+        try {
+            redisTemplate.opsForList().rightPush(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * @Description: 将list放入缓存
+     * @Param: [key, value]
+     * @Author: shiwn
+     * @Date: 2021/5/11 14:27
+     */
+    public boolean lSet(String key, List<Object> value) {
+        try {
+            redisTemplate.opsForList().rightPushAll(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * @Description: 将list放入缓存,并设置失效时间
+     * @Param: [key, value, time:失效时间(秒)]
+     * @Author: shiwn
+     * @Date: 2021/5/11 14:27
+     */
+    public boolean lSet(String key, Object value, long time) {
+        try {
+            redisTemplate.opsForList().rightPush(key, value);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * @Description: 将list放入缓存,并设置失效时间
+     * @Param: [key, value, time:失效时间(秒]
+     * @Author: shiwn
+     * @Date: 2021/5/11 14:28
+     */
+    public boolean lSet(String key, List<Object> value, long time) {
+        try {
+            redisTemplate.opsForList().rightPushAll(key, value);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * @Description: 获取list缓存的内容
+     * start:0,end:-1代表所有值
+     * @Param: [key, start:开始索引, end:结束索引]
+     * @Author: shiwn
+     * @Date: 2021/5/11 14:24
+     */
+    public List<Object> lGet(String key, long start, long end) {
+        try {
+            return redisTemplate.opsForList().range(key, start, end);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    public List<? extends Object> lGet(String key) {
+        try {
+            return redisTemplate.opsForList().range(key, 0, -1);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * @Description: 获取list缓存的长度
+     * @Param: [key]
+     * @Author: shiwn
+     * @Date: 2021/5/11 14:25
+     */
+    public long lGetSize(String key) {
+        try {
+            return redisTemplate.opsForList().size(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * @Description: 通过索引 获取list中的值
+     * @Param: [key, index:索引(index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推)]
+     * @Author: shiwn
+     * @Date: 2021/5/11 14:25
+     */
+    public Object lGetIndex(String key, long index) {
+        try {
+            return redisTemplate.opsForList().index(key, index);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * @Description: 根据索引修改list中的某条数据
+     * @Param: [key, index:索引, value]
+     * @Author: shiwn
+     * @Date: 2021/5/11 14:29
+     */
+    public boolean lUpdateIndex(String key, long index, Object value) {
+        try {
+            redisTemplate.opsForList().set(key, index, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * @Description: 移除N个值为value的缓存
+     * @Param: [key, count:移除数量, value]
+     * @Return 移除的个数
+     * @Author: shiwn
+     * @Date: 2021/5/11 14:29
+     */
+    public long lRemove(String key, long count, Object value) {
+        try {
+            Long remove = redisTemplate.opsForList().remove(key, count, value);
+            return remove;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+}

+ 81 - 0
code/robot2ips/src/main/java/com/sunwin/robot2ips/util/TimeUtil.java

@@ -0,0 +1,81 @@
+package com.sunwin.robot2ips.util;
+
+import java.sql.Time;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * @Description: Time工具类
+ * @Author: shiwn
+ * @Date: 2020/1/16 11:07
+ */
+public class TimeUtil {
+    /**
+     * @Description: 获取格式化后的Time
+     * @Param: [hour:小时, minute:分钟]
+     * @Author: shiwn
+     * @Date: 2020/1/16 11:09
+     */
+    public static Time getFormatTime(String hour, String minute) {
+        try {
+            String time = hour + ":" + minute + ":00";
+            Date date;
+            DateFormat sdf = new SimpleDateFormat("HH:mm:ss");
+            date = sdf.parse(time);
+            return new Time(date.getTime());
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /**
+     * @Description: 获取时间差(分钟)
+     * @Param: [startTime:开始时间, endTime:结束时间]
+     * @Author: shiwn
+     * @Date: 2020/3/2 13:52
+     */
+    public static int getDiffTime(Date startTime, Date endTime) {
+        long start = startTime.getTime();
+        long end = endTime.getTime();
+        //  判断是否有余数,自动补1分钟
+        return (end - start) % (1000 * 60) == 0 ? (int) ((end - start) / (1000 * 60)) : (int) ((end - start) / (1000 * 60) + 1);
+    }
+
+    /**
+     * @Description: 根据时间戳获取前 n 天的开始时间戳,例起始时间为:2020-12-01 00:00:00
+     * @Param: [timestamp, day]
+     * @Author: shiwn
+     * @Date: 2020/12/7 10:01
+     */
+    public static Long getStartTimestamp(Long timestamp, Integer day) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTimeInMillis(timestamp);
+        day = 0 - day;
+        calendar.add(Calendar.DATE, day);
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        return calendar.getTimeInMillis();
+    }
+
+    /**
+     * @Description: 根据时间戳获取前 n 天的结束时间戳,例起始时间为:2020-12-01 00:00:00
+     * @Param: [timestamp, day]
+     * @Author: shiwn
+     * @Date: 2020/12/7 10:15
+     */
+    public static Long getEndTimestamp(Long timestamp, Integer day) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTimeInMillis(timestamp);
+        day = 0 - day;
+        calendar.add(Calendar.DATE, day);
+        calendar.set(Calendar.HOUR_OF_DAY, 23);
+        calendar.set(Calendar.MINUTE, 59);
+        calendar.set(Calendar.SECOND, 59);
+        calendar.set(Calendar.MILLISECOND, 999);
+        return calendar.getTimeInMillis();
+    }
+}

+ 54 - 0
code/robot2ips/src/main/resources/application-prod.properties

@@ -0,0 +1,54 @@
+### 数据库配置信息
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+spring.datasource.url=jdbc:mysql://127.0.0.1:3306/robot_cloud_db.v4_new?serverTimezone=GMT%2B8&characterSetResults=UTF-8&characterEncoding=UTF-8&useUnicode=yes&useSSL=false
+spring.datasource.username=root
+spring.datasource.password=pass123
+spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
+#连接池的配置信息
+# 初始化大小,最小,最大
+spring.datasource.initialSize=5
+spring.datasource.minIdle=5
+spring.datasource.maxActive=20
+# 配置获取连接等待超时的时间
+spring.datasource.maxWait=60000
+# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+spring.datasource.timeBetweenEvictionRunsMillis=60000
+# 配置一个连接在池中最小生存的时间,单位是毫秒watchband execute error msg
+spring.datasource.minEvictableIdleTimeMillis=300000
+# 配置自动检测一些连接是否有效
+spring.datasource.validationQuery=SELECT 1 FROM DUAL
+spring.datasource.testWhileIdle=true
+spring.datasource.testOnBorrow=false
+spring.datasource.testOnReturn=false
+# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙(不推荐加上)
+spring.datasource.filters=stat,log4j
+# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
+#spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
+# 合并多个DruidDataSource的监控数据
+spring.datasource.useGlobalDataSourceStat=true
+############# 配置redis ###############
+#Redis
+# 连接的数据库(默认为0)
+spring.redis.database=0
+# redis服务ip
+spring.redis.host=127.0.0.1
+# redis端口号
+spring.redis.port=6379
+# redis密码
+spring.redis.password=sunwin@2021
+# 连接池最大连接数(使用负值表示没有限制)
+#spring.redis.pool.max-active=8
+# 连接池最大阻塞等待时间(使用负值表示没有限制)
+#spring.redis.pool.max-wait=-1
+# 连接池中的最大空闲连接
+#spring.redis.pool.max-idle=8
+# 连接池中的最小空闲连接
+#spring.redis.pool.min-idle=0
+# 连接超时时间(毫秒)
+spring.redis.timeout=2000
+
+############# 配置FTP信息(windows)#####
+ftp.host=127.0.0.1
+ftp.account=ftpadmin
+ftp.password=ftp@sunwin2021
+ftp.port=21

+ 54 - 0
code/robot2ips/src/main/resources/application-test.properties

@@ -0,0 +1,54 @@
+### 数据库配置信息
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+spring.datasource.url=jdbc:mysql://192.168.1.88:3306/robot_cloud_db.v4_new?serverTimezone=GMT%2B8&characterSetResults=UTF-8&characterEncoding=UTF-8&useUnicode=yes&useSSL=false
+spring.datasource.username=root
+spring.datasource.password=Sunwin@123.com
+spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
+#连接池的配置信息
+# 初始化大小,最小,最大
+spring.datasource.initialSize=5
+spring.datasource.minIdle=5
+spring.datasource.maxActive=20
+# 配置获取连接等待超时的时间
+spring.datasource.maxWait=60000
+# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+spring.datasource.timeBetweenEvictionRunsMillis=60000
+# 配置一个连接在池中最小生存的时间,单位是毫秒
+spring.datasource.minEvictableIdleTimeMillis=300000
+# 配置自动检测一些连接是否有效
+spring.datasource.validationQuery=SELECT 1 FROM DUAL
+spring.datasource.testWhileIdle=true
+spring.datasource.testOnBorrow=false
+spring.datasource.testOnReturn=false
+# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙(不推荐加上)
+spring.datasource.filters=stat,log4j
+# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
+#spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
+# 合并多个DruidDataSource的监控数据
+spring.datasource.useGlobalDataSourceStat=true
+############# 配置redis ###############
+#Redis
+# 连接的数据库(默认为0)
+spring.redis.database=0
+# redis服务ip
+spring.redis.host=127.0.0.1
+# redis端口号
+spring.redis.port=6379
+# redis密码
+spring.redis.password=sunwin@2021
+# 连接池最大连接数(使用负值表示没有限制)
+#spring.redis.pool.max-active=8
+# 连接池最大阻塞等待时间(使用负值表示没有限制)
+#spring.redis.pool.max-wait=-1
+# 连接池中的最大空闲连接
+#spring.redis.pool.max-idle=8
+# 连接池中的最小空闲连接
+#spring.redis.pool.min-idle=0
+# 连接超时时间(毫秒)
+spring.redis.timeout=2000
+
+############# 配置FTP信息(windows)#####
+ftp.host=192.168.1.144
+ftp.account=ftpadmin
+ftp.password=ftp@sunwin2021
+ftp.port=21

+ 51 - 0
code/robot2ips/src/main/resources/application.properties

@@ -0,0 +1,51 @@
+# 配置项目信息
+server.servlet.context-path=/
+server.port=8089
+# 获取pom文件中project.version值
+version=@project.version@
+# 配置数据源
+spring.profiles.active=test
+# 配置时区
+spring.jackson.time-zone=GMT+8
+# 配置文件请求大小设置
+spring.servlet.multipart.max-file-size=50MB
+spring.servlet.multipart.max-request-size=50MB
+# page helper分页插件配置
+pagehelper.helperDialect=mysql
+pagehelper.reasonable=true
+pagehelper.supportMethodsArguments=true
+pagehelper.params=count=countSql
+# 配置日志
+logging.level.com.sw=debug
+logging.file.path=./logs/pmp
+# ***解决swagger2.9.2版本“@ApiModelProperty”注解“example”属性不填时的报错问题
+logging.level.io.swagger.models.parameters.AbstractSerializableParameter:error
+# 配置请求信息
+spring.session.timeout=0
+server.max-http-header-size=1024000
+# thymeleaf的基本配置
+spring.thymeleaf.encoding=UTF-8
+spring.thymeleaf.cache=false
+spring.thymeleaf.mode=HTML
+spring.thymeleaf.servlet.content-type=text/html
+spring.thymeleaf.prefix=classpath:/view/
+spring.thymeleaf.suffix=.html
+############# 配置mybatis #############
+# 驼峰转换
+mybatis-plus.configuration.map-underscore-to-camel-case=true
+# 实体类地址
+mybatis-plus.typeAliasesPackage=com.sunwin.robot2ips.beans.dto
+# xml文件地址
+mybatis-plus.mapper-locations=classpath:/mapper/*.xml
+# 接收null字段
+mybatis-plus.configuration.call-setters-on-nulls=true
+# 删除值
+mybatis-plus.global-config.db-config.logic-delete-value=1
+mybatis-plus.global-config.db-config.logic-not-delete-value=0
+#服务器设备号(localhost)
+com.sunwin.server.id=421aa9eF7F9fa326b6494f812ad13e79
+#IPS提供机器人传输巡检结果接口地址
+ips.connect.url=http://localhost:10006/api/IpsRecord/RobotRecordsResult
+ips.point.fileName=IPS监测点清单.xls
+ips.query.count=30
+

+ 53 - 0
code/robot2ips/src/main/resources/mapper/UploadMapper.xml

@@ -0,0 +1,53 @@
+<?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.sunwin.robot2ips.dao.UploadMapper">
+    <insert id="insertBindLink">
+        insert into ips_sw_point_link (monitoring_point,point_id) VALUES
+        <foreach collection="list" item="item" separator=",">
+            (
+            #{item.monitoringPoint},
+            #{item.pointId}
+            )
+        </foreach>
+        ON DUPLICATE key update
+        point_id = values(point_id)
+    </insert>
+
+
+    <select id="queryDataByDate" resultType="com.sunwin.robot2ips.beans.vo.RecordTaskPoint">
+        select
+        c.id result_id,
+        c.point_name remark,
+        c.result result_value,
+        1 data_source,
+        ips.monitoring_point point_code,
+        c.time update_time,
+        c.robot_id
+        from ips_sw_point_link ips
+        left join check_data c on ips.point_id= c.point_id
+        where
+            c.time BETWEEN #{startDate} and #{endDate}
+    </select>
+    <select id="selectRobots" resultType="com.sunwin.robot2ips.beans.dto.RobotDTO">
+        select * from robot
+    </select>
+    <select id="queryDataAfterId" resultType="com.sunwin.robot2ips.beans.vo.RecordTaskPoint">
+        select
+        c.id result_id,
+        c.point_name remark,
+        c.result result_value,
+        1 data_source,
+        ips.monitoring_point point_code,
+        c.time update_time,
+        c.robot_id
+        from ips_sw_point_link ips
+        left join  check_data c on ips.point_id= c.point_id
+        where
+        1=1
+        <if test="lastDataId!=null">
+           and  c.id <![CDATA[ > ]]> #{lastDataId}
+        </if>
+        order by c.id desc
+        limit #{count}
+    </select>
+</mapper>

+ 13 - 0
code/robot2ips/src/test/java/com/sunwin/robot2ips/Robot2ipsApplicationTests.java

@@ -0,0 +1,13 @@
+package com.sunwin.robot2ips;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class Robot2ipsApplicationTests {
+
+    @Test
+    void contextLoads() {
+    }
+
+}