Browse Source

1.项目生成

xuzip 2 months ago
commit
9537f3fdf6
69 changed files with 301525 additions and 0 deletions
  1. 2 0
      .gitattributes
  2. 33 0
      .gitignore
  3. 19 0
      .mvn/wrapper/maven-wrapper.properties
  4. 124 0
      logs/dotMatrix.2024-11-23.log
  5. 372 0
      logs/dotMatrix.2024-11-25.log
  6. 259 0
      mvnw
  7. 149 0
      mvnw.cmd
  8. 84 0
      pom.xml
  9. 13 0
      src/main/java/com/yeechart/dotMatrix/DotMatrixApplication.java
  10. 593 0
      src/main/java/com/yeechart/dotMatrix/canvas/DotMatrixCanvasUtil.java
  11. 132 0
      src/main/java/com/yeechart/dotMatrix/canvas/DotMatrixConversionUtil.java
  12. 390 0
      src/main/java/com/yeechart/dotMatrix/canvas/DotMatrixDrawShapeUtil.java
  13. 397 0
      src/main/java/com/yeechart/dotMatrix/canvas/DotMatrixDrawtextUtil.java
  14. 324 0
      src/main/java/com/yeechart/dotMatrix/canvas/DotMatrixImageUtil.java
  15. 64 0
      src/main/java/com/yeechart/dotMatrix/crc/CustomCRC32Util.java
  16. 363 0
      src/main/java/com/yeechart/dotMatrix/font/XZPFontLoaderUtil.java
  17. 29 0
      src/main/java/com/yeechart/dotMatrix/font/bean/FontObject.java
  18. 863 0
      src/main/java/com/yeechart/dotMatrix/minilzo/MiniLZO.java
  19. 93 0
      src/main/java/com/yeechart/dotMatrix/minilzo/MiniLZOUtil.java
  20. 49 0
      src/main/java/com/yeechart/dotMatrix/minilzo/bean/LZOConstants.java
  21. 30 0
      src/main/java/com/yeechart/dotMatrix/minilzo/bean/MInt.java
  22. 213 0
      src/main/java/com/yeechart/dotMatrix/module/DotMatrix/controller/DotMatrixController.java
  23. 67 0
      src/main/java/com/yeechart/dotMatrix/module/DotMatrix/model/bean/CodeEnum.java
  24. 70 0
      src/main/java/com/yeechart/dotMatrix/module/DotMatrix/model/bean/ResultBean.java
  25. 26 0
      src/main/java/com/yeechart/dotMatrix/module/DotMatrix/service/DotMatrixService.java
  26. 44 0
      src/main/java/com/yeechart/dotMatrix/module/DotMatrix/service/impl/DotMatrixServiceImpl.java
  27. 221 0
      src/main/java/com/yeechart/dotMatrix/oss/LatticeOSSUpload.java
  28. 26 0
      src/main/java/com/yeechart/dotMatrix/oss/OSSRetryTask.java
  29. 318 0
      src/main/java/com/yeechart/dotMatrix/oss/OSSUpload.java
  30. 1164 0
      src/main/java/com/yeechart/dotMatrix/signage/SignageDrawLeftUtil.java
  31. 1859 0
      src/main/java/com/yeechart/dotMatrix/signage/SignageDrawRightUtil.java
  32. 1446 0
      src/main/java/com/yeechart/dotMatrix/signage/SignageDrawUtil.java
  33. 277 0
      src/main/java/com/yeechart/dotMatrix/signage/SignageFileUtil.java
  34. 303 0
      src/main/java/com/yeechart/dotMatrix/signage/SignageQualityUtil.java
  35. 226 0
      src/main/java/com/yeechart/dotMatrix/signage/TypeCodeUtil.java
  36. 39 0
      src/main/java/com/yeechart/dotMatrix/signage/bean/BitmapArraysVo.java
  37. 213 0
      src/main/java/com/yeechart/dotMatrix/signage/bean/SheetCheckVo.java
  38. 66 0
      src/main/java/com/yeechart/dotMatrix/signage/bean/SheetPVo.java
  39. 166 0
      src/main/java/com/yeechart/dotMatrix/signage/bean/Ter020201DriverBean.java
  40. 718 0
      src/main/java/com/yeechart/dotMatrix/signage/bean/Ter020201InfoVo.java
  41. 32 0
      src/main/java/com/yeechart/dotMatrix/signage/bean/Ter020201Vo.java
  42. 81 0
      src/main/java/com/yeechart/dotMatrix/signage/bean/TiClockBean.java
  43. 87 0
      src/main/java/com/yeechart/dotMatrix/signage/bean/TiOnusBean.java
  44. 48 0
      src/main/java/com/yeechart/dotMatrix/signage/bean/mizilzo/BitmapDataVo.java
  45. 27 0
      src/main/java/com/yeechart/dotMatrix/signage/bean/mizilzo/MiniLZOVo.java
  46. 79 0
      src/main/java/com/yeechart/dotMatrix/thread/RetryService.java
  47. 66 0
      src/main/java/com/yeechart/dotMatrix/thread/ThreadPoolTaskExecutorConfig.java
  48. 61 0
      src/main/java/com/yeechart/dotMatrix/util/OtherUtil.java
  49. 8 0
      src/main/resources/application.yml
  50. 289144 0
      src/main/resources/fonts/font_2024_03_15.DAT
  51. BIN
      src/main/resources/image/device/020201/Wi-Fi配网.png
  52. BIN
      src/main/resources/image/device/020201/init_left_default.png
  53. BIN
      src/main/resources/image/device/020201/init_right_default.jpg
  54. BIN
      src/main/resources/image/device/020201/init_right_default_20240601.jpg
  55. BIN
      src/main/resources/image/device/020201/left_state_0.png
  56. BIN
      src/main/resources/image/device/020201/left_state_1.png
  57. BIN
      src/main/resources/image/device/020201/left_state_2.png
  58. BIN
      src/main/resources/image/device/020201/left_state_254.png
  59. BIN
      src/main/resources/image/device/020201/left_state_3.png
  60. BIN
      src/main/resources/image/device/020201/left_state_4.png
  61. BIN
      src/main/resources/image/device/020201/left_state_5.png
  62. BIN
      src/main/resources/image/device/020201/nfc.png
  63. BIN
      src/main/resources/image/device/020201/nfc2.png
  64. BIN
      src/main/resources/image/device/020201/声音减.png
  65. BIN
      src/main/resources/image/device/020201/声音加.png
  66. BIN
      src/main/resources/image/device/020201/开关.png
  67. BIN
      src/main/resources/image/device/020201/语音.png
  68. 35 0
      src/main/resources/logback.xml
  69. 13 0
      src/test/java/com/yeechart/dotMatrix/DotMatrixApplicationTests.java

+ 2 - 0
.gitattributes

@@ -0,0 +1,2 @@
+/mvnw text eol=lf
+*.cmd text eol=crlf

+ 33 - 0
.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/

+ 19 - 0
.mvn/wrapper/maven-wrapper.properties

@@ -0,0 +1,19 @@
+# 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
+#
+#   http://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.
+wrapperVersion=3.3.2
+distributionType=only-script
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip

+ 124 - 0
logs/dotMatrix.2024-11-23.log

@@ -0,0 +1,124 @@
+2024-11-23 09:45:21.828 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Starting DotMatrixApplication on YiChao-XZP with PID 32448 (D:\WorkSpace\Java\DotMatrix2\DotMatrix\target\classes started by xuzip in D:\WorkSpace\Java\DotMatrix2\DotMatrix)
+2024-11-23 09:45:21.829 [main] DEBUG c.y.dotMatrix.DotMatrixApplication - Running with Spring Boot v2.3.3.RELEASE, Spring v5.2.8.RELEASE
+2024-11-23 09:45:21.829 [main] INFO  c.y.dotMatrix.DotMatrixApplication - No active profile set, falling back to default profiles: default
+2024-11-23 09:45:22.234 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 1111 (http)
+2024-11-23 09:45:22.238 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-1111"]
+2024-11-23 09:45:22.240 [main] INFO  o.a.catalina.core.StandardService - Starting service [Tomcat]
+2024-11-23 09:45:22.240 [main] INFO  o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.37]
+2024-11-23 09:45:22.279 [main] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
+2024-11-23 09:45:22.279 [main] INFO  o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 427 ms
+2024-11-23 09:45:22.353 [main] INFO  o.s.s.c.ThreadPoolTaskExecutor - Initializing ExecutorService 'applicationTaskExecutor'
+2024-11-23 09:45:22.433 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-1111"]
+2024-11-23 09:45:22.444 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 1111 (http) with context path ''
+2024-11-23 09:45:22.449 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Started DotMatrixApplication in 0.819 seconds (JVM running for 1.666)
+2024-11-23 10:52:50.878 [SpringContextShutdownHook] INFO  o.s.s.c.ThreadPoolTaskExecutor - Shutting down ExecutorService 'applicationTaskExecutor'
+2024-11-23 10:52:55.625 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Starting DotMatrixApplication on YiChao-XZP with PID 22140 (D:\WorkSpace\Java\DotMatrix2\DotMatrix\target\classes started by xuzip in D:\WorkSpace\Java\DotMatrix2\DotMatrix)
+2024-11-23 10:52:55.627 [main] DEBUG c.y.dotMatrix.DotMatrixApplication - Running with Spring Boot v2.3.3.RELEASE, Spring v5.2.8.RELEASE
+2024-11-23 10:52:55.628 [main] INFO  c.y.dotMatrix.DotMatrixApplication - No active profile set, falling back to default profiles: default
+2024-11-23 10:52:56.032 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 1111 (http)
+2024-11-23 10:52:56.036 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-1111"]
+2024-11-23 10:52:56.036 [main] INFO  o.a.catalina.core.StandardService - Starting service [Tomcat]
+2024-11-23 10:52:56.036 [main] INFO  o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.37]
+2024-11-23 10:52:56.073 [main] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
+2024-11-23 10:52:56.073 [main] INFO  o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 421 ms
+2024-11-23 10:52:56.148 [main] INFO  o.s.s.c.ThreadPoolTaskExecutor - Initializing ExecutorService 'applicationTaskExecutor'
+2024-11-23 10:52:56.237 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-1111"]
+2024-11-23 10:52:56.250 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 1111 (http) with context path ''
+2024-11-23 10:52:56.256 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Started DotMatrixApplication in 0.826 seconds (JVM running for 1.402)
+2024-11-23 14:19:01.824 [SpringContextShutdownHook] INFO  o.s.s.c.ThreadPoolTaskExecutor - Shutting down ExecutorService 'applicationTaskExecutor'
+2024-11-23 14:19:06.366 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Starting DotMatrixApplication on YiChao-XZP with PID 38140 (D:\WorkSpace\Java\DotMatrix2\DotMatrix\target\classes started by xuzip in D:\WorkSpace\Java\DotMatrix2\DotMatrix)
+2024-11-23 14:19:06.368 [main] DEBUG c.y.dotMatrix.DotMatrixApplication - Running with Spring Boot v2.3.3.RELEASE, Spring v5.2.8.RELEASE
+2024-11-23 14:19:06.368 [main] INFO  c.y.dotMatrix.DotMatrixApplication - No active profile set, falling back to default profiles: default
+2024-11-23 14:19:06.747 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 1111 (http)
+2024-11-23 14:19:06.751 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-1111"]
+2024-11-23 14:19:06.751 [main] INFO  o.a.catalina.core.StandardService - Starting service [Tomcat]
+2024-11-23 14:19:06.751 [main] INFO  o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.37]
+2024-11-23 14:19:06.790 [main] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
+2024-11-23 14:19:06.790 [main] INFO  o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 392 ms
+2024-11-23 14:19:06.892 [main] INFO  o.s.s.c.ThreadPoolTaskExecutor - Initializing ExecutorService 'applicationTaskExecutor'
+2024-11-23 14:19:07.037 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-1111"]
+2024-11-23 14:19:07.052 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 1111 (http) with context path ''
+2024-11-23 14:19:07.060 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Started DotMatrixApplication in 0.876 seconds (JVM running for 1.43)
+2024-11-23 14:19:22.764 [http-nio-1111-exec-1] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
+2024-11-23 14:19:22.766 [http-nio-1111-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
+2024-11-23 14:19:22.770 [http-nio-1111-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Completed initialization in 4 ms
+2024-11-23 14:19:25.144 [pool-2-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.144 [pool-2-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.144 [pool-2-thread-7] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.144 [pool-2-thread-6] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.144 [pool-2-thread-8] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.146 [pool-2-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.146 [pool-2-thread-2] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.146 [pool-2-thread-4] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.146 [pool-2-thread-3] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.146 [pool-2-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.146 [pool-2-thread-10] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.147 [pool-2-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.147 [pool-2-thread-10] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.147 [pool-2-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.147 [pool-2-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.147 [pool-2-thread-8] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.147 [pool-2-thread-10] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.147 [pool-2-thread-6] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.148 [pool-2-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.148 [pool-2-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.148 [pool-2-thread-7] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.148 [pool-2-thread-3] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.148 [pool-2-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.148 [pool-2-thread-4] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.148 [pool-2-thread-2] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.148 [pool-2-thread-8] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.148 [pool-2-thread-10] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.148 [pool-2-thread-6] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.149 [pool-2-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.149 [pool-2-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.149 [pool-2-thread-7] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.149 [pool-2-thread-3] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.149 [pool-2-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.149 [pool-2-thread-4] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.149 [pool-2-thread-2] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.149 [pool-2-thread-8] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.149 [pool-2-thread-10] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.149 [pool-2-thread-6] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.149 [pool-2-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.150 [pool-2-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.150 [pool-2-thread-7] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.150 [pool-2-thread-3] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.150 [pool-2-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.150 [pool-2-thread-4] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.150 [pool-2-thread-2] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.150 [pool-2-thread-8] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.150 [pool-2-thread-10] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.150 [pool-2-thread-6] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.150 [pool-2-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.151 [pool-2-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.151 [pool-2-thread-7] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.151 [pool-2-thread-3] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.151 [pool-2-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.151 [pool-2-thread-4] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.151 [pool-2-thread-2] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.151 [pool-2-thread-8] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.151 [pool-2-thread-10] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.151 [pool-2-thread-6] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.151 [pool-2-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.151 [pool-2-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.151 [pool-2-thread-7] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.151 [pool-2-thread-3] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.151 [pool-2-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.151 [pool-2-thread-4] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.151 [pool-2-thread-2] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.259 [pool-3-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.261 [pool-3-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.273 [pool-3-thread-6] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.289 [pool-3-thread-10] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.289 [pool-3-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.305 [pool-3-thread-4] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.321 [pool-3-thread-3] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.321 [pool-3-thread-2] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.337 [pool-3-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.337 [pool-3-thread-7] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.353 [pool-3-thread-8] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.353 [pool-3-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.353 [pool-3-thread-6] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.385 [pool-3-thread-10] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-23 14:19:25.385 [pool-3-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null

+ 372 - 0
logs/dotMatrix.2024-11-25.log

@@ -0,0 +1,372 @@
+2024-11-25 10:31:36.310 [SpringContextShutdownHook] INFO  o.s.s.c.ThreadPoolTaskExecutor - Shutting down ExecutorService 'applicationTaskExecutor'
+2024-11-25 10:31:43.644 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Starting DotMatrixApplication on YiChao-XZP with PID 43108 (D:\WorkSpace\Java\DotMatrix2\DotMatrix\target\classes started by xuzip in D:\WorkSpace\Java\DotMatrix2\DotMatrix)
+2024-11-25 10:31:43.654 [main] DEBUG c.y.dotMatrix.DotMatrixApplication - Running with Spring Boot v2.3.3.RELEASE, Spring v5.2.8.RELEASE
+2024-11-25 10:31:43.654 [main] INFO  c.y.dotMatrix.DotMatrixApplication - No active profile set, falling back to default profiles: default
+2024-11-25 10:31:44.357 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 1111 (http)
+2024-11-25 10:31:44.362 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-1111"]
+2024-11-25 10:31:44.363 [main] INFO  o.a.catalina.core.StandardService - Starting service [Tomcat]
+2024-11-25 10:31:44.363 [main] INFO  o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.37]
+2024-11-25 10:31:44.461 [main] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
+2024-11-25 10:31:44.461 [main] INFO  o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 783 ms
+2024-11-25 10:31:44.532 [main] INFO  o.s.s.c.ThreadPoolTaskExecutor - Initializing ExecutorService 'applicationTaskExecutor'
+2024-11-25 10:31:44.615 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-1111"]
+2024-11-25 10:31:44.625 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 1111 (http) with context path ''
+2024-11-25 10:31:44.631 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Started DotMatrixApplication in 1.238 seconds (JVM running for 2.086)
+2024-11-25 10:31:49.963 [http-nio-1111-exec-1] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
+2024-11-25 10:31:49.964 [http-nio-1111-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
+2024-11-25 10:31:49.966 [http-nio-1111-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Completed initialization in 2 ms
+2024-11-25 10:33:52.594 [SpringContextShutdownHook] INFO  o.s.s.c.ThreadPoolTaskExecutor - Shutting down ExecutorService 'applicationTaskExecutor'
+2024-11-25 10:33:56.141 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Starting DotMatrixApplication on YiChao-XZP with PID 27532 (D:\WorkSpace\Java\DotMatrix2\DotMatrix\target\classes started by xuzip in D:\WorkSpace\Java\DotMatrix2\DotMatrix)
+2024-11-25 10:33:56.142 [main] DEBUG c.y.dotMatrix.DotMatrixApplication - Running with Spring Boot v2.3.3.RELEASE, Spring v5.2.8.RELEASE
+2024-11-25 10:33:56.142 [main] INFO  c.y.dotMatrix.DotMatrixApplication - No active profile set, falling back to default profiles: default
+2024-11-25 10:33:56.470 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 1111 (http)
+2024-11-25 10:33:56.474 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-1111"]
+2024-11-25 10:33:56.474 [main] INFO  o.a.catalina.core.StandardService - Starting service [Tomcat]
+2024-11-25 10:33:56.474 [main] INFO  o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.37]
+2024-11-25 10:33:56.515 [main] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
+2024-11-25 10:33:56.516 [main] INFO  o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 355 ms
+2024-11-25 10:33:56.646 [main] INFO  o.s.s.c.ThreadPoolTaskExecutor - Initializing ExecutorService 'applicationTaskExecutor'
+2024-11-25 10:33:56.732 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-1111"]
+2024-11-25 10:33:56.743 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 1111 (http) with context path ''
+2024-11-25 10:33:56.748 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Started DotMatrixApplication in 0.754 seconds (JVM running for 1.237)
+2024-11-25 10:34:16.420 [http-nio-1111-exec-1] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
+2024-11-25 10:34:16.422 [http-nio-1111-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
+2024-11-25 10:34:16.426 [http-nio-1111-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Completed initialization in 4 ms
+2024-11-25 10:34:18.376 [pool-2-thread-7] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.376 [pool-2-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.376 [pool-2-thread-8] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.376 [pool-2-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.376 [pool-2-thread-10] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.377 [pool-2-thread-4] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.377 [pool-2-thread-3] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.377 [pool-2-thread-2] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.377 [pool-2-thread-6] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.377 [pool-2-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.377 [pool-2-thread-7] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.377 [pool-2-thread-8] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.377 [pool-2-thread-3] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.377 [pool-2-thread-8] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.378 [pool-2-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.378 [pool-2-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.378 [pool-2-thread-4] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.378 [pool-2-thread-10] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.378 [pool-2-thread-4] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.378 [pool-2-thread-3] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.378 [pool-2-thread-8] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.378 [pool-2-thread-7] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.378 [pool-2-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.378 [pool-2-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.378 [pool-2-thread-6] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.378 [pool-2-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.378 [pool-2-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.378 [pool-2-thread-6] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.378 [pool-2-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.378 [pool-2-thread-2] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.379 [pool-2-thread-10] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.379 [pool-2-thread-4] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.379 [pool-2-thread-3] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.379 [pool-2-thread-8] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.379 [pool-2-thread-7] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.379 [pool-2-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.379 [pool-2-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.379 [pool-2-thread-6] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.379 [pool-2-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.380 [pool-2-thread-2] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.380 [pool-2-thread-10] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.380 [pool-2-thread-4] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.380 [pool-2-thread-3] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.380 [pool-2-thread-8] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.380 [pool-2-thread-7] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.380 [pool-2-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.380 [pool-2-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.380 [pool-2-thread-6] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.380 [pool-2-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.380 [pool-2-thread-2] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.380 [pool-2-thread-10] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.381 [pool-2-thread-4] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.381 [pool-2-thread-3] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.381 [pool-2-thread-8] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.381 [pool-2-thread-7] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.381 [pool-2-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.381 [pool-2-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.381 [pool-2-thread-6] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.381 [pool-2-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.381 [pool-2-thread-2] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.381 [pool-2-thread-10] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.381 [pool-2-thread-4] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.381 [pool-2-thread-3] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.382 [pool-2-thread-8] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.382 [pool-2-thread-7] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.382 [pool-2-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.382 [pool-2-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.382 [pool-2-thread-6] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.382 [pool-2-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.382 [pool-2-thread-2] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.382 [pool-2-thread-10] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.382 [pool-2-thread-4] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.382 [pool-2-thread-3] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.382 [pool-2-thread-8] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.382 [pool-2-thread-7] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.382 [pool-2-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.383 [pool-2-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.490 [pool-3-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.490 [pool-3-thread-2] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.506 [pool-3-thread-4] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.521 [pool-3-thread-3] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.536 [pool-3-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.536 [pool-3-thread-10] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.536 [pool-3-thread-8] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.552 [pool-3-thread-7] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.552 [pool-3-thread-5] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.552 [pool-3-thread-1] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.552 [pool-3-thread-6] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.568 [pool-3-thread-2] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.568 [pool-3-thread-4] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.568 [pool-3-thread-3] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:34:18.568 [pool-3-thread-9] WARN  com.yeechart.dotMatrix.oss.OSSUpload - OSS上传尝试 1 次失败,错误为 : null
+2024-11-25 10:48:27.925 [SpringContextShutdownHook] INFO  o.s.s.c.ThreadPoolTaskExecutor - Shutting down ExecutorService 'applicationTaskExecutor'
+2024-11-25 11:18:34.574 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Starting DotMatrixApplication on YiChao-XZP with PID 23464 (D:\WorkSpace\Java\DotMatrix2\DotMatrix\target\classes started by xuzip in D:\WorkSpace\Java\DotMatrix2\DotMatrix)
+2024-11-25 11:18:34.575 [main] DEBUG c.y.dotMatrix.DotMatrixApplication - Running with Spring Boot v2.3.3.RELEASE, Spring v5.2.8.RELEASE
+2024-11-25 11:18:34.575 [main] INFO  c.y.dotMatrix.DotMatrixApplication - No active profile set, falling back to default profiles: default
+2024-11-25 11:18:35.004 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 1111 (http)
+2024-11-25 11:18:35.008 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-1111"]
+2024-11-25 11:18:35.009 [main] INFO  o.a.catalina.core.StandardService - Starting service [Tomcat]
+2024-11-25 11:18:35.009 [main] INFO  o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.37]
+2024-11-25 11:18:35.043 [main] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
+2024-11-25 11:18:35.043 [main] INFO  o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 448 ms
+2024-11-25 11:18:36.578 [main] INFO  o.s.s.c.ThreadPoolTaskExecutor - Initializing ExecutorService
+2024-11-25 11:18:36.579 [main] INFO  o.s.s.c.ThreadPoolTaskExecutor - Initializing ExecutorService 'voiceThreadPoolTaskExecutor'
+2024-11-25 11:18:36.932 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-1111"]
+2024-11-25 11:18:36.943 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 1111 (http) with context path ''
+2024-11-25 11:18:36.948 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Started DotMatrixApplication in 2.536 seconds (JVM running for 3.156)
+2024-11-25 11:21:09.334 [http-nio-1111-exec-1] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
+2024-11-25 11:21:09.335 [http-nio-1111-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
+2024-11-25 11:21:09.339 [http-nio-1111-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Completed initialization in 3 ms
+2024-11-25 11:22:52.511 [SpringContextShutdownHook] INFO  o.s.s.c.ThreadPoolTaskExecutor - Shutting down ExecutorService 'voiceThreadPoolTaskExecutor'
+2024-11-25 11:27:08.966 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Starting DotMatrixApplication on YiChao-XZP with PID 21604 (D:\WorkSpace\Java\DotMatrix2\DotMatrix\target\classes started by xuzip in D:\WorkSpace\Java\DotMatrix2\DotMatrix)
+2024-11-25 11:27:08.967 [main] DEBUG c.y.dotMatrix.DotMatrixApplication - Running with Spring Boot v2.3.3.RELEASE, Spring v5.2.8.RELEASE
+2024-11-25 11:27:08.967 [main] INFO  c.y.dotMatrix.DotMatrixApplication - No active profile set, falling back to default profiles: default
+2024-11-25 11:27:09.300 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 1111 (http)
+2024-11-25 11:27:09.307 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-1111"]
+2024-11-25 11:27:09.308 [main] INFO  o.a.catalina.core.StandardService - Starting service [Tomcat]
+2024-11-25 11:27:09.308 [main] INFO  o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.37]
+2024-11-25 11:27:09.351 [main] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
+2024-11-25 11:27:09.351 [main] INFO  o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 366 ms
+2024-11-25 11:27:10.883 [main] INFO  o.s.s.c.ThreadPoolTaskExecutor - Initializing ExecutorService
+2024-11-25 11:27:10.883 [main] INFO  o.s.s.c.ThreadPoolTaskExecutor - Initializing ExecutorService 'voiceThreadPoolTaskExecutor'
+2024-11-25 11:27:11.154 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-1111"]
+2024-11-25 11:27:11.164 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 1111 (http) with context path ''
+2024-11-25 11:27:11.169 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Started DotMatrixApplication in 2.344 seconds (JVM running for 3.205)
+2024-11-25 11:27:18.030 [http-nio-1111-exec-1] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
+2024-11-25 11:27:18.031 [http-nio-1111-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
+2024-11-25 11:27:18.034 [http-nio-1111-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Completed initialization in 3 ms
+2024-11-25 11:34:54.359 [SpringContextShutdownHook] INFO  o.s.s.c.ThreadPoolTaskExecutor - Shutting down ExecutorService 'voiceThreadPoolTaskExecutor'
+2024-11-25 11:34:57.793 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Starting DotMatrixApplication on YiChao-XZP with PID 20648 (D:\WorkSpace\Java\DotMatrix2\DotMatrix\target\classes started by xuzip in D:\WorkSpace\Java\DotMatrix2\DotMatrix)
+2024-11-25 11:34:57.794 [main] DEBUG c.y.dotMatrix.DotMatrixApplication - Running with Spring Boot v2.3.3.RELEASE, Spring v5.2.8.RELEASE
+2024-11-25 11:34:57.794 [main] INFO  c.y.dotMatrix.DotMatrixApplication - No active profile set, falling back to default profiles: default
+2024-11-25 11:34:58.167 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 1111 (http)
+2024-11-25 11:34:58.172 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-1111"]
+2024-11-25 11:34:58.172 [main] INFO  o.a.catalina.core.StandardService - Starting service [Tomcat]
+2024-11-25 11:34:58.172 [main] INFO  o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.37]
+2024-11-25 11:34:58.207 [main] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
+2024-11-25 11:34:58.207 [main] INFO  o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 388 ms
+2024-11-25 11:34:59.638 [main] INFO  o.s.s.c.ThreadPoolTaskExecutor - Initializing ExecutorService
+2024-11-25 11:34:59.638 [main] INFO  o.s.s.c.ThreadPoolTaskExecutor - Initializing ExecutorService 'voiceThreadPoolTaskExecutor'
+2024-11-25 11:34:59.880 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-1111"]
+2024-11-25 11:34:59.891 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 1111 (http) with context path ''
+2024-11-25 11:34:59.896 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Started DotMatrixApplication in 2.291 seconds (JVM running for 2.862)
+2024-11-25 11:35:20.566 [http-nio-1111-exec-1] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
+2024-11-25 11:35:20.567 [http-nio-1111-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
+2024-11-25 11:35:20.571 [http-nio-1111-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Completed initialization in 4 ms
+2024-11-25 11:50:42.637 [SpringContextShutdownHook] INFO  o.s.s.c.ThreadPoolTaskExecutor - Shutting down ExecutorService 'voiceThreadPoolTaskExecutor'
+2024-11-25 11:50:46.205 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Starting DotMatrixApplication on YiChao-XZP with PID 14852 (D:\WorkSpace\Java\DotMatrix2\DotMatrix\target\classes started by xuzip in D:\WorkSpace\Java\DotMatrix2\DotMatrix)
+2024-11-25 11:50:46.207 [main] DEBUG c.y.dotMatrix.DotMatrixApplication - Running with Spring Boot v2.3.3.RELEASE, Spring v5.2.8.RELEASE
+2024-11-25 11:50:46.207 [main] INFO  c.y.dotMatrix.DotMatrixApplication - No active profile set, falling back to default profiles: default
+2024-11-25 11:50:46.633 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 1111 (http)
+2024-11-25 11:50:46.640 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-1111"]
+2024-11-25 11:50:46.640 [main] INFO  o.a.catalina.core.StandardService - Starting service [Tomcat]
+2024-11-25 11:50:46.640 [main] INFO  o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.37]
+2024-11-25 11:50:46.682 [main] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
+2024-11-25 11:50:46.683 [main] INFO  o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 453 ms
+2024-11-25 11:50:48.198 [main] INFO  o.s.s.c.ThreadPoolTaskExecutor - Initializing ExecutorService
+2024-11-25 11:50:48.198 [main] INFO  o.s.s.c.ThreadPoolTaskExecutor - Initializing ExecutorService 'voiceThreadPoolTaskExecutor'
+2024-11-25 11:50:48.490 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-1111"]
+2024-11-25 11:50:48.500 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 1111 (http) with context path ''
+2024-11-25 11:50:48.506 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Started DotMatrixApplication in 2.47 seconds (JVM running for 3.03)
+2024-11-25 11:53:36.340 [http-nio-1111-exec-5] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
+2024-11-25 11:53:36.341 [http-nio-1111-exec-5] INFO  o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
+2024-11-25 11:53:36.345 [http-nio-1111-exec-5] INFO  o.s.web.servlet.DispatcherServlet - Completed initialization in 4 ms
+2024-11-25 11:53:41.377 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/000000/10000/00000002.txt错误java.net.MalformedURLException: no protocol: /000000/10000/00000002.txt
+2024-11-25 11:53:41.378 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010002/3764/010001000202.txt错误java.net.MalformedURLException: no protocol: /0100010002/3764/010001000202.txt
+2024-11-25 11:53:41.379 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010001/10000/010001000100.txt错误java.net.MalformedURLException: no protocol: /0100010001/10000/010001000100.txt
+2024-11-25 11:53:41.379 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF05/10000/010001FF0501.txt错误java.net.MalformedURLException: no protocol: /010001FF05/10000/010001FF0501.txt
+2024-11-25 11:53:41.380 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF03/10000/010001FF0302.txt错误java.net.MalformedURLException: no protocol: /010001FF03/10000/010001FF0302.txt
+2024-11-25 11:53:41.380 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF00/8884/010001FF0003.txt错误java.net.MalformedURLException: no protocol: /010001FF00/8884/010001FF0003.txt
+2024-11-25 11:53:41.380 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01010101/8884/0101010103.txt错误java.net.MalformedURLException: no protocol: /01010101/8884/0101010103.txt
+2024-11-25 11:53:41.380 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01010100/10000/0101010000.txt错误java.net.MalformedURLException: no protocol: /01010100/10000/0101010000.txt
+2024-11-25 11:53:41.380 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010001/3764/010001000102.txt错误java.net.MalformedURLException: no protocol: /0100010001/3764/010001000102.txt
+2024-11-25 11:53:41.381 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF00/10000/010001FF0000.txt错误java.net.MalformedURLException: no protocol: /010001FF00/10000/010001FF0000.txt
+2024-11-25 11:53:41.381 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010001/10000/010001000101.txt错误java.net.MalformedURLException: no protocol: /0100010001/10000/010001000101.txt
+2024-11-25 11:53:41.381 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010003/10000/010001000300.txt错误java.net.MalformedURLException: no protocol: /0100010003/10000/010001000300.txt
+2024-11-25 11:53:41.381 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FFFE/8884/010001FFFE03.txt错误java.net.MalformedURLException: no protocol: /010001FFFE/8884/010001FFFE03.txt
+2024-11-25 11:53:41.381 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF05/10000/010001FF0502.txt错误java.net.MalformedURLException: no protocol: /010001FF05/10000/010001FF0502.txt
+2024-11-25 11:53:41.382 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01010101/10000/0101010100.txt错误java.net.MalformedURLException: no protocol: /01010101/10000/0101010100.txt
+2024-11-25 11:53:41.382 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000100FE/10000/01000100FE00.txt错误java.net.MalformedURLException: no protocol: /01000100FE/10000/01000100FE00.txt
+2024-11-25 11:53:41.382 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF00/10000/010001FF0001.txt错误java.net.MalformedURLException: no protocol: /010001FF00/10000/010001FF0001.txt
+2024-11-25 11:53:41.382 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF02/10000/010001FF0200.txt错误java.net.MalformedURLException: no protocol: /010001FF02/10000/010001FF0200.txt
+2024-11-25 11:53:41.382 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000102FF/10000/01000102FF00.txt错误java.net.MalformedURLException: no protocol: /01000102FF/10000/01000102FF00.txt
+2024-11-25 11:53:41.383 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01010101/10000/0101010101.txt错误java.net.MalformedURLException: no protocol: /01010101/10000/0101010101.txt
+2024-11-25 11:53:41.383 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF01/10000/010001FF0101.txt错误java.net.MalformedURLException: no protocol: /010001FF01/10000/010001FF0101.txt
+2024-11-25 11:53:41.383 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF03/10000/010001FF0300.txt错误java.net.MalformedURLException: no protocol: /010001FF03/10000/010001FF0300.txt
+2024-11-25 11:53:41.383 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF05/8884/010001FF0503.txt错误java.net.MalformedURLException: no protocol: /010001FF05/8884/010001FF0503.txt
+2024-11-25 11:53:41.383 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF00/10000/010001FF0002.txt错误java.net.MalformedURLException: no protocol: /010001FF00/10000/010001FF0002.txt
+2024-11-25 11:53:41.383 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF02/10000/010001FF0201.txt错误java.net.MalformedURLException: no protocol: /010001FF02/10000/010001FF0201.txt
+2024-11-25 11:53:41.384 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000100FE/10000/01000100FE01.txt错误java.net.MalformedURLException: no protocol: /01000100FE/10000/01000100FE01.txt
+2024-11-25 11:53:41.384 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000102FF/10000/01000102FF01.txt错误java.net.MalformedURLException: no protocol: /01000102FF/10000/01000102FF01.txt
+2024-11-25 11:53:41.384 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF01/8884/010001FF0103.txt错误java.net.MalformedURLException: no protocol: /010001FF01/8884/010001FF0103.txt
+2024-11-25 11:53:41.384 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF04/10000/010001FF0400.txt错误java.net.MalformedURLException: no protocol: /010001FF04/10000/010001FF0400.txt
+2024-11-25 11:53:41.384 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF01/10000/010001FF0102.txt错误java.net.MalformedURLException: no protocol: /010001FF01/10000/010001FF0102.txt
+2024-11-25 11:53:41.384 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010000/3764/010001000002.txt错误java.net.MalformedURLException: no protocol: /0100010000/3764/010001000002.txt
+2024-11-25 11:53:41.385 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01010101/10000/0101010102.txt错误java.net.MalformedURLException: no protocol: /01010101/10000/0101010102.txt
+2024-11-25 11:53:41.385 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF03/10000/010001FF0301.txt错误java.net.MalformedURLException: no protocol: /010001FF03/10000/010001FF0301.txt
+2024-11-25 11:53:41.385 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010005/3764/010001000502.txt错误java.net.MalformedURLException: no protocol: /0100010005/3764/010001000502.txt
+2024-11-25 11:53:41.385 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF05/10000/010001FF0500.txt错误java.net.MalformedURLException: no protocol: /010001FF05/10000/010001FF0500.txt
+2024-11-25 11:53:41.385 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000101FF/3764/01000101FF02.txt错误java.net.MalformedURLException: no protocol: /01000101FF/3764/01000101FF02.txt
+2024-11-25 11:53:41.385 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/00010000/8884/0001000003.txt错误java.net.MalformedURLException: no protocol: /00010000/8884/0001000003.txt
+2024-11-25 11:53:41.386 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010000/10000/010001000000.txt错误java.net.MalformedURLException: no protocol: /0100010000/10000/010001000000.txt
+2024-11-25 11:53:41.386 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF02/10000/010001FF0202.txt错误java.net.MalformedURLException: no protocol: /010001FF02/10000/010001FF0202.txt
+2024-11-25 11:53:41.386 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF04/10000/010001FF0401.txt错误java.net.MalformedURLException: no protocol: /010001FF04/10000/010001FF0401.txt
+2024-11-25 11:53:41.386 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000102FF/3764/01000102FF02.txt错误java.net.MalformedURLException: no protocol: /01000102FF/3764/01000102FF02.txt
+2024-11-25 11:53:41.386 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/00010001/10000/0001000100.txt错误java.net.MalformedURLException: no protocol: /00010001/10000/0001000100.txt
+2024-11-25 11:53:41.386 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/00010000/10000/0001000001.txt错误java.net.MalformedURLException: no protocol: /00010000/10000/0001000001.txt
+2024-11-25 11:53:41.386 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000103FF/3764/01000103FF02.txt错误java.net.MalformedURLException: no protocol: /01000103FF/3764/01000103FF02.txt
+2024-11-25 11:53:41.387 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FFFE/10000/010001FFFE01.txt错误java.net.MalformedURLException: no protocol: /010001FFFE/10000/010001FFFE01.txt
+2024-11-25 11:53:41.387 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010000/10000/010001000001.txt错误java.net.MalformedURLException: no protocol: /0100010000/10000/010001000001.txt
+2024-11-25 11:53:41.387 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010002/10000/010001000200.txt错误java.net.MalformedURLException: no protocol: /0100010002/10000/010001000200.txt
+2024-11-25 11:53:41.388 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000100FE/3764/01000100FE02.txt错误java.net.MalformedURLException: no protocol: /01000100FE/3764/01000100FE02.txt
+2024-11-25 11:53:41.388 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/00010001/10000/0001000101.txt错误java.net.MalformedURLException: no protocol: /00010001/10000/0001000101.txt
+2024-11-25 11:53:41.388 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF04/10000/010001FF0402.txt错误java.net.MalformedURLException: no protocol: /010001FF04/10000/010001FF0402.txt
+2024-11-25 11:53:41.388 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FFFE/10000/010001FFFE02.txt错误java.net.MalformedURLException: no protocol: /010001FFFE/10000/010001FFFE02.txt
+2024-11-25 11:53:41.388 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF04/8884/010001FF0403.txt错误java.net.MalformedURLException: no protocol: /010001FF04/8884/010001FF0403.txt
+2024-11-25 11:53:41.388 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010004/3764/010001000402.txt错误java.net.MalformedURLException: no protocol: /0100010004/3764/010001000402.txt
+2024-11-25 11:53:41.388 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/00010000/10000/0001000002.txt错误java.net.MalformedURLException: no protocol: /00010000/10000/0001000002.txt
+2024-11-25 11:53:41.388 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF01/10000/010001FF0100.txt错误java.net.MalformedURLException: no protocol: /010001FF01/10000/010001FF0100.txt
+2024-11-25 11:53:41.389 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010002/10000/010001000201.txt错误java.net.MalformedURLException: no protocol: /0100010002/10000/010001000201.txt
+2024-11-25 11:53:41.389 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010004/10000/010001000400.txt错误java.net.MalformedURLException: no protocol: /0100010004/10000/010001000400.txt
+2024-11-25 11:53:41.389 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01010100/10000/0101010001.txt错误java.net.MalformedURLException: no protocol: /01010100/10000/0101010001.txt
+2024-11-25 11:53:41.389 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF02/8884/010001FF0203.txt错误java.net.MalformedURLException: no protocol: /010001FF02/8884/010001FF0203.txt
+2024-11-25 11:53:41.389 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/00010001/10000/0001000102.txt错误java.net.MalformedURLException: no protocol: /00010001/10000/0001000102.txt
+2024-11-25 11:53:41.389 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010003/10000/010001000301.txt错误java.net.MalformedURLException: no protocol: /0100010003/10000/010001000301.txt
+2024-11-25 11:53:41.389 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000103FF/10000/01000103FF00.txt错误java.net.MalformedURLException: no protocol: /01000103FF/10000/01000103FF00.txt
+2024-11-25 11:53:41.389 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/000000/10000/00000000.txt错误java.net.MalformedURLException: no protocol: /000000/10000/00000000.txt
+2024-11-25 11:53:41.389 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010005/10000/010001000500.txt错误java.net.MalformedURLException: no protocol: /0100010005/10000/010001000500.txt
+2024-11-25 11:53:41.389 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010003/3764/010001000302.txt错误java.net.MalformedURLException: no protocol: /0100010003/3764/010001000302.txt
+2024-11-25 11:53:41.389 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/000000/8884/00000003.txt错误java.net.MalformedURLException: no protocol: /000000/8884/00000003.txt
+2024-11-25 11:53:41.389 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000101FF/10000/01000101FF00.txt错误java.net.MalformedURLException: no protocol: /01000101FF/10000/01000101FF00.txt
+2024-11-25 11:53:41.390 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010004/10000/010001000401.txt错误java.net.MalformedURLException: no protocol: /0100010004/10000/010001000401.txt
+2024-11-25 11:53:41.390 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01010100/8884/0101010003.txt错误java.net.MalformedURLException: no protocol: /01010100/8884/0101010003.txt
+2024-11-25 11:53:41.390 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000103FF/10000/01000103FF01.txt错误java.net.MalformedURLException: no protocol: /01000103FF/10000/01000103FF01.txt
+2024-11-25 11:53:41.390 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01010100/10000/0101010002.txt错误java.net.MalformedURLException: no protocol: /01010100/10000/0101010002.txt
+2024-11-25 11:53:41.390 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010005/10000/010001000501.txt错误java.net.MalformedURLException: no protocol: /0100010005/10000/010001000501.txt
+2024-11-25 11:53:41.391 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/000000/10000/00000001.txt错误java.net.MalformedURLException: no protocol: /000000/10000/00000001.txt
+2024-11-25 11:53:41.391 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/00010001/8884/0001000103.txt错误java.net.MalformedURLException: no protocol: /00010001/8884/0001000103.txt
+2024-11-25 11:53:41.391 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF03/8884/010001FF0303.txt错误java.net.MalformedURLException: no protocol: /010001FF03/8884/010001FF0303.txt
+2024-11-25 11:53:41.391 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/00010000/10000/0001000000.txt错误java.net.MalformedURLException: no protocol: /00010000/10000/0001000000.txt
+2024-11-25 11:53:41.391 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000101FF/10000/01000101FF01.txt错误java.net.MalformedURLException: no protocol: /01000101FF/10000/01000101FF01.txt
+2024-11-25 11:53:41.391 [voiceThreadPool-1] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FFFE/10000/010001FFFE00.txt错误java.net.MalformedURLException: no protocol: /010001FFFE/10000/010001FFFE00.txt
+2024-11-25 13:54:11.949 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/000000/10000/00000002.txt错误java.net.MalformedURLException: no protocol: /000000/10000/00000002.txt
+2024-11-25 13:54:18.969 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010002/3764/010001000202.txt错误java.net.MalformedURLException: no protocol: /0100010002/3764/010001000202.txt
+2024-11-25 13:54:18.971 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010001/10000/010001000100.txt错误java.net.MalformedURLException: no protocol: /0100010001/10000/010001000100.txt
+2024-11-25 13:54:18.972 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF05/10000/010001FF0501.txt错误java.net.MalformedURLException: no protocol: /010001FF05/10000/010001FF0501.txt
+2024-11-25 13:54:18.973 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF03/10000/010001FF0302.txt错误java.net.MalformedURLException: no protocol: /010001FF03/10000/010001FF0302.txt
+2024-11-25 13:54:18.974 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF00/8884/010001FF0003.txt错误java.net.MalformedURLException: no protocol: /010001FF00/8884/010001FF0003.txt
+2024-11-25 13:54:18.975 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01010101/8884/0101010103.txt错误java.net.MalformedURLException: no protocol: /01010101/8884/0101010103.txt
+2024-11-25 13:54:18.976 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01010100/10000/0101010000.txt错误java.net.MalformedURLException: no protocol: /01010100/10000/0101010000.txt
+2024-11-25 13:54:18.977 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010001/3764/010001000102.txt错误java.net.MalformedURLException: no protocol: /0100010001/3764/010001000102.txt
+2024-11-25 13:54:18.978 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF00/10000/010001FF0000.txt错误java.net.MalformedURLException: no protocol: /010001FF00/10000/010001FF0000.txt
+2024-11-25 13:54:18.979 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010001/10000/010001000101.txt错误java.net.MalformedURLException: no protocol: /0100010001/10000/010001000101.txt
+2024-11-25 13:54:18.979 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010003/10000/010001000300.txt错误java.net.MalformedURLException: no protocol: /0100010003/10000/010001000300.txt
+2024-11-25 13:54:18.980 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FFFE/8884/010001FFFE03.txt错误java.net.MalformedURLException: no protocol: /010001FFFE/8884/010001FFFE03.txt
+2024-11-25 13:54:18.981 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF05/10000/010001FF0502.txt错误java.net.MalformedURLException: no protocol: /010001FF05/10000/010001FF0502.txt
+2024-11-25 13:54:18.982 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01010101/10000/0101010100.txt错误java.net.MalformedURLException: no protocol: /01010101/10000/0101010100.txt
+2024-11-25 13:54:18.982 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000100FE/10000/01000100FE00.txt错误java.net.MalformedURLException: no protocol: /01000100FE/10000/01000100FE00.txt
+2024-11-25 13:54:18.983 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF00/10000/010001FF0001.txt错误java.net.MalformedURLException: no protocol: /010001FF00/10000/010001FF0001.txt
+2024-11-25 13:54:18.984 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF02/10000/010001FF0200.txt错误java.net.MalformedURLException: no protocol: /010001FF02/10000/010001FF0200.txt
+2024-11-25 13:54:18.984 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000102FF/10000/01000102FF00.txt错误java.net.MalformedURLException: no protocol: /01000102FF/10000/01000102FF00.txt
+2024-11-25 13:54:18.985 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01010101/10000/0101010101.txt错误java.net.MalformedURLException: no protocol: /01010101/10000/0101010101.txt
+2024-11-25 13:54:18.986 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF01/10000/010001FF0101.txt错误java.net.MalformedURLException: no protocol: /010001FF01/10000/010001FF0101.txt
+2024-11-25 13:54:18.987 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF03/10000/010001FF0300.txt错误java.net.MalformedURLException: no protocol: /010001FF03/10000/010001FF0300.txt
+2024-11-25 13:54:18.987 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF05/8884/010001FF0503.txt错误java.net.MalformedURLException: no protocol: /010001FF05/8884/010001FF0503.txt
+2024-11-25 13:54:18.988 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF00/10000/010001FF0002.txt错误java.net.MalformedURLException: no protocol: /010001FF00/10000/010001FF0002.txt
+2024-11-25 13:54:18.989 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF02/10000/010001FF0201.txt错误java.net.MalformedURLException: no protocol: /010001FF02/10000/010001FF0201.txt
+2024-11-25 13:54:18.990 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000100FE/10000/01000100FE01.txt错误java.net.MalformedURLException: no protocol: /01000100FE/10000/01000100FE01.txt
+2024-11-25 13:54:18.990 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000102FF/10000/01000102FF01.txt错误java.net.MalformedURLException: no protocol: /01000102FF/10000/01000102FF01.txt
+2024-11-25 13:54:18.991 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF01/8884/010001FF0103.txt错误java.net.MalformedURLException: no protocol: /010001FF01/8884/010001FF0103.txt
+2024-11-25 13:54:18.992 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF04/10000/010001FF0400.txt错误java.net.MalformedURLException: no protocol: /010001FF04/10000/010001FF0400.txt
+2024-11-25 13:54:18.993 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF01/10000/010001FF0102.txt错误java.net.MalformedURLException: no protocol: /010001FF01/10000/010001FF0102.txt
+2024-11-25 13:54:18.994 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010000/3764/010001000002.txt错误java.net.MalformedURLException: no protocol: /0100010000/3764/010001000002.txt
+2024-11-25 13:54:18.995 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01010101/10000/0101010102.txt错误java.net.MalformedURLException: no protocol: /01010101/10000/0101010102.txt
+2024-11-25 13:54:18.995 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF03/10000/010001FF0301.txt错误java.net.MalformedURLException: no protocol: /010001FF03/10000/010001FF0301.txt
+2024-11-25 13:54:18.996 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010005/3764/010001000502.txt错误java.net.MalformedURLException: no protocol: /0100010005/3764/010001000502.txt
+2024-11-25 13:54:18.997 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF05/10000/010001FF0500.txt错误java.net.MalformedURLException: no protocol: /010001FF05/10000/010001FF0500.txt
+2024-11-25 13:54:18.998 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000101FF/3764/01000101FF02.txt错误java.net.MalformedURLException: no protocol: /01000101FF/3764/01000101FF02.txt
+2024-11-25 13:54:18.999 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/00010000/8884/0001000003.txt错误java.net.MalformedURLException: no protocol: /00010000/8884/0001000003.txt
+2024-11-25 13:54:18.999 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010000/10000/010001000000.txt错误java.net.MalformedURLException: no protocol: /0100010000/10000/010001000000.txt
+2024-11-25 13:54:19.000 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF02/10000/010001FF0202.txt错误java.net.MalformedURLException: no protocol: /010001FF02/10000/010001FF0202.txt
+2024-11-25 13:54:19.001 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF04/10000/010001FF0401.txt错误java.net.MalformedURLException: no protocol: /010001FF04/10000/010001FF0401.txt
+2024-11-25 13:54:19.002 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000102FF/3764/01000102FF02.txt错误java.net.MalformedURLException: no protocol: /01000102FF/3764/01000102FF02.txt
+2024-11-25 13:54:19.002 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/00010001/10000/0001000100.txt错误java.net.MalformedURLException: no protocol: /00010001/10000/0001000100.txt
+2024-11-25 13:54:19.003 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/00010000/10000/0001000001.txt错误java.net.MalformedURLException: no protocol: /00010000/10000/0001000001.txt
+2024-11-25 13:54:19.004 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000103FF/3764/01000103FF02.txt错误java.net.MalformedURLException: no protocol: /01000103FF/3764/01000103FF02.txt
+2024-11-25 13:54:19.005 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FFFE/10000/010001FFFE01.txt错误java.net.MalformedURLException: no protocol: /010001FFFE/10000/010001FFFE01.txt
+2024-11-25 13:54:19.005 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010000/10000/010001000001.txt错误java.net.MalformedURLException: no protocol: /0100010000/10000/010001000001.txt
+2024-11-25 13:54:19.006 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010002/10000/010001000200.txt错误java.net.MalformedURLException: no protocol: /0100010002/10000/010001000200.txt
+2024-11-25 13:54:19.007 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000100FE/3764/01000100FE02.txt错误java.net.MalformedURLException: no protocol: /01000100FE/3764/01000100FE02.txt
+2024-11-25 13:54:19.008 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/00010001/10000/0001000101.txt错误java.net.MalformedURLException: no protocol: /00010001/10000/0001000101.txt
+2024-11-25 13:54:19.009 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF04/10000/010001FF0402.txt错误java.net.MalformedURLException: no protocol: /010001FF04/10000/010001FF0402.txt
+2024-11-25 13:54:19.009 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FFFE/10000/010001FFFE02.txt错误java.net.MalformedURLException: no protocol: /010001FFFE/10000/010001FFFE02.txt
+2024-11-25 13:54:19.010 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF04/8884/010001FF0403.txt错误java.net.MalformedURLException: no protocol: /010001FF04/8884/010001FF0403.txt
+2024-11-25 13:54:19.011 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010004/3764/010001000402.txt错误java.net.MalformedURLException: no protocol: /0100010004/3764/010001000402.txt
+2024-11-25 13:54:19.012 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/00010000/10000/0001000002.txt错误java.net.MalformedURLException: no protocol: /00010000/10000/0001000002.txt
+2024-11-25 13:54:19.012 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF01/10000/010001FF0100.txt错误java.net.MalformedURLException: no protocol: /010001FF01/10000/010001FF0100.txt
+2024-11-25 13:54:19.013 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010002/10000/010001000201.txt错误java.net.MalformedURLException: no protocol: /0100010002/10000/010001000201.txt
+2024-11-25 13:54:19.014 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010004/10000/010001000400.txt错误java.net.MalformedURLException: no protocol: /0100010004/10000/010001000400.txt
+2024-11-25 13:54:19.014 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01010100/10000/0101010001.txt错误java.net.MalformedURLException: no protocol: /01010100/10000/0101010001.txt
+2024-11-25 13:54:19.015 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF02/8884/010001FF0203.txt错误java.net.MalformedURLException: no protocol: /010001FF02/8884/010001FF0203.txt
+2024-11-25 13:54:19.016 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/00010001/10000/0001000102.txt错误java.net.MalformedURLException: no protocol: /00010001/10000/0001000102.txt
+2024-11-25 13:54:19.017 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010003/10000/010001000301.txt错误java.net.MalformedURLException: no protocol: /0100010003/10000/010001000301.txt
+2024-11-25 13:54:19.017 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000103FF/10000/01000103FF00.txt错误java.net.MalformedURLException: no protocol: /01000103FF/10000/01000103FF00.txt
+2024-11-25 13:54:19.018 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/000000/10000/00000000.txt错误java.net.MalformedURLException: no protocol: /000000/10000/00000000.txt
+2024-11-25 13:54:19.019 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010005/10000/010001000500.txt错误java.net.MalformedURLException: no protocol: /0100010005/10000/010001000500.txt
+2024-11-25 13:54:19.019 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010003/3764/010001000302.txt错误java.net.MalformedURLException: no protocol: /0100010003/3764/010001000302.txt
+2024-11-25 13:54:19.020 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/000000/8884/00000003.txt错误java.net.MalformedURLException: no protocol: /000000/8884/00000003.txt
+2024-11-25 13:54:19.021 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000101FF/10000/01000101FF00.txt错误java.net.MalformedURLException: no protocol: /01000101FF/10000/01000101FF00.txt
+2024-11-25 13:54:19.021 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010004/10000/010001000401.txt错误java.net.MalformedURLException: no protocol: /0100010004/10000/010001000401.txt
+2024-11-25 13:54:19.022 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01010100/8884/0101010003.txt错误java.net.MalformedURLException: no protocol: /01010100/8884/0101010003.txt
+2024-11-25 13:54:19.023 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000103FF/10000/01000103FF01.txt错误java.net.MalformedURLException: no protocol: /01000103FF/10000/01000103FF01.txt
+2024-11-25 13:54:19.024 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01010100/10000/0101010002.txt错误java.net.MalformedURLException: no protocol: /01010100/10000/0101010002.txt
+2024-11-25 13:54:19.025 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/0100010005/10000/010001000501.txt错误java.net.MalformedURLException: no protocol: /0100010005/10000/010001000501.txt
+2024-11-25 13:54:19.025 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/000000/10000/00000001.txt错误java.net.MalformedURLException: no protocol: /000000/10000/00000001.txt
+2024-11-25 13:54:19.026 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/00010001/8884/0001000103.txt错误java.net.MalformedURLException: no protocol: /00010001/8884/0001000103.txt
+2024-11-25 13:54:19.027 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FF03/8884/010001FF0303.txt错误java.net.MalformedURLException: no protocol: /010001FF03/8884/010001FF0303.txt
+2024-11-25 13:54:19.028 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/00010000/10000/0001000000.txt错误java.net.MalformedURLException: no protocol: /00010000/10000/0001000000.txt
+2024-11-25 13:54:19.028 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/01000101FF/10000/01000101FF01.txt错误java.net.MalformedURLException: no protocol: /01000101FF/10000/01000101FF01.txt
+2024-11-25 13:54:19.029 [voiceThreadPool-2] ERROR com.yeechart.dotMatrix.oss.OSSUpload - 文件路径转换时,路径/010001FFFE/10000/010001FFFE00.txt错误java.net.MalformedURLException: no protocol: /010001FFFE/10000/010001FFFE00.txt
+2024-11-25 13:54:21.864 [SpringContextShutdownHook] INFO  o.s.s.c.ThreadPoolTaskExecutor - Shutting down ExecutorService 'voiceThreadPoolTaskExecutor'
+2024-11-25 13:54:24.533 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Starting DotMatrixApplication on YiChao-XZP with PID 39988 (D:\WorkSpace\Java\DotMatrix2\DotMatrix\target\classes started by xuzip in D:\WorkSpace\Java\DotMatrix2\DotMatrix)
+2024-11-25 13:54:24.534 [main] DEBUG c.y.dotMatrix.DotMatrixApplication - Running with Spring Boot v2.3.3.RELEASE, Spring v5.2.8.RELEASE
+2024-11-25 13:54:24.535 [main] INFO  c.y.dotMatrix.DotMatrixApplication - No active profile set, falling back to default profiles: default
+2024-11-25 13:54:24.872 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 1111 (http)
+2024-11-25 13:54:24.876 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-1111"]
+2024-11-25 13:54:24.876 [main] INFO  o.a.catalina.core.StandardService - Starting service [Tomcat]
+2024-11-25 13:54:24.876 [main] INFO  o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.37]
+2024-11-25 13:54:24.911 [main] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
+2024-11-25 13:54:24.911 [main] INFO  o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 357 ms
+2024-11-25 13:54:26.346 [main] INFO  o.s.s.c.ThreadPoolTaskExecutor - Initializing ExecutorService
+2024-11-25 13:54:26.346 [main] INFO  o.s.s.c.ThreadPoolTaskExecutor - Initializing ExecutorService 'voiceThreadPoolTaskExecutor'
+2024-11-25 13:54:26.639 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-1111"]
+2024-11-25 13:54:26.655 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 1111 (http) with context path ''
+2024-11-25 13:54:26.662 [main] INFO  c.y.dotMatrix.DotMatrixApplication - Started DotMatrixApplication in 2.293 seconds (JVM running for 2.791)
+2024-11-25 13:59:10.446 [http-nio-1111-exec-1] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
+2024-11-25 13:59:10.447 [http-nio-1111-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
+2024-11-25 13:59:10.454 [http-nio-1111-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Completed initialization in 7 ms

+ 259 - 0
mvnw

@@ -0,0 +1,259 @@
+#!/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
+#
+#    http://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.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Apache Maven Wrapper startup batch script, version 3.3.2
+#
+# Optional ENV vars
+# -----------------
+#   JAVA_HOME - location of a JDK home dir, required when download maven via java source
+#   MVNW_REPOURL - repo url base for downloading maven distribution
+#   MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
+#   MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
+# ----------------------------------------------------------------------------
+
+set -euf
+[ "${MVNW_VERBOSE-}" != debug ] || set -x
+
+# OS specific support.
+native_path() { printf %s\\n "$1"; }
+case "$(uname)" in
+CYGWIN* | MINGW*)
+  [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
+  native_path() { cygpath --path --windows "$1"; }
+  ;;
+esac
+
+# set JAVACMD and JAVACCMD
+set_java_home() {
+  # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
+  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"
+      JAVACCMD="$JAVA_HOME/jre/sh/javac"
+    else
+      JAVACMD="$JAVA_HOME/bin/java"
+      JAVACCMD="$JAVA_HOME/bin/javac"
+
+      if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
+        echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
+        echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
+        return 1
+      fi
+    fi
+  else
+    JAVACMD="$(
+      'set' +e
+      'unset' -f command 2>/dev/null
+      'command' -v java
+    )" || :
+    JAVACCMD="$(
+      'set' +e
+      'unset' -f command 2>/dev/null
+      'command' -v javac
+    )" || :
+
+    if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
+      echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
+      return 1
+    fi
+  fi
+}
+
+# hash string like Java String::hashCode
+hash_string() {
+  str="${1:-}" h=0
+  while [ -n "$str" ]; do
+    char="${str%"${str#?}"}"
+    h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
+    str="${str#?}"
+  done
+  printf %x\\n $h
+}
+
+verbose() { :; }
+[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
+
+die() {
+  printf %s\\n "$1" >&2
+  exit 1
+}
+
+trim() {
+  # MWRAPPER-139:
+  #   Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
+  #   Needed for removing poorly interpreted newline sequences when running in more
+  #   exotic environments such as mingw bash on Windows.
+  printf "%s" "${1}" | tr -d '[:space:]'
+}
+
+# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
+while IFS="=" read -r key value; do
+  case "${key-}" in
+  distributionUrl) distributionUrl=$(trim "${value-}") ;;
+  distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
+  esac
+done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties"
+[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties"
+
+case "${distributionUrl##*/}" in
+maven-mvnd-*bin.*)
+  MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
+  case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
+  *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
+  :Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
+  :Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
+  :Linux*x86_64*) distributionPlatform=linux-amd64 ;;
+  *)
+    echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
+    distributionPlatform=linux-amd64
+    ;;
+  esac
+  distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
+  ;;
+maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
+*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
+esac
+
+# apply MVNW_REPOURL and calculate MAVEN_HOME
+# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
+[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
+distributionUrlName="${distributionUrl##*/}"
+distributionUrlNameMain="${distributionUrlName%.*}"
+distributionUrlNameMain="${distributionUrlNameMain%-bin}"
+MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
+MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
+
+exec_maven() {
+  unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
+  exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
+}
+
+if [ -d "$MAVEN_HOME" ]; then
+  verbose "found existing MAVEN_HOME at $MAVEN_HOME"
+  exec_maven "$@"
+fi
+
+case "${distributionUrl-}" in
+*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
+*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
+esac
+
+# prepare tmp dir
+if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
+  clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
+  trap clean HUP INT TERM EXIT
+else
+  die "cannot create temp dir"
+fi
+
+mkdir -p -- "${MAVEN_HOME%/*}"
+
+# Download and Install Apache Maven
+verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
+verbose "Downloading from: $distributionUrl"
+verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
+
+# select .zip or .tar.gz
+if ! command -v unzip >/dev/null; then
+  distributionUrl="${distributionUrl%.zip}.tar.gz"
+  distributionUrlName="${distributionUrl##*/}"
+fi
+
+# verbose opt
+__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
+[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
+
+# normalize http auth
+case "${MVNW_PASSWORD:+has-password}" in
+'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
+has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
+esac
+
+if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
+  verbose "Found wget ... using wget"
+  wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
+elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
+  verbose "Found curl ... using curl"
+  curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
+elif set_java_home; then
+  verbose "Falling back to use Java to download"
+  javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
+  targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
+  cat >"$javaSource" <<-END
+	public class Downloader extends java.net.Authenticator
+	{
+	  protected java.net.PasswordAuthentication getPasswordAuthentication()
+	  {
+	    return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
+	  }
+	  public static void main( String[] args ) throws Exception
+	  {
+	    setDefault( new Downloader() );
+	    java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
+	  }
+	}
+	END
+  # For Cygwin/MinGW, switch paths to Windows format before running javac and java
+  verbose " - Compiling Downloader.java ..."
+  "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
+  verbose " - Running Downloader.java ..."
+  "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
+fi
+
+# If specified, validate the SHA-256 sum of the Maven distribution zip file
+if [ -n "${distributionSha256Sum-}" ]; then
+  distributionSha256Result=false
+  if [ "$MVN_CMD" = mvnd.sh ]; then
+    echo "Checksum validation is not supported for maven-mvnd." >&2
+    echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
+    exit 1
+  elif command -v sha256sum >/dev/null; then
+    if echo "$distributionSha256Sum  $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then
+      distributionSha256Result=true
+    fi
+  elif command -v shasum >/dev/null; then
+    if echo "$distributionSha256Sum  $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
+      distributionSha256Result=true
+    fi
+  else
+    echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
+    echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
+    exit 1
+  fi
+  if [ $distributionSha256Result = false ]; then
+    echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
+    echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
+    exit 1
+  fi
+fi
+
+# unzip and move
+if command -v unzip >/dev/null; then
+  unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
+else
+  tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
+fi
+printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url"
+mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
+
+clean || :
+exec_maven "$@"

+ 149 - 0
mvnw.cmd

@@ -0,0 +1,149 @@
+<# : batch portion
+@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    http://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 Apache Maven Wrapper startup batch script, version 3.3.2
+@REM
+@REM Optional ENV vars
+@REM   MVNW_REPOURL - repo url base for downloading maven distribution
+@REM   MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
+@REM   MVNW_VERBOSE - true: enable verbose log; others: silence the output
+@REM ----------------------------------------------------------------------------
+
+@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
+@SET __MVNW_CMD__=
+@SET __MVNW_ERROR__=
+@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
+@SET PSModulePath=
+@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
+  IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
+)
+@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
+@SET __MVNW_PSMODULEP_SAVE=
+@SET __MVNW_ARG0_NAME__=
+@SET MVNW_USERNAME=
+@SET MVNW_PASSWORD=
+@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
+@echo Cannot start maven from wrapper >&2 && exit /b 1
+@GOTO :EOF
+: end batch / begin powershell #>
+
+$ErrorActionPreference = "Stop"
+if ($env:MVNW_VERBOSE -eq "true") {
+  $VerbosePreference = "Continue"
+}
+
+# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
+$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
+if (!$distributionUrl) {
+  Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
+}
+
+switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
+  "maven-mvnd-*" {
+    $USE_MVND = $true
+    $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
+    $MVN_CMD = "mvnd.cmd"
+    break
+  }
+  default {
+    $USE_MVND = $false
+    $MVN_CMD = $script -replace '^mvnw','mvn'
+    break
+  }
+}
+
+# apply MVNW_REPOURL and calculate MAVEN_HOME
+# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
+if ($env:MVNW_REPOURL) {
+  $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
+  $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
+}
+$distributionUrlName = $distributionUrl -replace '^.*/',''
+$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
+$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
+if ($env:MAVEN_USER_HOME) {
+  $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain"
+}
+$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
+$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
+
+if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
+  Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
+  Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
+  exit $?
+}
+
+if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
+  Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
+}
+
+# prepare tmp dir
+$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
+$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
+$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
+trap {
+  if ($TMP_DOWNLOAD_DIR.Exists) {
+    try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
+    catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
+  }
+}
+
+New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
+
+# Download and Install Apache Maven
+Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
+Write-Verbose "Downloading from: $distributionUrl"
+Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
+
+$webclient = New-Object System.Net.WebClient
+if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
+  $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
+}
+[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
+
+# If specified, validate the SHA-256 sum of the Maven distribution zip file
+$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
+if ($distributionSha256Sum) {
+  if ($USE_MVND) {
+    Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
+  }
+  Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
+  if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
+    Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
+  }
+}
+
+# unzip and move
+Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
+Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
+try {
+  Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
+} catch {
+  if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
+    Write-Error "fail to move MAVEN_HOME"
+  }
+} finally {
+  try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
+  catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
+}
+
+Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"

+ 84 - 0
pom.xml

@@ -0,0 +1,84 @@
+<?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.3.3.RELEASE</version>
+        <relativePath/>
+    </parent>
+    <groupId>com.example</groupId>
+    <artifactId>DotMatrix</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>DotMatrix</name>
+    <description>DotMatrix</description>
+
+
+    <properties>
+        <java.version>8</java.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </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>
+
+          <!--json-->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.54</version>
+        </dependency>
+
+        <!--data-->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.12</version>
+        </dependency>
+
+        <!--阿里云OSS-->
+        <dependency>
+            <groupId>com.aliyun.oss</groupId>
+            <artifactId>aliyun-sdk-oss</artifactId>
+            <version>3.15.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>30.1-jre</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>
+        </plugins>
+    </build>
+
+</project>

+ 13 - 0
src/main/java/com/yeechart/dotMatrix/DotMatrixApplication.java

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

+ 593 - 0
src/main/java/com/yeechart/dotMatrix/canvas/DotMatrixCanvasUtil.java

@@ -0,0 +1,593 @@
+package com.yeechart.dotMatrix.canvas;
+
+/**
+ * 点阵图 绘制 工具类
+ */
+public class DotMatrixCanvasUtil {
+
+
+    /**
+     * 点阵图 放大
+     *
+     * @param originalMatrix 原点阵
+     * @param scaledColumns  放大后的大小(如果小于当前则返回当前)
+     * @return
+     */
+    public static int[][] scaleDotMatrix(int[][] originalMatrix, int scaledColumns) {
+
+        if (scaledColumns <= originalMatrix[0].length) {
+//            System.out.println("字体大小相同或者更小:"+scaledColumns);
+            return originalMatrix;
+        }
+
+        int rows = originalMatrix.length;
+        int columns = originalMatrix[0].length;
+
+        int scaledRows = rows * scaledColumns / columns;
+        int[][] scaledMatrix = new int[scaledRows][scaledColumns];
+
+        for (int i = 0; i < scaledRows; i++) {
+            for (int j = 0; j < scaledColumns; j++) {
+                int originalRow = i * rows / scaledRows;
+                int originalColumn = j * columns / scaledColumns;
+                scaledMatrix[i][j] = originalMatrix[originalRow][originalColumn];
+            }
+        }
+
+        return scaledMatrix;
+    }
+
+
+    /**
+     * 合并点阵图
+     *
+     * @param matrix1
+     * @param matrix2
+     * @return
+     */
+    public static int[][] mergeDotMatrices(int[][] matrix1, int[][] matrix2) {
+
+        int rows1 = matrix1.length;
+        int rows2 = matrix2.length;
+
+        int rowsMax = Math.max(rows1, rows2);
+
+        int columns1 = matrix1[0].length;
+        int columns2 = matrix2[0].length;
+
+        int offsetRows1 = (rowsMax - rows1) / 2;
+        int offsetRows2 = (rowsMax - rows1) / 2;
+
+        int[][] mergedMatrix = new int[rowsMax][columns1 + columns2];
+
+        for (int i = 0; i < rows1; i++) {
+
+            for (int j = 0; j < columns1; j++) {
+                mergedMatrix[i + offsetRows1][j] = matrix1[i][j];
+            }
+
+            for (int j = 0; j < columns2; j++) {
+                mergedMatrix[i + offsetRows2][columns1 + j] = matrix2[i][j];
+            }
+
+        }
+
+
+        return mergedMatrix;
+    }
+
+
+    /**
+     * 合并点阵图  会扩充为同样大小的点阵
+     *
+     * @param matrix1
+     * @param matrix2
+     * @return
+     */
+    public static int[][] mergeDotMatrices(int rows, int columns, int[][] matrix1, int[][] matrix2) {
+
+        int rows1 = matrix1.length;
+        int columns1 = matrix1[0].length;
+
+
+        int rows2 = matrix2.length;
+        int columns2 = matrix2[0].length;
+
+        //偏移量
+        int offsetRows1 = (rows - rows1) / 2;
+        int offsetRows2 = (rows - rows2) / 2;
+
+        int offsetColumns1 = (columns - columns1) / 2;
+        int offsetColumns2 = (columns - columns2) / 2;
+
+        if (offsetColumns1 < 0) {
+            offsetColumns1 = 0;
+        }
+
+        if (offsetColumns2 < 0) {
+            offsetColumns2 = 0;
+        }
+        int[][] mergedMatrix = new int[rows][columns1 + columns2];
+
+        //开始合并
+        for (int i = 0; i < rows; i++) {
+
+            for (int j = 0; j < columns1; j++) {
+                if (rows1 > i) {
+                    mergedMatrix[i + offsetRows1][j + offsetColumns1] = matrix1[i][j];
+                }
+
+            }
+
+            for (int j = 0; j < columns2; j++) {
+                if (rows2 > i) {
+                    mergedMatrix[i + offsetRows2]
+                            [columns1 + offsetColumns2 + j]
+                            = matrix2[i][j];
+                }
+
+            }
+
+        }
+
+
+        return mergedMatrix;
+    }
+
+
+    /**
+     * 合并点阵图 维持高度 横向排列
+     *
+     * @param matrix1
+     * @param matrix2
+     * @return
+     */
+    public static int[][] mergeDotMatricesWidth(int rows, int columns, int[][] matrix1, int[][] matrix2, boolean isHorizontal) {
+
+        int rows1 = matrix1.length;
+        int columns1 = matrix1[0].length;
+
+
+        int rows2 = matrix2.length;
+        int columns2 = matrix2[0].length;
+
+        //偏移量
+        int offsetRows1 = (rows - rows1) / 2;
+        int offsetRows2 = (rows - rows2) / 2;
+
+        int offsetColumns1 = (columns - columns1) / 2;
+        int offsetColumns2 = (columns - columns2) / 2;
+
+
+        int x = 0;
+        int x1 = 0;
+        int x2 = 0;
+        int y1 = 0;
+        int y2 = 0;
+
+        int[][] mergedMatrix = null;
+
+        if (isHorizontal) {
+            mergedMatrix = new int[rows][columns1 + columns2];
+            x = rows;
+            x1 = rows1;
+            x2 = rows2;
+            y1 = columns1;
+            y2 = columns2;
+        } else {
+            mergedMatrix = new int[rows1 + rows2][columns];
+            x = columns;
+            x1 = columns1;
+            x2 = columns2;
+            y1 = rows1;
+            y2 = rows2;
+
+        }
+
+
+        //开始合并
+        for (int i = 0; i < x; i++) {
+
+            for (int j = 0; j < y1; j++) {
+                if (x1 > i) {
+                    if (isHorizontal) {
+                        mergedMatrix[i + offsetRows1][j] = matrix1[i][j];
+                    } else {
+                        mergedMatrix[j][i + offsetColumns1] = matrix1[j][i];
+                    }
+                }
+            }
+
+            for (int j = 0; j < y2; j++) {
+                if (x2 > i) {
+                    if (isHorizontal) {
+                        mergedMatrix[i + offsetRows2]
+                                [y1 + j]
+                                = matrix2[i][j];
+                    } else {
+                        mergedMatrix[y1 + j]
+                                [i + offsetColumns2]
+                                = matrix2[j][i];
+                    }
+                }
+            }
+        }
+
+        return mergedMatrix;
+    }
+
+
+    /**
+     * 将 指定左上角位置的点阵数组 添加至 点阵画布数组中
+     *
+     * @param largeMatrix  点阵画布
+     * @param smallMatrix  数据点阵
+     * @param startRow     起始行
+     * @param startColumn  起始列
+     * @param confuseModel 混淆模式:  0 数据点阵完全覆盖点阵画布 ; 1 数据点阵中与点阵画布中有内容重叠的部分时,将透明出该部分
+     */
+    public static void mergeDotMatricesConfuse(int[][] largeMatrix, int[][] smallMatrix, int startRow, int startColumn, int confuseModel) {
+        int smallRows = smallMatrix.length;
+        int smallColumns = smallMatrix[0].length;
+
+        for (int i = 0; i < smallRows; i++) {
+            for (int j = 0; j < smallColumns; j++) {
+                if (startRow + i < largeMatrix.length && startColumn + j < largeMatrix[0].length) {
+
+                    if (confuseModel == 0) {
+                        largeMatrix[startRow + i][startColumn + j] = smallMatrix[i][j];
+                    } else if (confuseModel == 1) {
+
+                        if (smallMatrix[i][j] == 1) {
+                            if (largeMatrix[startRow + i][startColumn + j] == 1) {
+                                largeMatrix[startRow + i][startColumn + j] = 0;
+                            } else {
+                                largeMatrix[startRow + i][startColumn + j] = smallMatrix[i][j];
+                            }
+                        }
+
+                    }
+
+                } else {
+//                    System.out.print("内容超出 画布范围 :" + i+"  "+j);
+                }
+
+            }
+        }
+
+
+    }
+
+
+    /**
+     * 将点阵数组进行 指定角度的旋转 需要注意的是旋转之后数组可能会变大
+     *
+     * @param matrix
+     * @param rotationAngle
+     * @return
+     */
+    public static int[][] rotateDotMatrix(int[][] matrix, int rotationAngle) {
+        int rows = matrix.length;
+        int columns = matrix[0].length;
+
+        // 计算旋转角度的弧度值
+        double theta = Math.toRadians(rotationAngle);
+        double cosTheta = Math.cos(theta);
+        double sinTheta = Math.sin(theta);
+
+        // 计算旋转后的矩阵尺寸
+        int rotatedRows = (int) Math.round(rows * Math.abs(cosTheta) + columns * Math.abs(sinTheta));
+        int rotatedColumns = (int) Math.round(rows * Math.abs(sinTheta) + columns * Math.abs(cosTheta));
+
+        // 创建旋转后的矩阵
+        int[][] rotatedMatrix = new int[rotatedRows][rotatedColumns];
+
+        // 计算旋转中心点
+        double centerRow = rows / 2.0;
+        double centerColumn = columns / 2.0;
+        double rotatedCenterRow = rotatedRows / 2.0;
+        double rotatedCenterColumn = rotatedColumns / 2.0;
+
+        // 进行旋转
+        for (int i = 0; i < rows; i++) {
+            for (int j = 0; j < columns; j++) {
+                // 计算旋转后的坐标
+                double x = (i - centerRow) * cosTheta - (j - centerColumn) * sinTheta + rotatedCenterRow;
+                double y = (i - centerRow) * sinTheta + (j - centerColumn) * cosTheta + rotatedCenterColumn;
+
+                // 四舍五入取整
+                int rotatedRow = (int) Math.round(x);
+                int rotatedColumn = (int) Math.round(y);
+
+                // 将原始点阵的值复制到旋转后的矩阵中
+                if (matrix[i][j] == 1) {
+
+
+                    if (rotatedRow >= 0 &&
+                            rotatedRow < rotatedRows &&
+                            rotatedColumn >= 0 &&
+                            rotatedColumn < rotatedColumns) {
+
+                        if (rotatedMatrix[rotatedRow][rotatedColumn] == 1) {
+                            //已经有值了 可能被舍弃掉了 进行加1处理
+                            rotatedRow = rotatedRow + 1;
+                            rotatedColumn = rotatedColumn + 1;
+                            if (rotatedRow < rotatedRows &&
+                                    rotatedColumn < rotatedColumns) {
+                                rotatedMatrix[rotatedRow][rotatedColumn] = matrix[i][j];
+                            }
+                        } else {
+                            rotatedMatrix[rotatedRow][rotatedColumn] = matrix[i][j];
+                        }
+
+
+                    }
+                }
+
+            }
+        }
+
+        return rotatedMatrix;
+    }
+
+
+    /**
+     * 将 指定左上角位置的点阵数组 添加至 点阵画布数组中
+     *
+     * @param largeMatrix 点阵画布
+     * @param smallMatrix 数据点阵
+     * @param startRow    起始行
+     * @param startColumn 起始列
+     */
+    public static void mergeDotMatrices(int[][] largeMatrix, int[][] smallMatrix, int startRow, int startColumn) {
+
+        mergeDotMatricesConfuse(largeMatrix, smallMatrix, startRow, startColumn, 0);
+    }
+
+    public static void mergeDotMatrices(int[][] largeMatrix, int[][] smallMatrix, int startRow, int startColumn, int[] type) {
+
+        mergeDotMatricesConfuse(largeMatrix, smallMatrix, startRow, startColumn, 0);
+        removeEdgeResidue(largeMatrix, smallMatrix, startRow, startColumn, type);
+    }
+
+
+    public static void removeEdgeResidue(int[][] largeMatrix, int[][] smallMatrix, int startRow, int startColumn, int[] type) {
+        removeEdgeResidue(largeMatrix, smallMatrix, startRow, startColumn, type, 1);
+    }
+
+
+    /**
+     * 去除 指定点数数组 在 画布数组 中 周边的残影
+     *
+     * @param largeMatrix
+     * @param smallMatrix
+     * @param startRow
+     * @param startColumn
+     * @param type        4位数组,分别为上下左右 new int[]{0,0,0,0},0-为关闭,1-为开启
+     */
+    public static void removeEdgeResidue(int[][] largeMatrix, int[][] smallMatrix, int startRow, int startColumn, int[] type, int interval) {
+        //去除附近的残留
+        int startRows = startRow + 1;
+        int startColumns = startColumn + 1;
+
+        int endRows = startRow + smallMatrix.length;
+        int endColumns = startColumn + smallMatrix[0].length;
+
+        if (endRows > largeMatrix.length) {
+            endRows = largeMatrix.length;
+        }
+
+        if (endColumns > largeMatrix[0].length) {
+            endColumns = largeMatrix[0].length;
+        }
+
+
+        if (type == null) {
+            type = new int[4];
+        }
+
+        //判断四个方向是否有
+        boolean isTop = type[0] == 1;
+        boolean isDown = type[1] == 1;
+        boolean isLeft = type[2] == 1;
+        boolean isRight = type[3] == 1;
+
+
+        while (isTop || isDown || isLeft || isRight) {
+
+            for (int in = 1; in <= interval; in++) {
+                boolean isTopHave = false;
+                int i = startRows - in;
+
+                boolean isDownHave = false;
+                int i2 = endRows + in;
+
+                //转换为坐标
+                i = i - 1;
+                i2 = i2 - 1;
+
+                if (i <= 0) {
+                    i = 0;
+                }
+
+                if (i2 > largeMatrix.length - 1) {
+                    i2 = largeMatrix.length - 1;
+                }
+                if (i > largeMatrix.length - 1) {
+                    i = largeMatrix.length - 1;
+                }
+
+                for (int j = startColumns - 1; j <= endColumns + 1; j++) {
+
+                    if (j - 1 < 0) {
+                        break;
+                    }
+                    if (j - 1 > largeMatrix[0].length - 1) {
+                        break;
+                    }
+
+                    if (isTop) {
+                        if (largeMatrix[i][j - 1] == 1) {
+                            isTopHave = true;
+                            largeMatrix[i][j - 1] = 0;
+                        }
+                    }
+
+                    if (isDown) {
+                        if (largeMatrix[i2][j - 1] == 1) {
+                            isDownHave = true;
+                            largeMatrix[i2][j - 1] = 0;
+                        }
+                    }
+
+                }
+
+                if (isTopHave && in == interval) {
+                    startRows = i + 1;
+                }
+                isTop = isTopHave;
+
+                if (isDownHave && in == interval) {
+                    endRows = i2 + 1;
+                }
+                isDown = isDownHave;
+
+
+                boolean isLeftHave = false;
+                int j = startColumns - in;
+
+                boolean isRightHave = false;
+                int j2 = endColumns + in;
+
+
+                j = j - 1;
+                j2 = j2 - 1;
+
+                if (j < 0) {
+                    j = 0;
+                }
+
+                if (j2 > largeMatrix[0].length - 1) {
+                    j2 = largeMatrix[0].length - 1;
+                }
+                if (j > largeMatrix[0].length - 1) {
+                    j = largeMatrix[0].length - 1;
+                }
+
+                for (i = startRows - 1; i <= endRows + 1; i++) {
+
+                    if (i - 1 < 0) {
+                        break;
+                    }
+                    if (i - 1 > largeMatrix.length - 1) {
+                        break;
+                    }
+
+                    if (isLeft) {
+                        if (largeMatrix[i - 1][j] == 1) {
+                            isLeftHave = true;
+                            largeMatrix[i - 1][j] = 0;
+                        }
+                    }
+
+                    if (isRight) {
+                        if (largeMatrix[i - 1][j2] == 1) {
+                            isRightHave = true;
+                            largeMatrix[i - 1][j2] = 0;
+                        }
+                    }
+                }
+
+                if (isLeftHave && in == interval) {
+                    startColumns = j + 1;
+                }
+                isLeft = isLeftHave;
+                if (isRightHave && in == interval) {
+                    endColumns = j2 + 1;
+                }
+                isRight = isRightHave;
+            }
+        }
+
+
+    }
+
+    /**
+     * 合并指定大小的画布内容 合并的数组中
+     *
+     * @param width
+     * @param height
+     * @param type    0-叠加; 1-后面的覆盖前面的
+     * @param canvass
+     * @return
+     */
+    public static int[][] mergeCanvasBitmap(int width, int height, int type, int[][]... canvass) {
+        int[][] canvasBitmap = new int[height][width];
+
+        for (int i = 0; i < height; i++) {
+            for (int j = 0; j < width; j++) {
+
+                int a = 0;
+                if (type == 0) {
+                    //叠加
+                    for (int[][] canvas : canvass) {
+                        if (canvas.length > i && canvas[0].length > j) {
+                            if (canvas[i][j] == 1) {
+                                a = 1;
+                                break;
+                            }
+                        }
+                    }
+
+                } else if (type == 1) {
+                    //后面的覆盖前面的
+                    for (int k = canvass.length - 1; k >= 0; k--) {
+
+                        int[][] canvas = canvass[k];
+                        if (canvas.length > i && canvas[0].length > j) {
+                            a = canvas[i][j];
+                            break;
+                        }
+
+                    }
+
+                }
+
+                canvasBitmap[i][j] = a;
+            }
+        }
+
+        return canvasBitmap;
+    }
+
+    /**
+     * 合并指定大小的画布内容 合并的数组中只要有一个为1 则为1
+     *
+     * @param width
+     * @param height
+     * @param canvass
+     * @return
+     */
+    public int[][] mergeCanvasBitmap(int width, int height, int[][]... canvass) {
+        int[][] canvasBitmap = new int[height][width];
+
+        for (int i = 0; i < height; i++) {
+            for (int j = 0; j < width; j++) {
+
+                int a = 0;
+                for (int[][] canvas : canvass) {
+                    if (canvas.length > i && canvas[0].length > j) {
+                        if (canvas[i][j] == 1) {
+                            a = 1;
+                            break;
+                        }
+                    }
+                }
+                canvasBitmap[i][j] = a;
+            }
+        }
+        return canvasBitmap;
+    }
+
+
+}

+ 132 - 0
src/main/java/com/yeechart/dotMatrix/canvas/DotMatrixConversionUtil.java

@@ -0,0 +1,132 @@
+package com.yeechart.dotMatrix.canvas;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.ForkJoinPool;
+import java.util.stream.IntStream;
+
+/**
+ * 点阵图 转换 工具
+ */
+public class DotMatrixConversionUtil {
+
+    /**
+     * 二进制点阵转换为16进制点阵数组
+     *
+     * @param twoBytes 字节型
+     * @return
+     */
+    public static byte[] twoTo16Lattice(byte[] twoBytes) {
+
+        int byteCount = twoBytes.length / 8;
+        if (twoBytes.length % 8 > 0) {
+            byteCount = byteCount + 1;
+        }
+        ByteBuffer byteBuffer = ByteBuffer.allocate(byteCount);
+        int byteValue = 0;
+        int bitCount = 0;
+
+        for (int i = 0; i < twoBytes.length; i++) {
+            int bit = twoBytes[i];
+            byteValue = (byteValue << 1) | bit;
+            bitCount++;
+
+            if (bitCount == 8) {
+                byteBuffer.put((byte) byteValue);
+                byteValue = 0;
+                bitCount = 0;
+            }
+        }
+
+        if (bitCount > 0) {
+            byteBuffer.put((byte) byteValue);
+        }
+
+        byteBuffer.flip();
+        byte[] byteArray = new byte[byteBuffer.remaining()];
+        byteBuffer.get(byteArray);
+
+        return byteArray;
+
+
+    }
+
+
+    /**
+     * 16进制点阵图转换为二进制点阵图
+     *
+     * @param sixteenBytes
+     * @return
+     */
+    public static byte[] sixteenTo2Lattice(byte[] sixteenBytes) {
+
+        int length = sixteenBytes.length * 8;
+        byte[] result = new byte[length];
+
+        int batchSize = 1024; // 每批次处理的字节数
+        int numBatches = (sixteenBytes.length + batchSize - 1) / batchSize;
+
+        ForkJoinPool.commonPool().submit(() -> IntStream.range(0, numBatches)
+                .parallel()
+                .forEach(batch -> {
+                    int start = batch * batchSize;
+                    int end = Math.min(start + batchSize, sixteenBytes.length);
+
+                    for (int i = start; i < end; i++) {
+                        for (int b = 7, k = i * 8; b >= 0; b--, k++) {
+                            result[k] = (byte) ((sixteenBytes[i] & (1 << b)) != 0 ? 1 : 0);
+                        }
+                    }
+                })).join();
+
+        return result;
+    }
+
+
+    /**
+     * 二进制点阵转换为16进制点阵数组
+     *
+     * @param canvasBitmapArrays 二位素组
+     * @return
+     */
+    public static byte[] twoTo16Lattice(int[][] canvasBitmapArrays) {
+
+        int[] twoBytes = new int[canvasBitmapArrays.length * canvasBitmapArrays[0].length];
+
+        for (int i = 0; i < canvasBitmapArrays.length; i++) {
+            for (int j = 0; j < canvasBitmapArrays[i].length; j++) {
+                twoBytes[i * canvasBitmapArrays[i].length + j] = canvasBitmapArrays[i][j];
+            }
+        }
+
+        int byteCount = twoBytes.length / 8;
+        if (twoBytes.length % 8 > 0) {
+            byteCount = byteCount + 1;
+        }
+        ByteBuffer byteBuffer = ByteBuffer.allocate(byteCount);
+        int byteValue = 0;
+        int bitCount = 0;
+
+        for (int i = 0; i < twoBytes.length; i++) {
+            int bit = twoBytes[i];
+            byteValue = (byteValue << 1) | bit;
+            bitCount++;
+
+            if (bitCount == 8) {
+                byteBuffer.put((byte) byteValue);
+                byteValue = 0;
+                bitCount = 0;
+            }
+        }
+
+        if (bitCount > 0) {
+            byteBuffer.put((byte) byteValue);
+        }
+
+        byteBuffer.flip();
+        byte[] byteArray = new byte[byteBuffer.remaining()];
+        byteBuffer.get(byteArray);
+
+        return byteArray;
+
+    }
+}

+ 390 - 0
src/main/java/com/yeechart/dotMatrix/canvas/DotMatrixDrawShapeUtil.java

@@ -0,0 +1,390 @@
+package com.yeechart.dotMatrix.canvas;
+
+import java.awt.geom.Point2D;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 绘制图形
+ */
+public class DotMatrixDrawShapeUtil {
+
+
+    /**
+     * 绘制 直/虚 直线
+     *
+     * @param largeMatrix 点阵画布
+     * @param lineWidth   直/虚 的宽度
+     * @param lineSegment 虚线段 的长度  (绘制直线时此处的长度会被无视掉)
+     * @param interval    直/虚 的间隔 (0为绘制的是直线,非0则是虚线)
+     * @param startRow    直/虚 的起始行
+     * @param startColumn 直/虚 的起始列
+     * @param endColumn   直/虚 的结束列
+     */
+    public static void drawLine(int[][] largeMatrix, int lineWidth, int lineSegment, int interval, int startRow, int startColumn, int endColumn) {
+
+        //线条数组
+        int[][] lineMatrix = new int[lineWidth][endColumn - startColumn];
+
+
+        for (int i = 0; i < lineMatrix.length; i++) {
+
+            for (int j = 0; j < lineMatrix[0].length; j++) {
+
+                int value = 0;
+
+                if (interval > 0 && lineSegment > 0) {
+                    //表示绘制的为虚线
+
+                    int part = j % (lineSegment + interval);
+
+                    if (part < lineSegment) {
+                        value = 1;
+                    } else {
+                        value = 0;
+                    }
+
+                } else {
+                    //表示绘制的为直线
+                    value = 1;
+                }
+
+                lineMatrix[i][j] = value;
+
+            }
+
+        }
+
+
+        DotMatrixCanvasUtil.mergeDotMatrices(largeMatrix, lineMatrix, startRow, startColumn);//,new int[]{1,1,1,1}
+
+
+    }
+
+
+    /**
+     * 绘制 直/虚 竖线
+     *
+     * @param largeMatrix 点阵画布
+     * @param lineWidth   直/虚 的宽度
+     * @param lineSegment 虚线段 的长度  (绘制直线时此处的长度会被无视掉)
+     * @param interval    直/虚 的间隔 (0为绘制的是直线,非0则是虚线)
+     * @param startRow    直/虚 的起始行
+     * @param startColumn 直/虚 的起始列
+     * @param endRow      直/虚 的结束行
+     */
+    public static void drawVerticalLine(int[][] largeMatrix, int lineWidth, int lineSegment, int interval, int startRow, int startColumn, int endRow) {
+
+        //线条数组
+        int[][] lineMatrix = new int[endRow - startRow][lineWidth];
+
+
+        for (int i = 0; i < lineMatrix.length; i++) {
+
+            for (int j = 0; j < lineMatrix[0].length; j++) {
+
+                int value = 0;
+
+                if (interval > 0 && lineSegment > 0) {
+                    //表示绘制的为虚线
+
+                    int part = i % (lineSegment + interval);
+
+                    if (part < lineSegment) {
+                        value = 1;
+                    } else {
+                        value = 0;
+                    }
+
+                } else {
+                    //表示绘制的为直线
+                    value = 1;
+                }
+
+                lineMatrix[i][j] = value;
+
+            }
+
+        }
+
+
+        DotMatrixCanvasUtil.mergeDotMatrices(largeMatrix, lineMatrix, startRow, startColumn);//,new int[]{1,1,1,1}
+
+    }
+
+
+    /**
+     * 新贝塞尔曲线算法
+     **/
+    public static List<int[]> computeBezierCurve(List<int[]> controlPoints) {
+
+        float tension = 1f;
+
+        int[][] points = controlPoints.stream()
+                .map(int[]::clone)
+                .collect(Collectors.toList())
+                .toArray(new int[controlPoints.size()][]);
+
+        Map<String, int[]> circleMap = new LinkedHashMap<>();
+
+//        List<int[]> curvePoints = new ArrayList<>();
+
+        //System.out.println(Arrays.deepToString(points));
+
+        for (int i = 0; i < points.length - 1; i++) {
+            Point2D start = new Point2D.Float(points[i][0], points[i][1]);
+            Point2D end = new Point2D.Float(points[i + 1][0], points[i + 1][1]);
+
+            // 检查是否为直线
+            if (isHLinear(start, end)) {
+                // 横向相等
+                for (int j = 0; j < Math.abs(end.getY() - start.getY()); j++) {
+                    //curvePoints.add(new int[]{(int) start.getX(), (int) (start.getY() + j)});
+                    int[] array = new int[]{(int) start.getX(), (int) (start.getY() + j)};
+                    circleMap.put(Arrays.toString(array), array);
+                }
+
+            } else if (isVLinear(start, end)) {
+                // 纵向相等
+                for (int j = 0; j < Math.abs(end.getX() - start.getX()); j++) {
+//                    curvePoints.add(new int[]{(int) (start.getX() + j), (int) start.getY()});
+                    int[] array = new int[]{(int) (start.getX() + j), (int) start.getY()};
+                    circleMap.put(Arrays.toString(array), array);
+                }
+            } else {
+
+                // 判断曲线方向
+                boolean isDownward = start.getX() > end.getX();//X越大 高度越小
+
+                // 计算控制点
+                Point2D control1;
+                Point2D control2;
+//                if (isDownward) {
+//                    // 从起点到中间点,曲线向下凹
+//                    control1 = new Point2D.Float((float) (start.getX() - (end.getY() - start.getY()) / 4 * tension), (float) start.getY());
+//                    control2 = new Point2D.Float((float) (end.getX() + (end.getY() - start.getY()) / 4 * tension), (float) end.getY());
+//
+//                } else {
+//                    // 从中间点到终点,曲线向上凸
+//                    control1 = new Point2D.Float((float) (start.getX() + (end.getY() - start.getY()) / 4 * tension), (float) start.getY());
+//                    control2 = new Point2D.Float((float) (end.getX() - (end.getY() - start.getY()) / 4 * tension), (float) end.getY());
+//
+//                }
+//                System.out.println(control1);
+//                System.out.println(control2);
+//                curvePoints.add(new int[]{(int) control1.getX(), (int) control1.getY()});
+//                curvePoints.add(new int[]{(int) control2.getX(), (int) control2.getY()});
+
+                // 判断曲线方向
+//                boolean isDownward = start.getX() > end.getX(); // 如果起点高于终点,曲线向下凹
+
+                // 计算控制点
+//                Point2D control1;
+//                Point2D control2;
+                if (isDownward) {
+                    // 从起点到中间点,曲线向下凹
+                    control1 = new Point2D.Float((float) (start.getX() - (end.getY() - start.getY()) / 6 * tension), (float) (start.getY() + (end.getY() - start.getY()) / 2 * tension));
+
+                    control2 = new Point2D.Float((float) (end.getX() + (end.getY() - start.getY()) / 6 * tension), (float) (end.getY() - (end.getY() - start.getY()) / 1 * tension));
+
+                } else {
+                    // 从中间点到终点,曲线向上凸
+                    control1 = new Point2D.Float((float) (start.getX() + (end.getY() - start.getY()) / 6 * tension), (float) (start.getY() + (end.getY() - start.getY()) / 1 * tension));
+
+                    control2 = new Point2D.Float((float) (end.getX() - (end.getY() - start.getY()) / 6 * tension), (float) (end.getY() - (end.getY() - start.getY()) / 2 * tension));
+
+                }
+
+//                if(i == 2){
+//                    curvePoints.add(new int[]{(int) control1.getX(), (int) control1.getY()});
+////                    curvePoints.add(new int[]{(int) control2.getX(), (int) control2.getY()});
+//                    //System.out.println(control1);
+//                    System.out.println(control1);
+//                }
+
+                // 根据精度生成贝塞尔曲线上的点
+                for (float t = 0; t <= 1; t += 0.0001f) {
+
+                    double x = (1 - t) * (1 - t) * (1 - t) * start.getX() + 3 * (1 - t) * (1 - t) * t * control1.getX() + 3 * (1 - t) * t * t * control2.getX() + t * t * t * end.getX();
+                    double y = (1 - t) * (1 - t) * (1 - t) * start.getY() + 3 * (1 - t) * (1 - t) * t * control1.getY() + 3 * (1 - t) * t * t * control2.getY() + t * t * t * end.getY();
+
+//                    curvePoints.add(new int[]{(int) x, (int) y});
+                    int[] array = new int[]{(int) x, (int) y};
+                    circleMap.put(Arrays.toString(array), array);
+                }
+
+            }
+        }
+
+
+        return new ArrayList<>(circleMap.values());
+    }
+
+    /**
+     * 判断是否是横线
+     *
+     * @param p1
+     * @param p2
+     * @return
+     */
+    public static boolean isHLinear(Point2D p1, Point2D p2) {
+        return p1.getX() == p2.getX();
+    }
+
+    /**
+     * 判断 是否是竖线
+     *
+     * @param p1
+     * @param p2
+     * @return
+     */
+    public static boolean isVLinear(Point2D p1, Point2D p2) {
+        return p1.getY() == p2.getY();
+    }
+
+
+    /**
+     * 绘制出 指定的圆角矩形
+     *
+     * @param width
+     * @param height
+     * @param cornerRadius 0为不圆角
+     * @return
+     */
+    public static int[][] createRoundedRectangularArray(int width, int height, int cornerRadius) {
+        int[][] grid = new int[height][width];
+
+        // 绘制矩形
+        for (int i = 0; i < height; i++) {
+            Arrays.fill(grid[i], 1);
+        }
+
+        // 圆角算法:剔除不在圆弧曲线的点
+        int radius = cornerRadius;
+        int centerX = cornerRadius;
+        int centerY = cornerRadius;
+
+        for (int y = 0; y <= radius; y++) {
+            for (int x = 0; x <= radius; x++) {
+                if (distance(x, y, centerX, centerY) > radius) {
+                    // 左上角
+                    grid[y][x] = 0;
+                    // 右上角
+                    grid[y][width - x - 1] = 0;
+                    // 左下角
+                    grid[height - y - 1][x] = 0;
+                    // 右下角
+                    grid[height - y - 1][width - x - 1] = 0;
+                }
+            }
+        }
+
+        return grid;
+    }
+
+    /**
+     * 计算出起点坐标和终点坐标之间的圆弧范围
+     *
+     * @param x1
+     * @param y1
+     * @param x2
+     * @param y2
+     * @return
+     */
+    public static double distance(int x1, int y1, int x2, int y2) {
+        int dx = x1 - x2;
+        int dy = y1 - y2;
+        return Math.sqrt(dx * dx + dy * dy);
+    }
+
+
+    /**
+     * 绘制 圆形 点阵数组
+     *
+     * @param radius 圆得半径
+     * @return
+     */
+    public static int[][] createCustomRadiusArray(int radius) {
+        int[][] grid = new int[radius * 2][radius * 2];
+
+        int centerX = radius; // 圆心 x 坐标
+        int centerY = radius; // 圆心 y 坐标
+
+        int xStart = 0;
+        int xEnd = Math.min(radius * 2 - 1, centerX + radius);
+        int yStart = 0;
+        int yEnd = Math.min(radius * 2 - 1, centerY + radius);
+
+        double sqrRadius = radius * radius;
+
+        for (int y = yStart; y <= yEnd; y++) {
+            for (int x = xStart; x <= xEnd; x++) {
+                double distanceSqr = (x - centerX) * (x - centerX) + (y - centerY) * (y - centerY);
+                if (distanceSqr <= sqrRadius) {
+                    grid[y][x] = 1;
+                }
+            }
+        }
+
+        return grid;
+    }
+
+
+    /**
+     * 绘制出 指定的 底部为弧形的 三角形
+     *
+     * @param width        三
+     * @param height
+     * @param cornerRadius 弧线的半径
+     * @return
+     */
+    public static int[][] createCustomTriangleArray(int width, int height, int cornerRadius) {
+        int[][] grid = new int[height][width];
+
+        // 绘制三角形
+        int top = 0; // 三角形顶部位置
+        int bottom = height - 1; // 三角形底部位置
+
+        // 绘制等腰三角形
+        for (int i = top; i <= bottom; i++) {
+            int rowStart = (width - i) / 2; // 当前行的起始位置
+            int rowEnd = rowStart + i; // 当前行的结束位置
+
+            for (int j = rowStart; j <= rowEnd; j++) {
+                grid[i][j] = 1; // 填充等腰三角形内部
+            }
+        }
+
+        //得出底部的左右两个点
+        int start = 0;
+        int end = 0;
+        for (int i = 0; i < grid[0].length; i++) {
+            if (grid[height - 1][i] == 1) {
+                if (start == 0) {
+                    start = i;
+                } else {
+                    end = i;
+                }
+            }
+        }
+
+        //算出圆弧的圆点
+        double midX = (height + height) / 2.0; // AB线中点 x 坐标为两点中点的 x 坐标
+        double midY = (start + end) / 2.0; // AB线中点 y 坐标为两点中点的 y 坐标  限定此点为圆点的Y轴
+
+        double centerX = (int) (midX + Math.sqrt((cornerRadius * cornerRadius) - (end - midY) * (end - midY)));//使用勾股定理xzp
+
+        //替换圆弧内的点
+        for (int i = 0; i < height; i++) {
+            for (int j = 0; j < width; j++) {
+                // 判断当前点是否在圆弧范围内
+                if (Math.sqrt(Math.pow(i - centerX, 2) + Math.pow(j - midY, 2)) < cornerRadius) {
+                    grid[i][j] = 0; // 设置为0,表示在圆弧内部
+                }
+            }
+        }
+
+        return grid;
+    }
+
+}

+ 397 - 0
src/main/java/com/yeechart/dotMatrix/canvas/DotMatrixDrawtextUtil.java

@@ -0,0 +1,397 @@
+package com.yeechart.dotMatrix.canvas;
+
+import com.yeechart.dotMatrix.font.XZPFontLoaderUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 绘制文字
+ */
+@Component
+public class DotMatrixDrawtextUtil {
+
+    @Autowired
+    private XZPFontLoaderUtil xzpFontLoaderUtil;
+
+    /**
+     * 绘制文字 横向
+     *
+     * @param bitmapData  二进制点阵画布数组
+     * @param text        文本内容
+     * @param startRow    文本内容左上角的横坐标 (列)
+     * @param startColumn 文本内容左上角的纵坐标  (行)
+     * @param fontSize    文本的字体大小(不写,或者不合适时将自动使用字体库中该文本的最小的字体样式)
+     * @return 绘制之后的二进制点阵画布数组
+     */
+    public  void drawingText(int[][] bitmapData, String text, int startRow, int startColumn, int fontSize) {
+        int[][] fontBinaryArray = getManyFontBinaryArray(text, fontSize, fontSize, true);
+        DotMatrixCanvasUtil.mergeDotMatrices(bitmapData, fontBinaryArray, startRow, startColumn);
+
+    }
+
+    /**
+     * 绘制文字 横向
+     *
+     * @param bitmapData        二进制点阵画布数组
+     * @param text              文本内容
+     * @param startRow          文本内容左上角的横坐标 (列)
+     * @param startColumn       文本内容左上角的纵坐标  (行)
+     * @param fontSize          文本的字体大小(不写,或者不合适时将自动使用字体库中该文本的最小的字体样式)
+     * @param noChineseFontSize 当遇到非中文字时的字体大小
+     * @return 绘制之后的二进制点阵画布数组
+     */
+
+    public  void drawingText(int[][] bitmapData, String text, int startRow, int startColumn, int fontSize, int noChineseFontSize) {
+
+        int[][] fontBinaryArray = getManyFontBinaryArray(text, fontSize, noChineseFontSize, true);
+
+
+        DotMatrixCanvasUtil.mergeDotMatrices(bitmapData, fontBinaryArray, startRow, startColumn);
+
+
+    }
+
+
+    /**
+     * 绘制文本,返回二进制点阵画布数组
+     *
+     * @param text
+     * @param fontSize
+     * @param noChineseFontSize
+     * @return
+     */
+    public  int[][] drawingText(String text, int fontSize, int noChineseFontSize) {
+        int[][] fontBinaryArray = getManyFontBinaryArray(text, fontSize, noChineseFontSize, true);
+
+        return fontBinaryArray;
+    }
+
+    /**
+     * 绘制文本,返回二进制点阵画布数组
+     *
+     * @param text
+     * @param fontSize
+     * @param noChineseFontSize
+     * @param isHorizontal
+     * @return
+     */
+    public  int[][] drawingText(String text, int fontSize, int noChineseFontSize, boolean isHorizontal) {
+        int[][] fontBinaryArray = getManyFontBinaryArray(text, fontSize, noChineseFontSize, isHorizontal);
+
+        return fontBinaryArray;
+    }
+
+    /**
+     * 获取多个字体的点阵数组
+     *
+     * @param text
+     * @param font
+     * @return
+     */
+    public  int[][] getManyFontBinaryArray(String text, int font, int noChineseFontSize, boolean isHorizontal) {
+        char[] chars = text.toCharArray();
+        List<int[][]> binaryList = new ArrayList<>();
+        for (char c : chars) {
+            String singleChar = String.valueOf(c);
+            String encoding = xzpFontLoaderUtil.getEncoding(singleChar, "GB2312");
+            if (encoding == null) {
+                System.out.println("没有找到对应的字 : " + encoding);
+                break;
+            }
+            //非中文
+            int font2 = font;
+            if (encoding.length() <= 2) {
+                font2 = noChineseFontSize;
+            }
+            int[][] binaryArray = xzpFontLoaderUtil.getSingleFontBinaryArray(encoding, font2);
+
+            if (binaryArray != null) {
+                //进行倍数放大
+                binaryArray = DotMatrixCanvasUtil.scaleDotMatrix(binaryArray, font2);
+                binaryList.add(binaryArray);
+            }
+        }
+
+        int[][] binaryArray = null;
+
+        int rowsMax = binaryList.get(0).length;
+        int columnsMax = binaryList.get(0)[0].length;
+
+        for (int i = 0; i < binaryList.size(); i++) {
+            int[][] b = binaryList.get(i);
+            rowsMax = Math.max(rowsMax, b.length);
+            columnsMax = Math.max(columnsMax, b[0].length);
+        }
+
+        for (int[][] b : binaryList) {
+            if (binaryArray == null) {
+                binaryArray = b;
+            } else {
+                binaryArray = DotMatrixCanvasUtil.mergeDotMatricesWidth(rowsMax, columnsMax, binaryArray, b, isHorizontal);
+            }
+        }
+
+
+        return binaryArray;
+
+    }
+
+
+    /**
+     * 对于中文是竖向排列的,对于其中的英文和数字进行旋转
+     *
+     * @param text
+     * @param fontSize
+     * @param noChineseFontSize
+     * @return
+     */
+    public  int[][] drawingChineseAndNonChinese(String text, int fontSize, int noChineseFontSize) {
+
+        //全由数字或英文组成 将其倒转
+        char[] chars = text.toCharArray();
+        int fontWidth = 0;
+        int fontHeight = 0;
+        int maxHeight = 0;
+
+        List<int[][]> textFontBinaryArray = new ArrayList<>();
+        for (int i = 0; i < chars.length; i++) {
+            String str = String.valueOf(chars[i]);
+
+            int[][] charFontBinaryArray = drawingText(str, fontSize, noChineseFontSize, false);
+
+            if (xzpFontLoaderUtil.isAlphanumeric(str)) {
+
+                fontHeight += charFontBinaryArray[0].length;
+
+                if (fontWidth < charFontBinaryArray.length) {
+                    fontWidth = charFontBinaryArray.length;
+                }
+
+                if (maxHeight < charFontBinaryArray[0].length) {
+                    maxHeight = charFontBinaryArray[0].length;
+                }
+
+                //需要旋转
+                charFontBinaryArray = DotMatrixCanvasUtil.rotateDotMatrix(charFontBinaryArray, 90);
+            } else {
+                //无需旋转
+                fontHeight += charFontBinaryArray.length;
+
+                if (fontWidth < charFontBinaryArray[0].length) {
+                    fontWidth = charFontBinaryArray[0].length;
+                }
+
+                if (maxHeight < charFontBinaryArray.length) {
+                    maxHeight = charFontBinaryArray.length;
+                }
+
+            }
+
+            textFontBinaryArray.add(charFontBinaryArray);
+        }
+
+        //将文字合并
+        int[][] fontBinaryArray = new int[fontHeight]
+                [fontWidth];
+
+        for (int i = 0; i < textFontBinaryArray.size(); i++) {
+            int[][] fontBinaryArray2 = textFontBinaryArray.get(i);
+
+            DotMatrixCanvasUtil.mergeDotMatrices(
+                    fontBinaryArray,
+                    fontBinaryArray2,
+                    maxHeight * i,
+                    fontBinaryArray[0].length / 2 - fontBinaryArray2[0].length / 2);
+        }
+
+        return fontBinaryArray;
+    }
+
+
+    /**
+     * 倒序且旋转90度去绘制竖向的文字
+     *
+     * @param text
+     * @param noChineseFontSize
+     * @return
+     */
+    public  int[][] drawingNonChinese(String text, int noChineseFontSize) {
+
+        char[] chars = text.toCharArray();
+        int fontWidth = 0;
+        int fontHeight = 0;
+        int maxHeight = 0;
+        //将每个字生成之后旋转270度
+        List<int[][]> textFontBinaryArray = new ArrayList<>();
+        for (int i = chars.length - 1; i >= 0; i--) {
+            String str = String.valueOf(chars[i]);
+            int[][] charFontBinaryArray = drawingText(str, noChineseFontSize, noChineseFontSize, false);
+
+            if (fontWidth < charFontBinaryArray.length) {
+                fontWidth = charFontBinaryArray.length;
+            }
+            fontHeight += charFontBinaryArray[0].length;
+
+            if (maxHeight < charFontBinaryArray[0].length) {
+                maxHeight = charFontBinaryArray[0].length;
+            }
+
+            charFontBinaryArray = DotMatrixCanvasUtil.rotateDotMatrix(charFontBinaryArray, 90);
+
+            textFontBinaryArray.add(charFontBinaryArray);
+        }
+
+        //将文字合并
+        int[][] fontBinaryArray = new int[fontHeight]
+                [fontWidth];
+
+        for (int i = 0; i < textFontBinaryArray.size(); i++) {
+            int[][] fontBinaryArray2 = textFontBinaryArray.get(i);
+
+            DotMatrixCanvasUtil.mergeDotMatrices(
+                    fontBinaryArray,
+                    fontBinaryArray2,
+                    maxHeight * i,
+                    fontBinaryArray[0].length / 2 - fontBinaryArray2[0].length / 2);
+        }
+
+        return fontBinaryArray;
+    }
+
+
+    /**
+     * 限制文本在单行 将文本限制在一定的范围内,超出范围的使用...代替
+     *
+     * @param text              文本内容
+     * @param fontSize          字体大小
+     * @param noChineseFontSize 非中文的字体大小
+     * @param maxWidth          一行的最大长度
+     * @return
+     */
+    public  String changeTextOneLine(String text, int fontSize, int noChineseFontSize, int maxWidth) {
+
+        return changeTextMoreLine(text, fontSize, noChineseFontSize, maxWidth, 1).get(0);
+
+    }
+
+    /**
+     * 限制文本在多行 将文本限制在一定的范围内,超出范围的使用...代替
+     *
+     * @param text              文本内容
+     * @param fontSize          字体大小
+     * @param noChineseFontSize 非中文的字体大小
+     * @param maxWidth          一行的最大长度
+     * @param maxLine           最多支持多少行
+     * @return
+     */
+    public  List<String> changeTextMoreLine(String text, int fontSize, int noChineseFontSize, int maxWidth, int maxLine) {
+
+        List<String> dataList = new ArrayList<>();
+        //首先计算文本的长度
+        try {
+
+
+            char[] chars = text.toCharArray();
+
+            List<String> textList = new ArrayList<>();//记录每个字符
+            List<Integer> textLengthList = new ArrayList<>();//记录每个字符的大小
+
+            int textSumLength = 0;
+
+            for (char c : chars) {
+
+                String singleChar = String.valueOf(c);
+
+                int textLength = 0;
+
+                byte[] bytes = singleChar.getBytes("GB2312");
+
+                StringBuilder hex = new StringBuilder();
+
+                for (byte b : bytes) {
+                    hex.append(String.format("%02x", b));
+                }
+
+                if (hex.toString().length() <= 2) {
+                    //非中文
+                    textLength = noChineseFontSize;
+                } else {
+                    //中文
+                    textLength = fontSize;
+                }
+
+                textList.add(singleChar);
+                textLengthList.add(textLength);
+                textSumLength = textSumLength + textLength;
+
+            }
+
+
+            //将字段进行分装
+            String data = "";
+            int dataSize = 0;
+            int endNumber = 0;
+
+            int line = 1;
+
+            for (int i = 0; i < textList.size(); i++) {
+                dataSize = dataSize + textLengthList.get(i);
+                if (dataSize <= maxWidth) {
+                    data = data + textList.get(i);
+                } else {
+                    if (line < maxLine) {
+                        dataList.add(data);
+                        data = textList.get(i);
+                        dataSize = textLengthList.get(i);
+                        endNumber = i;//记录换行点 该点为换行的第一个字符的下标
+
+                        line++;
+                    } else {
+                        break;//无需再循环 因为已经超出了
+                    }
+                }
+            }
+
+            if (textSumLength <= maxWidth * maxLine) {
+                //字符长度小于限制长度 无需处理 直接返回
+                dataList.add(data);//将最后一项 添加至列表
+                return dataList;
+            }
+
+            //需要进行省略处理
+            String substituteSymbol = ".";//省略点需要三个  [・] 这个点间隔太大 且此点为中文点 [·]这个点找不到编码 所以暂时使用[.]这个点
+            data = "";//重新初始化
+            dataSize = 0;//重新初始化
+
+            //此处可以优化为从后面开始计数的方式 暂时没时间优化
+            for (int i = endNumber; i < textList.size(); i++) {
+                dataSize = dataSize + textLengthList.get(i);
+                if ((dataSize + 3 * noChineseFontSize) <= maxWidth) {
+
+                    data = data + textList.get(i);
+
+                    int dataSize2 = dataSize + textLengthList.get(i + 1);
+                    if ((dataSize2 + 3 * noChineseFontSize) > maxWidth) {
+                        //跳出循环 找到了拼接点
+                        break;
+                    }
+                }
+            }
+
+
+            dataList.add(data + substituteSymbol + substituteSymbol + substituteSymbol);//将最后一项 添加至列表
+            return dataList;
+
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return dataList;
+    }
+
+
+}

+ 324 - 0
src/main/java/com/yeechart/dotMatrix/canvas/DotMatrixImageUtil.java

@@ -0,0 +1,324 @@
+package com.yeechart.dotMatrix.canvas;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.concurrent.ForkJoinPool;
+import java.util.stream.IntStream;
+
+/**
+ * 点阵图 画布转换 工具类
+ */
+public class DotMatrixImageUtil {
+
+
+    /**
+     * 根据图片绘制点阵图
+     *
+     * @param resourcePath
+     * @param width
+     * @param height
+     * @param tolerance    容差
+     * @return
+     */
+    public static byte[] canvasImageBitmapArrays(String resourcePath, int width, int height, int tolerance) {
+        try {
+            //因为是墨水屏 所有使用 灰度模型 BufferedImage.TYPE_BYTE_GRAY 但是灰度模型的颜色不准 所以使用BufferedImage.TYPE_INT_ARGB_PRE
+            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
+            Graphics2D graphics = image.createGraphics();
+
+            // 设置背景色为白色
+            graphics.setBackground(Color.WHITE);
+            graphics.clearRect(0, 0, image.getWidth(), image.getHeight());
+
+            // 加载图片
+            InputStream inputStream = DotMatrixImageUtil.class.getClassLoader().getResourceAsStream(resourcePath);
+
+            if (inputStream == null) {
+                throw new RuntimeException("文件未找到!");
+            }
+
+            BufferedImage originalImage = ImageIO.read(inputStream);
+            //绘制图片
+            graphics.drawImage(originalImage, 0, 0, width, height, Color.WHITE, null);
+
+
+            //获取点阵数组
+            byte[] twoBytes = DotMatrixImageUtil.convertImageToPixelArray(image, tolerance);
+
+
+            return twoBytes;
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        return null;
+    }
+
+
+    /**
+     * 将图片转换为点阵图
+     *
+     * @param bufferedImage
+     * @param tolerance     容差
+     * @return
+     */
+    public static byte[] convertImageToPixelArray(BufferedImage bufferedImage, int tolerance) {
+
+        int width = bufferedImage.getWidth();
+        int height = bufferedImage.getHeight();
+        byte[] pixelArray = new byte[width * height];
+
+        DataBuffer dataBuffer = bufferedImage.getData().getDataBuffer();
+
+        if (dataBuffer instanceof DataBufferByte) {
+            byte[] pixels = ((DataBufferByte) dataBuffer).getData();
+            processPixels(pixels, width, height, pixelArray, tolerance);
+        } else if (dataBuffer instanceof DataBufferInt) {
+            int[] pixels = ((DataBufferInt) dataBuffer).getData();
+            processPixels(pixels, width, height, pixelArray, tolerance);
+        }
+
+
+        return pixelArray;
+    }
+
+    private static void processPixels(byte[] pixels, int width, int height, byte[] pixelArray, int tolerance) {
+        ForkJoinPool.commonPool().submit(() -> IntStream.range(0, height)
+                .parallel()
+                .forEach(y -> {
+                    for (int x = 0; x < width; x++) {
+                        int index = y * width + x;
+                        int pixelIndex = index * 3;
+
+                        int red = pixels[pixelIndex] & 0xFF;
+                        int green = pixels[pixelIndex + 1] & 0xFF;
+                        int blue = pixels[pixelIndex + 2] & 0xFF;
+
+                        boolean isWhite = (red >= 255 - tolerance) && (green >= 255 - tolerance) && (blue >= 255 - tolerance);
+                        pixelArray[index] = (byte) (isWhite ? 0x00 : 0x01);
+                    }
+                })).join();
+    }
+
+    private static void processPixels(int[] pixels, int width, int height, byte[] pixelArray, int tolerance) {
+        ForkJoinPool.commonPool().submit(() -> IntStream.range(0, height)
+                .parallel()
+                .forEach(y -> {
+                    for (int x = 0; x < width; x++) {
+                        int index = y * width + x;
+                        int pixel = pixels[index];
+
+                        int red = (pixel >> 16) & 0xFF;
+                        int green = (pixel >> 8) & 0xFF;
+                        int blue = pixel & 0xFF;
+
+                        boolean isWhite = (red >= 255 - tolerance) && (green >= 255 - tolerance) && (blue >= 255 - tolerance);
+                        pixelArray[index] = (byte) (isWhite ? 0x00 : 0x01);
+                    }
+                })).join();
+    }
+
+
+    /**
+     * 判断像素是否是白色
+     *
+     * @param pixel
+     * @return
+     */
+//    private int tolerance = 50;//白色 容差
+    private static boolean isWhite(int pixel, int tolerance) {
+
+        int alpha = (pixel >> 24) & 0xFF;
+        int red = (pixel >> 16) & 0xFF;
+        int green = (pixel >> 8) & 0xFF;
+        int blue = pixel & 0xFF;
+
+//        if(pixel == Color.WHITE.getRGB()
+////                ||
+////                ( ( ( pixel >> 24 ) & 0xFF ) == 0 )//pixel == Color.TRANSPARENT
+//        ){
+//            return true;
+//        }
+        //判断是否是纯白
+        if ((red == 255 && green == 255 && blue == 255)) {   //|| alpha == 0
+            return true;
+        }
+
+        //判断是完全透明
+//        if(alpha == 0){
+////            System.out.println("走了判断是否是纯透明");
+//            return true;
+//        }
+
+
+//        int tolerance = 220;//容差  84     140
+
+
+//
+//        // 判断像素是否在白色范围内
+        boolean isWhite = (red >= (255 - tolerance)) && (green >= (255 - tolerance)) && (blue >= (255 - tolerance));
+
+        return isWhite;
+
+//        return false;
+
+    }
+
+
+    /**
+     * 将点阵图转换为图片
+     *
+     * @param twoBytes
+     * @return
+     */
+    public static BufferedImage pixelArrayToConvertImage(byte[] twoBytes, int width, int height) {
+
+        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
+
+        for (int y = 0; y < image.getHeight(); y++) {
+            for (int x = 0; x < image.getWidth(); x++) {
+
+                byte pixel = twoBytes[y * image.getWidth() + x];
+
+                image.setRGB(x, y, pixel == 0x01 ? Color.BLACK.getRGB() : Color.WHITE.getRGB());
+
+            }
+        }
+        return image;
+
+    }
+
+
+    public static BufferedImage pixelArrayToConvertImage(int[][] canvasBitmapArrays) {
+
+        int width = canvasBitmapArrays[0].length;
+
+        int height = canvasBitmapArrays.length;
+
+        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
+
+        for (int y = 0; y < height; y++) {
+            for (int x = 0; x < width; x++) {
+
+                int pixel = canvasBitmapArrays[y][x];
+
+                image.setRGB(x, y, pixel == 0x01 ? Color.BLACK.getRGB() : Color.WHITE.getRGB());
+
+            }
+        }
+        return image;
+
+    }
+
+
+    /**
+     * 将画布数组转化为 点阵数组
+     *
+     * @param canvasBitmapArrays 这个数组的内容需要强转为byte的
+     * @return
+     */
+    public static byte[] canvasBitmapArraysToTwo(int[][] canvasBitmapArrays) {
+        int width = canvasBitmapArrays[0].length;
+        int height = canvasBitmapArrays.length;
+
+        byte[] data = new byte[width * height];
+
+        for (int i = 0; i < height; i++) {
+
+            for (int j = 0; j < width; j++) {
+
+                data[i * width + j] = (byte) canvasBitmapArrays[i][j];
+
+            }
+        }
+
+        return data;
+    }
+
+
+    /**
+     * 将点阵数组转换为 画布数组
+     *
+     * @param data
+     * @param width
+     * @param height
+     * @return
+     */
+    public static int[][] twoToCanvasBitmapArrays(byte[] data, int width, int height) {
+        int[][] canvasBitmapArrays = new int[height][width];
+
+        for (int i = 0; i < height; i++) {
+
+            for (int j = 0; j < width; j++) {
+
+                canvasBitmapArrays[i][j] = data[i * width + j];
+
+            }
+        }
+        return canvasBitmapArrays;
+    }
+
+
+    /**
+     * 将 画布进行横竖切换 即 画布 的横竖屏进行切换 类似于将画布进行旋转 竖的旋转-90° or 横的旋转90°
+     *
+     * @param data
+     * @return
+     */
+    public static int[][] screenHorizontalToVertical(int[][] data) {
+        //首先获取原画布的宽高
+        int width = data[0].length;
+        int height = data.length;
+
+        int[][] canvasBitmapArrays = new int[width][height];
+
+        for (int i = 0; i < width; i++) {
+            for (int j = 0; j < height; j++) {
+                if (height > width) {
+                    //竖向转横向 -90°
+//                    canvasBitmapArrays[i][j] = data[height-j-1][width-i-1];  这个效果为镜像 且角度为90°
+                    canvasBitmapArrays[i][j] = data[j][width - i - 1];
+                } else {
+                    //横向转竖向 90°
+                    canvasBitmapArrays[i][j] = data[height - 1 - j][i];
+                }
+
+            }
+        }
+
+        return canvasBitmapArrays;
+    }
+
+
+    /**
+     * 将画布倒装
+     *
+     * @param data
+     * @return
+     */
+    public static int[][] screenFlip(int[][] data) {
+        //首先获取原画布的宽高
+        int width = data[0].length;
+        int height = data.length;
+
+        int[][] canvasBitmapArrays = new int[height][width];
+
+        for (int i = 0; i < height; i++) {
+            for (int j = 0; j < width; j++) {
+
+                canvasBitmapArrays[i][j] = data[height - 1 - i][width - 1 - j];
+
+            }
+        }
+
+        return canvasBitmapArrays;
+    }
+
+}

+ 64 - 0
src/main/java/com/yeechart/dotMatrix/crc/CustomCRC32Util.java

@@ -0,0 +1,64 @@
+package com.yeechart.dotMatrix.crc;
+
+/**
+ * xzp 配置暂时为默认 后续有需要可增加自定义接口实现自定义配置
+ * 暂不支持配置多项式公式,当前使用的为 x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1
+ * 自定义 CRC32工具类
+ */
+public class CustomCRC32Util {
+    private static final int WIDTH = 32;//宽度位数
+    private static final int POLYNOMIAL = 0x04C11DB7;//多项式POLY(HEX)
+    private static final long INITIAL_VALUE = 0xFFFFFFFFL;//初始值
+    private static final long FINAL_XOR_VALUE = 0xFFFFFFFFL;//结果异或值
+    private static final boolean REVERSE_DATA = true;//数据反转
+    private static final boolean REVERSE_OUTPUT = true;//输出反转
+
+    public static long calculateCRC32(byte[] bytes) {
+        long crc = INITIAL_VALUE;
+
+        if (REVERSE_DATA) {
+            bytes = reverseBytes(bytes);
+        }
+
+        for (byte b : bytes) {
+            crc ^= ((long) b) << (WIDTH - 8);
+            for (int j = 0; j < 8; j++) {
+                if ((crc & 0x80000000L) != 0) {
+                    crc = (crc << 1) ^ POLYNOMIAL;
+                } else {
+                    crc <<= 1;
+                }
+            }
+        }
+
+        if (REVERSE_OUTPUT) {
+            crc = reverseBits(crc);
+        }
+
+        return crc ^ FINAL_XOR_VALUE;
+    }
+
+    private static byte[] reverseBytes(byte[] bytes) {
+        byte[] reversedBytes = new byte[bytes.length];
+        for (int i = 0; i < bytes.length; i++) {
+            reversedBytes[i] = reverseBits(bytes[i]);
+        }
+        return reversedBytes;
+    }
+
+    private static byte reverseBits(byte b) {
+        int reversed = 0;
+        for (int i = 0; i < 8; i++) {
+            reversed = (reversed << 1) | ((b >> i) & 1);
+        }
+        return (byte) reversed;
+    }
+
+    private static long reverseBits(long value) {
+        long reversed = 0;
+        for (int i = 0; i < WIDTH; i++) {
+            reversed = (reversed << 1) | ((value >> i) & 1);
+        }
+        return reversed;
+    }
+}

+ 363 - 0
src/main/java/com/yeechart/dotMatrix/font/XZPFontLoaderUtil.java

@@ -0,0 +1,363 @@
+package com.yeechart.dotMatrix.font;
+
+
+import com.yeechart.dotMatrix.font.bean.FontObject;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * 自定义字体库 XZP
+ */
+
+
+@Component
+public class XZPFontLoaderUtil {
+
+
+    private List<FontObject> fontObjects = new ArrayList<>();
+    private Map<String, List<FontObject>> fontMap = new HashMap<>();
+
+
+    @PostConstruct
+    public void init() {
+        String filePath = "fonts/font_2024_03_15.DAT";
+
+        // 获取资源文件的输入流
+        InputStream inputStream = XZPFontLoaderUtil.class.getClassLoader().getResourceAsStream(filePath);
+
+        if (inputStream == null) {
+            throw new RuntimeException("文件未找到!");
+        }
+
+        try {
+            fontObjects = parseFontFile(inputStream);
+            fontMap = fontlistToMap(fontObjects);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        } finally {
+            try {
+                inputStream.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+
+    /**
+     * 得到 字符串 指定的编码集 编号
+     *
+     * @param text
+     * @return
+     */
+    public  String getEncoding(String text, String charsetName) {
+        String encoding = "";
+        try {
+            byte[] bytes = String.valueOf(text).getBytes(charsetName);
+            StringBuilder hex = new StringBuilder();
+            if (bytes != null && bytes.length > 0) {
+                // 将字节转换为16进制字符串
+                for (byte b : bytes) {
+                    hex.append(String.format("%02x", b));
+                }
+//                 System.out.println(text+"  GB2312编码: " + hex.toString());
+            }
+
+            encoding = hex.toString();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return encoding;
+    }
+
+    /**
+     * 判断字符串是否仅由英文字母构成
+     *
+     * @param str
+     * @return
+     */
+    public  boolean isAllLetters(String str) {
+        return str.matches("^[a-zA-Z]+$");
+    }
+
+    /**
+     * 判断字符串是否仅由数字组成
+     *
+     * @param str
+     * @return
+     */
+    public  boolean isAllDigits(String str) {
+        return str.matches("^[0-9]+$");
+    }
+
+    /**
+     * 判断字符串是否仅由英文字母和数字组成
+     *
+     * @param str
+     * @return
+     */
+    public  boolean isAlphanumeric(String str) {
+        return str.matches("^[a-zA-Z0-9]+$");
+    }
+
+    /**
+     * 将 字库点阵列表 转换为 map
+     *
+     * @param fontObjectList
+     * @return
+     */
+    private Map<String, List<FontObject>> fontlistToMap(List<FontObject> fontObjectList) {
+        Map<String, List<FontObject>> fontMap = new HashMap<>();
+        for (FontObject fontObject : fontObjectList) {
+            List<FontObject> fontObjects1;
+            if (fontMap.containsKey(fontObject.getEncoding())) {
+                fontObjects1 = fontMap.get(fontObject.getEncoding());
+                fontObjects1.add(fontObject);
+            } else {
+                fontObjects1 = new ArrayList<>();
+                fontObjects1.add(fontObject);
+            }
+            fontMap.put(fontObject.getEncoding(), fontObjects1);
+        }
+
+        return fontMap;
+    }
+
+    private List<FontObject> parseFontFile(InputStream inputStream) {
+        List<FontObject> fontObjects = new ArrayList<>();
+
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
+            String line;
+            FontObject fontObject = null;
+
+            Pattern pattern = null;
+            Matcher matcher = null;
+
+            //一行行读取
+            while ((line = reader.readLine()) != null) {
+
+                //这是第一行
+                if (line.contains("[Paint_DrawChar] font lib start") || line.contains("[Paint_DrawChar_CN] font lib start")) {
+
+                    fontObject = new FontObject();
+                    fontObjects.add(fontObject);
+
+                    //将字符串去掉头
+                    line = line.replace("[Paint_DrawChar] font lib start", "");
+                    line = line.replace("[Paint_DrawChar_CN] font lib start", "");
+
+                    //按照逗号隔开
+//                    String[] lineArray = line.split(",");
+
+
+                    // 解析fontEncoding和encoding
+                    pattern = Pattern.compile("\\[(\\S+) = (0x[\\da-fA-F]+(?:\\s+0x[\\da-fA-F]+)*)\\]");
+                    matcher = pattern.matcher(line);
+
+                    if (matcher.find()) {
+                        // 解析fontEncoding
+                        fontObject.setFontEncoding(matcher.group(1));
+                        // 解析encoding
+                        fontObject.setEncoding(matcher.group(2).replace("0x", "").replace(" ", ""));
+
+                    }
+
+                    // 解析type
+                    pattern = Pattern.compile("\\[type\\s=\\s(.*?)\\]");
+                    matcher = pattern.matcher(line);
+                    if (matcher.find()) {
+                        fontObject.setType(matcher.group(1));
+                    }
+
+                    // 解析fontWidth和fontHeight
+                    pattern = Pattern.compile("width=\\s(.*?)\\s,\\sheight=\\s(.*?)\\s");
+                    matcher = pattern.matcher(line);
+                    if (matcher.find()) {
+                        fontObject.setFontWidth(Integer.parseInt(matcher.group(1)));
+                        fontObject.setFontHeight(Integer.parseInt(matcher.group(2)));
+                    }
+
+                } else if (line.contains("font lib end!!")) {
+                    fontObject = null;
+
+                } else if (fontObject != null) {
+                    // 解析hexArrays
+                    pattern = Pattern.compile("(0x[\\da-fA-F]+)\\s");
+                    matcher = pattern.matcher(line);
+
+                    while (matcher.find()) {
+                        fontObject.addHexArray(matcher.group(1));
+                    }
+
+                }
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        return fontObjects;
+    }
+
+    /**
+     * 转换为完整的一维的二进制
+     *
+     * @param hexStrings
+     * @return
+     */
+    private int[] convertToBinaryArray(List<String> hexStrings) {
+        int numRows = hexStrings.size();
+        int[] binaryArray = new int[numRows * 8];
+
+        for (int i = 0; i < numRows; i++) {
+
+            String hexString = hexStrings.get(i);
+            int decimalValue = Integer.parseInt(hexString.substring(2), 16);
+            String binaryString = String.format("%8s", Integer.toBinaryString(decimalValue)).replace(' ', '0');
+
+            for (int j = 0; j < 8; j++) {
+
+                binaryArray[i * 8 + j] = Integer.parseInt(String.valueOf(binaryString.charAt(j)));
+            }
+        }
+        return binaryArray;
+    }
+
+    /**
+     * 转换为指定像素的二进制
+     *
+     * @param hexStrings
+     * @param fontWidth
+     * @param fontHeight
+     * @return
+     */
+    private int[][] convertToBinaryArray(List<String> hexStrings, int fontWidth, int fontHeight) {
+
+        int[] binaryArray1 = convertToBinaryArray(hexStrings);
+
+        //System.out.println("该字体的完整的2进制点阵: "+ Arrays.toString(binaryArray1));
+
+        int[][] binaryArray = new int[fontHeight][fontWidth];
+
+        //获取每行的点数
+        int pooints = fontWidth / 8;
+        if (fontWidth % 8 > 0) {
+            pooints = pooints + 1;
+        }
+
+        //先转换为完整二进制
+        for (int i = 0; i < fontHeight; i++) {
+            for (int j = 0; j < fontWidth; j++) {
+                binaryArray[i][j] = binaryArray1[i * pooints * 8 + j];
+            }
+
+        }
+        return binaryArray;
+    }
+
+    /**
+     * 获取单个字体的点阵数组
+     *
+     * @param encoding 文本编码
+     * @param font     文本的字体大小
+     * @return
+     */
+    public int[][] getSingleFontBinaryArray(String encoding, int font) {
+
+        try {
+
+            List<FontObject> myFontList = new ArrayList<>();
+
+            List<FontObject> myFontList2 = new ArrayList<>();
+
+            List<FontObject> myFontList3 = new ArrayList<>();
+            if (fontMap.containsKey(encoding)) {
+                myFontList3.addAll(fontMap.get(encoding));
+            }
+
+            if (encoding.length() <= 2) {
+                if (fontMap.containsKey("00" + encoding)) {
+                    myFontList3.addAll(fontMap.get("00" + encoding));
+                }
+            }
+
+            //过滤掉无效的字库 即内容为空的
+            if (!"20".equals(encoding)) {
+                myFontList2 = myFontList3.stream().filter(
+                        value -> !value.getHexArrays().stream().allMatch(s -> s.equals("0x00"))
+                ).collect(Collectors.toList());
+            } else {
+                myFontList2 = myFontList3;
+            }
+
+            myFontList = myFontList2;
+
+            if (myFontList.isEmpty()) {
+                System.out.println("没有找到对应的字库编码 : " + encoding);
+                return null;
+            }
+
+            //获取第一个
+            FontObject fontObject = null;
+            FontObject miniFontObject = myFontList.get(0);//最小字体
+            FontObject multipleFontObject = null;//适合的倍数字体
+
+            for (FontObject fontObject1 : myFontList) {
+
+
+                if (fontObject1.getFontWidth() == font) {
+                    fontObject = fontObject1;
+                    break;
+
+                }
+
+                if (fontObject1.getFontWidth() < miniFontObject.getFontWidth()) {
+                    miniFontObject = fontObject1;
+                }
+
+                if (font % fontObject1.getFontWidth() == 0) {
+                    //使用最大的放大
+                    if (multipleFontObject == null || multipleFontObject.getFontHeight() <= fontObject1.getFontWidth()) {
+                        multipleFontObject = fontObject1;
+                    }
+
+                }
+
+            }
+
+            if (fontObject == null) {
+                if (multipleFontObject != null) {
+                    fontObject = multipleFontObject;
+                } else {
+                    fontObject = miniFontObject;
+                }
+            }
+
+            List<String> hexArrays = fontObject.getHexArrays();
+
+
+            return convertToBinaryArray(hexArrays, fontObject.getFontWidth(), fontObject.getFontHeight());
+
+        } catch (Exception e) {
+            e.printStackTrace();
+
+        }
+
+        return null;
+
+    }
+
+
+}
+

+ 29 - 0
src/main/java/com/yeechart/dotMatrix/font/bean/FontObject.java

@@ -0,0 +1,29 @@
+package com.yeechart.dotMatrix.font.bean;
+
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * 字体对象
+ */
+
+
+@Data
+public class FontObject {
+
+    private String fontEncoding;
+    private String encoding;
+    private String type;
+    private int fontWidth;
+    private int fontHeight;
+    private List<String> hexArrays = new ArrayList<>();
+
+    public void addHexArray(String hexArray) {
+        hexArrays.add(hexArray);
+    }
+
+
+}

+ 863 - 0
src/main/java/com/yeechart/dotMatrix/minilzo/MiniLZO.java

@@ -0,0 +1,863 @@
+package com.yeechart.dotMatrix.minilzo;
+
+
+import com.yeechart.dotMatrix.minilzo.bean.LZOConstants;
+import com.yeechart.dotMatrix.minilzo.bean.MInt;
+
+/**
+ * 对 minilzo.c(2.03) 进行 JAVA化
+ * XZP minilzo 库
+ */
+public final class MiniLZO implements LZOConstants {
+    public static final int c_top_loop = 1;
+    public static final int c_first_literal_run = 2;
+    public static final int c_match = 3;
+    public static final int c_copy_match = 4;
+    public static final int c_match_done = 5;
+    public static final int c_match_next = 6;
+
+    public static final int c_eof_found = 7;
+    public static final int c_input_overrun = 8;
+    public static final int c_output_overrun = 9;
+    public static final int c_lookbehind_overrun = 10;
+
+    public static final int c0_top = 1;
+    public static final int c0_try_match = 2;
+    public static final int c0_literal = 3;
+    public static final int c0_match = 4;
+    public static final int c0_m3_m4_len = 5;
+    public static final int c0_m3_m4_offset = 6;
+    public static final int c0_last = 7;
+
+    private static final boolean debug = false;
+
+    private static final int U(byte b) {
+        return b & 0xff;
+    }
+
+    private final static int _lzo1x_1_do_compress(final byte[] in, final int in_len, final byte[] out, MInt out_len, int[] dict) {
+        int ip = 0;
+        int in_base = 0;
+        int out_base = 0;
+        int op;
+        int in_end = in_base + in_len;
+        int ip_end = in_base + in_len - 8 - 5;
+        int ii = 0;
+        int state = c0_top;
+        op = out_base;
+        ip = in_base;
+        ii = ip;
+
+        ip += 4;
+        int m_pos = in_base;
+        int m_off = in_base;
+        int m_len = 0;
+        int dindex = 0;
+
+        loop0:
+        for (; ; ) {
+            switch (state) {
+                case c0_top:
+                    dindex = (((((int) ((0x21) * ((((((((int) ((in[ip + 1 + 2 + 1] & 0xff) << (6)) ^ (in[ip + 1 + 1 + 1] & 0xff) << (5)) ^ (in[ip + 1 + 0] & 0xff) << (5)) ^ (in[ip + 0] & 0xff))))) >> 5) & (((1 << (14)) - 1) >> (0))) << (0)))));
+                    m_pos = dict[dindex];
+                    m_pos = ip - (ip - m_pos);
+                    if ((m_pos <= in_base) ||
+                            ((m_off = (ip - m_pos)) <= 0) ||
+                            (m_off > 0xbfff)) {//49151
+                        if (debug) {
+                            System.out.println("1:m_pos:" + m_pos + ", ip:" + ip + ", m_off:" + m_off);
+                        }
+                        state = c0_literal;
+                        continue loop0;//goto literal;
+                    }
+                    //System.out.println("2:m_pos:"+m_pos+", ip:"+ip+", m_off:"+m_off);
+                    if (m_off <= 0x0800 || in[m_pos + 3] == in[ip + 3]) {
+                        state = c0_try_match;
+                        continue loop0;//goto try_match;
+                    }
+                    dindex = (dindex & (((1 << (14)) - 1) & 0x7ff)) ^ (((((1 << (14)) - 1) >> 1) + 1) | 0x1f);
+
+                    m_pos = dict[dindex];
+                    if ((m_pos < in_base) || (m_off = (ip - m_pos)) <= 0 || m_off > 0xbfff) {
+                        state = c0_literal;
+                        continue loop0;//goto literal;
+                    }
+                    if (m_off <= 0x0800 || in[m_pos + 3] == in[ip + 3]) {
+                        state = c0_try_match;
+                        continue loop0;//goto try_match;
+                    }
+                    state = c0_literal;
+                    continue loop0;//goto literal;
+
+                case c0_try_match:
+                    //if ((* (const unsigned short *) m_pos != * (const unsigned short *) ip) { }
+                    if (in[m_pos] != in[ip] || in[m_pos + 1] != in[ip + 1]) {
+                    } else {
+                        if (in[m_pos + 2] == in[ip + 2]) {
+                            state = c0_match;
+                            continue loop0;//goto match;
+                        }// else { }
+                    }
+
+                case c0_literal:
+                    dict[dindex] = (ip);
+                    ip++;
+                    if (ip >= ip_end) {
+                        break loop0;
+                    }
+                    state = c0_top;
+                    continue loop0;
+
+                case c0_match:
+                    dict[dindex] = (ip);
+                    if ((ip - ii) > 0) {
+                        int t = ip - ii;
+
+                        if (t <= 3) {
+                            out[op - 2] |= (byte) t;
+                        } else if (t <= 18) {
+                            out[op++] = (byte) (t - 3);
+                        } else {
+                            int tt = t - 18;
+
+                            out[op++] = 0;
+                            while (tt > 255) {
+                                tt -= 255;
+                                out[op++] = 0;
+                            }
+                            out[op++] = (byte) tt;
+                        }
+                        do {
+                            out[op++] = in[ii++];
+                        } while (--t > 0);
+                    }
+
+                    ip += 3;
+                    if (in[m_pos + 3] != in[ip++] || in[m_pos + 4] != in[ip++] || in[m_pos + 5] != in[ip++] ||
+                            in[m_pos + 6] != in[ip++] || in[m_pos + 7] != in[ip++] || in[m_pos + 8] != in[ip++]) {
+                        --ip;
+                        m_len = ip - ii;
+
+                        if (m_off <= 0x0800) {
+                            m_off -= 1;
+
+                            out[op++] = (byte) (((m_len - 1) << 5) | ((m_off & 7) << 2));
+                            out[op++] = (byte) (m_off >> 3);
+                        } else if (m_off <= 0x4000) {
+                            m_off -= 1;
+                            out[op++] = (byte) (32 | (m_len - 2));
+                            state = c0_m3_m4_offset;
+                            continue loop0;//goto m3_m4_offset;
+                        } else {
+                            m_off -= 0x4000;
+                            out[op++] = (byte) (16 | ((m_off & 0x4000) >> 11) | (m_len - 2));
+                            state = c0_m3_m4_offset;
+                            continue loop0;// goto m3_m4_offset;
+                        }
+                        state = c0_last;
+                        continue loop0;
+                    } else {
+                        int end = in_end;
+                        int m = m_pos + 8 + 1;
+                        while (ip < end && in[m] == in[ip]) {
+                            m++;
+                            ip++;
+                        }
+                        m_len = ip - ii;
+
+                        if (m_off <= 0x4000) {
+                            m_off -= 1;
+                            if (m_len <= 33) {
+                                out[op++] = (byte) (32 | (m_len - 2));
+                            } else {
+                                m_len -= 33;
+                                out[op++] = 32 | 0;
+                                state = c0_m3_m4_len;
+                                continue loop0;// goto m3_m4_len;
+                            }
+                        } else {
+                            m_off -= 0x4000;
+                            if (m_len <= 9) {
+                                out[op++] = (byte) (16 | ((m_off & 0x4000) >> 11) | (m_len - 2));
+                            } else {
+                                m_len -= 9;
+                                out[op++] = (byte) (16 | ((m_off & 0x4000) >> 11));
+//m3_m4_len:
+                                while (m_len > 255) {
+                                    m_len -= 255;
+                                    out[op++] = 0;
+                                }
+                                out[op++] = (byte) m_len;
+                            }
+                        }
+//m3_m4_offset:            
+                        out[op++] = (byte) ((m_off & 63) << 2);
+                        out[op++] = (byte) (m_off >> 6);
+
+                        state = c0_last;
+                        continue loop0;
+                    }
+                    // These two case statements were duplicated, as I am  not able to break m3_m4_len & m3_m4_offset labels
+                    // from nested if/else blocks :)
+                case c0_m3_m4_len:
+                    while (m_len > 255) {
+                        m_len -= 255;
+                        out[op++] = 0;
+                    }
+                    out[op++] = (byte) m_len;
+
+                case c0_m3_m4_offset:
+                    out[op++] = (byte) ((m_off & 63) << 2);
+                    out[op++] = (byte) (m_off >> 6);
+                case c0_last:
+                    ii = ip;
+                    if (ip >= ip_end) {
+                        break loop0;
+                    }
+                    state = c0_top;
+            }
+        }
+
+        out_len.v = op - out_base;
+        return (in_end - ii);
+    }
+
+
+    /**
+     * 压缩数据。将返回错误代码
+     * 压缩长度通过out_len 返回。传递整数数组
+     * 字典(以便用户可以在多次调用中重复使用相同的字典。确保
+     * 将字典内容归零)。
+     *
+     * @param in      要压缩的输入字节数组
+     * @param in_len  输入长度
+     * @param out     压缩输出字节数组。确保 out_len = (in_len + in_len / 16 + 64 + 3)
+     * @param out_len 压缩数据长度
+     * @param dict    字典数组。重新使用前清零。
+     */
+    public final static int lzo1x_1_compress(final byte[] in, final int in_len, final byte[] out, MInt out_len, int[] dict) {
+        int in_base = 0;
+        int out_base = 0;
+        int op = 0;//out;
+        int t = 0;
+
+        if ((in_len <= 8 + 5)) {
+            t = in_len;
+        } else {
+            t = _lzo1x_1_do_compress(in, in_len, out, out_len, dict);
+            op += out_len.v;
+        }
+
+        if (t > 0) {
+            int ii = in_base + in_len - t;
+
+            if (op == out_base && t <= 238) {
+                out[op++] = (byte) (17 + t);
+            } else if (t <= 3) {
+                out[op - 2] |= (byte) t;
+            } else if (t <= 18) {
+                out[op++] = (byte) (t - 3);
+            } else {
+                int tt = t - 18;
+                out[op++] = 0;
+                while (tt > 255) {
+                    tt -= 255;
+                    out[op++] = 0;
+                }
+                out[op++] = (byte) tt;
+            }
+            do {
+                out[op++] = in[ii++];
+            } while (--t > 0);
+        }
+
+        out[op++] = (byte) (16 | 1);
+        out[op++] = 0;
+        out[op++] = 0;
+
+        out_len.v = (op - out_base);
+        return 0;
+    }
+
+    /**
+     * 解压缩数据。将返回错误代码。
+     * 解压后的长度通过out_len 返回。
+     *
+     * @param in      要解压缩的输入字节数组
+     * @param in_len  输入长度
+     * @param out     解压缩的输出字节数组。确保out数组有足够的长度
+     * @param out_len 解压后的数据长度
+     */
+    public final static int lzo1x_decompress(final byte[] in, final int in_len, final byte[] out, MInt out_len) {
+        int op = 0;
+        int ip = 0;
+        int t;
+        int state = c_top_loop;
+        int max = 0, diff = 0, min = 0;
+        int m_pos = 0;
+        int ip_end = in_len;
+
+        out_len.v = 0;
+
+        t = (in[ip] & 0xff);
+        if (t > 17) {
+            ip++;
+            t -= 17;
+            if (t < 4) {
+                state = c_match_next; //goto match_next;
+            } else {
+                do {
+                    out[op++] = in[ip++];
+                } while (--t > 0);
+                state = c_first_literal_run;//goto first_literal_run;
+            }
+        }
+        top_loop_ori:
+        do {
+            boolean if_block = false;
+            switch (state) {
+                //while (true)  top_loop_ori
+                case c_top_loop:
+                    t = (in[ip++] & 0xff);
+                    if (t >= 16) {
+                        state = c_match;
+                        continue top_loop_ori; //goto match;
+                    }
+                    if (t == 0) {
+                        while (in[ip] == 0) {
+                            t += 255;
+                            ip++;
+                        }
+                        t += 15 + (in[ip++] & 0xff);
+                    }
+
+                    //s=3; do out[op++] = in[ip++]; while(--s > 0);//* (lzo_uint32 *)(op) = * (const lzo_uint32 *)(ip);op += 4; ip += 4;
+                    out[op] = in[ip];
+                    out[op + 1] = in[ip + 1];
+                    out[op + 2] = in[ip + 2];
+                    out[op + 3] = in[ip + 3];
+                    op += 4;
+                    ip += 4;
+                    //op++; ip++; //GSSM ?? for the forth byte
+
+                    if (--t > 0) {
+                        if (t >= 4) {
+                            do {
+                                //* (lzo_uint32 *)(op) = * (const lzo_uint32 *)(ip);
+                                //op += 4; ip += 4; t -= 4;
+                                out[op] = in[ip];
+                                out[op + 1] = in[ip + 1];
+                                out[op + 2] = in[ip + 2];
+                                out[op + 3] = in[ip + 3];
+                                op += 4;
+                                ip += 4;
+                                t -= 4;
+                            } while (t >= 4);
+                            if (t > 0) {
+                                do {
+                                    out[op++] = in[ip++];
+                                } while (--t > 0);
+                            }
+                        } else {
+                            do {
+                                out[op++] = in[ip++];
+                            } while (--t > 0);
+                        }
+                    }
+                case c_first_literal_run: /*first_literal_run: */
+                    t = (in[ip++] & 0xff);
+                    if (t >= 16) {
+                        state = c_match;
+                        continue top_loop_ori;  //goto match;
+                    }
+                    //m_pos = op - (1 + 0x0800);
+                    //m_pos -= t >> 2;
+                    //m_pos -= U(in[ip++]) << 2;
+                    m_pos = op - 0x801 - (t >> 2) - ((in[ip++] & 0xff) << 2);
+                    diff = Math.abs(m_pos - op);
+                    if (diff > max) {
+                        max = diff;
+                    }
+                    diff = (m_pos - op);
+                    if (diff < min) {
+                        min = diff;
+                    }
+                    //*op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;
+                    out[op++] = out[m_pos++];
+                    out[op++] = out[m_pos++];
+                    out[op++] = out[m_pos];
+
+                    state = c_match_done;
+                    continue top_loop_ori;//goto match_done;
+                case c_match:
+                    //do {
+                    //match:
+                    if (t >= 64) {
+                        m_pos = op - 1;
+                        m_pos -= (t >> 2) & 7;
+                        m_pos -= (in[ip++] & 0xff) << 3;
+                        diff = Math.abs(m_pos - op);
+                        if (diff > max) {
+                            max = diff;
+                        }
+                        diff = (m_pos - op);
+                        if (diff < min) {
+                            min = diff;
+                        }
+                        t = (t >> 5) - 1;
+                        state = c_copy_match;
+                        continue top_loop_ori;//goto copy_match;
+
+                    } else if (t >= 32) {
+                        t &= 31;
+                        if (t == 0) {
+                            while (in[ip] == 0) {
+                                t += 255;
+                                ip++;
+                            }
+                            t += 31 + (in[ip++] & 0xff);
+                        }
+                        m_pos = op - 1;
+                        m_pos -= (((in[ip] & 0xff) + ((in[ip + 1] & 0xff) << 8)) >> 2);//m_pos -= (* (const unsigned short *) ip) >> 2;
+                        diff = Math.abs(m_pos - op);
+                        if (diff > max) {
+                            max = diff;
+                        }
+                        diff = (m_pos - op);
+                        if (diff < min) {
+                            min = diff;
+                        }
+
+                        ip += 2;
+                    } else if (t >= 16) {
+                        m_pos = op;
+                        m_pos -= (t & 8) << 11;
+                        diff = Math.abs(m_pos - op);
+                        if (diff > max) {
+                            max = diff;
+                        }
+                        diff = (m_pos - op);
+                        if (diff < min) {
+                            min = diff;
+                        }
+
+                        t &= 7;
+                        if (t == 0) {
+                            while (in[ip] == 0) {
+                                t += 255;
+                                ip++;
+                            }
+                            t += 7 + (in[ip++] & 0xff);
+                        }
+                        m_pos -= (((in[ip] & 0xff) + ((in[ip + 1] & 0xff) << 8)) >> 2);//m_pos -= (* (const unsigned short *) ip) >> 2;
+                        diff = Math.abs(m_pos - op);
+                        if (diff > max) {
+                            max = diff;
+                        }
+                        diff = (m_pos - op);
+                        if (diff < min) {
+                            min = diff;
+                        }
+                        ip += 2;
+                        if (m_pos == op) {
+                            break top_loop_ori;//goto eof_found;
+                        }
+                        m_pos -= 0x4000;
+                    } else {
+                        m_pos = op - 1;
+                        m_pos -= t >> 2;
+                        m_pos -= (in[ip++] & 0xff) << 2;
+                        diff = Math.abs(m_pos - op);
+                        if (diff > max) {
+                            max = diff;
+                        }
+                        diff = (m_pos - op);
+                        if (diff < min) {
+                            min = diff;
+                        }
+
+                        out[op++] = out[m_pos++];
+                        out[op++] = out[m_pos];//*op++ = *m_pos++; *op++ = *m_pos;
+                        state = c_match_done;
+                        continue top_loop_ori;//goto match_done;
+                    }
+                    if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) {
+                        if_block = true;
+                        //* (lzo_uint32 *)(op) = * (const lzo_uint32 *)(m_pos);
+                        out[op] = out[m_pos];
+                        out[op + 1] = out[m_pos + 1];
+                        out[op + 2] = out[m_pos + 2];
+                        out[op + 3] = out[m_pos + 3];
+                        op += 4;
+                        m_pos += 4;
+                        t -= 2;
+                        do {
+                            /// * (lzo_uint32 *)(op) = * (const lzo_uint32 *)(m_pos);
+                            out[op] = out[m_pos];
+                            out[op + 1] = out[m_pos + 1];
+                            out[op + 2] = out[m_pos + 2];
+                            out[op + 3] = out[m_pos + 3];
+                            op += 4;
+                            m_pos += 4;
+                            t -= 4;
+                        } while (t >= 4);
+                        if (t > 0) {
+                            do {
+                                out[op++] = out[m_pos++];
+                            } while (--t > 0);
+                        }
+                    }// else
+                case c_copy_match:
+                    if (!if_block) {
+                        //*op++ = *m_pos++; *op++ = *m_pos++;
+                        out[op++] = out[m_pos++];
+                        out[op++] = out[m_pos++];
+                        //do *op++ = *m_pos++; while (--t > 0);
+                        do {
+                            out[op++] = out[m_pos++];
+                        } while (--t > 0);
+                    }
+                case c_match_done:
+                    t = (in[ip - 2] & 0xff) & 3;
+                    if (t == 0) {
+                        state = c_top_loop;
+                        continue top_loop_ori; //break;
+                    }
+                case c_match_next:
+                    //*op++ = *ip++;
+                    out[op++] = in[ip++];
+                    //if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
+                    if (t > 1) {
+                        out[op++] = in[ip++];
+                        if (t > 2) {
+                            out[op++] = in[ip++];
+                        }
+                    }
+                    t = (in[ip++] & 0xff);
+                    state = c_match;
+                    continue top_loop_ori;
+                    //}// while (1);
+                    //// state=c_top_loop; continue top_loop_ori;
+            }
+        } while (true);
+
+        //eof_found:
+        //out_len = ((lzo_uint) ((op)-(out)));
+        out_len.v = op;
+        if (debug) {
+            System.err.println("\n@@@@@@@@@@@@ diff:" + max + ": min:" + min + "\n");
+        }
+        //return (ip == ip_end ? 0 : (ip < ip_end ? (-8) : (-4)));
+        return (ip == in.length ? 0 : (ip < in.length ? (-8) : (-4)));
+    }
+
+
+    /**
+     * 通过更多错误检查安全地解压缩数据。将返回错误代码。
+     * 解压后的长度通过out_len 返回。
+     *
+     * @param in      要解压缩的输入字节数组
+     * @param in_len  输入长度
+     * @param out     解压缩输出字节数组。确保输出数组有足够的长度
+     * @param out_len 解压数据长度
+     */
+
+    public final static int lzo1x_decompress_safe(final byte[] in, int in_len, byte[] out, MInt out_len) {
+        int op = 0;
+        int ip = 0;
+        int t = 0;
+        int m_pos = 0;
+        int state = c_top_loop;
+
+        out_len.v = 0;
+        t = (in[ip] & 0xff);
+        if (t > 17) {
+            ip++;
+            t -= 17;
+            if (t < 4) {
+                state = c_match_next;//goto match_next;
+            } else if (out.length < t) {
+                state = c_output_overrun;//goto output_overrun;
+            } else if (in.length < (t + 1)) {
+                state = c_input_overrun;//goto input_overrun;
+            } else {
+                do {
+                    out[op++] = in[ip++];
+                } while (--t > 0);
+                state = c_first_literal_run;//goto first_literal_run;
+            }
+        }
+        final int out_base = 0;
+        final int ip_end = in.length;
+        final int op_end = out.length;
+        top_loop_ori:
+        while (ip < ip_end) {
+            boolean if_block = false;
+            switch (state) {
+                default:
+                    break top_loop_ori;
+                case c_top_loop:
+                    t = (in[ip++] & 0xff);
+                    if (t >= 16) {
+                        state = c_match;
+                        continue top_loop_ori;//goto match;
+                    }
+                    if (t == 0) {
+                        if ((ip_end - ip) < 1) {
+                            state = c_input_overrun;
+                            continue top_loop_ori;//goto input_overrun;
+                        }
+                        while (in[ip] == 0) {
+                            t += 255;
+                            ip++;
+                            if ((ip_end - ip) < 1) {
+                                state = c_input_overrun;
+                                continue top_loop_ori;//goto input_overrun;
+                            }
+                        }
+                        t += 15 + (in[ip++] & 0xff);
+                    }
+                    if ((op_end - op) < (t + 3)) {
+                        state = c_output_overrun;
+                        continue top_loop_ori;// goto output_overrun;
+                    }
+                    if ((ip_end - ip) < (t + 4)) {
+                        state = c_input_overrun;
+                        continue top_loop_ori;//goto input_overrun;
+                    }
+                    // * (lzo_uint32 *)(op) = * (const lzo_uint32 *)(ip);
+                    out[op] = in[ip];
+                    out[op + 1] = in[ip + 1];
+                    out[op + 2] = in[ip + 2];
+                    out[op + 3] = in[ip + 3];
+                    op += 4;
+                    ip += 4;
+
+                    if (--t > 0) {
+                        if (t >= 4) {
+                            do {
+                                //* (lzo_uint32 *)(op) = * (const lzo_uint32 *)(ip);
+                                out[op] = in[ip];
+                                out[op + 1] = in[ip + 1];
+                                out[op + 2] = in[ip + 2];
+                                out[op + 3] = in[ip + 3];
+                                op += 4;
+                                ip += 4;
+                            } while (t >= 4);
+                            if (t > 0) {
+                                do {
+                                    out[op++] = in[ip++];
+                                } while (--t > 0);
+                            }
+                        } else {
+                            do {
+                                out[op++] = in[ip++];
+                            } while (--t > 0);
+                        }
+                    }
+                case c_first_literal_run:
+                    t = (in[ip++] & 0xff);
+                    if (t >= 16) {
+                        state = c_match;
+                        continue top_loop_ori;  //goto match;
+                    }
+                    //m_pos = op - (1 + 0x0800);
+                    //m_pos -= t >> 2;
+                    //m_pos -= *ip++ << 2;
+                    m_pos = op - 0x801 - (t >> 2) - ((in[ip++] & 0xff) << 2);
+
+                    if (m_pos < out_base || m_pos >= op) {
+                        state = c_lookbehind_overrun;
+                        continue top_loop_ori;// goto lookbehind_overrun;
+                    }
+                    if ((op_end - op) < (3)) {
+                        state = c_output_overrun;
+                        continue top_loop_ori;// goto output_overrun;
+                    }
+                    //*op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;
+                    out[op++] = out[m_pos++];
+                    out[op++] = out[m_pos++];
+                    out[op++] = out[m_pos];
+
+                    state = c_match_done;
+                    continue top_loop_ori;//goto match_done;
+
+                case c_match:
+                    //do {
+                    if (t >= 64) {
+                        m_pos = op - 1;
+                        m_pos -= (t >> 2) & 7;
+                        m_pos -= (in[ip++] & 0xff) << 3;
+                        t = (t >> 5) - 1;
+                        if (m_pos < out_base || m_pos >= op) {
+                            state = c_lookbehind_overrun;
+                            continue top_loop_ori;// goto lookbehind_overrun;
+                        }
+                        if ((op_end - op) < (t + 3 - 1)) {
+                            state = c_output_overrun;
+                            continue top_loop_ori;// goto output_overrun;
+                        }
+
+                        state = c_match_done;
+                        continue top_loop_ori;//goto match_done;
+                    } else if (t >= 32) {
+                        t &= 31;
+                        if (t == 0) {
+                            if ((ip_end - ip) < 1) {
+                                state = c_input_overrun;
+                                continue top_loop_ori;//goto input_overrun;
+                            }
+                            while (in[ip] == 0) {
+                                t += 255;
+                                ip++;
+                                if ((ip_end - ip) < 1) {
+                                    state = c_input_overrun;
+                                    continue top_loop_ori;//goto input_overrun;
+                                }
+                            }
+                            t += 31 + (in[ip++] & 0xff);
+                        }
+                        m_pos = op - 1;
+                        m_pos -= (((in[ip] & 0xff) + ((in[ip + 1] & 0xff) << 8)) >> 2);//m_pos -= (* (const unsigned short *) ip) >> 2;
+                        ip += 2;
+                    } else if (t >= 16) {
+                        m_pos = op;
+                        m_pos -= (t & 8) << 11;
+                        t &= 7;
+                        if (t == 0) {
+                            if ((ip_end - ip) < 1) {
+                                state = c_input_overrun;
+                                continue top_loop_ori;//goto input_overrun;
+                            }
+                            while (in[ip] == 0) {
+                                t += 255;
+                                ip++;
+                                if ((ip_end - ip) < 1) {
+                                    state = c_input_overrun;
+                                    continue top_loop_ori;//goto input_overrun;
+                                }
+                            }
+                            t += 7 + (in[ip++] & 0xff);
+                        }
+                        m_pos -= (((in[ip] & 0xff) + ((in[ip + 1] & 0xff) << 8)) >> 2);//m_pos -= (* (const unsigned short *) ip) >> 2;
+                        ip += 2;
+                        if (m_pos == op) {
+                            state = c_eof_found;
+                            break top_loop_ori;//goto eof_found;
+                        }
+                        m_pos -= 0x4000;
+                    } else {
+                        m_pos = op - 1;
+                        m_pos -= t >> 2;
+                        m_pos -= (in[ip++] & 0xff) << 2;
+
+                        if (m_pos < out_base || m_pos >= op) {
+                            state = c_lookbehind_overrun;
+                            continue top_loop_ori;// goto lookbehind_overrun;
+                        }
+                        if ((op_end - op) < 2) {
+                            state = c_output_overrun;
+                            continue top_loop_ori;// goto output_overrun;
+                        }
+
+                        out[op++] = out[m_pos++];
+                        out[op++] = out[m_pos];//*op++ = *m_pos++; *op++ = *m_pos;
+                        state = c_match_done;
+                        continue top_loop_ori;//goto match_done;
+                    }
+                    if (m_pos < out_base || m_pos >= op) {
+                        state = c_lookbehind_overrun;
+                        continue top_loop_ori;// goto lookbehind_overrun;
+                    }
+                    if ((op_end - op) < (t + 3 - 1)) {
+                        state = c_output_overrun;
+                        continue top_loop_ori;// goto output_overrun;
+                    }
+
+                    if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) {
+                        if_block = true;
+                        //* (lzo_uint32 *)(op) = * (const lzo_uint32 *)(m_pos);
+                        out[op] = out[m_pos];
+                        out[op + 1] = out[m_pos + 1];
+                        out[op + 2] = out[m_pos + 2];
+                        out[op + 3] = out[m_pos + 3];
+                        op += 4;
+                        m_pos += 4;
+                        t -= 4 - (3 - 1);
+                        do {
+                            //* (lzo_uint32 *)(op) = * (const lzo_uint32 *)(m_pos);
+                            out[op] = out[m_pos];
+                            out[op + 1] = out[m_pos + 1];
+                            out[op + 2] = out[m_pos + 2];
+                            out[op + 3] = out[m_pos + 3];
+                            op += 4;
+                            m_pos += 4;
+                            t -= 4;
+                        } while (t >= 4);
+                        if (t > 0) {
+                            do {
+                                out[op++] = out[m_pos++];
+                            } while (--t > 0);
+                        }
+                    }// else {
+                case c_copy_match:
+                    if (!if_block) {
+                        out[op++] = out[m_pos++];
+                        out[op++] = out[m_pos++];
+                        do {
+                            out[op++] = out[m_pos++];
+                        } while (--t > 0);
+                    }
+                case c_match_done:
+                    t = in[ip - 2] & 3;
+
+                    if (t == 0) {
+                        state = c_top_loop;
+                        continue top_loop_ori; //break;
+                    }
+                case c_match_next:
+                    if ((op_end - op) < t) {
+                        state = c_output_overrun;
+                        continue top_loop_ori;// goto output_overrun;
+                    }
+                    if ((ip_end - ip) < (t + 1)) {
+                        state = c_input_overrun;
+                        continue top_loop_ori;//goto input_overrun;
+                    }
+                    out[op++] = in[ip++];
+                    //if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
+                    if (t > 1) {
+                        out[op++] = in[ip++];
+                        if (t > 2) {
+                            out[op++] = in[ip++];
+                        }
+                    }
+                    t = (in[ip++] & 0xff);
+                    //} while ((ip < ip_end) && 1);
+                    if (ip < ip_end) {
+                        state = c_match;
+                        continue top_loop_ori;
+                    } else {
+                        state = c_top_loop;
+                        continue top_loop_ori;
+                    }
+            }
+        }
+
+        out_len.v = op - out_base;
+        switch (state) {
+            //case c_eof_found: return (ip == ip_end ? 0 : (ip < ip_end ? (-8) : (-4)));
+            case c_eof_found:
+                return (ip == ip_end ? LZO_E_OK :
+                        (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+            case c_input_overrun:
+                return LZO_E_INPUT_OVERRUN;//(-4);
+            case c_output_overrun:
+                return LZO_E_OUTPUT_OVERRUN;// (-5);
+            case c_lookbehind_overrun:
+                return LZO_E_LOOKBEHIND_OVERRUN;//(-6);
+            default:
+                return LZO_E_EOF_NOT_FOUND;
+        }
+    }
+}

+ 93 - 0
src/main/java/com/yeechart/dotMatrix/minilzo/MiniLZOUtil.java

@@ -0,0 +1,93 @@
+package com.yeechart.dotMatrix.minilzo;
+
+import com.yeechart.dotMatrix.crc.CustomCRC32Util;
+import com.yeechart.dotMatrix.minilzo.bean.MInt;
+import com.yeechart.dotMatrix.signage.bean.mizilzo.MiniLZOVo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MiniLZOUtil {
+
+
+    private static int maxByteSize = 10 * 1000;
+    private static MiniLZOUtil miniLZOUtil;
+
+    public static MiniLZOUtil getInstance() {
+        if (miniLZOUtil == null) {
+            synchronized (MiniLZOUtil.class) {
+                if (miniLZOUtil == null) {
+                    miniLZOUtil = new MiniLZOUtil();
+                }
+            }
+        }
+        return miniLZOUtil;
+    }
+
+    public static void initConfig(int maxByteSize2) {
+        maxByteSize = maxByteSize2;
+    }
+    /************************************** 压缩和解压缩  **************************************/
+
+
+    /**
+     * 分段压缩
+     *
+     * @param data
+     * @return
+     */
+    public List<MiniLZOVo> subMiniLZO(byte[] data) {
+        int multiple = data.length / maxByteSize;
+        if (data.length % maxByteSize > 0) {
+            multiple++;
+        }
+
+        List<MiniLZOVo> miniLZOVoList = new ArrayList<>();
+        byte[] dataByte = new byte[data.length];
+        for (int i = 0; i < multiple; i++) {
+            int trueSize = Math.min(maxByteSize, data.length - i * maxByteSize);
+            dataByte = new byte[trueSize];
+            System.arraycopy(data, i * maxByteSize, dataByte, 0,
+                    trueSize);
+
+            miniLZOVoList.add(MiniLZO(dataByte));
+        }
+
+        return miniLZOVoList;
+    }
+
+
+    /**
+     * 将数据进行压缩
+     *
+     * @param data
+     * @return
+     */
+    private MiniLZOVo MiniLZO(byte[] data) {
+        byte[] outByte = new byte[data.length];
+        MInt outL = new MInt();
+        int[] dict = new int[128 * 1024];
+
+        MiniLZO.lzo1x_1_compress(data, data.length, outByte, outL, dict);
+
+//        logger.info("压缩后的长度 outLen  len:" + outL.v);
+
+        //实际数据为
+        byte[] outByteTrue = new byte[outL.v];
+
+        System.arraycopy(outByte, 0, outByteTrue, 0, outL.v);
+
+//        logger.info("真实的数组长度:" + outByteTrue.length);
+
+        MiniLZOVo miniLZOVo = new MiniLZOVo();
+        miniLZOVo.setOgSize(data.length);
+        miniLZOVo.setData(outByteTrue);
+
+        //进行CRC32算法
+        long crc = CustomCRC32Util.calculateCRC32(outByteTrue);
+        miniLZOVo.setCrc32(crc);
+
+        return miniLZOVo;
+    }
+
+}

+ 49 - 0
src/main/java/com/yeechart/dotMatrix/minilzo/bean/LZOConstants.java

@@ -0,0 +1,49 @@
+/* LZOConstants.java -- various constants (Original file)
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+   Markus F.X.J. Oberhumer
+   <markus.oberhumer@jk.uni-linz.ac.at>
+   http://wildsau.idv.uni-linz.ac.at/mfx/lzo.html
+   
+
+   Java Porting of minilzo.c (2.03) by
+   Copyright (C) 2010 Mahadevan Gorti Surya Srinivasa <sgorti@gmail.com>
+ */
+package com.yeechart.dotMatrix.minilzo.bean;
+
+/**
+ *
+ */
+public interface LZOConstants {
+    int LZO_E_OK = 0;
+    int LZO_E_ERROR = -1;
+    int LZO_E_OUT_OF_MEMORY = -2;
+    int LZO_E_NOT_COMPRESSIBLE = -3;
+    int LZO_E_INPUT_OVERRUN = -4;
+    int LZO_E_OUTPUT_OVERRUN = -5;
+    int LZO_E_LOOKBEHIND_OVERRUN = -6;
+    int LZO_E_EOF_NOT_FOUND = -7;
+    int LZO_E_INPUT_NOT_CONSUMED = -8;
+}
+

+ 30 - 0
src/main/java/com/yeechart/dotMatrix/minilzo/bean/MInt.java

@@ -0,0 +1,30 @@
+/* 
+
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License;
+   see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+   Copyright (C) 2010 Mahadevan Gorti Surya Srinivasa <sgorti@gmail.com>
+ */
+
+
+/**
+ * Mutable integer
+ *
+ * @author mahadevan.gss
+ */
+
+package com.yeechart.dotMatrix.minilzo.bean;
+
+public class MInt {
+    public int v;
+
+    public MInt() {
+    }
+}

+ 213 - 0
src/main/java/com/yeechart/dotMatrix/module/DotMatrix/controller/DotMatrixController.java

@@ -0,0 +1,213 @@
+package com.yeechart.dotMatrix.module.DotMatrix.controller;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.aliyuncs.utils.StringUtils;
+import com.yeechart.dotMatrix.canvas.DotMatrixImageUtil;
+import com.yeechart.dotMatrix.module.DotMatrix.model.bean.ResultBean;
+import com.yeechart.dotMatrix.module.DotMatrix.service.DotMatrixService;
+import com.yeechart.dotMatrix.signage.SignageFileUtil;
+import com.yeechart.dotMatrix.signage.bean.Ter020201InfoVo;
+import com.yeechart.dotMatrix.signage.bean.Ter020201Vo;
+import com.yeechart.dotMatrix.signage.bean.mizilzo.BitmapDataVo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping(value = "/DotMatrix")
+public class DotMatrixController {
+    protected Logger logger = LoggerFactory.getLogger(DotMatrixController.class);
+
+    @Autowired
+    private DotMatrixService dotMatrixService;
+
+    @Autowired
+    private SignageFileUtil signageFileUtil;
+
+    /**
+     * 获取点阵图
+     *
+     * @param terLampInfoVO
+     * @return
+     */
+    @PostMapping("getDotMatrix")
+    public ResultBean getDotMatrix(@RequestBody Ter020201Vo terLampInfoVO) {
+
+        logger.info("################### 获取点整图 #########   更新的类别 " + JSONObject.toJSONString(terLampInfoVO));
+        List<BitmapDataVo> bitmapDataVoList = dotMatrixService.getSignageDotMatrix(terLampInfoVO);
+
+        return bitmapDataVoList == null ? ResultBean.defeated("获取点整图失败") : ResultBean.succeed(bitmapDataVoList);
+
+    }
+
+    /**
+     * 获取自检图
+     *
+     * @return
+     */
+    @GetMapping("getSelfCheckDiagram")
+    public ResultBean getSelfCheckDiagram() {
+
+        List<BitmapDataVo> bitmapDataVoList = dotMatrixService.getBatchBitmapQualityInspection();
+
+        return bitmapDataVoList == null ? ResultBean.defeated("获取自检图失败") : ResultBean.succeed(bitmapDataVoList);
+
+    }
+
+
+    /**
+     * 删除点阵图
+     *
+     * @return
+     */
+    @GetMapping("delDotMatrix")
+    public ResultBean delDotMatrix(String deID) {
+
+         dotMatrixService.delDotMatrix(deID);
+
+        return  ResultBean.succeed();
+
+    }
+
+
+    /**
+     * 预览点阵图
+     *
+     * @param typeCode  需要预览的点阵图类型编号
+     * @param DEID      设备编号(默认图图时可不传)
+     * @param isDefault 是否是初始图(不传时,默认为业务图)
+     * @return
+     */
+    @GetMapping("previewBitmap")
+    public ResponseEntity<byte[]> previewBitmap(String typeCode, String DEID, Boolean isDefault) {
+
+        if (isDefault == null || !isDefault) {
+            if (StringUtils.isEmpty(DEID)) {
+                return ResponseEntity.status(HttpStatus.NOT_FOUND)
+                        .header("Content-Type", "text/plain; charset=UTF-8")
+                        .body("预览业务图时,设备ID不正确".getBytes());
+            }
+
+            if (StringUtils.isEmpty(typeCode)) {
+                return ResponseEntity.status(HttpStatus.NOT_FOUND)
+                        .header("Content-Type", "text/plain; charset=UTF-8")
+                        .body("预览业务图时,点阵图类型编号不正确".getBytes());
+            }
+        } else {
+            if (StringUtils.isEmpty(typeCode)) {
+                return ResponseEntity.status(HttpStatus.NOT_FOUND)
+                        .header("Content-Type", "text/plain; charset=UTF-8")
+                        .body("预览初始图时,点阵图类型编号不正确".getBytes());
+            }
+            if (!typeCode.startsWith("D")) {
+                return ResponseEntity.status(HttpStatus.NOT_FOUND)
+                        .header("Content-Type", "text/plain; charset=UTF-8")
+                        .body("预览初始图时,点阵图类型编号不正确,必须为D开头".getBytes());
+            }
+            DEID = "default";
+        }
+
+        // 设置响应头,指定内容类型为image/png
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.IMAGE_PNG);
+
+
+        BufferedImage bufferedImage;
+
+        BitmapDataVo bitmapDataVo;
+        if("test".equals(DEID)){
+                Ter020201Vo ter020201Vo = new Ter020201Vo();
+                ter020201Vo.setTer020201InfoVo(Ter020201InfoVo.test3("测试使用"));
+                     Set<String> typeCodeList = new HashSet<>();
+                typeCodeList.add(typeCode);
+                ter020201Vo.setType(new Integer[]{0});
+
+
+                List<BitmapDataVo> bitmapDataVoList  = dotMatrixService.getSignageDotMatrix(ter020201Vo);
+                Map<String,BitmapDataVo> bitmapDataVoMap = bitmapDataVoList.stream().collect(Collectors.toMap(BitmapDataVo::getTypeCode, Function.identity()));
+                bitmapDataVo =bitmapDataVoMap.get(typeCode);
+
+        }else{
+        bitmapDataVo =  signageFileUtil.getLastBitmapDataVo(DEID, typeCode, isDefault);
+        }
+
+
+
+
+        byte[] twoBytes = bitmapDataVo.getTwoData();
+
+        int width = 480;
+        int height = 648;
+
+
+        typeCode = typeCode.replace("D", "");
+        if (typeCode.startsWith("0000") || typeCode.startsWith("0100")) {
+
+            if (typeCode.length() > 8) {
+                String typeCode2 = typeCode.substring(6);
+                String chartStr = typeCode2.substring(0, 2);
+                String stateStr = typeCode2.substring(2);
+
+                if (!"FF".equals(chartStr)) {
+                    //图表类
+                    height = height - width / 10 * 2 - width / 40 * 2;
+
+                    width = width - width / 10 * 2 - width / 40 * 2;
+
+                }
+            }
+
+            twoBytes = DotMatrixImageUtil.canvasBitmapArraysToTwo(
+                    DotMatrixImageUtil.screenFlip(DotMatrixImageUtil.twoToCanvasBitmapArrays(twoBytes, height, width)
+                    )
+            );
+
+            //点阵图转换为图片
+            bufferedImage = DotMatrixImageUtil.pixelArrayToConvertImage(twoBytes, height, width);
+        } else {
+            twoBytes = DotMatrixImageUtil.canvasBitmapArraysToTwo(
+                    DotMatrixImageUtil.screenHorizontalToVertical(DotMatrixImageUtil.twoToCanvasBitmapArrays(twoBytes, height, width)
+                    )
+            );
+
+            //点阵图转换为图片
+            bufferedImage = DotMatrixImageUtil.pixelArrayToConvertImage(twoBytes, width, height);
+        }
+
+
+        // 将图片转换为字节数组
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try {
+            ImageIO.write(bufferedImage, "png", baos);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+
+        byte[] imageBytes = baos.toByteArray();
+
+        // 返回图片数据
+        return new ResponseEntity<>(imageBytes, headers, HttpStatus.OK);
+
+
+    }
+
+
+}

+ 67 - 0
src/main/java/com/yeechart/dotMatrix/module/DotMatrix/model/bean/CodeEnum.java

@@ -0,0 +1,67 @@
+package com.yeechart.dotMatrix.module.DotMatrix.model.bean;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by 56844 on 2023/5/8.
+ */
+public enum CodeEnum {
+    SUCCESS("SUCCESS", 200, "操作成功!"),
+    FAIL("FAIL", 0, "网络异常!"),
+
+    requestTimeout(null, 105, "请求超时!"),
+    ;
+    private String name;
+    private String message;
+    private int code;
+    private Map map = new HashMap<String, String>();
+
+    private CodeEnum(String name, int code, String message) {
+        this.name = name;
+        this.code = code;
+        this.message = message;
+        map.put(code, message);
+    }
+
+    public static CodeEnum getByCode(int code) {
+        for (CodeEnum it : CodeEnum.values()) {
+            if (it.getCode() == code) {
+                return it;
+            }
+        }
+        return null;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public Integer getCodeInteger() {
+        return code;
+    }
+
+    public String getMessage(String code) {
+        return map.get(code) + "";
+    }
+}

+ 70 - 0
src/main/java/com/yeechart/dotMatrix/module/DotMatrix/model/bean/ResultBean.java

@@ -0,0 +1,70 @@
+package com.yeechart.dotMatrix.module.DotMatrix.model.bean;
+
+
+import lombok.Data;
+import org.springframework.util.StringUtils;
+
+
+@Data
+/**
+ * 封装类
+ */
+public class ResultBean<T> {
+    /**
+     * 状态码
+     */
+    private int code;
+    /**
+     * 提示
+     */
+    private String message;
+    /**
+     * 内容
+     */
+    private T data;
+
+
+    public static ResultBean succeed() {
+        return succeed(CodeEnum.SUCCESS.getMessage());
+    }
+
+    public static ResultBean succeed(Object data) {
+        return succeed(CodeEnum.SUCCESS.getMessage(), data);
+    }
+
+    public static ResultBean succeed(String message, Object data) {
+        ResultBean resultBean = new ResultBean();
+        resultBean.setCode(CodeEnum.SUCCESS.getCode());
+        resultBean.setMessage(message);
+        resultBean.setData(data);
+        return resultBean;
+    }
+
+    public static ResultBean defeated() {
+        return defeated(CodeEnum.FAIL.getCode(), CodeEnum.FAIL.getMessage());
+    }
+
+    public static ResultBean defeated(String message) {
+        return defeated(CodeEnum.FAIL.getCode(), StringUtils.isEmpty(message) ? CodeEnum.FAIL.getMessage() : message);
+    }
+
+
+    public static ResultBean defeated(int code, String message) {
+        return defeated(code, message, null);
+    }
+
+    public static ResultBean defeated(int code) {
+        CodeEnum codeEnum = CodeEnum.getByCode(code);
+        return defeated(codeEnum.getCode(), codeEnum.getMessage(), codeEnum.getName());
+    }
+
+    public static ResultBean defeated(int code, String message, Object data) {
+        ResultBean resultBean = new ResultBean();
+        resultBean.setCode(code);
+        resultBean.setMessage(message);
+        resultBean.setData(data);
+        return resultBean;
+    }
+
+
+}

+ 26 - 0
src/main/java/com/yeechart/dotMatrix/module/DotMatrix/service/DotMatrixService.java

@@ -0,0 +1,26 @@
+package com.yeechart.dotMatrix.module.DotMatrix.service;
+
+import com.yeechart.dotMatrix.signage.bean.Ter020201Vo;
+import com.yeechart.dotMatrix.signage.bean.mizilzo.BitmapDataVo;
+
+import java.util.List;
+
+public interface DotMatrixService {
+
+    /**
+     * 获取 指定属性的点整图
+     *
+     * @param ter020201Vo
+     * @return
+     */
+     List<BitmapDataVo> getSignageDotMatrix(Ter020201Vo ter020201Vo);
+
+    /**
+     * 获取硬件质检图
+     *
+     * @return
+     */
+    List<BitmapDataVo> getBatchBitmapQualityInspection();
+
+    void delDotMatrix(String deID);
+}

+ 44 - 0
src/main/java/com/yeechart/dotMatrix/module/DotMatrix/service/impl/DotMatrixServiceImpl.java

@@ -0,0 +1,44 @@
+package com.yeechart.dotMatrix.module.DotMatrix.service.impl;
+
+import com.yeechart.dotMatrix.module.DotMatrix.service.DotMatrixService;
+import com.yeechart.dotMatrix.signage.SignageDrawUtil;
+import com.yeechart.dotMatrix.signage.SignageFileUtil;
+import com.yeechart.dotMatrix.signage.SignageQualityUtil;
+import com.yeechart.dotMatrix.signage.bean.Ter020201Vo;
+import com.yeechart.dotMatrix.signage.bean.mizilzo.BitmapDataVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+@Service
+public class DotMatrixServiceImpl implements DotMatrixService {
+
+
+    @Autowired
+    private SignageDrawUtil signageDrawUtil;
+
+        @Autowired
+    private SignageQualityUtil signageQualityUtil;
+
+        @Autowired
+        private SignageFileUtil signageFileUtil;
+
+    @Override
+    public List<BitmapDataVo> getSignageDotMatrix(Ter020201Vo ter020201Vo) {
+        return signageDrawUtil.getSignageDotMatrix(ter020201Vo);
+
+    }
+
+    @Override
+    public List<BitmapDataVo> getBatchBitmapQualityInspection() {
+        CompletableFuture<List<BitmapDataVo>> completableFuture = signageQualityUtil.getBatchBitmapQualityInspection();
+        return completableFuture.join();
+    }
+
+    @Override
+    public void delDotMatrix(String deID) {
+         signageFileUtil.deleteSignageDotMatrix(deID);
+    }
+}

+ 221 - 0
src/main/java/com/yeechart/dotMatrix/oss/LatticeOSSUpload.java

@@ -0,0 +1,221 @@
+package com.yeechart.dotMatrix.oss;
+
+
+import com.yeechart.dotMatrix.signage.bean.mizilzo.BitmapDataVo;
+import com.yeechart.dotMatrix.signage.bean.mizilzo.MiniLZOVo;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Component;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.stream.Collectors;
+
+/**
+ * OSS 上传文件
+ */
+@Component
+@Slf4j
+public class LatticeOSSUpload {
+
+    @Autowired
+    private OSSUpload ossUpload;
+        @javax.annotation.Resource
+    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
+    private Map<String, ConcurrentHashMap<String, CompletableFuture<String>>> deviceConcurrentHashMap = new HashMap<>();
+    private Map<String, Map<String, BitmapDataVo>> bitmapDataVoMap = new HashMap<>();
+
+
+    /**
+     * 批量文件上传
+     *
+     * @param deID
+     * @throws InterruptedException
+     */
+    public CompletableFuture<Void> uploadImages(String deID, List<BitmapDataVo> bitmapDataVoList) {
+        if (bitmapDataVoList == null || bitmapDataVoList.isEmpty()) {
+            return CompletableFuture.completedFuture(null);
+        }
+
+        ConcurrentHashMap<String, CompletableFuture<String>> imageUploadFutures = new ConcurrentHashMap<>();
+
+        Map<String, BitmapDataVo> bitmapDataVoMap1 = new HashMap<>();
+
+        for (BitmapDataVo bitmapDataVo : bitmapDataVoList) {
+
+            Map<String, MiniLZOVo> miniLZOVoList = bitmapDataVo.getMiniLZOVoList();
+
+            String path = bitmapDataVo.getPath();
+
+            for (Map.Entry<String, MiniLZOVo> entry : miniLZOVoList.entrySet()) {
+                String fileName = entry.getKey();
+                MiniLZOVo miniLZOVo = entry.getValue();
+                byte[] data = miniLZOVo.getData();
+
+                String finalFileName = path + "/" + fileName;
+
+                CompletableFuture<String> future = new CompletableFuture<>();
+                imageUploadFutures.put(finalFileName, future);
+
+                threadPoolTaskExecutor.execute(() -> {
+                    try {
+                        ossUpload.enqueueUploadWithRetryAndCallback(data, finalFileName,
+                                future::complete,
+                                future::completeExceptionally);
+                    } catch (Exception e) {
+                        future.completeExceptionally(e);
+                    }
+                });
+
+            }
+
+
+            bitmapDataVoMap1.put(path, bitmapDataVo);
+
+
+        }
+
+        deviceConcurrentHashMap.put(deID, imageUploadFutures);
+        bitmapDataVoMap.put(deID, bitmapDataVoMap1);
+//        System.out.println("总共要传输的次数 " + imageUploadFutures.size() );
+        // 等待所有上传完成并处理结果
+        CompletableFuture<Void> allUploadsFuture = CompletableFuture.allOf(imageUploadFutures.values().toArray(new CompletableFuture[0]))
+                .thenAcceptAsync(v -> handleAllUploadsCompleted(deID), threadPoolTaskExecutor); // 使用线程池执行handleAllUploadsCompleted
+        //.thenAcceptAsync(unused -> { /* 这里可以添加处理完成后的其他逻辑,如果有的话 */ }, threadPoolTaskExecutor);
+
+        return allUploadsFuture;
+    }
+
+    private void handleAllUploadsCompleted(String deID) {
+        // 收集所有成功的URL
+        List<String> successfulUris = new ArrayList<>();
+        ConcurrentHashMap<String, CompletableFuture<String>> imageUploadFutures = deviceConcurrentHashMap.get(deID);
+
+        for (Map.Entry<String, CompletableFuture<String>> entry : imageUploadFutures.entrySet()) {
+            String imageName = entry.getKey();
+            CompletableFuture<String> future = entry.getValue();
+            try {
+                String url = future.get();
+                successfulUris.add(url);
+            } catch (Exception e) {
+                // 处理失败的情况
+                System.out.println("上传文件失败:" + imageName + " 异常为:" + e);
+
+            }
+        }
+
+        // 处理成功URIs
+        List<String> basePaths = successfulUris.stream()
+//                .map(uri -> uri
+//                {
+//                    String afterDevice = uri.substring(uri.indexOf("device"));
+//                    afterDevice = afterDevice.substring(0, afterDevice.lastIndexOf('/'));
+//                    return afterDevice;
+//                }
+//                )
+                .distinct() // 去重,确保每个path只更新一次
+                .collect(Collectors.toList());
+
+        // 更新BitmapDataVo的path属性
+        Map<String, BitmapDataVo> bitmapDataVoMapForDeID = bitmapDataVoMap.get(deID);
+        if (bitmapDataVoMapForDeID != null) {
+            basePaths.forEach(basePath -> {
+
+                try {
+
+                    URL url = new URL(basePath);
+                    String fullPath = url.getPath(); // 获取完整路径
+                    fullPath = fullPath.substring(1);//去掉前面的"/"
+
+                    int lastSlashIndex = fullPath.lastIndexOf('/');
+                    String directoryPath = fullPath.substring(0, lastSlashIndex); // +1则保留末尾的 "/"
+                    BitmapDataVo bitmapDataVo = bitmapDataVoMapForDeID.get(directoryPath);
+                    if (bitmapDataVo != null && !bitmapDataVo.getPath().startsWith("http")) {
+                        String afterDevice = basePath.substring(0, basePath.indexOf("device"));
+                        bitmapDataVo.setPath(afterDevice + directoryPath);
+                    }
+
+                } catch (MalformedURLException e) {
+                    System.out.println("uri转换异常 basePath:" + basePath);
+                }
+
+
+            });
+        }
+
+
+        //然后清除数据
+        deviceConcurrentHashMap.remove(deID);
+        bitmapDataVoMap.remove(deID);
+
+    }
+
+
+    /**
+     * 删除指定文件夹及其子文件夹中的所有文件
+     *
+     * @param folderPath 文件夹路径前缀
+     */
+    public void deleteFolderAndSubFolders(String folderPath) {
+        // 列出指定前缀的所有文件
+        CompletableFuture<Map<String, byte[]>> fileContentsFuture = listFilesByPath(folderPath);
+
+        fileContentsFuture.thenAcceptAsync(fileContents -> {
+            // 遍历所有文件并逐个删除
+            for (String filePath : fileContents.keySet()) {
+                ossUpload.deleteFile(folderPath+filePath);
+            }
+        }, threadPoolTaskExecutor);
+    }
+
+    /**
+     * 删除指定设备ID下的所有已上传文件
+     */
+    public void deleteFilePaths(List<String> filePaths) {
+        for (String filePath : filePaths) {
+            ossUpload.deleteFile(filePath);
+        }
+    }
+
+    /**
+     * 查询指定路径下的所有文件内容
+     *
+     * @param path 文件路径前缀
+     * @return 匹配该路径前缀的所有文件内容 < 原始文件大小/文件名 , 文件内容 >
+     */
+    public CompletableFuture<Map<String, byte[]>> listFilesByPath(String path) {
+
+        // 假设ossUpload有一个方法listFilesByPrefix用于列出指定前缀的所有文件
+        try {
+            URL url = new URL(path);
+            String fullPath = url.getPath(); // 获取完整路径
+//            int lastSlashIndex = fullPath.lastIndexOf('/');
+//            String directoryPath = fullPath.substring(0, lastSlashIndex + 1); // 保留末尾的 "/"
+            String directoryPath = fullPath.substring(1);//去掉前面的"/"
+
+
+            // 假设ossUpload有一个异步方法用于列出指定前缀的所有文件内容
+            CompletableFuture<Map<String, byte[]>> fileContentsFuture = ossUpload.getFileContentsByPrefix(directoryPath);
+
+            // 使用thenApply处理成功情况,直接返回结果
+            return fileContentsFuture.thenApply(future -> future);
+
+
+        } catch (Exception e) {
+            System.out.println("获取指定文件路径 " + path + " 下的所有文件出现异常: " + e.getMessage());
+
+        }
+        return CompletableFuture.completedFuture(null);
+    }
+
+
+}

+ 26 - 0
src/main/java/com/yeechart/dotMatrix/oss/OSSRetryTask.java

@@ -0,0 +1,26 @@
+package com.yeechart.dotMatrix.oss;
+
+
+import lombok.Data;
+
+import java.util.function.Consumer;
+
+
+@Data
+/**
+ * OSS重试任务
+ */
+public class OSSRetryTask {
+
+    private byte[] data;
+    private String fileName;//包含文件连接以及文件名称
+    private Consumer<String> onSuccessCallback;
+    private Consumer<Throwable> onFailureCallback;
+
+    OSSRetryTask(byte[] data, String fileName, Consumer<String> onSuccessCallback, Consumer<Throwable> onFailureCallback) {
+        this.data = data;
+        this.fileName = fileName;
+        this.onSuccessCallback = onSuccessCallback;
+        this.onFailureCallback = onFailureCallback;
+    }
+}

+ 318 - 0
src/main/java/com/yeechart/dotMatrix/oss/OSSUpload.java

@@ -0,0 +1,318 @@
+package com.yeechart.dotMatrix.oss;
+
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClient;
+import com.aliyun.oss.model.ListObjectsRequest;
+import com.aliyun.oss.model.OSSObjectSummary;
+import com.aliyun.oss.model.ObjectListing;
+import com.aliyun.oss.model.PutObjectResult;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.*;
+import java.util.concurrent.locks.LockSupport;
+import java.util.function.Consumer;
+
+
+@Component
+@Slf4j
+public class OSSUpload {
+    private  final int THREAD_POOL_SIZE = 10; // 线程池大小
+    private  final ExecutorService executor = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
+
+    @Value("${oss.endpoint}")
+    private String endpoint;
+    @Value("${oss.accesskeyid}")
+    private String accessKeyId;
+    @Value("${oss.accesskeysecret}")
+    private String accessKeySecret;
+    @Value("${oss.bucket}")
+    private String bucketName;
+
+    public String getEndpoint() {
+        return endpoint;
+    }
+    private final int MAX_RETRIES = 5;// 5个并发重试
+    private final Semaphore semaphore = new Semaphore(MAX_RETRIES); // 并发重试
+    private final BlockingQueue<OSSRetryTask> retryQueue = new ArrayBlockingQueue<>(400); // 假定的重试任务队列大小
+    private final int MAX_RETRY_ATTEMPTS = 3; // 最大重试次数
+    private final long SLEEP_INTERVAL_MS = 100; // 每次重试之间的延迟
+    private final ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(10, new ThreadPoolExecutor.CallerRunsPolicy());
+    protected Logger logger = LoggerFactory.getLogger(OSSUpload.class);
+
+
+    private  OSSClient ossClient;//OSS
+    @PostConstruct
+    public  void init() {
+        ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
+    }
+
+
+    @PreDestroy
+    public void destroy() {
+        if (ossClient != null) {
+            ossClient.shutdown();
+        }
+        executor.shutdown();
+
+        try {
+            if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
+                executor.shutdownNow();
+            }
+        } catch (InterruptedException e) {
+            executor.shutdownNow();
+        }
+
+        scheduler.shutdown();
+        try {
+            if (!scheduler.awaitTermination(60, TimeUnit.SECONDS)) {
+                scheduler.shutdownNow();
+            }
+        } catch (InterruptedException e) {
+            scheduler.shutdownNow();
+        }
+    }
+
+    /**
+     * 上传文件
+     *
+     * @param data
+     * @param originalFileName
+     * @param onSuccessCallback
+     * @param onFailureCallback
+     * @return
+     */
+    public void enqueueUploadWithRetryAndCallback(byte[] data, String originalFileName,
+                                                  Consumer<String> onSuccessCallback,
+                                                  Consumer<Throwable> onFailureCallback) {
+
+        OSSRetryTask task = new OSSRetryTask(data, originalFileName,
+                onSuccessCallback, onFailureCallback);
+        int retryAttempts = 0;
+        while (retryAttempts <= MAX_RETRY_ATTEMPTS) {
+            try {
+                if (retryQueue.offer(task, 1, TimeUnit.SECONDS)) {
+                    processRetryQueue();
+                    return; // 成功加入队列,结束重试
+                }
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                onFailureCallback.accept(new RuntimeException("将任务添加到队列时中断", e));
+                return;
+            }
+
+            // 如果队列满,等待一段时间后重试
+            retryAttempts++;
+            logger.warn("重试队列已满,将在 #{} 毫秒内重试。尝试 #{}", SLEEP_INTERVAL_MS, retryAttempts);
+            try {
+                LockSupport.parkNanos(100_000_000);
+//                Thread.sleep(SLEEP_INTERVAL_MS);
+            } catch (Exception e) {
+                Thread.currentThread().interrupt();
+                onFailureCallback.accept(new RuntimeException("等待重试时中断", e));
+                return;
+            }
+        }
+
+        // 达到最大重试次数后,执行失败回调
+        onFailureCallback.accept(new Exception("Failed to enqueue task after maximum retry attempts"));
+
+
+    }
+
+    private void processRetryQueue() {
+        if (executor.isShutdown()) {
+            return;
+        }
+        executor.submit(this::processRetryTasks);
+    }
+
+    private void processRetryTasks() {
+        while (true) {
+            try {
+                OSSRetryTask task = retryQueue.poll(1, TimeUnit.SECONDS);
+                if (task == null) {
+                    break;
+                } // 队列为空则退出
+                doUploadWithRetry(task);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                break;
+            }
+        }
+    }
+
+    //private int count = 0;
+    public void doUploadWithRetry(OSSRetryTask task) {
+        if (task == null) {
+            return;
+        }
+
+        String fileName = task.getFileName();
+
+        InputStream fileStream = new ByteArrayInputStream(task.getData());
+        Random random = new Random();
+
+        try {
+            for (int attempt = 1; attempt <= MAX_RETRIES; attempt++) {
+                try {
+                    semaphore.acquire(); // 获取信号量,限制并发数
+
+//                    PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, fileStream);
+                    PutObjectResult putResult = ossClient.putObject(bucketName, fileName, fileStream);
+                    if (putResult != null) {
+                        // logger.info("OSS上传成功,次数为 {},文件为 {} , 调用次数 {}", attempt, fileName,++count);
+                        // 上传成功,释放信号量
+                        semaphore.release();
+                        String url = "http://" + endpoint + "/" + fileName;//"https://"  bucketName + "." +
+                        task.getOnSuccessCallback().accept(url);
+                        return;
+                    } else {
+                        logger.warn("OSS上传尝试 " + attempt + " 次 失败,无返回结果");
+                    }
+                } catch (Exception e) {
+                    logger.warn("OSS上传尝试 {} 次失败,错误为 : {}", attempt, e.getMessage());
+                } finally {
+                    if (semaphore.availablePermits() < 1) {
+                        semaphore.release(); // 确保信号量正确释放
+                    }
+                }
+
+                if (attempt < MAX_RETRIES) {
+                    long delayMs = random.nextInt(500) + 100; // 随机退避,范围100ms至600ms
+                    scheduler.schedule(() -> doUploadWithRetry(task), delayMs, TimeUnit.MILLISECONDS);
+                    return; // 退出当前方法,等待重试
+                }
+            }
+        } finally {
+
+            try {
+                fileStream.close();
+
+            } catch (IOException e) {
+
+            }
+
+        }
+
+        logger.warn("OSS上传尝试 最大次数 失败");
+
+        task.getOnFailureCallback().accept(new Exception("上传异常."));
+
+    }
+
+
+    /**
+     * 删除指定路径的文件
+     *
+     * @param filePath 完整的文件路径(包含Bucket名称)
+     */
+    public void deleteFile(String filePath) {
+        //取出文件路径
+        URL url = null;
+        try {
+            url = new URL(filePath);
+            String objectKey = url.getPath().substring(1); // 提取Object Key,去掉开头的'/'
+            ossClient.deleteObject(bucketName, objectKey);
+        } catch (Exception e) {
+            logger.error("文件路径转换时,路径" + filePath + "错误" + e);
+        }
+
+    }
+
+    /**
+     * 获取指定前缀下所有文件的内容
+     *
+     * @param prefix 文件路径前缀
+     * @return 匹配前缀的所有文件内容列表,每个元素为一个文件的字节内容
+     */
+    public CompletableFuture<Map<String, byte[]>> getFileContentsByPrefix(String prefix) throws IOException {
+
+        return CompletableFuture.supplyAsync(() -> {
+//            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // 确保endpoint等参数已定义
+
+            ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName)
+                    .withPrefix(prefix)
+                    .withMaxKeys(1000); // 根据实际情况调整
+
+            Map<String, byte[]> fileNameContentMap = new HashMap<>();
+
+            try {
+                ObjectListing objectListing;
+                do {
+                    objectListing = ossClient.listObjects(listObjectsRequest);
+
+                    for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
+                        String fileName = extractFileNameWithFolder(objectSummary.getKey(), prefix);
+
+                        byte[] content = downloadFileContent(ossClient, bucketName, objectSummary.getKey());
+
+                        fileNameContentMap.put(fileName, content);
+                    }
+
+                    listObjectsRequest.setMarker(objectListing.getNextMarker());
+                } while (objectListing.isTruncated());
+            } catch (Exception e) {
+                logger.error("OSS获取文件,出现异常" + e);
+            }
+//            finally {
+//                ossClient.shutdown(); // 确保OSS客户端在最后被关闭
+//            }
+
+            return fileNameContentMap;
+
+        });
+
+    }
+
+    /**
+     * 提取文件名,保留上一层文件夹路径
+     *
+     * @param key
+     * @param prefix
+     * @return
+     */
+    public String extractFileNameWithFolder(String key, String prefix) {
+        // 提取文件名并保留文件夹路径
+        if (key.startsWith(prefix)) {
+            key = key.substring(prefix.length());
+        }
+        return key;
+    }
+
+    /**
+     * 只获取文件名称
+     *
+     * @param key
+     * @return
+     */
+    public String extractFileNameFromKey(String key) {
+        return key.substring(key.lastIndexOf("/") + 1);
+    }
+
+    public byte[] downloadFileContent(OSS ossClient, String bucketName, String objectKey) throws IOException {
+        try (InputStream objectContent = ossClient.getObject(bucketName, objectKey).getObjectContent();
+             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+            byte[] buffer = new byte[1024];
+            int bytesRead;
+            while ((bytesRead = objectContent.read(buffer)) != -1) {
+                baos.write(buffer, 0, bytesRead);
+            }
+            return baos.toByteArray();
+        }
+    }
+
+}

File diff suppressed because it is too large
+ 1164 - 0
src/main/java/com/yeechart/dotMatrix/signage/SignageDrawLeftUtil.java


File diff suppressed because it is too large
+ 1859 - 0
src/main/java/com/yeechart/dotMatrix/signage/SignageDrawRightUtil.java


File diff suppressed because it is too large
+ 1446 - 0
src/main/java/com/yeechart/dotMatrix/signage/SignageDrawUtil.java


+ 277 - 0
src/main/java/com/yeechart/dotMatrix/signage/SignageFileUtil.java

@@ -0,0 +1,277 @@
+package com.yeechart.dotMatrix.signage;
+
+import com.yeechart.dotMatrix.canvas.DotMatrixConversionUtil;
+import com.yeechart.dotMatrix.crc.CustomCRC32Util;
+import com.yeechart.dotMatrix.minilzo.MiniLZO;
+import com.yeechart.dotMatrix.minilzo.MiniLZOUtil;
+import com.yeechart.dotMatrix.minilzo.bean.MInt;
+import com.yeechart.dotMatrix.oss.LatticeOSSUpload;
+import com.yeechart.dotMatrix.oss.OSSUpload;
+import com.yeechart.dotMatrix.signage.bean.mizilzo.BitmapDataVo;
+import com.yeechart.dotMatrix.signage.bean.mizilzo.MiniLZOVo;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import com.yeechart.dotMatrix.util.OtherUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.stream.Collectors;
+
+/**
+ * 对 点阵图 文件操作
+ */
+@Component
+public class SignageFileUtil {
+    /**
+     * 终端类总路径名称
+     */
+    public static final String ROOT_FILE_NAME = "Device/";
+    /**
+     * 默认的文件名称
+     */
+    public static final String ROOT_FILE_TYPE_NAME = ".txt";
+    public static String fileName = "device/020201/lattice/";//路径;
+    protected static Logger logger = LoggerFactory.getLogger(SignageFileUtil.class);
+    //private ThreadPoolExecutor threadPoolTaskExecutor = ThreadPoolTaskExecutor.getInstance().getThreadPoolExecutor();
+
+    @javax.annotation.Resource
+    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
+
+    @Autowired
+    private LatticeOSSUpload latticeOSSUpload;
+
+    @Autowired
+    private OSSUpload ossUpload;
+    /**
+     * 获取最新的点阵图文件对象
+     *
+     * @param dId       设备ID
+     * @param typeCode  功能code
+     * @param isDefault 是否是默认图
+     * @return
+     */
+    public  BitmapDataVo getLastBitmapDataVo(String dId, String typeCode, boolean isDefault) {
+        if (isDefault) {
+            typeCode = "D" + typeCode;
+        }
+
+        String url = "http://" + ossUpload.getEndpoint() + "/" + fileName + dId + "/" + typeCode;
+
+        BitmapDataVo bitmapDataVo = new BitmapDataVo();
+        bitmapDataVo.setTypeCode(typeCode);
+        bitmapDataVo.setPath(url);
+
+
+        return getFileBitmapArrays(bitmapDataVo);
+    }
+
+
+    /**
+     * 删除点阵图
+     * @param dId 设备ID
+     */
+    public void deleteSignageDotMatrix(String dId){
+
+        String url = "http://" + ossUpload.getEndpoint() + "/" + fileName + dId ;
+
+        latticeOSSUpload.deleteFolderAndSubFolders(url);
+
+
+    }
+
+    /**
+     * 从 指定路径中,获取对应的文件夹数据,并解压数据合并为原始数据
+     *
+     * @return
+     */
+    public  BitmapDataVo getFileBitmapArrays(BitmapDataVo bitmapDataVo) {
+
+
+        try {
+
+            Map<String, byte[]> fileMap = new HashMap<>();
+
+            CompletableFuture<Map<String, byte[]>> completableFuture = latticeOSSUpload.listFilesByPath(bitmapDataVo.getPath());
+            fileMap = completableFuture.get();
+
+            if (fileMap.isEmpty()) {
+                return null;
+            }
+
+            //排序
+            List<Map.Entry<String, byte[]>> entries = new ArrayList<>(fileMap.entrySet());
+
+            Map<String, Integer> sizeMap = new HashMap<>();
+
+            // 定义比较器,根据文件名最后两位数字进行排序
+            entries.sort((entry1, entry2) -> {
+                String name1 = entry1.getKey();
+                String name2 = entry2.getKey();
+
+                int lastDotIndex = name1.lastIndexOf('.');
+                name1 = name1.substring(0, lastDotIndex);
+
+                lastDotIndex = name2.lastIndexOf('.');
+                name2 = name2.substring(0, lastDotIndex);
+
+
+                int a1 = Integer.parseInt(name1.substring(name1.length() - 2));
+                int a2 = Integer.parseInt(name2.substring(name2.length() - 2));
+                return Integer.compare(a1, a2);
+            });
+
+            // 根据排序后的列表构造一个新的LinkedHashMap,以保持排序顺序
+            Map<String, byte[]> sortedMap = new LinkedHashMap<>();
+            for (Map.Entry<String, byte[]> entry : entries) {
+                String name = entry.getKey();
+                sortedMap.put(name, entry.getValue());
+
+                //获取文件路径中的图的原始数据大小
+                if (!sizeMap.containsKey(name)) {
+                    String sum = name.substring(0, name.lastIndexOf('/'));
+                    sizeMap.put(name, Integer.parseInt(sum));
+                }
+            }
+
+            //整图的原始数据的大小 sizeMap 的value 总和
+            String fileName = null;
+            Integer ogSize = null;
+
+            byte[] data = new byte[sizeMap.values().stream().mapToInt(Integer::intValue).sum()];
+
+            int length = 0;
+
+            Map<String, MiniLZOVo> miniLZOVoList = new HashMap<>();
+
+            for (Map.Entry<String, byte[]> entry : sortedMap.entrySet()) {
+                fileName = entry.getKey();
+
+                ogSize = Integer.parseInt(fileName.substring(0, fileName.lastIndexOf('/')));
+
+                byte[] dataBytes = entry.getValue();
+
+                //解压缩
+                byte[] dataBytes2 = new byte[ogSize];
+                MInt outL2 = new MInt();
+                MiniLZO.lzo1x_decompress(dataBytes, ogSize, dataBytes2, outL2);
+
+//                logger.info("解压缩后的长度 outLen  len:" +outL2.v);
+                System.arraycopy(dataBytes2, 0, data, length, outL2.v);
+
+                MiniLZOVo miniLZOVo = new MiniLZOVo();
+                miniLZOVo.setOgSize(ogSize);
+                miniLZOVo.setData(dataBytes);
+                miniLZOVo.setCrc32(CustomCRC32Util.calculateCRC32(dataBytes2));
+                miniLZOVoList.put(fileName, miniLZOVo);
+
+                length = length + ogSize;
+
+            }
+
+//            byte[] dataBytes33 = new byte[4];
+//            System.arraycopy(data,data.length-4,dataBytes33,0,4);
+
+            byte[] dataBytes3 = new byte[data.length - 4];
+            System.arraycopy(data, 0, dataBytes3, 0, data.length - 4);
+
+            //将 16点阵数据 转换为 二进制点阵数据
+            byte[] twoBytes = DotMatrixConversionUtil.sixteenTo2Lattice(data);
+
+            bitmapDataVo.setMiniLZOVoList(miniLZOVoList);
+            bitmapDataVo.setTwoData(twoBytes);
+
+            return bitmapDataVo;
+        } catch (Exception e) {
+            e.printStackTrace();
+            logger.error("获取 点阵图文件 :" + e + "  路径为 " + bitmapDataVo.getPath());
+
+        }
+
+        return null;
+    }
+
+
+    /************************************** 处理的点阵数据对象  **************************************/
+
+    /**
+     * 将完整的点阵图数据 转换为 点整图对象
+     *
+     * @param twoBytes
+     * @param deId
+     * @param path
+     * @param typeCode
+     * @param isDefault
+     * @return
+     */
+    public  BitmapDataVo dealWithBitmapDataVo(byte[] twoBytes, String deId, String path, String typeCode, boolean isDefault) {
+        BitmapDataVo bitmapDataVo = new BitmapDataVo();
+
+        bitmapDataVo.setTwoData(twoBytes);
+
+        bitmapDataVo.setTime(System.currentTimeMillis());
+
+        //区分默认点阵图
+        if (isDefault) {
+            typeCode = "D" + typeCode;
+        }
+        bitmapDataVo.setTypeCode(typeCode);
+        bitmapDataVo.setPath(path + typeCode);
+
+        //保存文件
+        Map<String, MiniLZOVo> sizeMap = dealWithMiniLZOVo(typeCode, twoBytes);
+
+
+        bitmapDataVo.setMiniLZOVoList(sizeMap);
+
+        return bitmapDataVo;
+    }
+
+
+    /**
+     * 将完整的点阵图数据 进行 分割并压缩
+     *
+     * @param typeCode
+     * @param twoBytes
+     * @return
+     */
+    public  Map<String, MiniLZOVo> dealWithMiniLZOVo(String typeCode, byte[] twoBytes) {
+
+        Map<String, MiniLZOVo> sizeMap = new HashMap<>();
+
+
+        // 将二进制点阵图转换为16进制点阵图
+        byte[] dataBytes2 = DotMatrixConversionUtil.twoTo16Lattice(twoBytes);
+
+        //2024/04/09 新增 在整体点阵数据后面追加整体CRC32的值
+        //进行CRC32算法
+        long crc32 = CustomCRC32Util.calculateCRC32(dataBytes2);
+        byte[] crc32Bytes = OtherUtil.longToByteArray(crc32, 4);//固定4位
+
+        byte[] dataBytes = new byte[dataBytes2.length + crc32Bytes.length];
+
+        System.arraycopy(dataBytes2, 0, dataBytes, 0, dataBytes2.length);
+        System.arraycopy(crc32Bytes, 0, dataBytes, dataBytes2.length, crc32Bytes.length);
+
+        //将16进制点阵图进行压缩
+        List<MiniLZOVo> miniLZOVoList = MiniLZOUtil.getInstance().subMiniLZO(dataBytes);
+
+        //生成对应的文件名称
+        for (int i = 0; i < miniLZOVoList.size(); i++) {
+
+            String fileName = typeCode +
+                    (i < 10 ? "0" + i : i) + ROOT_FILE_TYPE_NAME;
+
+            MiniLZOVo miniLZOVo = miniLZOVoList.get(i);
+
+            sizeMap.put(miniLZOVo.getOgSize() + "/" + fileName, miniLZOVo);
+        }
+
+        return sizeMap;
+    }
+
+
+}

+ 303 - 0
src/main/java/com/yeechart/dotMatrix/signage/SignageQualityUtil.java

@@ -0,0 +1,303 @@
+package com.yeechart.dotMatrix.signage;
+
+import com.yeechart.dotMatrix.canvas.*;
+import com.yeechart.dotMatrix.oss.LatticeOSSUpload;
+import com.yeechart.dotMatrix.signage.bean.mizilzo.BitmapDataVo;
+import com.yeechart.dotMatrix.util.OtherUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+import static com.yeechart.dotMatrix.signage.SignageDrawUtil.*;
+import static com.yeechart.dotMatrix.signage.TypeCodeUtil.*;
+
+/**
+ * 生成硬件质检图
+ */
+
+@Component
+public class SignageQualityUtil {
+
+    @javax.annotation.Resource
+    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
+
+    @Autowired
+    private LatticeOSSUpload latticeOSSUpload;
+
+    @Autowired
+    private SignageFileUtil signageFileUtil;
+
+     @Autowired
+    private DotMatrixDrawtextUtil dotMatrixDrawtextUtil;
+
+    /************************************** 生成质检图  **************************************/
+
+    /**
+     * 绘制整图/背景图
+     *
+     * @param isBg 是否为背景图(false 则生产有结果的整图, true 则生产不带结果的背景图)
+     * @return
+     */
+    private  int[][] canvasBitmapQualityInspection(boolean isBg) {
+
+        int[][] canvasBitmapArrays = new int[height][width];
+
+        int startRowA = height / 40;
+
+        String text = "蚁巢工厂测试";
+
+        int[][] fontBinaryArray = dotMatrixDrawtextUtil.drawingText(text, textFontSize, noChineseFontSize2);
+
+        int startColumnA = width / 2 - fontBinaryArray[0].length / 2;
+
+        DotMatrixCanvasUtil.mergeDotMatrices(canvasBitmapArrays, fontBinaryArray, startRowA, startColumnA, new int[]{1, 1, 1, 1});
+
+        //绘制间隔实线
+        DotMatrixDrawShapeUtil.drawLine(canvasBitmapArrays, 1, 0, 0, height / 20 + height / 40 + noChineseFontSize * 4, rightMargins, width - rightMargins);
+
+
+        String[] data = new String[]{
+                "运行", "待料", "停机", "保养", "故障", "维修",
+                "NFC", "WIFI",
+                "充电", "语音键",
+                "音量加键", "音量减键"
+        };
+
+        for (int i = 0; i < data.length; i++) {
+            canvasBitmapQualityInspectionItem(canvasBitmapArrays, i, data[i],
+                    isBg ? null : false);
+        }
+        if (!isBg) {
+            canvasBitmapQualityInspectionBigResult(canvasBitmapArrays, false);
+        }
+
+
+        return canvasBitmapArrays;
+    }
+
+
+    /**
+     * 绘制质检项目
+     *
+     * @param canvasBitmapArrays 画布
+     * @param number             质检的项目序号
+     * @param text               质检的名称
+     * @param pass               是否通过(为空时 则不绘制质检结果,true 为通过, false 为不通过)
+     */
+    private  void canvasBitmapQualityInspectionItem(int[][] canvasBitmapArrays, int number, String text, Boolean pass) {
+
+        int startRowA = height / 20 + noChineseFontSize * 7 + Math.max(textFontSize2Height, noChineseFontSizeHeight);
+        int startColumnA = rightMargins;
+        int interval = height / 20;
+
+
+        int rows = number / 2;//行数
+        int columns = number % 2;//列数
+
+        startRowA = startRowA + (Math.max(textFontSize2Height, noChineseFontSizeHeight) + interval) * rows;
+
+        if (columns != 0) {
+            startColumnA = canvasBitmapArrays[0].length / 2 + startColumnA;
+        }
+
+
+        text = text + ":";
+        dotMatrixDrawtextUtil.drawingText(
+                canvasBitmapArrays,
+                text,
+                startRowA,
+                startColumnA,
+                textFontSize2,
+                noChineseFontSize);
+
+        //绘制结果
+        if (pass != null) {
+            interval = canvasBitmapArrays[0].length / 2 - rightMargins * 2 - textFontSize2 * 2;
+            text = pass ? "通过" : "异常";
+
+            dotMatrixDrawtextUtil.drawingText(
+                    canvasBitmapArrays,
+                    text,
+                    startRowA,
+                    startColumnA + interval,
+                    textFontSize2,
+                    noChineseFontSize);
+        }
+
+    }
+
+    /**
+     * 绘制 单项结果文本
+     *
+     * @param pass
+     * @return
+     */
+    private  int[][] canvasBitmapQualityInspectionResult(boolean pass) {
+        String text = pass ? "通过" : "异常";
+        return dotMatrixDrawtextUtil.drawingText(text, textFontSize2, noChineseFontSize);
+    }
+
+
+    /**
+     * 绘制最终的结果
+     *
+     * @param canvasBitmapArrays
+     * @param pass
+     */
+    private  int[][] canvasBitmapQualityInspectionBigResult(int[][] canvasBitmapArrays, boolean pass) {
+        String text = pass ? "通过" : "异常";
+        int[][] canvasBgArrays = new int[160]//height/8*2
+                [width - rightMargins * 2];//
+        //赋值初始化全为1
+        for (int i = 0; i < canvasBgArrays.length; i++) {
+            for (int j = 0; j < canvasBgArrays[0].length; j++) {
+                canvasBgArrays[i][j] = 1;
+            }
+        }
+
+        int[][] fontBinaryArray = dotMatrixDrawtextUtil.drawingText(text, textFontSizeCheck, noChineseFontSizeCheck);
+
+        DotMatrixCanvasUtil.mergeDotMatricesConfuse(
+                canvasBgArrays,
+                fontBinaryArray,
+                canvasBgArrays.length / 2 - fontBinaryArray.length / 2,
+                canvasBgArrays[0].length / 2 - fontBinaryArray[0].length / 2,
+                1
+        );
+
+
+        if (canvasBitmapArrays != null) {
+            //合并画布
+            DotMatrixCanvasUtil.mergeDotMatricesConfuse(
+                    canvasBitmapArrays,
+                    canvasBgArrays,
+                    height - canvasBgArrays.length / 2 * 3,
+                    rightMargins,
+                    0
+            );
+        }
+
+        return canvasBgArrays;
+
+    }
+
+
+    /**
+     * 生成自检点阵图
+     *
+     * @param
+     * @return
+     */
+    public  CompletableFuture<List<BitmapDataVo>> getBatchBitmapQualityInspection() {
+
+        List<BitmapDataVo> bitmapDataVoList = new ArrayList<>();
+
+
+        String dId = "SelfTest";//deviceStock.getDeviceId();
+
+        String path = "device/020201/lattice/" + dId + "/";//路径;
+
+        byte[] data = null;
+
+        BitmapDataVo bitmapDataVo = null;
+        //背景图
+        int[][] bgCanvasBitmapArrays = canvasBitmapQualityInspection(true);
+
+        // 由于 硬件屏幕原因 需要将 将右屏的画布旋转
+        data = DotMatrixImageUtil.canvasBitmapArraysToTwo(
+                DotMatrixImageUtil.screenHorizontalToVertical(
+                        bgCanvasBitmapArrays
+                )
+        );
+        bitmapDataVo = signageFileUtil.dealWithBitmapDataVo(data, dId, path, "T" + CODE_ON + CODE_RIGHT + CODE_SELF_TEST + "00", false);
+        bitmapDataVoList.add(bitmapDataVo);
+
+
+        int[][] yesResultCanvasBitmapArrays = canvasBitmapQualityInspectionBigResult(null, true);
+        // 由于 硬件屏幕原因 需要将 将右屏的画布旋转
+        data = DotMatrixImageUtil.canvasBitmapArraysToTwo(
+                DotMatrixImageUtil.screenFlip(
+                        DotMatrixImageUtil.screenHorizontalToVertical(
+                                yesResultCanvasBitmapArrays
+                        )
+                )
+        );
+        bitmapDataVo = signageFileUtil.dealWithBitmapDataVo(data, dId, path, "T" + CODE_ON + CODE_RIGHT + CODE_SELF_TEST + "03", false);
+        bitmapDataVoList.add(bitmapDataVo);
+
+
+        int[][] noResultCanvasBitmapArrays = canvasBitmapQualityInspectionBigResult(null, false);
+        // 由于 硬件屏幕原因 需要将 将右屏的画布旋转
+        data = DotMatrixImageUtil.canvasBitmapArraysToTwo(
+                DotMatrixImageUtil.screenFlip(
+                        DotMatrixImageUtil.screenHorizontalToVertical(
+                                noResultCanvasBitmapArrays
+                        )
+                )
+
+        );
+        bitmapDataVo = signageFileUtil.dealWithBitmapDataVo(data, dId, path, "T" + CODE_ON + CODE_RIGHT + CODE_SELF_TEST + "04", false);
+        bitmapDataVoList.add(bitmapDataVo);
+
+
+        CompletableFuture<Void> uploadFuture = latticeOSSUpload.uploadImages(dId, bitmapDataVoList);
+
+        // 在上传操作完成后,才执行返回操作
+        return uploadFuture.thenApplyAsync(v -> {
+            // 这里可以添加更多操作,如果需要
+            return bitmapDataVoList; // 最终返回 bitmapDataVoList
+        }, threadPoolTaskExecutor);
+
+
+    }
+
+
+    /**
+     * 基础字节库
+     */
+    private void GenerateCustomFonts() {
+
+        String[] fonts = 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",
+                "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",
+                ".", "-", "_", " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-",
+        };
+
+        StringBuilder sb = new StringBuilder();
+        for (String font : fonts) {
+
+            byte[] data = DotMatrixConversionUtil.twoTo16Lattice(
+                    DotMatrixImageUtil.canvasBitmapArraysToTwo(
+                            DotMatrixImageUtil.screenFlip(
+                                    DotMatrixImageUtil.screenHorizontalToVertical(
+                                            dotMatrixDrawtextUtil.drawingText(font, noChineseFontSize, noChineseFontSize)
+                                    )
+                            )
+
+                    )
+            );
+
+
+            sb.append("\n");
+            sb.append("字符为【");
+            sb.append(font);
+            sb.append("】的点阵图:");
+            sb.append("\n");
+            for (byte a : data) {
+                String b = OtherUtil.Bytes2HexString(new byte[]{a});
+                sb.append("0x");
+                sb.append(OtherUtil.strToHighZeroPadding(b, 2));
+                sb.append(",");
+            }
+
+        }
+
+//        saveToFile("D:/WorkSpace/Web/image/Device/自定义字库","硬件","基础字库", sb.toString().getBytes());
+    }
+
+}

+ 226 - 0
src/main/java/com/yeechart/dotMatrix/signage/TypeCodeUtil.java

@@ -0,0 +1,226 @@
+package com.yeechart.dotMatrix.signage;
+
+import java.util.*;
+
+public class TypeCodeUtil {
+
+    /************************************** 点阵图形成  **************************************/
+
+
+    /**
+     * 关机
+     */
+    public static final String CODE_OFF = "00";
+    /**
+     * 开机
+     */
+    public static final String CODE_ON = "01";
+    /**
+     * 左屏
+     */
+    public static final String CODE_LEFT = "00";
+    /**
+     * 右屏
+     */
+    public static final String CODE_RIGHT = "01";
+
+    /**
+     * 引导图
+     */
+    public static final String CODE_GUIDE = "00";
+    /**
+     * 业务图
+     */
+    public static final String CODE_BUSINESS = "01";
+    /**
+     * 自检图
+     */
+    public static final String CODE_SELF_TEST = "02";
+    /**
+     * 占位符 FF
+     */
+    public static final String CODE_FF = "FF";
+    /**
+     * 无状态 FE
+     */
+    public static final String CODE_FE = "FE";
+
+    private static Map<Integer, Set<String>> typeCodeMap = new HashMap<>();
+
+    /**
+     * 将改变的下标 转换为对应的typeCode
+     *
+     * @param types
+     * @return
+     */
+    public static Set<String> changTypeToTypeCode(List<Integer> types) {
+
+        Set<String> typeCodeList = new HashSet<>();
+
+        for (int type : types) {
+            typeCodeList.addAll(typeToTypeCodeList(type));
+        }
+
+        return typeCodeList;
+    }
+
+
+    /**
+     * 将改变的下标 转换为对应的typeCode列表
+     *
+     * @param type
+     * @return
+     */
+    public static Set<String> typeToTypeCodeList(Integer type) {
+        if (typeCodeMap.isEmpty()) {
+            initTypeCodeMap();
+        }
+
+        return typeCodeMap.get(type);
+    }
+
+    public static void initTypeCodeMap() {
+
+        int max = 1 + 36;//由 下标0 加上 Ter020201InfoVo中最大的type数
+        // 现将原左屏图改为 状态6个+指针6个+图表三个 + 无状态和无指针
+
+
+        for (int type = 0; type < max; type++) {
+            Set<String> typeCodeList = new HashSet<>();
+            //左右屏都需要更改的
+            if (type == 20) {
+                //左屏
+//                for(int j = 0 ; j<6; j++){//6种状态
+//                    typeCodeList.add(CODE_ON+CODE_LEFT+CODE_BUSINESS+"01"+"0"+j);//签到表
+//                    typeCodeList.add(CODE_ON+CODE_LEFT+CODE_BUSINESS+"03"+"0"+j);//二合一表
+//                }
+                typeCodeList.add(CODE_ON + CODE_LEFT + CODE_BUSINESS + "01" + CODE_FF);//签到表
+                typeCodeList.add(CODE_ON + CODE_LEFT + CODE_BUSINESS + "03" + CODE_FF);//二合一表
+
+                //右屏
+                typeCodeList.add(CODE_ON + CODE_RIGHT + CODE_BUSINESS + "00");
+                typeCodeList.add(CODE_ON + CODE_RIGHT + CODE_BUSINESS + "01");
+
+                typeCodeMap.put(type, typeCodeList);
+
+                continue;
+            }
+
+            //左屏业务相关
+            if (type == 0 || type == 29 || type == 30 ||
+                    type == 19 || type == 36
+            ) {//|| type == 4
+
+                //状态历史数据
+                //状态历史表
+                if (type == 0 || type == 29 || type == 19) {
+
+//                    for(int j = 0 ; j<6; j++){//6种状态
+//                        typeCodeList.add(CODE_ON+CODE_LEFT+CODE_BUSINESS+"02"+"0"+j);//状态表
+//                        typeCodeList.add(CODE_ON+CODE_LEFT+CODE_BUSINESS+"03"+"0"+j);//二合一表
+//                    }
+                    typeCodeList.add(CODE_ON + CODE_LEFT + CODE_BUSINESS + "02" + CODE_FF);//状态表
+                    typeCodeList.add(CODE_ON + CODE_LEFT + CODE_BUSINESS + "03" + CODE_FF);//二合一表
+                    typeCodeMap.put(type, typeCodeList);
+                    if (type == 29) {
+                        continue;
+                    }
+
+                }
+
+                //签到历史数据 现为 工时历史数据
+                if (type == 0 || type == 30) {
+
+//                    for(int j = 0 ; j<6; j++){//6种状态
+//                        typeCodeList.add(CODE_ON+CODE_LEFT+CODE_BUSINESS+"01"+"0"+j);//签到表
+//                        typeCodeList.add(CODE_ON+CODE_LEFT+CODE_BUSINESS+"03"+"0"+j);//二合一表
+//                    }
+                    typeCodeList.add(CODE_ON + CODE_LEFT + CODE_BUSINESS + "01" + CODE_FF);//签到表
+                    typeCodeList.add(CODE_ON + CODE_LEFT + CODE_BUSINESS + "03" + CODE_FF);//二合一表
+                    typeCodeMap.put(type, typeCodeList);
+                    if (type == 30) {
+                        continue;
+                    }
+
+                }
+
+                //状态
+//                for(int i = 0 ; i < 4 ; i++){ //4种报表
+//                    for(int j = 0 ; j<6; j++){//6种状态
+//                        typeCodeList.add(CODE_ON+CODE_LEFT+CODE_BUSINESS+"0"+i+"0"+j);
+//                    }
+//                }
+
+                for (int j = 0; j < 7; j++) {//6种状态 + 无状态
+
+
+                    typeCodeList.add(CODE_ON + CODE_LEFT + CODE_BUSINESS + CODE_FF +
+                            (j != 6 ? "0" + j : CODE_FE)
+                    );
+                    if (type != 36) {
+                        //特殊处理图表0 指针款的状态
+                        typeCodeList.add(CODE_ON + CODE_LEFT + CODE_BUSINESS + "00" +
+                                (j != 6 ? "0" + j : CODE_FE)
+                        );
+                    }
+
+                }
+
+                if (type == 36) {
+                    //关机左屏引导图
+                    typeCodeList.add(CODE_OFF + CODE_LEFT + CODE_GUIDE);
+                }
+            }
+
+
+            //右屏业务相关
+            if (type == 0 || type == 1 || type == 2 //|| type == 5
+
+                    || type == 9 || type == 10 || type == 11
+                    || type == 12 || type == 13 || type == 14 || type == 15 || type == 16 || type == 17
+                    || type == 18
+                    || type == 23 || type == 24 || type == 25 || type == 26
+                    || type == 21 || type == 22 || type == 31 || type == 32
+
+            ) {//|| type == 5
+
+                //只改了图表数据
+                if (type == 32) {
+                    typeCodeList.add(CODE_ON + CODE_RIGHT + CODE_BUSINESS + "00");//图表1
+                    typeCodeMap.put(type, typeCodeList);
+                    continue;
+                }
+                if (type == 31) {
+                    typeCodeList.add(CODE_ON + CODE_RIGHT + CODE_BUSINESS + "01");//图表2
+                    typeCodeMap.put(type, typeCodeList);
+                    continue;
+                }
+
+                //引导图 已配网
+                if (type == 0 || type == 1 || type == 2 || type == 9 || type == 10) {
+                    typeCodeList.add(CODE_OFF + CODE_RIGHT + CODE_GUIDE + "01");
+
+                }
+
+                typeCodeList.add(CODE_ON + CODE_RIGHT + CODE_BUSINESS + "00");
+                typeCodeList.add(CODE_ON + CODE_RIGHT + CODE_BUSINESS + "01");
+
+            }
+
+
+            //特殊处理
+            if (type == 0) {
+                //关机左屏引导图
+                typeCodeList.add(CODE_OFF + CODE_LEFT + CODE_GUIDE);
+
+                //关机右屏引导图未配网
+                typeCodeList.add(CODE_OFF + CODE_RIGHT + CODE_GUIDE + "00");
+
+            }
+
+            typeCodeMap.put(type, typeCodeList);
+        }
+
+    }
+
+}

+ 39 - 0
src/main/java/com/yeechart/dotMatrix/signage/bean/BitmapArraysVo.java

@@ -0,0 +1,39 @@
+package com.yeechart.dotMatrix.signage.bean;
+
+
+import lombok.Data;
+
+@Data
+/**
+ * 产品类型020201 终端 的点阵数组对象 使用
+ */
+public class BitmapArraysVo {
+
+    /**
+     * crc32的值
+     */
+    private Long crc32;
+
+
+    /**
+     * 原文件大小
+     */
+    private Long zipSize;
+
+    /**
+     * 文件生成时间
+     */
+    private Long time;
+
+    /**
+     * 文件名(无后缀)
+     */
+    private String fileName;
+
+    /**
+     * 文件下载地址
+     */
+    private String uri;
+
+
+}

+ 213 - 0
src/main/java/com/yeechart/dotMatrix/signage/bean/SheetCheckVo.java

@@ -0,0 +1,213 @@
+package com.yeechart.dotMatrix.signage.bean;
+
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+
+@Data
+/**
+ * 报表-人数/工时
+ */
+public class SheetCheckVo implements Serializable {
+
+    /**
+     * 时间节点-开始
+     */
+    private String timeStart;
+
+    /**
+     * 时间节点-结束
+     */
+    private String timeEnd;
+
+    /**
+     * 展示时间
+     */
+    private String time;
+
+
+    /**
+     * 人数-首页用,累计打卡数,不区分用户
+     */
+    private Integer peopleNum = 0;
+
+    /**
+     * 工时
+     */
+    private Integer work = 0;
+
+    /**
+     * 0生产人数-首页用
+     */
+    private Integer peoplep = 0;
+
+    /**
+     * 1维修人数-首页用
+     */
+    private Integer peoplew = 0;
+
+    /**
+     * 2巡检人数-首页用
+     */
+    private Integer peoplei = 0;
+
+    /**
+     * 3保养人数-首页用
+     */
+    private Integer peopleu = 0;
+    private String _id;
+    private Long tId;
+    private Long wSId;
+
+
+    /**
+     * 0生产
+     */
+    private Integer peoplepWork = 0;
+
+    /**
+     * 1维修人数
+     */
+    private Integer peoplewWork = 0;
+
+    /**
+     * 2巡检人数
+     */
+    private Integer peopleiWork = 0;
+
+    /**
+     * 3保养人数
+     */
+    private Integer peopleuWork = 0;
+
+    //打卡人
+    private List<Long> uIds = new ArrayList<>();
+
+
+    /**
+     * 人数-概览用,累计打卡数,区分用户,签出不变
+     */
+    private Integer peopleNumo = 0;
+
+    /**
+     * 0生产人数-概览用,累计打卡数,区分用户,签出不变
+     */
+    private Integer peoplepo = 0;
+
+    /**
+     * 1维修人数-概览用,累计打卡数,区分用户,签出不变
+     */
+    private Integer peoplewo = 0;
+
+    /**
+     * 2巡检人数-概览用,累计打卡数,区分用户,签出不变
+     */
+    private Integer peopleio = 0;
+
+    /**
+     * 3保养人数-概览用,累计打卡数,区分用户,签出不变
+     */
+    private Integer peopleuo = 0;
+
+
+    /**
+     * 0生产人数-详情用,累计打卡数,同类型区分用户,签出不变
+     */
+    private Integer peoplepx = 0;
+
+    /**
+     * 1维修人数-详情用,累计打卡数,同类型区分用户,签出不变
+     */
+    private Integer peoplewx = 0;
+
+    /**
+     * 2巡检人数-详情用,累计打卡数,同类型区分用户,签出不变
+     */
+    private Integer peopleix = 0;
+
+    /**
+     * 3保养人数-详情用,累计打卡数,同类型区分用户,签出不变
+     */
+    private Integer peopleux = 0;
+
+    //累计打卡人
+
+    /**
+     * 0生产人数打卡人
+     */
+    private List<Long> uIdsp = new ArrayList<>();
+
+    /**
+     * 1维修打卡人
+     */
+    private List<Long> uIdsw = new ArrayList<>();
+
+    /**
+     * 2巡检打卡人
+     */
+    private List<Long> uIdsi = new ArrayList<>();
+
+    /**
+     * 3保养打卡人
+     */
+    private List<Long> uIdsu = new ArrayList<>();
+
+    //签入未签出的打卡人数,主要用于计算哪些需要延伸
+    //统计工站报表签入未签出的打卡人数
+    private Set<Long> uIdsoIn = new HashSet<>();
+
+
+    /**
+     * 0生产人数打卡人
+     */
+    private Set<Long> uIdspIn = new HashSet<>();
+
+    /**
+     * 1维修打卡人
+     */
+    private Set<Long> uIdswIn = new HashSet<>();
+
+    /**
+     * 2巡检打卡人
+     */
+    private Set<Long> uIdsiIn = new HashSet<>();
+
+    /**
+     * 3保养打卡人
+     */
+    private Set<Long> uIdsuIn = new HashSet<>();
+
+
+    /**
+     * 未签出工站详情报表工时
+     */
+    private Integer oWorkIn = 0;
+
+    /**
+     * 未签出0生产工时
+     */
+    private Integer pWorkIn = 0;
+
+    /**
+     * 未签出1维修工时
+     */
+    private Integer wWorkIn = 0;
+
+    /**
+     * 未签出2巡检工时
+     */
+    private Integer iWorkIn = 0;
+
+    /**
+     * 未签出3保养工时
+     */
+    private Integer uWorkIn = 0;
+
+
+}

+ 66 - 0
src/main/java/com/yeechart/dotMatrix/signage/bean/SheetPVo.java

@@ -0,0 +1,66 @@
+package com.yeechart.dotMatrix.signage.bean;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+
+@Data
+
+/**
+ * 报表-生产
+ */
+public class SheetPVo implements Serializable {
+
+
+    /**
+     * 时间节点-开始
+     */
+    private String timeStart;
+
+    /**
+     * 时间节点-结束
+     */
+    private String timeEnd;
+
+    /**
+     * 展示时间
+     */
+    private String time;
+
+    /**
+     * 良品数量
+     */
+    private Double good = 0.0;
+
+    /**
+     * 不良品数量
+     */
+    private Double noGood = 0.0;
+
+    /**
+     * 产能
+     */
+    private Double production = 0.0;
+
+    /**
+     * 良品率
+     */
+    private BigDecimal goodRate = BigDecimal.valueOf(0.0);
+
+    /**
+     * 稼动率
+     */
+    private BigDecimal utilizationRate = BigDecimal.valueOf(0.0);
+
+    /**
+     * 状态持续时长
+     */
+    private BigDecimal duration = BigDecimal.valueOf(0.0);
+    private Long tId;
+    private Long wSId;
+    private String _id;
+
+
+}

+ 166 - 0
src/main/java/com/yeechart/dotMatrix/signage/bean/Ter020201DriverBean.java

@@ -0,0 +1,166 @@
+package com.yeechart.dotMatrix.signage.bean;
+
+
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+
+/**
+ * 终端020201状态驱动源
+ */
+public class Ter020201DriverBean {
+
+
+    /**
+     * 设备ID
+     */
+    private String deId;
+
+
+    /**
+     * 运行 驱动源(0,按键,1:所属工站)
+     */
+    private Integer runDriver;
+
+
+    /**
+     * 待料 驱动源(0,按键,1:所属工站)
+     */
+    private Integer waitDriver;
+
+
+    /**
+     * 维修 驱动源(0,按键,1:所属工站)
+     */
+    private Integer maintainDriver;
+
+
+    /**
+     * 故障 驱动源(0,按键,1:所属工站)
+     */
+    private Integer faultDriver;
+
+
+    /**
+     * 保养 驱动源(0,按键,1:所属工站)
+     */
+    private Integer upkeepDriver;
+
+
+    /**
+     * 停机 驱动源(0,按键,1:所属工站)
+     */
+    private Integer haltDriver;
+
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+
+
+    /**
+     * 运行 是否开启(0:开启,1:不开启)
+     */
+    private Integer run = 0;
+
+    /**
+     * 运行的别名
+     */
+    private String rAlias;
+
+    /**
+     * 序号
+     */
+    private Integer rOrder;
+
+
+    /**
+     * 待料 是否开启(0:开启,1:不开启)
+     */
+    private Integer wait = 0;
+
+    /**
+     * 待料的别名
+     */
+    private String wAlias;
+
+    /**
+     * 序号
+     */
+
+    private Integer wOrder;
+
+
+    /**
+     * 维修 是否开启(0:开启,1:不开启)
+     */
+    private Integer maintain = 0;
+
+    /**
+     * 维修的别名
+     */
+    private String mAlias;
+
+    /**
+     * 序号
+     */
+    private Integer mOrder;
+
+
+    /**
+     * 故障 是否开启(0:开启,1:不开启)
+     */
+    private Integer fault = 0;
+
+    /**
+     * 故障的别名
+     */
+    private String fAlias;
+
+    /**
+     * 序号
+     */
+    private Integer fOrder;
+
+
+    /**
+     * 保养 是否开启(0:开启,1:不开启)
+     */
+    private Integer upkeep = 0;
+
+    /**
+     * 保养的别名
+     */
+    private String uAlias;
+
+    /**
+     * 序号
+     */
+    private Integer uOrder;
+
+
+    /**
+     * 停机 是否开启(0:开启,1:不开启)
+     */
+    private Integer halt = 0;
+
+    /**
+     * 停机的别名
+     */
+    private String hAlias;
+
+    /**
+     * 序号
+     */
+    private Integer hOrder;
+
+}

+ 718 - 0
src/main/java/com/yeechart/dotMatrix/signage/bean/Ter020201InfoVo.java

@@ -0,0 +1,718 @@
+package com.yeechart.dotMatrix.signage.bean;
+
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+
+@Data
+
+/**
+ * 产品类型020201 终端 的所有的属性详情
+ */
+public class Ter020201InfoVo {
+
+
+    /**
+     * 产品ID
+     */
+    private String productId;
+
+
+    /**
+     * 设备ID
+     */
+    private String deId;
+
+
+    /**
+     * 终端编码, type:1
+     */
+    private String terWorkCode;
+
+
+    /**
+     * 终端名称, type:2
+     */
+    private String terName;
+
+
+    /**
+     * 电池电量
+     */
+    private Integer battery;
+
+
+    /**
+     * 信号
+     */
+    private Integer signalNum;
+
+
+    /**
+     * 在线状态(0离线,1在线)
+     */
+    private Integer online;
+
+
+    /**
+     * 屏幕刷新周期(0:1分钟 1:5分钟 2:10分钟,3:30), type:3
+     */
+    private Integer screenRef;
+
+
+    /**
+     * 左屏幕设置, type:4
+     */
+    private Integer leftScreen;
+
+
+    /**
+     * 右屏幕设置, type:5
+     */
+    private Integer rightScreen;
+
+
+    /**
+     * 音量大小, type:6
+     */
+    private Integer volume;
+
+
+    /**
+     * 电池温度
+     */
+    private String temp;
+
+
+    /**
+     * 设备最新的工作状态, type:7
+     */
+    private Integer currentStatus;
+
+
+    /**
+     * 设备最新的工作状态开始时间, type:8
+     */
+    //@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
+    private Date statusTime;
+
+
+    /**
+     * 工站_编码, type:9
+     */
+    private String wsWorkCode;
+
+
+    /**
+     * 工站_名称, type:10
+     */
+    private String wsName;
+
+
+    /**
+     * 工站_公告, type:11
+     */
+    private String wsNotice;
+
+
+    /**
+     * 工站责任人设置, type:12
+     */
+    private TiOnusBean tiOnusBean;
+
+
+    /**
+     * 工站_生产责任人, type:13
+     */
+    private String produce;
+
+
+    /**
+     * 工站_维修责任人, type:14
+     */
+    private String maintain;
+
+
+    /**
+     * 工站_巡检责任人, type:15
+     */
+    private String inspection;
+
+
+    /**
+     * 工站_保养责任人, type:16
+     */
+    private String upkeep;
+
+
+    /**
+     * 工站_操作员, type:17
+     */
+    private String operator;
+
+
+    /**
+     * 工站_产能标准线, type:18
+     */
+    private Integer standardNum;
+
+
+//
+//    @ApiModelProperty(value = "工站_状态信息设置, type:19")// ,当更新此项时需将type-29和type-30均更新一次,用来刷新报表数据
+//    private TiSetStateBean tiSetState;
+
+    //@ApiModelProperty(value = "终端_状态信息设置, type:19")// ,当更新此项时需将type-29和type-30均更新一次,用来刷新报表数据
+    /**
+     * 终端_状态信息设置, type:19
+     */
+    private Ter020201DriverBean ter020201DriverBean;
+
+
+    /**
+     * 工站_打卡设置, type:20
+     */
+    private TiClockBean tiClock;
+
+
+    /**
+     * 系统公告, type:21
+     */
+    private String sysNotice;
+
+
+    /**
+     * 版本公告, type:22
+     */
+    private String verNotice;
+
+
+    /**
+     * 工站_打卡,实时 生产人员打卡个数, type:23
+     */
+    private Integer checkProduce;
+
+
+    /**
+     * 工站_打卡,实时 巡检人员打卡个数, type:24
+     */
+    private Integer checkInspect;
+
+
+    /**
+     * 工站_打卡,实时 维修人员打卡个数, type:25
+     */
+    private Integer checkMaintain;
+
+
+    /**
+     * 工站_打卡,实时 保养人员打卡个数, type:26
+     */
+    private Integer checkUpkeep;
+
+
+    /**
+     * 硬件版本, type:27
+     */
+    private String version;
+
+
+    /**
+     * 硬件升级状态(0 默认 正常状态 , 1 正在升级中), type:28
+     */
+    private Integer otaState;
+
+
+    /**
+     * 终端_状态历史( 0-运行 1-保养 2-维修/封存 3-故障 4-待料 5-停机  ), type:29
+     */
+    private Long[] stateHistoryArray = new Long[]{0L, 0L, 0L, 0L, 0L, 0L};
+
+
+    /**
+     * 终端_工时历史(0-生产打卡工时, 1-巡检打卡工时, 2-保养打卡工时, 3-维修打卡工时), type:30
+     */
+    private Long[] workingHoursHistoryArray = new Long[]{0L, 0L, 0L, 0L};
+
+//    @ApiModelProperty(value = "终端_签到历史(0-生产打卡人数, 1-巡检打卡人数, 2-保养打卡人数, 3-维修打卡人数), type:30") 2024/05/31 将打卡历史更换为 工时历史
+//    private Long[] checkHistoryArray = new Long[]{0L,0L,0L,0L};
+
+
+    /**
+     * 工站_报表_人数/工时, type:31
+     */
+    private List<SheetCheckVo> sheetCheckVos = new ArrayList<>();
+
+
+    /**
+     * 工站_报表_生产产能, type:32
+     */
+    private List<SheetPVo> sheetVos = new ArrayList<>();
+
+
+    /**
+     * 工站_良品率基线, type:33
+     */
+    private Integer yieldRate;
+
+
+    /**
+     * 工站_稼动率基线, type:34
+     */
+    private Integer cropRate;
+
+
+    private Boolean isDefault = false;//是否是默认数据
+
+
+    /**
+     * 硬件重启, type:35
+     */
+    private Integer recover;// 0为重启 1为恢复出厂(暂未实装)
+
+
+    /**
+     * NFC开关, (0 开 1关)type:36
+     */
+    private Integer nfcOpen;
+
+
+    /**
+     * 是否切换到该状态,( 0-停机 1-运行 2-维修 3-故障 )
+     */
+    private Integer forceState;
+
+
+    /**
+     * 当设备关机时 需要将状态进行更改( 0-停机 1-运行 2-封存 3-故障 4-保养 5-待料 ,  7 -延续上一次的状态, 255 不统计 ,  ), type:38
+     */
+    private Integer offlineStatus;
+
+
+    public static Ter020201InfoVo defaultInit() {
+        Ter020201InfoVo ter020201InfoVo = new Ter020201InfoVo();
+        ter020201InfoVo.setProductId("020201");
+        ter020201InfoVo.setDeId("default");
+
+        ter020201InfoVo.setTerWorkCode("00000001");
+        ter020201InfoVo.setTerName("蚁巢标识牌");
+        ter020201InfoVo.setBattery(100);
+        ter020201InfoVo.setSignalNum(100);
+        ter020201InfoVo.setScreenRef(30);
+        ter020201InfoVo.setLeftScreen(0);
+        ter020201InfoVo.setRightScreen(0);
+        ter020201InfoVo.setVolume(50);
+        ter020201InfoVo.setTemp("30.0");
+        ter020201InfoVo.setCurrentStatus(0);
+        ter020201InfoVo.setStatusTime(new Date());
+        ter020201InfoVo.setVersion("3.0.0");
+        ter020201InfoVo.setOtaState(0);
+
+
+        ter020201InfoVo.setStateHistoryArray(new Long[]{0L, 0L, 0L, 0L, 0L, 0L});
+
+
+        ter020201InfoVo.setWorkingHoursHistoryArray(new Long[]{0L, 0L, 0L, 0L});
+
+
+        ter020201InfoVo.setWsWorkCode("000000001");
+        ter020201InfoVo.setWsName("未绑定工站");
+        ter020201InfoVo.setWsNotice("");
+
+        TiOnusBean tiOnusBean1 = new TiOnusBean();
+
+        tiOnusBean1.setPAlias("生产责任人");
+        tiOnusBean1.setIsProduce(0);
+
+        tiOnusBean1.setMAlias("维修责任人");
+        tiOnusBean1.setIsMaintain(0);
+
+        tiOnusBean1.setOAlias("操作人员");
+        tiOnusBean1.setIsOperate(0);
+
+        tiOnusBean1.setIAlias("巡检责任人");
+        tiOnusBean1.setIsInspect(0);
+
+        tiOnusBean1.setUAlias("保养责任人");
+        tiOnusBean1.setIsUpkeep(0);
+
+        ter020201InfoVo.setTiOnusBean(tiOnusBean1);
+
+        ter020201InfoVo.setProduce("");
+        ter020201InfoVo.setMaintain("");
+        ter020201InfoVo.setInspection("");
+        ter020201InfoVo.setUpkeep("");
+        ter020201InfoVo.setOperator("");
+
+        ter020201InfoVo.setStandardNum(100);
+        ter020201InfoVo.setYieldRate(90);
+        ter020201InfoVo.setCropRate(75);
+
+        Ter020201DriverBean ter020201DriverBean1 = new Ter020201DriverBean();
+
+        ter020201DriverBean1.setRAlias("运行");
+        ter020201DriverBean1.setRun(0);
+        //tiSetStateBean.setRShow(0);
+
+        ter020201DriverBean1.setWAlias("待料");
+        ter020201DriverBean1.setWait(0);
+        //tiSetStateBean.setWShow(0);
+
+        ter020201DriverBean1.setMAlias("维修");
+        ter020201DriverBean1.setMaintain(0);
+        //tiSetStateBean.setMShow(0);
+
+        ter020201DriverBean1.setFAlias("故障");
+        ter020201DriverBean1.setFault(0);
+        //tiSetStateBean.setFShow(0);
+
+        ter020201DriverBean1.setUAlias("保养");
+        ter020201DriverBean1.setUpkeep(0);
+        //tiSetStateBean.setUShow(0);
+
+        ter020201DriverBean1.setHAlias("停机");
+        ter020201DriverBean1.setHalt(0);
+        //tiSetStateBean.setHShow(0);
+
+
+        ter020201InfoVo.setTer020201DriverBean(ter020201DriverBean1);
+
+        TiClockBean tiClockBean = new TiClockBean();
+
+        tiClockBean.setPAlias("生产");
+        tiClockBean.setProduce(0);
+
+        tiClockBean.setMAlias("维修");
+        tiClockBean.setMaintain(0);
+
+        tiClockBean.setIAlias("巡检");
+        tiClockBean.setInspect(0);
+
+        tiClockBean.setUAlias("保养");
+        tiClockBean.setUpkeep(0);
+
+
+        ter020201InfoVo.setTiClock(tiClockBean);
+
+        ter020201InfoVo.setCheckProduce(0);
+        ter020201InfoVo.setCheckInspect(0);
+        ter020201InfoVo.setCheckMaintain(0);
+        ter020201InfoVo.setCheckUpkeep(0);
+
+        ter020201InfoVo.setSysNotice("");
+        ter020201InfoVo.setVerNotice("");
+
+
+        List<SheetCheckVo> sheetCheckVos = new ArrayList<>();
+
+        for (int i = 0; i < 8; i++) {
+            SheetCheckVo sheetCheckVo = new SheetCheckVo();
+            sheetCheckVo.setTime("00:00");//展示时间
+            sheetCheckVo.setPeopleNum(0);//人数
+            sheetCheckVo.setWork(0);//工时
+            sheetCheckVo.setPeoplep(0);
+            ;
+            sheetCheckVo.setPeoplew(0);
+            ;
+            sheetCheckVo.setPeoplei(0);
+            ;
+            sheetCheckVo.setPeopleu(0);
+            ;
+            sheetCheckVos.add(sheetCheckVo);
+        }
+
+        ter020201InfoVo.setSheetCheckVos(sheetCheckVos);
+
+        List<SheetPVo> sheetVos = new ArrayList<>();
+        for (int i = 0; i < 8; i++) {
+
+            SheetPVo sheetPVo = new SheetPVo();
+
+            sheetPVo.setTime("00:00");//展示时间
+
+            sheetPVo.setGood(0.0);
+            sheetPVo.setNoGood(0.0);
+            sheetPVo.setProduction((double) 0L);
+
+            //sheetPVo.setGoodRate(Double.valueOf(AllUtil.getdecimal(String.valueOf(0),2)));
+            sheetPVo.setGoodRate(new BigDecimal(0.0));
+            sheetPVo.setUtilizationRate(new BigDecimal(0));
+
+            sheetVos.add(sheetPVo);
+
+        }
+
+        ter020201InfoVo.setSheetVos(sheetVos);
+
+
+        return ter020201InfoVo;
+    }
+
+
+    public static Ter020201InfoVo test3(String str) {
+        Ter020201InfoVo ter020201InfoVo = new Ter020201InfoVo();
+        ter020201InfoVo.setProductId("020201");
+        ter020201InfoVo.setDeId("test");
+
+        ter020201InfoVo.setTerWorkCode("11111111");
+        ter020201InfoVo.setTerName("终端名称");
+        ter020201InfoVo.setBattery(100);
+        ter020201InfoVo.setSignalNum(100);
+        ter020201InfoVo.setScreenRef(30);
+        ter020201InfoVo.setLeftScreen(1);
+        ter020201InfoVo.setRightScreen(1);
+        ter020201InfoVo.setVolume(50);
+        ter020201InfoVo.setTemp("30.0");
+        ter020201InfoVo.setCurrentStatus(1);
+        ter020201InfoVo.setStatusTime(new Date());
+        ter020201InfoVo.setVersion("3.0.0");
+        ter020201InfoVo.setOtaState(0);
+
+
+//        for(int i =0;i < 6;i++){
+//            RecordTStateBean recordTStateBean = new RecordTStateBean();
+//            recordTStateBean.setState(0);
+//            recordTStateBean.setDuration(20*i);
+//            ter020201InfoVo.getRecordTStateBeanList().add(recordTStateBean);
+//        }
+
+        ter020201InfoVo.setStateHistoryArray(new Long[]{100L, 50L, 80L, 10L, 0L, 60L});
+
+
+        ter020201InfoVo.setWorkingHoursHistoryArray(new Long[]{200L, 20L, 180L, 3000L});
+
+
+        ter020201InfoVo.setWsWorkCode("22222222");
+        ter020201InfoVo.setWsName("工站名称");
+        ter020201InfoVo.setWsNotice("这是一个工站的公告,不过是测试使用的,需要多打几个字看看如何换行处理之类的,还有后续考虑省略号的奥iu不到你千万会被丢弃表不对哦白uiu啊不会的iu哦啊是对iu还u收到iu哎u阿斯u豆瓣iu啊ui地球该海湾地区有困境和关怀和改革和白素会给丢啊");
+
+        TiOnusBean tiOnusBean1 = new TiOnusBean();
+
+        tiOnusBean1.setPAlias("生产责任人别名");
+        tiOnusBean1.setIsProduce(0);
+
+        tiOnusBean1.setMAlias("维修责任人别名");
+        tiOnusBean1.setIsMaintain(0);
+
+        tiOnusBean1.setOAlias("操作员别名");
+        tiOnusBean1.setIsOperate(0);
+
+        tiOnusBean1.setIAlias("巡检责任人别名");
+        tiOnusBean1.setIsInspect(0);
+
+        tiOnusBean1.setUAlias("保养责任人别名");
+        tiOnusBean1.setIsUpkeep(0);
+
+        ter020201InfoVo.setTiOnusBean(tiOnusBean1);
+
+        ter020201InfoVo.setProduce("生产责任人的内容,这样度过的");
+        ter020201InfoVo.setMaintain("那就轰炸不符合以上南沙海域撒娇你不是赛那啥啥金沙萨");
+        ter020201InfoVo.setInspection("就篡改活跃于计划的用户接口对接急啊急啊就就接电话将按计划和绝对是");
+        ter020201InfoVo.setUpkeep("惊险刺激的剩余环境环境据四四恶化的集合和但遗憾的是 决定快递看见大家核对就");
+        ter020201InfoVo.setOperator("进行创业时代是佳能单反觉得还是有看见安河桥进度计划的决定接口暗杀计划是大家就阿萨");
+
+
+        ter020201InfoVo.setStandardNum(50);
+        ter020201InfoVo.setYieldRate(80);
+        ter020201InfoVo.setCropRate(80);
+
+        Ter020201DriverBean tiSetStateBean = new Ter020201DriverBean();
+
+        tiSetStateBean.setRAlias("ABCDEF");
+        tiSetStateBean.setRun(0);
+        //tiSetStateBean.setRShow(0);
+
+        tiSetStateBean.setWAlias(str);
+        tiSetStateBean.setWait(0);
+        //tiSetStateBean.setWShow(0);
+
+        tiSetStateBean.setMAlias("/+大-和*");
+        tiSetStateBean.setMaintain(0);
+        //tiSetStateBean.setMShow(0);
+
+        tiSetStateBean.setFAlias("我a你b才g");
+        tiSetStateBean.setFault(0);
+        //tiSetStateBean.setFShow(0);
+
+        tiSetStateBean.setUAlias("好1早2骄y");
+        tiSetStateBean.setUpkeep(0);
+        //tiSetStateBean.setUShow(0);
+
+        tiSetStateBean.setHAlias("0g9y1R");
+        tiSetStateBean.setHalt(0);
+        //tiSetStateBean.setHShow(0);
+
+
+        ter020201InfoVo.setTer020201DriverBean(tiSetStateBean);
+
+        TiClockBean tiClockBean = new TiClockBean();
+
+        tiClockBean.setPAlias("生产");
+        tiClockBean.setProduce(0);
+
+        tiClockBean.setMAlias("维修");
+        tiClockBean.setMaintain(0);
+
+        tiClockBean.setIAlias("巡检");
+        tiClockBean.setInspect(0);
+
+        tiClockBean.setUAlias("保养");
+        tiClockBean.setUpkeep(0);
+
+
+        ter020201InfoVo.setTiClock(tiClockBean);
+
+        ter020201InfoVo.setCheckProduce(0);
+        ter020201InfoVo.setCheckInspect(123);
+        ter020201InfoVo.setCheckMaintain(456);
+        ter020201InfoVo.setCheckUpkeep(789);
+
+        ter020201InfoVo.setSysNotice("这是测试的系统公告金卡稍等哈晒ui偶是对哦奥会丢哈iu哈桑对哈斯u的hi撒谎丢啊大撒大撒谁的iu好低啊u是对哦i啊u是丢哈");
+        ter020201InfoVo.setVerNotice("这是测试的版本公告按时间哦好的哈是呵呵大弧度坏坏的i不都啊随队前往的iu去啊不阿三大苏打丢啊大雾i百度哦i啊是不对还很多");
+
+
+        List<SheetCheckVo> sheetCheckVos = new ArrayList<>();
+
+        SheetCheckVo sheetCheckVo = new SheetCheckVo();
+        sheetCheckVo.setTime("10:30");//展示时间
+        sheetCheckVos.add(sheetCheckVo);
+
+        SheetCheckVo sheetCheckVo1 = new SheetCheckVo();
+        sheetCheckVo1.setTime("11:00");//展示时间
+        sheetCheckVos.add(sheetCheckVo1);
+
+        SheetCheckVo sheetCheckVo2 = new SheetCheckVo();
+        sheetCheckVo2.setTime("11:30");//展示时间
+        sheetCheckVos.add(sheetCheckVo2);
+
+        SheetCheckVo sheetCheckVo3 = new SheetCheckVo();
+        sheetCheckVo3.setTime("12:00");//展示时间
+        sheetCheckVos.add(sheetCheckVo3);
+
+        SheetCheckVo sheetCheckVo4 = new SheetCheckVo();
+        sheetCheckVo4.setTime("12:30");//展示时间
+        sheetCheckVos.add(sheetCheckVo4);
+
+        SheetCheckVo sheetCheckVo5 = new SheetCheckVo();
+        sheetCheckVo5.setTime("13:00");//展示时间
+        sheetCheckVos.add(sheetCheckVo5);
+
+        SheetCheckVo sheetCheckVo6 = new SheetCheckVo();
+        sheetCheckVo6.setTime("13:30");//展示时间
+        sheetCheckVos.add(sheetCheckVo6);
+
+        SheetCheckVo sheetCheckVo7 = new SheetCheckVo();
+        sheetCheckVo7.setTime("14:00");//展示时间
+        sheetCheckVos.add(sheetCheckVo7);
+
+
+//        for(int i = 0; i < 8 ; i++){
+//            SheetCheckVo sheetCheckVo = new SheetCheckVo();
+//            int time = i*30;
+//
+//            int hour = time/60;
+//            int minute = time%60;
+//
+//            sheetCheckVo.setTime(
+//                    (hour>10?hour:"0"+hour) +
+//                    ":" +
+//                    (minute>10?minute:"0"+minute)
+//            );//展示时间
+//
+//            sheetCheckVo.setPeopleNum(i*30);//人数
+//            sheetCheckVo.setWork(i*22);//工时
+//
+//            sheetCheckVo.setPeoplep(i*2);;
+//            sheetCheckVo.setPeoplew(i*3);;
+//            sheetCheckVo.setPeoplei(i*4);;
+//            sheetCheckVo.setPeopleu(i*5);;
+//
+//
+//            sheetCheckVos.add(sheetCheckVo);
+//        }
+
+        ter020201InfoVo.setSheetCheckVos(sheetCheckVos);
+
+
+        List<SheetPVo> sheetVos = new ArrayList<>();
+
+
+        SheetPVo sheetPVo = new SheetPVo();
+        sheetPVo.setTime("10:30");//展示时间
+        sheetVos.add(sheetPVo);
+
+        SheetPVo sheetPVo1 = new SheetPVo();
+        sheetPVo1.setTime("11:00");//展示时间
+        sheetPVo1.setUtilizationRate(new BigDecimal(13.33));
+        sheetPVo1.setDuration(new BigDecimal(4.0));
+        sheetVos.add(sheetPVo1);
+
+        SheetPVo sheetPVo2 = new SheetPVo();
+        sheetPVo2.setTime("11:30");//展示时间
+        sheetPVo2.setUtilizationRate(new BigDecimal(20.0));
+        sheetPVo2.setDuration(new BigDecimal(6.0));
+        sheetVos.add(sheetPVo2);
+
+        SheetPVo sheetPVo3 = new SheetPVo();
+        sheetPVo3.setTime("12:00");//展示时间
+        sheetVos.add(sheetPVo3);
+
+        SheetPVo sheetPVo4 = new SheetPVo();
+        sheetPVo4.setTime("12:30");//展示时间
+        sheetVos.add(sheetPVo4);
+
+        SheetPVo sheetPVo5 = new SheetPVo();
+        sheetPVo5.setTime("13:00");//展示时间
+        sheetVos.add(sheetPVo5);
+
+        SheetPVo sheetPVo6 = new SheetPVo();
+        sheetPVo6.setTime("13:30");//展示时间
+        sheetVos.add(sheetPVo6);
+
+
+        SheetPVo sheetPVo7 = new SheetPVo();
+        sheetPVo7.setTime("14:00");//展示时间
+        sheetPVo7.setUtilizationRate(new BigDecimal(71.43));
+        sheetPVo7.setDuration(new BigDecimal(25.0));
+        sheetVos.add(sheetPVo7);
+
+
+//        for(int i = 0; i < 8 ; i++){
+//
+//            SheetPVo sheetPVo = new SheetPVo();
+//
+//            int time = i*30;
+//
+//            int hour = time/60;
+//            int minute = time%60;
+//
+//            sheetPVo.setTime(
+//                    (hour>10?hour:"0"+hour) +
+//                            ":" +
+//                            (minute>10?minute:"0"+minute)
+//            );//展示时间
+//
+//            sheetPVo.setGood(i*123.45);
+//            sheetPVo.setNoGood(i*12.34);
+//            sheetPVo.setProduction(i*300);
+//
+//            sheetPVo.setGoodRate(Double.valueOf(AllUtil.getdecimal(String.valueOf(i*0.10),2)));
+//            sheetPVo.setUtilizationRate(Double.valueOf(AllUtil.getdecimal(String.valueOf(i*0.05),2)));
+//
+//            sheetVos.add(sheetPVo);
+//
+//        }
+
+        ter020201InfoVo.setSheetVos(sheetVos);
+
+
+        return ter020201InfoVo;
+    }
+
+
+}
+

+ 32 - 0
src/main/java/com/yeechart/dotMatrix/signage/bean/Ter020201Vo.java

@@ -0,0 +1,32 @@
+package com.yeechart.dotMatrix.signage.bean;
+
+
+import lombok.Data;
+
+
+@Data
+
+/**
+ * 终端信息更新对象
+ */
+public class Ter020201Vo {
+
+
+    /**
+     * 设备信息对象
+     */
+    private Ter020201InfoVo ter020201InfoVo;
+
+
+    /**
+     * 要更新的类别[0 全更新,其他按照Ter020201InfoVo中的说明使用]
+     */
+    private Integer[] type;
+
+
+    /**
+     * 时间
+     */
+    private Long time;
+
+}

+ 81 - 0
src/main/java/com/yeechart/dotMatrix/signage/bean/TiClockBean.java

@@ -0,0 +1,81 @@
+package com.yeechart.dotMatrix.signage.bean;
+
+
+import lombok.Data;
+
+import java.util.Date;
+
+
+@Data
+
+/**
+ * 终端信息-打卡设置
+ */
+public class TiClockBean {
+
+
+    /**
+     * 工站ID
+     */
+    private Long wSId;
+
+
+    /**
+     * 生产别名
+     */
+    private String pAlias;
+
+    /**
+     * 生产 是否启用(0:启用,1:不启动)
+     */
+    private Integer produce = 0;
+
+
+    /**
+     * 巡检别名
+     */
+    private String iAlias;
+
+    /**
+     * 巡检 是否启用(0:启用,1:不启动)
+     */
+    private Integer inspect = 0;
+
+
+    /**
+     * 维修别名
+     */
+    private String mAlias;
+
+    /**
+     * 维修 是否启用(0:启用,1:不启动)
+     */
+    private Integer maintain = 0;
+
+
+    /**
+     * 保养别名
+     */
+    private String uAlias;
+
+    /**
+     * 保养 是否启用(0:启用,1:不启动)
+     */
+    private Integer upkeep = 0;
+
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+
+    public TiClockBean() {
+
+    }
+
+}

+ 87 - 0
src/main/java/com/yeechart/dotMatrix/signage/bean/TiOnusBean.java

@@ -0,0 +1,87 @@
+package com.yeechart.dotMatrix.signage.bean;
+
+
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+/**
+ * 工站责任人设置
+ */
+public class TiOnusBean {
+
+
+    /**
+     * 工站ID
+     */
+    private Long wSId;
+
+
+    /**
+     * 生产责任人别名
+     */
+    private String pAlias;
+
+    /**
+     * 生产责任人 是否启用(0:启用,1:不启动)
+     */
+    private Integer isProduce = 0;
+
+
+    /**
+     * 巡检责任人别名
+     */
+    private String iAlias;
+
+    /**
+     * 巡检责任人 是否启用(0:启用,1:不启动)
+     */
+    private Integer isInspect = 0;
+
+
+    /**
+     * 维修责任人别名
+     */
+    private String mAlias;
+
+    /**
+     * 维修责任人 是否启用(0:启用,1:不启动)
+     */
+    private Integer isMaintain = 0;
+
+
+    /**
+     * 保养责任人别名
+     */
+    private String uAlias;
+
+    /**
+     * 保养责任人 是否启用(0:)
+     */
+    private Integer isUpkeep = 0;
+
+
+    /**
+     * 操作人员 别名
+     */
+    private String oAlias;
+
+    /**
+     * 操作人员 是否启用(0:启用,1:不启动)
+     */
+    private Integer isOperate = 0;
+
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+
+
+}

+ 48 - 0
src/main/java/com/yeechart/dotMatrix/signage/bean/mizilzo/BitmapDataVo.java

@@ -0,0 +1,48 @@
+package com.yeechart.dotMatrix.signage.bean.mizilzo;
+
+
+import lombok.Data;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 字节数据 对象
+ */
+
+@Data
+/**
+ * 文件点阵图相关数据对象
+ */
+public class BitmapDataVo {
+
+
+    /**
+     * 功能编码
+     */
+    private String typeCode;
+
+
+    /**
+     * 二进制点阵数组数据(整图)
+     */
+    private byte[] twoData;
+
+
+    /**
+     * 点阵数据访问路径
+     */
+    private String path;
+
+
+    /**
+     * 点阵数据形成的时间
+     */
+    private Long time;
+
+
+    /**
+     * 点阵数据文件夹中各个文件的属性<文件名,子文件数据>(整图切割的分图)
+     */
+    private Map<String, MiniLZOVo> miniLZOVoList = new HashMap<>();
+}

+ 27 - 0
src/main/java/com/yeechart/dotMatrix/signage/bean/mizilzo/MiniLZOVo.java

@@ -0,0 +1,27 @@
+package com.yeechart.dotMatrix.signage.bean.mizilzo;
+
+
+import lombok.Data;
+
+@Data
+/**
+ * MiniLZO 压缩后的属性
+ */
+public class MiniLZOVo {
+
+    /**
+     * 原本的数据大小(非压缩前)
+     */
+    private Integer ogSize;
+
+    /**
+     * 压缩后的十六进制数组数据
+     */
+    private byte[] data;
+
+    /**
+     * 压缩后的十六进制数组数据的CRC32校验
+     */
+    private Long crc32;
+
+}

+ 79 - 0
src/main/java/com/yeechart/dotMatrix/thread/RetryService.java

@@ -0,0 +1,79 @@
+package com.yeechart.dotMatrix.thread;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@Service
+public class RetryService {
+
+    Logger logger = LoggerFactory.getLogger(RetryService.class);
+    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);
+    private final ConcurrentHashMap<Runnable, AtomicInteger> retryCountMap = new ConcurrentHashMap<>();
+
+    // 核心线程数,基于CPU核心数的两倍,适合大多数并发场景
+    private static final int MAX_RETIES = 5;
+    // 基础重试间隔,单位秒
+    private static final int BASE_DELAY = 1;
+    // 重试间隔乘数
+    private static final double BACKOFF_MULTIPLIER = 1.5;
+    public interface TaskSubmitCallback {
+        void onTaskSubmitted();
+    }
+
+    /**
+     * 动态调整重试间隔的计算方法
+     * @param retryCount 重试次数
+     * @return 计算后的重试延迟时间
+     */
+    private long calculateDelay(int retryCount) {
+        return (long)(BASE_DELAY * Math.pow(BACKOFF_MULTIPLIER, retryCount - 1));
+    }
+    /**
+     * 重试 进入线程池
+     * @param task 线程
+     * @param initialDelay  开始延时的时间
+     * @param unit  延迟的时间单位
+     * @param callback  回调
+     * @return
+     */
+    public ScheduledFuture<?> scheduleRetry(Runnable task, long initialDelay, TimeUnit unit, TaskSubmitCallback callback) {
+        AtomicInteger count = retryCountMap.computeIfAbsent(task, k -> new AtomicInteger(0));
+        if (count.getAndIncrement() >= MAX_RETIES) {
+            logger.error("  count.getAndIncrement() >= MAX_RETIES  是 重试调用线程池 超出次数: " + task);
+            retryCountMap.remove(task);
+            return null;
+        }
+        long delay = calculateDelay(count.get());
+        ScheduledFuture<?> future = scheduler.schedule(() -> {
+            try {
+                logger.error("拒绝策略 排队成功:{}", task.toString());
+                task.run();
+                // 任务成功执行,通过回调清除重试记录
+                if (callback != null) {
+                    callback.onTaskSubmitted();
+                }
+            } catch (Exception e) {
+                if (count.get() < MAX_RETIES) {
+                    logger.warn("任务执行失败,安排重试第{}次: {}", count.get(), task);
+                    scheduleRetry(task, delay, unit, callback);
+                } else {
+                    logger.error("  count.get() < MAX_RETIES  否  任务最终重试失败: " + task);
+                }
+            }
+        }, initialDelay, unit);
+        return future;
+    }
+
+    public void cancelRetry(Runnable task) {
+        AtomicInteger count = retryCountMap.remove(task);
+        if (count != null) {
+            // 取消所有与该任务相关的未来重试
+            logger.error("取消 重试调用线程池  " + task);
+        }
+    }
+}
+
+

+ 66 - 0
src/main/java/com/yeechart/dotMatrix/thread/ThreadPoolTaskExecutorConfig.java

@@ -0,0 +1,66 @@
+package com.yeechart.dotMatrix.thread;
+
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.TimeUnit;
+
+@Configuration
+public class ThreadPoolTaskExecutorConfig {
+
+    private static final Logger log = LoggerFactory.getLogger(ThreadPoolTaskExecutorConfig.class);
+    // 获取服务器的CPU核心数
+    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
+
+    // 核心线程数,基于CPU核心数的两倍,适合大多数并发场景
+    private static final int CORE_POOL_SIZE =  (int) (CPU_COUNT * 1.5);//CPU_COUNT*2
+
+    // 最大线程数,基于CPU核心数的四倍,适用于高并发短暂任务
+    private static final int MAX_POOL_SIZE =  Math.max(4, (int) (CPU_COUNT * 3));//CPU_COUNT*4
+
+    // 队列容量,设置为最大线程数的两倍,以平衡内存使用和任务排队,避免无界队列导致的内存溢出
+    private static final int QUEUE_CAPACITY = MAX_POOL_SIZE * 2;
+
+    // 空闲线程存活时间,单位秒,这里设置为60秒
+    private static final int KEEP_ALIVE_SECONDS = 30;//
+
+
+    @Autowired
+    private RetryService retryService;
+
+    @Bean(name="voiceThreadPoolTaskExecutor")
+    public ThreadPoolTaskExecutor voiceThreadPoolTaskExecutor(){
+        ThreadPoolTaskExecutor poolTaskExecutor = new ThreadPoolTaskExecutor();
+
+        // 设置核心线程数
+        poolTaskExecutor.setCorePoolSize(CORE_POOL_SIZE);
+        // 设置最大线程数
+        poolTaskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
+        // 使用有界队列,避免内存无限增长
+        poolTaskExecutor.setQueueCapacity(QUEUE_CAPACITY);
+        // 空闲线程存活时间
+        poolTaskExecutor.setKeepAliveSeconds(KEEP_ALIVE_SECONDS);
+        // 当线程池关闭时等待所有任务完成
+        poolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
+        // 设置线程池中任务的等待时间,如果超过这个时间还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住
+        poolTaskExecutor.setAwaitTerminationSeconds(60);
+        // 设置线程前缀,便于定位
+        poolTaskExecutor.setThreadNamePrefix("voiceThreadPool-");
+        // 自定义拒绝策略
+        poolTaskExecutor.setRejectedExecutionHandler((r, executor1) -> {
+            log.error("线程池已满,任务被拒绝,正在重新进入拒绝策略:{}", r.toString());
+            RetryService.TaskSubmitCallback callback = () -> retryService.cancelRetry(r);
+            retryService.scheduleRetry(r, 1,  TimeUnit.SECONDS,  callback);
+        });
+
+        // 初始化线程池
+        poolTaskExecutor.initialize();
+
+        return poolTaskExecutor;
+    }
+}

+ 61 - 0
src/main/java/com/yeechart/dotMatrix/util/OtherUtil.java

@@ -0,0 +1,61 @@
+package com.yeechart.dotMatrix.util;
+
+public class OtherUtil {
+    /**
+     * 字节数组转为16进制字符串
+     *
+     * @param b     字节数组
+     * @return 16进制字符串
+     * 2018.5.5
+     */
+    private final static byte[] hex = "0123456789ABCDEF".getBytes();
+
+    /**
+     * long 转 16进制字节数组
+     *
+     * @param number
+     * @return
+     */
+    public static byte[] longToByteArray(long number, int len) {
+        byte[] byteArray = new byte[len];
+        for (int i = len - 1; i >= 0; i--) {
+            byteArray[i] = (byte) (number & 0xFF);
+            number >>>= 8;
+        }
+        return byteArray;
+    }
+
+    /**
+     * 将String,转化为高位补0的固定格式
+     *
+     * @param str   需要格式化的str
+     * @param scale 规定的格式(如2位 即2)
+     * @return
+     */
+    public static String strToHighZeroPadding(String str, int scale) {
+        int length = str.length();
+        if (length > scale) {
+//            throw new IllegalArgumentException(
+//                    "转换的格式必须小于规定的格式");
+            return null;
+        }
+
+        if (length < scale) {
+            str = "0" + str;
+            return strToHighZeroPadding(str, scale);
+        }
+        return str;//这是等于
+    }
+
+    public static String Bytes2HexString(byte[] b) {
+        //先把byte[] 转换为buff[],再把buff[]转换为字符串
+        byte[] buff = new byte[2 * b.length];
+        for (int i = 0; i < b.length; i++) {
+            buff[2 * i] = hex[(b[i] >> 4) & 0x0f];
+            buff[2 * i + 1] = hex[b[i] & 0x0f];
+        }
+        String a = new String(buff);
+        return new String(buff);
+    }
+
+}

+ 8 - 0
src/main/resources/application.yml

@@ -0,0 +1,8 @@
+server:
+  #port: 9006
+  port: 1111
+oss:
+  accesskeyid: LTAI5t9avf8qyfJSiWCCPgGj
+  accesskeysecret: OcCaklsOVwv7ccOlWB1tOyKemyaqXW
+  bucket: yichao-filestorage-test
+  endpoint: filestoragetest.yeechart.com

File diff suppressed because it is too large
+ 289144 - 0
src/main/resources/fonts/font_2024_03_15.DAT


BIN
src/main/resources/image/device/020201/Wi-Fi配网.png


BIN
src/main/resources/image/device/020201/init_left_default.png


BIN
src/main/resources/image/device/020201/init_right_default.jpg


BIN
src/main/resources/image/device/020201/init_right_default_20240601.jpg


BIN
src/main/resources/image/device/020201/left_state_0.png


BIN
src/main/resources/image/device/020201/left_state_1.png


BIN
src/main/resources/image/device/020201/left_state_2.png


BIN
src/main/resources/image/device/020201/left_state_254.png


BIN
src/main/resources/image/device/020201/left_state_3.png


BIN
src/main/resources/image/device/020201/left_state_4.png


BIN
src/main/resources/image/device/020201/left_state_5.png


BIN
src/main/resources/image/device/020201/nfc.png


BIN
src/main/resources/image/device/020201/nfc2.png


BIN
src/main/resources/image/device/020201/声音减.png


BIN
src/main/resources/image/device/020201/声音加.png


BIN
src/main/resources/image/device/020201/开关.png


BIN
src/main/resources/image/device/020201/语音.png


+ 35 - 0
src/main/resources/logback.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <!-- encoders are  by default assigned the type
+             ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <!-- 时间滚动输出 level为 ERROR 日志 -->
+    <appender name="rollingFile"
+              class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <FileNamePattern>logs/dotMatrix.%d{yyyy-MM-dd}.log</FileNamePattern>
+            <MaxHistory>7</MaxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+            </pattern>
+        </encoder>
+    </appender>
+
+    <appender name="asyncFileAppender" class="ch.qos.logback.classic.AsyncAppender">
+        <discardingThreshold>0</discardingThreshold>
+        <queueSize>100</queueSize>
+        <appender-ref ref="rollingFile"/>
+    </appender>
+    <logger name="com.yeechart.dotMatrix" level="debug"/>
+    <root level="info">
+        <appender-ref ref="STDOUT"/>
+        <appender-ref ref="rollingFile"/>
+    </root>
+</configuration>

+ 13 - 0
src/test/java/com/yeechart/dotMatrix/DotMatrixApplicationTests.java

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