pruple_boy vor 2 Jahren
Commit
19303b641a
100 geänderte Dateien mit 22761 neuen und 0 gelöschten Zeilen
  1. 37 0
      .gitignore
  2. 54 0
      mjava-cloudpure/pom.xml
  3. 32 0
      mjava-cloudpure/src/main/java/com.malk.cloudpure/Boot.java
  4. 17 0
      mjava-cloudpure/src/main/java/com.malk.cloudpure/controller/XBBController.java
  5. 53 0
      mjava-cloudpure/src/main/resources/application-dev.yml
  6. 34 0
      mjava-cloudpure/src/main/resources/application-prod.yml
  7. 35 0
      mjava-cloudpure/src/test/resources/server.sh
  8. 53 0
      mjava-cloudpure/target/classes/application-dev.yml
  9. 34 0
      mjava-cloudpure/target/classes/application-prod.yml
  10. 35 0
      mjava-cloudpure/target/test-classes/server.sh
  11. 60 0
      mjava-guyuan/pom.xml
  12. 30 0
      mjava-guyuan/src/main/java/Boot.java
  13. 149 0
      mjava-guyuan/src/main/java/com/malk/guyuan/controller/GYController.java
  14. 166 0
      mjava-guyuan/src/main/java/com/malk/guyuan/controller/IVController.java
  15. 26 0
      mjava-guyuan/src/main/java/com/malk/guyuan/filter/CatchException_YXY.java
  16. 185 0
      mjava-guyuan/src/main/java/com/malk/guyuan/server/model/McInvoiceDto.java
  17. 62 0
      mjava-guyuan/src/main/java/com/malk/guyuan/server/model/McInvoiceKind.java
  18. 92 0
      mjava-guyuan/src/main/java/com/malk/guyuan/server/model/sample.md
  19. 32 0
      mjava-guyuan/src/main/java/com/malk/guyuan/server/tencent/TXYConf.java
  20. 24 0
      mjava-guyuan/src/main/java/com/malk/guyuan/service/tencent/TXYInvoice.java
  21. 104 0
      mjava-guyuan/src/main/java/com/malk/guyuan/service/tencent/impl/TXYImplInvoice.java
  22. 64 0
      mjava-guyuan/src/main/resources/application-dev.yml
  23. 45 0
      mjava-guyuan/src/main/resources/application-prod.yml
  24. 8921 0
      mjava-guyuan/src/main/resources/static/mjs/mjs.js
  25. 1 0
      mjava-guyuan/src/main/resources/static/mjs/mjs.min.js
  26. 38 0
      mjava-guyuan/target/classes/META-INF/spring-configuration-metadata.json
  27. 64 0
      mjava-guyuan/target/classes/application-dev.yml
  28. 45 0
      mjava-guyuan/target/classes/application-prod.yml
  29. 8921 0
      mjava-guyuan/target/classes/static/mjs/mjs.js
  30. 1 0
      mjava-guyuan/target/classes/static/mjs/mjs.min.js
  31. 5 0
      mjava-guyuan/target/maven-archiver/pom.properties
  32. 1 0
      mjava-guyuan/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
  33. 9 0
      mjava-guyuan/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
  34. BIN
      mjava-guyuan/target/mjava-guyuan.jar.original
  35. 54 0
      mjava-hangshi/pom.xml
  36. 32 0
      mjava-hangshi/src/main/java/com/malk/hangshi/Boot.java
  37. 34 0
      mjava-hangshi/src/main/java/com/malk/hangshi/controller/HSController.java
  38. 53 0
      mjava-hangshi/src/main/resources/application-dev.yml
  39. 39 0
      mjava-hangshi/src/main/resources/application-prod.yml
  40. 35 0
      mjava-hangshi/src/test/resources/server.sh
  41. 53 0
      mjava-hangshi/target/classes/application-dev.yml
  42. 39 0
      mjava-hangshi/target/classes/application-prod.yml
  43. 35 0
      mjava-hangshi/target/test-classes/server.sh
  44. 113 0
      mjava-mcli/pom.xml
  45. 68 0
      mjava-mcli/src/main/java/com/malk/mcli/config/CxfConfig.java
  46. 40 0
      mjava-mcli/src/main/java/com/malk/mcli/config/WsInInterceptor.java
  47. 71 0
      mjava-mcli/src/main/java/com/malk/mcli/config/WsOutInterceptor.java
  48. 120 0
      mjava-mcli/src/main/java/com/malk/mcli/controller/DocController.java
  49. 11 0
      mjava-mcli/src/main/java/com/malk/mcli/repository/dao/AyUserAttachmentRelRepository.java
  50. 16 0
      mjava-mcli/src/main/java/com/malk/mcli/repository/entity/AyUserAttachmentRel.java
  51. 41 0
      mjava-mcli/src/main/java/com/malk/mcli/service/IH3yunWebService.java
  52. 34 0
      mjava-mcli/src/main/java/com/malk/mcli/service/InvoiceWebService.java
  53. 46 0
      mjava-mcli/src/main/java/com/malk/mcli/service/impl/H3yunWebServiceImpl.java
  54. 56 0
      mjava-mcli/src/main/java/com/malk/mcli/service/impl/InvoiceWebServiceImpl.java
  55. 68 0
      mjava-mcli/src/main/java/com/malk/mcli/test/JSPTestController.java
  56. 37 0
      mjava-mcli/src/main/java/com/malk/mcli/test/MGTestController.java
  57. 48 0
      mjava-mcli/src/main/java/com/malk/mcli/utils/UtilVendor.java
  58. 55 0
      mjava-mcli/src/main/resources/application-dev.yml
  59. 39 0
      mjava-mcli/src/main/resources/application-prod.yml
  60. 42 0
      mjava-mcli/src/main/webapp/WEB-INF/jsp/echart.jsp
  61. 24 0
      mjava-mcli/src/main/webapp/WEB-INF/jsp/index.jsp
  62. 31 0
      mjava-mcli/src/main/webapp/WEB-INF/jsp/test.jsp
  63. 6 0
      mjava-mcli/src/main/webapp/WEB-INF/web.xml
  64. 41 0
      mjava-mcli/src/test/java/com/malk/mcli/DDTest.java
  65. 41 0
      mjava-mcli/src/test/java/com/malk/mcli/JpaTest.java
  66. 99 0
      mjava-mcli/src/test/java/com/malk/mcli/McTest.java
  67. 31 0
      mjava-mcli/src/test/java/com/malk/mcli/U8Test.java
  68. 97 0
      mjava-mcli/src/test/java/com/malk/mcli/YDTest.java
  69. 66 0
      mjava-mcli/src/test/java/com/malk/mcli/YSTest.java
  70. 35 0
      mjava-mcli/src/test/resources/server.sh
  71. 56 0
      mjava-mcli/src/test/resources/winsw.xml
  72. 55 0
      mjava-mcli/target/classes/application-dev.yml
  73. 39 0
      mjava-mcli/target/classes/application-prod.yml
  74. 35 0
      mjava-mcli/target/test-classes/server.sh
  75. 56 0
      mjava-mcli/target/test-classes/winsw.xml
  76. 54 0
      mjava-suodisi/pom.xml
  77. 32 0
      mjava-suodisi/src/main/java/com/malk/suodisi/Boot.java
  78. 106 0
      mjava-suodisi/src/main/java/com/malk/suodisi/controller/SDSController.java
  79. 53 0
      mjava-suodisi/src/main/resources/application-dev.yml
  80. 34 0
      mjava-suodisi/src/main/resources/application-prod.yml
  81. 35 0
      mjava-suodisi/src/test/resources/server.sh
  82. 53 0
      mjava-suodisi/target/classes/application-dev.yml
  83. 34 0
      mjava-suodisi/target/classes/application-prod.yml
  84. 35 0
      mjava-suodisi/target/test-classes/server.sh
  85. 49 0
      mjava/pom.xml
  86. 29 0
      mjava/src/main/java/com/malk/Boot.java
  87. 215 0
      mjava/src/main/java/com/malk/Filter/CatchException.java
  88. 53 0
      mjava/src/main/java/com/malk/Filter/ExceptionNotice.java
  89. 32 0
      mjava/src/main/java/com/malk/Filter/RequestFilter.java
  90. 41 0
      mjava/src/main/java/com/malk/Filter/RequestInterceptor.java
  91. 29 0
      mjava/src/main/java/com/malk/base/BaseDao.java
  92. 112 0
      mjava/src/main/java/com/malk/base/BaseDto.java
  93. 55 0
      mjava/src/main/java/com/malk/base/BasePo.java
  94. 9 0
      mjava/src/main/java/com/malk/base/BaseRepository.java
  95. 73 0
      mjava/src/main/java/com/malk/base/JpaMap.java
  96. 35 0
      mjava/src/main/java/com/malk/config/JpaConfiguration.java
  97. 52 0
      mjava/src/main/java/com/malk/config/WebConfiguration.java
  98. 41 0
      mjava/src/main/java/com/malk/config/mutilSource/DataSourceConfig.java
  99. 80 0
      mjava/src/main/java/com/malk/config/mutilSource/PrimaryConfig.java
  100. 0 0
      mjava/src/main/java/com/malk/config/mutilSource/SlaveConfig.java

+ 37 - 0
.gitignore

@@ -0,0 +1,37 @@
+# IntelliJ project files
+.idea
+*.iml
+out
+gen
+### Java template
+# Compiled class file
+*.class
+
+# Log file
+*.log
+/log/
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+mvnw
+mvnw.cmd
+
+# tmp file
+.tmp
+/tmp/

+ 54 - 0
mjava-cloudpure/pom.xml

@@ -0,0 +1,54 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>java-mcli</artifactId>
+        <groupId>com.malk</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>mjava-cloudpure</artifactId>
+    <description>云璞环境, 销帮帮对接, yd-tb方案</description>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.malk</groupId>
+            <artifactId>mjava</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                    <!-- 如果没有该配置,devtools不会生效: 打包时关闭 -->
+                    <fork>false</fork>
+                    <!-- 避免中文乱码 -->
+                    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
+                </configuration>
+                <!-- 允许生成可运行jar -->
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

+ 32 - 0
mjava-cloudpure/src/main/java/com.malk.cloudpure/Boot.java

@@ -0,0 +1,32 @@
+package com.malk.cloudpure;
+
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+import javax.persistence.EntityManager;
+
+/**
+ * corp项目: 扫描公共模块
+ * -
+ * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ */
+@EnableJpaAuditing
+@SpringBootApplication(scanBasePackages = {"com.malk"})
+public class Boot {
+
+    public static void main(String... args) {
+        SpringApplication.run(Boot.class, args);
+    }
+
+    /**
+     * 让Spring管理JPAQueryFactory [不使用Qualifier详见mjava-Boot]
+     */
+    @Bean
+    public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
+        return new JPAQueryFactory(entityManager);
+    }
+}

+ 17 - 0
mjava-cloudpure/src/main/java/com.malk.cloudpure/controller/XBBController.java

@@ -0,0 +1,17 @@
+package com.malk.cloudpure.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 错误抛出与拦截详见 CatchException
+ */
+@Slf4j
+@RestController
+@RequestMapping
+public class XBBController {
+
+}
+
+

+ 53 - 0
mjava-cloudpure/src/main/resources/application-dev.yml

@@ -0,0 +1,53 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api/suodisi
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/server/_Tool/var/mjava/tmp/file/
+    image: /Users/malk/server/_Tool/var/mjava/tmp/image/
+    tmp: /Users/malk/server/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/server/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/server/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 1963716187
+  appKey: ding8qyulwwmad6j7k6c
+  appSecret: e_hRHuubw-Xi0OuPJOYdXSElVzOC0IPgMrHQTBuAM9BqW-DFnrcsSyBHi7Me3xSv
+  corpId: ding321c72787fffc78b35c2f4657eb6378f
+  aesKey:
+  token:
+  operator: "095358016629044412"   # 牧语[开头需要转一下字符串], OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_YH7W0E5637YUBU5UJ837
+  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9
+
+

+ 34 - 0
mjava-cloudpure/src/main/resources/application-prod.yml

@@ -0,0 +1,34 @@
+# 环境配置
+server:
+  port: 9011
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# dingtalk
+dingtalk:
+  agentId: 1963716187
+  appKey: ding8qyulwwmad6j7k6c
+  appSecret: e_hRHuubw-Xi0OuPJOYdXSElVzOC0IPgMrHQTBuAM9BqW-DFnrcsSyBHi7Me3xSv
+  corpId: ding321c72787fffc78b35c2f4657eb6378f
+  aesKey:
+  token:
+  operator: "095358016629044412"   # 牧语[开头需要转一下字符串], OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_YH7W0E5637YUBU5UJ837
+  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9

+ 35 - 0
mjava-cloudpure/src/test/resources/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-cloudpure'
+if [ "$1" == "dev" ]; then
+  java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=dev
+else
+  if [ "$1" == "start" ]; then
+    nohup java -Xms256m -Xmx256m -jar $appname.jar &
+    echo "server prod is starting"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    else
+      if [ "$1" == "stop" ]; then
+        PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+        if [ -z "$PID" ]; then
+          echo "server is already stopped"
+        else
+          echo kill $PID
+          kill $PID
+        fi
+      else
+        if [ "$1" == "status" ]; then
+          PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+          if [ -z "$PID" ]; then
+            echo "server is stopped"
+          else
+            echo "server is running"
+            echo $PID
+          fi
+        fi
+      fi
+    fi
+  fi
+fi

+ 53 - 0
mjava-cloudpure/target/classes/application-dev.yml

@@ -0,0 +1,53 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api/suodisi
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/server/_Tool/var/mjava/tmp/file/
+    image: /Users/malk/server/_Tool/var/mjava/tmp/image/
+    tmp: /Users/malk/server/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/server/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/server/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 1963716187
+  appKey: ding8qyulwwmad6j7k6c
+  appSecret: e_hRHuubw-Xi0OuPJOYdXSElVzOC0IPgMrHQTBuAM9BqW-DFnrcsSyBHi7Me3xSv
+  corpId: ding321c72787fffc78b35c2f4657eb6378f
+  aesKey:
+  token:
+  operator: "095358016629044412"   # 牧语[开头需要转一下字符串], OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_YH7W0E5637YUBU5UJ837
+  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9
+
+

+ 34 - 0
mjava-cloudpure/target/classes/application-prod.yml

@@ -0,0 +1,34 @@
+# 环境配置
+server:
+  port: 9011
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# dingtalk
+dingtalk:
+  agentId: 1963716187
+  appKey: ding8qyulwwmad6j7k6c
+  appSecret: e_hRHuubw-Xi0OuPJOYdXSElVzOC0IPgMrHQTBuAM9BqW-DFnrcsSyBHi7Me3xSv
+  corpId: ding321c72787fffc78b35c2f4657eb6378f
+  aesKey:
+  token:
+  operator: "095358016629044412"   # 牧语[开头需要转一下字符串], OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_YH7W0E5637YUBU5UJ837
+  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9

+ 35 - 0
mjava-cloudpure/target/test-classes/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-cloudpure'
+if [ "$1" == "dev" ]; then
+  java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=dev
+else
+  if [ "$1" == "start" ]; then
+    nohup java -Xms256m -Xmx256m -jar $appname.jar &
+    echo "server prod is starting"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    else
+      if [ "$1" == "stop" ]; then
+        PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+        if [ -z "$PID" ]; then
+          echo "server is already stopped"
+        else
+          echo kill $PID
+          kill $PID
+        fi
+      else
+        if [ "$1" == "status" ]; then
+          PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+          if [ -z "$PID" ]; then
+            echo "server is stopped"
+          else
+            echo "server is running"
+            echo $PID
+          fi
+        fi
+      fi
+    fi
+  fi
+fi

+ 60 - 0
mjava-guyuan/pom.xml

@@ -0,0 +1,60 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>java-mcli</artifactId>
+        <groupId>com.malk</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>mjava-guyuan</artifactId>
+    <description>谷元发票功能开发, 查重验真, 混票识别</description>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.malk</groupId>
+            <artifactId>mjava</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <!-- go to https://search.maven.org/search?q=tencentcloud-sdk-java and get the latest version. -->
+        <dependency>
+            <groupId>com.tencentcloudapi</groupId>
+            <artifactId>tencentcloud-sdk-java</artifactId>
+            <version>3.1.778</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                    <!-- 如果没有该配置,devtools不会生效: 打包时关闭 -->
+                    <fork>false</fork>
+                    <!-- 避免中文乱码 -->
+                    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
+                </configuration>
+                <!-- 允许生成可运行jar -->
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

+ 30 - 0
mjava-guyuan/src/main/java/Boot.java

@@ -0,0 +1,30 @@
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+import javax.persistence.EntityManager;
+
+/**
+ * corp项目: 扫描公共模块
+ * -
+ * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ */
+@EnableJpaAuditing
+@SpringBootApplication(scanBasePackages = {"com.malk"})
+public class Boot {
+
+    public static void main(String... args) {
+        SpringApplication.run(Boot.class, args);
+    }
+
+    /**
+     * 让Spring管理JPAQueryFactory [不使用Qualifier详见mjava-Boot]
+     */
+    @Bean
+    public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
+        return new JPAQueryFactory(entityManager);
+    }
+}

+ 149 - 0
mjava-guyuan/src/main/java/com/malk/guyuan/controller/GYController.java

@@ -0,0 +1,149 @@
+package com.malk.guyuan.controller;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McException;
+import com.malk.server.common.McR;
+import com.malk.server.dingtalk.DDR_New;
+import com.malk.service.aliwork.YDClient;
+import com.malk.service.aliyun.ALYInvoice;
+import com.malk.utils.UtilServlet;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 错误抛出与拦截详见CatchException
+ */
+@Slf4j
+@RestController
+@RequestMapping("/")
+public class GYController {
+
+    @Autowired
+    private ALYInvoice invoice;
+
+    @Autowired
+    private YDClient ydClient;
+
+    /**
+     * 阿里发票验真
+     */
+    @PostMapping("/invoice/check")
+    McR invoiceCheckPDF(@RequestBody Map<String, String> param) {
+        log.info("阿里发票验真, 文件, {}", param);
+        McException.assertParamException_Null(param, "url");
+        return McR.success(invoice.invoiceCheckPDF("4e2c048bfe1d4feea7354a66c7944fd1", param.get("url")));
+    }
+
+    /**
+     * 阿里发票验真: image
+     */
+    @PostMapping("invoice/ocr")
+    McR invoiceCheckImage(@RequestBody Map<String, String> param) {
+        log.info("阿里发票验真, 图片, {}", param);
+        return McR.success(invoice.invoiceCheckOCR("4e2c048bfe1d4feea7354a66c7944fd1", param.get("url")));
+    }
+
+    /**
+     * 宜搭临时免登地址: 钉钉平台
+     */
+    @PostMapping("openUrl")
+    McR openUrl(@RequestBody Map<String, String> param) {
+        McException.assertParamException_Null(param, "url");
+        return McR.success(ydClient.convertTemporaryUrl(param.get("url")));
+    }
+
+
+    /**
+     * 全局查询子表单
+     */
+    @PostMapping("queryAll")
+    McR queryAll(@RequestBody YDParam ydParam) {
+        return McR.success(ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_list_all));
+    }
+
+    /**
+     * 全局查询(不匹配子表单)
+     */
+    @PostMapping("validate")
+    McR queryAll(HttpServletRequest request) {
+        Map<String, ?> param = UtilServlet.getParamMap(request);
+        log.info("全局查询(不匹配子表单), {}", param);
+        if (ObjectUtil.isNull(param.get("uniques"))) {
+            return McR.success();
+        }
+        McException.assertParamException_Null(param, "uniques", "formUuid", "compId");
+        // 容错 - 尾部分号的空格会被输入框忽略
+        String[] uniques = String.valueOf(param.get("uniques")).replace("; ", ";").split(";");
+        for (String val : uniques) {
+            // 查重校验: 单张发票唯一标识 + 审批已通过 / 审批中
+            List<Map> conditions = new ArrayList<>();
+            Map unique = new HashMap();
+            unique.put("key", param.get("compId"));
+            unique.put("value", val.split(": ")[1]);
+            unique.put("type", "TEXT");
+            unique.put("operator", "like");
+            unique.put("componentName", "TextField");
+            conditions.add(unique);
+
+            Map approve = new HashMap();
+            approve.put("key", "processApprovedResult");
+            approve.put("value", new String[]{"agree"});
+            approve.put("type", "ARRAY");
+            approve.put("operator", "in");
+            approve.put("componentName", "SelectField");
+            conditions.add(approve);
+            YDParam ydParam = YDParam.builder()
+                    .appType("APP_FKRK7Y94DPI1S9DV1605")
+                    .systemToken("FN7666A1ZD0STZZ75W4CKD1GD07X3PUW2FBRKT")
+                    .formUuid(String.valueOf(param.get("formUuid")))
+                    .searchCondition(JSON.toJSONString(conditions))
+                    .build();
+            DDR_New ddr_new = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_list);
+            log.info("审批通过匹配结果, {}, {}", ddr_new.getTotalCount(), ddr_new.getData());
+            if (ddr_new.getTotalCount() > 0) {
+                return McR.errorAccess("发票已被使用, 请勿重复提交!");
+            }
+
+            conditions.remove(approve);
+            Map status = new HashMap();
+            status.put("key", "processInstanceStatus");
+            status.put("value", new String[]{"RUNNING"});
+            status.put("type", "ARRAY");
+            status.put("operator", "in");
+            status.put("componentName", "SelectField");
+            conditions.add(status);
+            ydParam.setSearchCondition(JSON.toJSONString(conditions));
+            ddr_new = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_list);
+            log.info("审批通过匹配结果, {}, {}", ddr_new.getTotalCount(), ddr_new.getData());
+            if (ddr_new.getTotalCount() > 0) {
+                return McR.errorAccess("发票已在流程中, 请勿重复提交!");
+            }
+        }
+        return McR.success();
+    }
+
+    /**
+     * 服务状态返回
+     */
+    @PostMapping("validateTips")
+    McR validateTaxNo(HttpServletRequest request) {
+        Map data = UtilServlet.getParamMap(request);
+        if (!data.get("status").equals(1)) {
+            return McR.errorAccess("error");
+        }
+        return McR.success(data);
+    }
+}

+ 166 - 0
mjava-guyuan/src/main/java/com/malk/guyuan/controller/IVController.java

@@ -0,0 +1,166 @@
+package com.malk.guyuan.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.malk.guyuan.server.model.McInvoiceDto;
+import com.malk.guyuan.server.model.McInvoiceKind;
+import com.malk.guyuan.server.tencent.TXYConf;
+import com.malk.guyuan.service.tencent.TXYInvoice;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McException;
+import com.malk.server.common.McR;
+import com.malk.service.aliwork.YDClient;
+import com.malk.utils.UtilMap;
+import com.malk.utils.UtilMc;
+import com.malk.utils.UtilNumber;
+import com.tencentcloudapi.common.exception.TencentCloudSDKException;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * 错误抛出与拦截详见CatchException
+ */
+@Slf4j
+@RestController
+@RequestMapping
+public class IVController {
+
+
+    @Autowired
+    private TXYInvoice txyInvoice;
+
+    @Autowired
+    private YDClient ydClient;
+
+    private String findValue(List<Map<String, String>> infos, String... names) {
+        for (String name : names) {
+            Optional optional = infos.stream().filter(info -> info.get("Name").equals(name)).findAny();
+            if (optional.isPresent()) {
+                return String.valueOf(((Map) optional.get()).get("Value"));
+            }
+        }
+        return "";
+    }
+
+    /**
+     * 混票识别
+     */
+    @PostMapping("invoice-iv")
+    McR invoice_iv(@RequestBody Map<String, String> data) throws TencentCloudSDKException {
+
+        McException.assertParamException_Null(data, "url");
+        String imageUrl = ydClient.convertTemporaryUrl(data.get("url"));
+        log.info("混票识别, 免登地址, {}", imageUrl);
+
+        // ppExt: 通用字段定义
+        List<Map> invoices = (List<Map>) txyInvoice.doMixedInvoiceOCR(imageUrl).get("MixedInvoiceItems");
+        List<McInvoiceDto> result = invoices.stream().map(item -> {
+            String kind = TXYConf.TYPE_INVOICE.get(item.get("Type").toString());
+            List<Map<String, String>> infos = (List<Map<String, String>>) item.get("SingleInvoiceInfos");
+
+            McInvoiceDto.assertSuccess(item, kind); // 响应断言
+
+            String invoiceName = findValue(infos, "发票名称");
+            if (kind.equals("全电发票")) {
+                kind = invoiceName.contains("增值税专用发票") ? "增值税电子专用发票" : "增值税电子普通发票";
+            }
+            if (kind.equals("增值税发票")) {
+                kind = invoiceName.contains("增值税专用发票") ? "增值税专用发票" : "增值税普通发票";
+            }
+            McInvoiceDto invoiceDto = McInvoiceDto.builder()
+                    .name(invoiceName)
+                    .kindName(kind)
+                    .kind(McInvoiceKind.getKindCode(kind))
+                    .code(findValue(infos, "发票代码", "票据代码")) // 发票, 非税发票
+                    // 储存唯一ID [发票, 火车票, 行程单]
+                    .serial(findValue(infos, "发票号码", "编号", "电子客票号码", "票据号码").replace("No", "")) // 发票, 非税发票
+                    .date(findValue(infos, "开票日期").replace("年", "-").replace("月", "-").replace("日", ""))
+                    .checkCode(findValue(infos, "校验码"))
+                    .amount(new BigDecimal(UtilNumber.replaceCurrencyCHY(findValue(infos, "小写金额", "价税合计(小写)", "合计金额", "票价", "金额")))) // 发票, 全电票, 行程单, 火车票, 过路过桥费
+                    .excludingTax(new BigDecimal(findValue(infos, "金额", "票价", "小写金额"))) // 行程单, 火车票, 定额发票
+                    .buyerName(findValue(infos, "购买方名称", "交款人")) // 发票, 非税发票
+                    .buyerTaxId(findValue(infos, "购买方识别号", "购买方统一社会信用代码/纳税人识别号", "交款人统一社会信用代码")) // 发票, 全电票, 非税发票
+                    .sellerName(findValue(infos, "销售方名称", "填开单位")) // 行程单
+                    .sellerTaxId(findValue(infos, "销售方识别号", "销售方统一社会信用代码/纳税人识别号", "销售单位代号")) // 发票, 全电票, 行程单
+                    .passengerName(findValue(infos, "旅客姓名", "姓名")) // 行程单, 火车票
+                    .seatType(findValue(infos, "座位等级", "席别")) // 行程单, 火车票
+                    .departurePort(findValue(infos, "始发地", "出发站", "入口")) // 行程单, 火车票, 过路过桥费
+                    .arrivePort(findValue(infos, "目的地", "到达站", "出口")) // 行程单, 火车票, 过路过桥费
+                    .trainNo(findValue(infos, "航班号", "车次", "车牌号")) // 行程单, 火车票, 出租车
+                    .insuranceCosts(UtilNumber.setBigDecimal((findValue(infos, "保险费")))) // 行程单
+                    .fuelCosts(UtilNumber.setBigDecimal((findValue(infos, "燃油附加费")))) // 行程单
+                    .constructionCosts(UtilNumber.setBigDecimal((findValue(infos, "民航发展基金")))) // 行程单
+                    .build();
+            // 机票行程单
+            if (kind.equals(McInvoiceKind.JP.getDesc())) {
+                String date = findValue(infos, "日期").replace("年", "-").replace("月", "-").replace("日", " ");
+                invoiceDto.setDepartureTime(date + " " + findValue(infos, "时间"));
+            }
+            // 火车票
+            if (kind.equals(McInvoiceKind.HC.getDesc())) {
+                invoiceDto.setDepartureTime(findValue(infos, "出发时间").replace("年", "-").replace("月", "-").replace("日", " "));
+            }
+            // 出租车
+            if (kind.equals(McInvoiceKind.CZC.getDesc())) {
+                String date = findValue(infos, "日期").replace("年", "-").replace("月", "-").replace("日", " ");
+                invoiceDto.setDepartureTime(date + " " + findValue(infos, "上车"));
+            }
+            return invoiceDto;
+        }).collect(Collectors.toList());
+        return McR.success(McInvoiceDto.formatResponse(result));
+    }
+
+    /**
+     * 发票查重, 验真
+     */
+    @PostMapping("invoice-va")
+    McR invoice_va(@RequestBody Map data) {
+        McException.assertParamException_Null(data, "param");
+        List<McInvoiceDto> invoices = JSON.parseArray(JSON.toJSONString(data.get("param")), McInvoiceDto.class);
+
+        log.info("发票查重, 验真, {}", invoices);
+        invoices.forEach(UtilMc.consumerWithIndex((item, index) -> {
+
+            McInvoiceDto dto = (McInvoiceDto) item;
+            String invoiceNo = dto.getSerial(); // 唯一标识, 发票号码
+
+            String serial = "第【" + (index + 1) + "】张发票";
+            McException.assertAccessException(StringUtils.isBlank(invoiceNo), serial + ", 识别结果为空, 请检查!");
+            YDParam ydParam = YDParam.builder()
+                    .formUuid("FORM-W2A66Z910O9B3LP9C6IYUDPRVWY62DO0YHIILY")
+                    .searchFieldJson(JSON.toJSONString(UtilMap.map("radioField_liihyrtb, textField_liihyrt8", "否", invoiceNo)))
+                    .build();
+            List<String> idList = (List<String>) ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_search_form_id).getData();
+            if (idList.size() > 0) {
+                McException.exceptionAccess(serial + "已存在, 请勿重复提交!");
+            }
+            // prd 仅仅识别增值税普通发票
+            if (dto.getKindName().contains("普通发票")) {
+                try {
+                    // ppExt: 识别与验真后抬头对比
+                    Map rsp = txyInvoice.VatInvoiceVerifyNew(dto.getKindName(), dto.getCode(), invoiceNo, dto.getDate(), String.valueOf(dto.getAmount()), dto.getCheckCode(), String.valueOf(dto.getExcludingTax()));
+                    Map invoice = (Map) rsp.get("Invoice");
+                    McException.assertAccessException(!dto.getBuyerName().equals(invoice.get("BuyerName")), "发票有疑问, 购买方名称不匹配!");
+                    McException.assertAccessException(!dto.getBuyerTaxId().equals(invoice.get("BuyerTaxCode")), "发票有疑问, 购买方税号不匹配!");
+                    McException.assertAccessException(!dto.getSellerName().equals(invoice.get("SellerName")), "发票有疑问, 销售方名称不匹配!");
+                    McException.assertAccessException(!dto.getSellerTaxId().equals(invoice.get("SellerTaxCode")), "发票有疑问, 销售方税号不匹配!");
+                } catch (TencentCloudSDKException e) {
+                    McException.exceptionAccess(serial + e.getMessage());
+                }
+            }
+        }));
+
+        return McR.success("发票查重, 验真响应");
+    }
+}

+ 26 - 0
mjava-guyuan/src/main/java/com/malk/guyuan/filter/CatchException_YXY.java

@@ -0,0 +1,26 @@
+package com.malk.guyuan.filter;
+
+import com.malk.Filter.CatchException;
+import com.malk.server.common.McR;
+import com.tencentcloudapi.common.exception.TencentCloudSDKException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+/**
+ * 腾讯云 [通用拦截参考 CatchException]
+ */
+@Slf4j
+@RestControllerAdvice(annotations = RestController.class)
+public class CatchException_YXY extends CatchException {
+
+    /**
+     * 错误类抛出
+     */
+    @ExceptionHandler(TencentCloudSDKException.class)
+    public McR TencentCloudSDKException(TencentCloudSDKException e) {
+        log.error(e.getMessage(), e);  // 记录错误日志
+        return McR.errorVendor(e.getMessage(), "tencent");
+    }
+}

+ 185 - 0
mjava-guyuan/src/main/java/com/malk/guyuan/server/model/McInvoiceDto.java

@@ -0,0 +1,185 @@
+package com.malk.guyuan.server.model;
+
+import com.malk.base.BaseDto;
+import com.malk.server.common.McException;
+import com.malk.server.common.McREnum;
+import com.malk.utils.UtilMap;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+import java.math.BigDecimal;
+import java.util.Map;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class McInvoiceDto extends BaseDto {
+
+
+    /**************** 发票 ****************/
+
+    /**
+     * 发票名称
+     */
+    private String name;
+
+    // 兼容: 不为空
+    public String getName() {
+        if (StringUtils.isBlank(name)) {
+            return kindName;
+        }
+        return name;
+    }
+
+    /**
+     * 发票类型
+     */
+    private String kindName;
+
+    /**
+     * 发票类型 [编码]
+     */
+    private int kind;
+
+    /**
+     * 发票代码
+     */
+    private String code;
+
+    /**
+     * 发票号码
+     */
+    private String serial;
+
+    /**
+     * 开票日期 [yyyy-MM-dd]
+     */
+    private String date;
+
+    /**
+     * 校验码
+     */
+    private String checkCode;
+
+    /**
+     * 价税合计
+     */
+    private BigDecimal amount;
+
+    /**
+     * 不含税金额
+     */
+    private BigDecimal excludingTax;
+
+    /**
+     * 购买方名称
+     */
+    private String buyerName;
+
+    /**
+     * 购买方税号
+     */
+    private String buyerTaxId;
+
+    /**
+     * 销售方名称
+     */
+    private String sellerName;
+
+    /**
+     * 销售方税号
+     */
+    private String sellerTaxId;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**************** 交通 ****************/
+
+    /**
+     * 乘客姓名
+     */
+    private String passengerName;
+
+    /**
+     * 座位类型
+     */
+    private String seatType;
+
+    /**
+     * 出发地
+     */
+    private String departurePort;
+
+    /**
+     * 到达地
+     */
+    private String arrivePort;
+
+    /**
+     * 出发时间 [yyyy-MM-dd HH:mm]
+     */
+    private String departureTime;
+
+    /**
+     * 车次编号/航班号
+     */
+    private String trainNo;
+
+    /**
+     * 保险费
+     */
+    private BigDecimal insuranceCosts;
+
+    /**
+     * 燃油附加费
+     */
+    private BigDecimal fuelCosts;
+
+    /**
+     * 民航发展基金
+     */
+    private BigDecimal constructionCosts;
+
+    /**************** 格式化 ****************/
+
+    /**
+     * 实例Map, 服务宜搭组件映射 [明细组件获取表头, 通过名称转换字段]
+     *
+     * @implSpec const headers = this.$("tableField_liv5f4d2").props.children[0].props.children.map(({ props: { label, fieldId } }) => ({ label, compId: fieldId }))
+     */
+    public static Map formatDtoLabelAndProp() {
+
+        Map data = UtilMap.map("发票名称, 发票类型, 发票代码, 发票号码, 开票日期, 校验码, 价税合计, 不含税金额", "name, kindName, code, serial, date, checkCode, amount, excludingTax");
+        data.putAll(UtilMap.map("购买方名称, 购买方税号, 销售方名称, 销售方税号", "buyerName, buyerTaxId, sellerName, sellerTaxId"));
+        data.putAll(UtilMap.map("乘客姓名, 座位类型, 出发地, 到达地, 出发时间, 车次编号/航班号, 保险费, 燃油附加费, 民航发展基金", "passengerName, seatType, departurePort, arrivePort, departureTime, trainNo, insuranceCosts, fuelCosts, constructionCosts"));
+        return data;
+    }
+
+    /**
+     * 格式化返回
+     */
+    public static Map formatResponse(Object result) {
+        return UtilMap.map("result, dto", result, formatDtoLabelAndProp());
+    }
+
+    /**************** 返回值 ****************/
+
+    // 成功状态标记
+    private final static String SUC_CODE = "OK";
+
+    /**
+     * 断言错误信息
+     */
+    public static void assertSuccess(Map result, String kind) {
+        String code = UtilMap.getString(result, "Code");
+        McException.assertException(!SUC_CODE.equals(code), McREnum.VENDOR_ERROR.getCode(), kind, "tencent");
+    }
+}
+

+ 62 - 0
mjava-guyuan/src/main/java/com/malk/guyuan/server/model/McInvoiceKind.java

@@ -0,0 +1,62 @@
+package com.malk.guyuan.server.model;
+
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+/**
+ * 定义返回值和对应状态的信息
+ */
+@Slf4j
+public enum McInvoiceKind {
+
+    PP("增值税普通发票", 1),
+    ZP("增值税专用发票", 2),
+    DP("增值税电子普通发票", 3),
+    DZ("增值税电子专用发票", 4),
+
+    HC("火车票", 11),
+    JP("机票行程单", 12),
+    CZC("出租车发票", 13),
+    DE("定额发票", 14),
+    GLGQ("过路过桥费发票", 15),
+
+    FS("非税发票", 21),
+    OT("其它特殊发票", 22),
+
+    UN("未知类型", -1);
+
+    @Getter
+    private String desc;
+    @Getter
+    private int code;
+
+    /**
+     * 根据code查找
+     */
+    public final static String getKindName(int code) {
+        Optional optional = Arrays.stream(McInvoiceKind.values()).filter(item -> item.code == code).findAny();
+        if (optional.isPresent()) {
+            return ((McInvoiceKind) optional.get()).desc;
+        }
+        return UN.getDesc();
+    }
+
+    /**
+     * 根据name查找
+     */
+    public final static int getKindCode(String name) {
+        Optional optional = Arrays.stream(McInvoiceKind.values()).filter(item -> item.desc.equals(name)).findAny();
+        if (optional.isPresent()) {
+            return ((McInvoiceKind) optional.get()).code;
+        }
+        return UN.getCode();
+    }
+
+    McInvoiceKind(String name, int code) {
+        this.desc = name;
+        this.code = code;
+    }
+}

+ 92 - 0
mjava-guyuan/src/main/java/com/malk/guyuan/server/model/sample.md

@@ -0,0 +1,92 @@
+## 上传发票
+
+```
+/*** mc 系列之 mjs
+ * 对接宜搭公共JavaScript库
+ * 公共库地址:https://mc.cloudpure.cn/mjs/mjs.min.js
+ ***/
+export function _mjsLoad() {
+  // const src = "https://mc.cloudpure.cn/mjs/mjs.min.js"
+  // const src = "http://127.0.0.1:7001/dist/mjs.js"
+  const src = "https://mc.cloudpure.cn/api/guyuan/mjs/mjs.min.js"
+  const script = document.createElement('script');
+  script.type = 'text/javascript';
+  script.src = src;
+  script.addEventListener('load', () => this._mjsInit(), false);
+  document.head.appendChild(script);
+};
+
+//---------------------- private ----------------------//
+
+// 加载即调用方法请在此处进行调用
+export async function _mjsInit() {
+  await mjs.init(this, { vconsole: false })
+  // 页面环境:0提交(其它),1查看,2编辑(审批)
+  if (mjs.env) { }
+}
+
+
+//---------------------- event ----------------------//
+
+// 页面节点加载渲染完毕
+export function didMount() {
+  // 工具库: mjs & 初始化
+  this._mjsLoad();
+}
+
+// 发票上传
+export function onSuccess(file, value) {
+  mjs.corp.guyuan.mixedInvoice(file.url)
+}
+
+// 发票移除
+export function onRemove(file) {
+  this.$('tableField_liv5f4d2').setValue([]);
+}
+
+// 发票查重、验真
+export function beforeSubmit({ formDataMap }) {
+  return mjs.corp.guyuan.batchCheck()
+}
+```
+
+## 发票夹
+
+```
+/*** mc 系列之 mjs
+ * 对接宜搭公共JavaScript库
+ * 公共库地址:https://mc.cloudpure.cn/mjs/mjs.min.js
+ ***/
+export function _mjsLoad() {
+  // const src = "https://mc.cloudpure.cn/mjs/mjs.min.js"
+  // const src = "http://127.0.0.1:7001/dist/mjs.js"
+  const src = "https://mc.cloudpure.cn/api/guyuan/mjs/mjs.min.js"
+  const script = document.createElement('script');
+  script.type = 'text/javascript';
+  script.src = src;
+  script.addEventListener('load', () => this._mjsInit(), false);
+  document.head.appendChild(script);
+};
+
+//---------------------- private ----------------------//
+
+// 加载即调用方法请在此处进行调用
+export async function _mjsInit() {
+  await mjs.init(this, { vconsole: false })
+  // 页面环境:0提交(其它),1查看,2编辑(审批)
+  if (mjs.env) { }
+}
+
+//---------------------- event ----------------------//
+
+// 页面节点加载渲染完毕
+export function didMount() {
+  // 工具库: mjs & 初始化
+  this._mjsLoad();
+}
+
+// 发票查重、验真
+export function beforeSubmit({ formDataMap }) {
+  return mjs.corp.guyuan.validate()
+}
+```

+ 32 - 0
mjava-guyuan/src/main/java/com/malk/guyuan/server/tencent/TXYConf.java

@@ -0,0 +1,32 @@
+package com.malk.guyuan.server.tencent;
+
+import com.malk.utils.UtilMap;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * 读取配置文件参考FilePah
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "tencent")
+public class TXYConf {
+
+    private String APPID;
+
+    private String SecretId;
+
+    private String SecretKey;
+
+    private String Region;
+
+    /**
+     * 票据类型
+     */
+    public static final Map<String, String> TYPE_INVOICE = UtilMap.map("-1, 0, 1, 2, 3, 5, 8, 9, 10, 11, 12, 13, 15, 16",
+            "未知类型, 出租车发票, 定额发票, 火车票, 增值税发票, 机票行程单, 通用机打发票, 汽车票, 轮船票, 增值税发票(卷票) , 购车发票, 过路过桥费发票, 非税发票, 全电发票");
+
+}

+ 24 - 0
mjava-guyuan/src/main/java/com/malk/guyuan/service/tencent/TXYInvoice.java

@@ -0,0 +1,24 @@
+package com.malk.guyuan.service.tencent;
+
+import com.tencentcloudapi.common.exception.TencentCloudSDKException;
+
+import java.util.Map;
+
+public interface TXYInvoice {
+
+    /**
+     * 混贴票据识别
+     *
+     * @param imageUrl 图片不超过6m
+     */
+    Map doMixedInvoiceOCR(String imageUrl) throws TencentCloudSDKException;
+
+    /**
+     * 发票验真[新版]
+     *
+     * @param invoiceCode         票代码(10或12 位),全电发票为空
+     * @param checkCode           校验码后 6 位,增值税普通发票、增值税电子普通发票、增值税普通发票(卷式)、增值税电子普通发票(通行费)时必填;
+     * @param excludingTax/amount 不含税金额,增值税专用发票、增值税电子专用发票、机动车销售统一发票、二手车销售统一发票、区块链发票时必填; 全电发票为价税合计(含税金额)
+     */
+    Map VatInvoiceVerifyNew(String invoiceKind, String invoiceCode, String invoiceNo, String invoiceDate, String amount, String checkCode, String excludingTax) throws TencentCloudSDKException;
+}

+ 104 - 0
mjava-guyuan/src/main/java/com/malk/guyuan/service/tencent/impl/TXYImplInvoice.java

@@ -0,0 +1,104 @@
+package com.malk.guyuan.service.tencent.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.malk.guyuan.server.tencent.TXYConf;
+import com.malk.guyuan.service.tencent.TXYInvoice;
+import com.malk.server.common.McException;
+import com.malk.utils.UtilMap;
+import com.malk.utils.UtilNumber;
+import com.tencentcloudapi.common.Credential;
+import com.tencentcloudapi.common.exception.TencentCloudSDKException;
+import com.tencentcloudapi.common.profile.ClientProfile;
+import com.tencentcloudapi.common.profile.HttpProfile;
+import com.tencentcloudapi.ocr.v20181119.OcrClient;
+import com.tencentcloudapi.ocr.v20181119.models.MixedInvoiceOCRRequest;
+import com.tencentcloudapi.ocr.v20181119.models.MixedInvoiceOCRResponse;
+import com.tencentcloudapi.ocr.v20181119.models.VatInvoiceVerifyNewRequest;
+import com.tencentcloudapi.ocr.v20181119.models.VatInvoiceVerifyNewResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+@Slf4j
+@Service
+public class TXYImplInvoice implements TXYInvoice {
+
+    @Autowired
+    private TXYConf txyConf;
+
+    // 创建请求描述
+    private ClientProfile doRequest(String endPoint) {
+
+        HttpProfile httpProfile = new HttpProfile();
+        httpProfile.setEndpoint(endPoint);
+        ClientProfile clientProfile = new ClientProfile();
+        clientProfile.setHttpProfile(httpProfile);
+        return clientProfile;
+    }
+
+    /**
+     * 混贴票据识别
+     *
+     * @apiNote https://cloud.tencent.com/document/product/866/37835
+     */
+    @Override
+    public Map doMixedInvoiceOCR(String imageUrl) throws TencentCloudSDKException {
+
+        Credential cred = new Credential(txyConf.getSecretId(), txyConf.getSecretKey());
+        ClientProfile clientProfile = doRequest("ocr.tencentcloudapi.com");
+        OcrClient client = new OcrClient(cred, txyConf.getRegion(), clientProfile);
+
+        MixedInvoiceOCRRequest req = new MixedInvoiceOCRRequest();
+        req.setImageUrl(imageUrl);
+        req.setReturnMultiplePage(true); // PDF多页识别, 仅支持返回文件前30页
+        MixedInvoiceOCRResponse resp = client.MixedInvoiceOCR(req);
+        String result = MixedInvoiceOCRResponse.toJsonString(resp);
+        log.debug("请求响应, {}", result);
+        return (Map) JSON.parse(result);
+    }
+
+    /**
+     * 发票验真[新版]
+     *
+     * @apiNote https://cloud.tencent.com/document/product/866/73674
+     */
+    @Override
+    public Map VatInvoiceVerifyNew(String invoiceKind, String invoiceCode, String invoiceNo, String invoiceDate, String amount, String checkCode, String excludingTax) throws TencentCloudSDKException {
+        Credential cred = new Credential(txyConf.getSecretId(), txyConf.getSecretKey());
+        ClientProfile clientProfile = doRequest("ocr.tencentcloudapi.com");
+        OcrClient client = new OcrClient(cred, txyConf.getRegion(), clientProfile);
+
+        if (StringUtils.isNotBlank(checkCode)) {
+            checkCode = checkCode.substring(checkCode.length() - 6);
+        }
+
+        VatInvoiceVerifyNewRequest req = new VatInvoiceVerifyNewRequest();
+        req.setInvoiceNo(invoiceNo);
+        req.setInvoiceDate(invoiceDate);
+        req.setInvoiceCode(invoiceCode);
+        req.setCheckCode(checkCode);
+        if (invoiceKind.contains("增值税电子") || invoiceKind.contains("电子发票") || invoiceKind.contains("全电发票")) {
+            // 全电票, 需要价税合计且无发票代码与校验码
+            req.setCheckCode(null);
+            req.setInvoiceCode(null);
+            req.setAmount(amount);
+        } else {
+            req.setAmount(null);
+            req.setAmount(excludingTax);
+        }
+        VatInvoiceVerifyNewResponse resp = client.VatInvoiceVerifyNew(req);
+        String result = VatInvoiceVerifyNewResponse.toJsonString(resp);
+        Map rsp = (Map) JSON.parse(result);
+
+        // 因全电票取值, 取值价税合计, 单独校验下金额
+        Map invoice = (Map) rsp.get("Invoice");
+        McException.assertAccessException(!UtilNumber.equalBigDecimal(UtilMap.getString(invoice, "AmountWithTax"), amount), "发票有疑问, 价税合计金额不匹配!");
+        McException.assertAccessException(!UtilNumber.equalBigDecimal(UtilMap.getString(invoice, "AmountWithoutTax"), excludingTax), "发票有疑问, 不含税金额不匹配!");
+
+        log.debug("请求响应, {}", result);
+        return rsp;
+    }
+}

+ 64 - 0
mjava-guyuan/src/main/resources/application-dev.yml

@@ -0,0 +1,64 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api/guyuan
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+  flyway:
+    enabled: false        #  需要配置 jpa.hibernate.ddl-auto 为 none. 否则 flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+
+# swagger3
+swagger:
+  enable: true
+
+# filepath
+file:
+  path:
+    file: /Users/malk/server/_Tool/var/mjava/tmp/file
+    image: /Users/malk/server/_Tool/var/mjava/tmp/image
+    tmp: /Users/mcli/server/_Tool/var/mjava/tmp
+  source:
+    fonts: /Users/malk/server/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/server/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 2356105659
+  appKey: dinghov5fyfjlhzk1ej1
+  appSecret: QR_1_7D0UUYtfdtMlDlmnjNSkvU2Uo3gOyabo2h09rmvj5_x0uk0Lw7N9pCy7sf-
+  corpId: dinge281bf50c488ebfd35c2f4657eb6378f
+  aesKey:
+  token:
+  operator: ""   # OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_FKRK7Y94DPI1S9DV1605
+  systemToken: FN7666A1ZD0STZZ75W4CKD1GD07X3PUW2FBRKT
+
+# tencent [腾讯云]
+tencent:
+  APPID: 1309939821
+  SecretId: AKID2uqoryukbO2XuBThuxzdEpnmnmoocuCH
+  SecretKey: wnmgYHo8wrmjlldKoHnIkDZlqvrVDpOz
+  Region: ap-shanghai

+ 45 - 0
mjava-guyuan/src/main/resources/application-prod.yml

@@ -0,0 +1,45 @@
+# 环境配置
+server:
+  port: 9004
+  servlet:
+    context-path: /api/guyuan
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+  flyway:
+    enabled: false      #  需要配置 jpa.hibernate.ddl-auto 为 none. 否则 flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+
+# dingtalk
+dingtalk:
+  agentId: 2356105659
+  appKey: dinghov5fyfjlhzk1ej1
+  appSecret: QR_1_7D0UUYtfdtMlDlmnjNSkvU2Uo3gOyabo2h09rmvj5_x0uk0Lw7N9pCy7sf-
+  corpId: dinge281bf50c488ebfd35c2f4657eb6378f
+  aesKey:
+  token:
+  operator: ""   # OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_FKRK7Y94DPI1S9DV1605
+  systemToken: FN7666A1ZD0STZZ75W4CKD1GD07X3PUW2FBRKT
+
+# tencent [腾讯云]
+tencent:
+  APPID: 1309939821
+  SecretId: AKID2uqoryukbO2XuBThuxzdEpnmnmoocuCH
+  SecretKey: wnmgYHo8wrmjlldKoHnIkDZlqvrVDpOz
+  Region: ap-shanghai

Datei-Diff unterdrückt, da er zu groß ist
+ 8921 - 0
mjava-guyuan/src/main/resources/static/mjs/mjs.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 0
mjava-guyuan/src/main/resources/static/mjs/mjs.min.js


+ 38 - 0
mjava-guyuan/target/classes/META-INF/spring-configuration-metadata.json

@@ -0,0 +1,38 @@
+{
+  "groups": [
+    {
+      "name": "tencent",
+      "type": "com.malk.guyuan.server.tencent.TXYConf",
+      "sourceType": "com.malk.guyuan.server.tencent.TXYConf"
+    }
+  ],
+  "properties": [
+    {
+      "name": "tencent.a-p-p-i-d",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.guyuan.server.tencent.TXYConf"
+    },
+    {
+      "name": "tencent.region",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.guyuan.server.tencent.TXYConf"
+    },
+    {
+      "name": "tencent.secret-id",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.guyuan.server.tencent.TXYConf"
+    },
+    {
+      "name": "tencent.secret-key",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.guyuan.server.tencent.TXYConf"
+    },
+    {
+      "name": "tencent.t-y-p-e-i-n-v-o-i-c-e",
+      "type": "java.util.Map<java.lang.String,java.lang.String>",
+      "description": "票据类型",
+      "sourceType": "com.malk.guyuan.server.tencent.TXYConf"
+    }
+  ],
+  "hints": []
+}

+ 64 - 0
mjava-guyuan/target/classes/application-dev.yml

@@ -0,0 +1,64 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api/guyuan
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+  flyway:
+    enabled: false        #  需要配置 jpa.hibernate.ddl-auto 为 none. 否则 flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+
+# swagger3
+swagger:
+  enable: true
+
+# filepath
+file:
+  path:
+    file: /Users/malk/server/_Tool/var/mjava/tmp/file
+    image: /Users/malk/server/_Tool/var/mjava/tmp/image
+    tmp: /Users/mcli/server/_Tool/var/mjava/tmp
+  source:
+    fonts: /Users/malk/server/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/server/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 2356105659
+  appKey: dinghov5fyfjlhzk1ej1
+  appSecret: QR_1_7D0UUYtfdtMlDlmnjNSkvU2Uo3gOyabo2h09rmvj5_x0uk0Lw7N9pCy7sf-
+  corpId: dinge281bf50c488ebfd35c2f4657eb6378f
+  aesKey:
+  token:
+  operator: ""   # OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_FKRK7Y94DPI1S9DV1605
+  systemToken: FN7666A1ZD0STZZ75W4CKD1GD07X3PUW2FBRKT
+
+# tencent [腾讯云]
+tencent:
+  APPID: 1309939821
+  SecretId: AKID2uqoryukbO2XuBThuxzdEpnmnmoocuCH
+  SecretKey: wnmgYHo8wrmjlldKoHnIkDZlqvrVDpOz
+  Region: ap-shanghai

+ 45 - 0
mjava-guyuan/target/classes/application-prod.yml

@@ -0,0 +1,45 @@
+# 环境配置
+server:
+  port: 9004
+  servlet:
+    context-path: /api/guyuan
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+  flyway:
+    enabled: false      #  需要配置 jpa.hibernate.ddl-auto 为 none. 否则 flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+
+# dingtalk
+dingtalk:
+  agentId: 2356105659
+  appKey: dinghov5fyfjlhzk1ej1
+  appSecret: QR_1_7D0UUYtfdtMlDlmnjNSkvU2Uo3gOyabo2h09rmvj5_x0uk0Lw7N9pCy7sf-
+  corpId: dinge281bf50c488ebfd35c2f4657eb6378f
+  aesKey:
+  token:
+  operator: ""   # OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_FKRK7Y94DPI1S9DV1605
+  systemToken: FN7666A1ZD0STZZ75W4CKD1GD07X3PUW2FBRKT
+
+# tencent [腾讯云]
+tencent:
+  APPID: 1309939821
+  SecretId: AKID2uqoryukbO2XuBThuxzdEpnmnmoocuCH
+  SecretKey: wnmgYHo8wrmjlldKoHnIkDZlqvrVDpOz
+  Region: ap-shanghai

Datei-Diff unterdrückt, da er zu groß ist
+ 8921 - 0
mjava-guyuan/target/classes/static/mjs/mjs.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 0
mjava-guyuan/target/classes/static/mjs/mjs.min.js


+ 5 - 0
mjava-guyuan/target/maven-archiver/pom.properties

@@ -0,0 +1,5 @@
+#Generated by Maven
+#Thu Jun 15 07:58:49 CST 2023
+version=1.0-SNAPSHOT
+groupId=com.malk
+artifactId=mjava-guyuan

+ 1 - 0
mjava-guyuan/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst

@@ -0,0 +1 @@
+com/malk/guyuan/controller/IVController.class

+ 9 - 0
mjava-guyuan/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst

@@ -0,0 +1,9 @@
+/Users/malk/server/java-mcli-3/mjava-guyuan/src/main/java/com/malk/guyuan/service/tencent/TXYInvoice.java
+/Users/malk/server/java-mcli-3/mjava-guyuan/src/main/java/com/malk/guyuan/server/model/McInvoiceDto.java
+/Users/malk/server/java-mcli-3/mjava-guyuan/src/main/java/com/malk/guyuan/controller/IVController.java
+/Users/malk/server/java-mcli-3/mjava-guyuan/src/main/java/Boot.java
+/Users/malk/server/java-mcli-3/mjava-guyuan/src/main/java/com/malk/guyuan/server/tencent/TXYConf.java
+/Users/malk/server/java-mcli-3/mjava-guyuan/src/main/java/com/malk/guyuan/server/model/McInvoiceKind.java
+/Users/malk/server/java-mcli-3/mjava-guyuan/src/main/java/com/malk/guyuan/service/tencent/impl/TXYImplInvoice.java
+/Users/malk/server/java-mcli-3/mjava-guyuan/src/main/java/com/malk/guyuan/controller/GYController.java
+/Users/malk/server/java-mcli-3/mjava-guyuan/src/main/java/com/malk/guyuan/filter/CatchException_YXY.java

BIN
mjava-guyuan/target/mjava-guyuan.jar.original


+ 54 - 0
mjava-hangshi/pom.xml

@@ -0,0 +1,54 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>java-mcli</artifactId>
+        <groupId>com.malk</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>mjava-hangshi</artifactId>
+    <description>航食宜搭开发服务</description>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.malk</groupId>
+            <artifactId>mjava</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                    <!-- 如果没有该配置,devtools不会生效: 打包时关闭 -->
+                    <fork>false</fork>
+                    <!-- 避免中文乱码 -->
+                    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
+                </configuration>
+                <!-- 允许生成可运行jar -->
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

+ 32 - 0
mjava-hangshi/src/main/java/com/malk/hangshi/Boot.java

@@ -0,0 +1,32 @@
+package com.malk.hangshi;
+
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+import javax.persistence.EntityManager;
+
+/**
+ * corp项目: 扫描公共模块
+ * -
+ * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ */
+@EnableJpaAuditing
+@SpringBootApplication(scanBasePackages = {"com.malk"})
+public class Boot {
+
+    public static void main(String... args) {
+        SpringApplication.run(Boot.class, args);
+    }
+
+    /**
+     * 让Spring管理JPAQueryFactory [不使用Qualifier详见mjava-Boot]
+     */
+    @Bean
+    public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
+        return new JPAQueryFactory(entityManager);
+    }
+}

+ 34 - 0
mjava-hangshi/src/main/java/com/malk/hangshi/controller/HSController.java

@@ -0,0 +1,34 @@
+package com.malk.hangshi.controller;
+
+import com.malk.server.common.McR;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Contacts;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 错误抛出与拦截详见CatchException
+ */
+@Slf4j
+@RestController
+@RequestMapping
+public class HSController {
+
+    @Autowired
+    private DDClient ddClient;
+
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+
+    /**
+     * 获取员工人数
+     */
+    @PostMapping("user/count")
+    McR queryCount() {
+        return McR.success(ddClient_contacts.getUserCount(ddClient.getAccessToken(), true));
+    }
+}
+

+ 53 - 0
mjava-hangshi/src/main/resources/application-dev.yml

@@ -0,0 +1,53 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api/hangshi
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/server/_Tool/var/mjava/tmp/file/
+    image: /Users/malk/server/_Tool/var/mjava/tmp/image/
+    tmp: /Users/malk/server/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/server/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/server/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 2554541552
+  appKey: dingibsmij0bzwbtyfrr
+  appSecret: JEtzUtRjXBN3yiF6v9bw0uF_jWAVmVvIWfoCqIyaRTK-TEWVQLGU-xsYu7Ni_GKB
+  corpId: ding6bd8f2716554297135c2f4657eb6378f
+  aesKey:
+  token:
+  operator: "81007710"   # 孙云嵩 [开头需要转一下字符串], OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_YH7W0E5637YUBU5UJ837
+  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9
+
+

+ 39 - 0
mjava-hangshi/src/main/resources/application-prod.yml

@@ -0,0 +1,39 @@
+# 环境配置
+server:
+  port: 9009
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# ekuaibao
+ekuaibao:
+  corpId: -yQbjbywbc640011                # 易快报的 corpId
+  platformApi: https://app.ekuaibao.com   # 易快报不同平台获取前缀的方式不同
+
+# dingtalk
+dingtalk:
+  agentId: 2554541552
+  appKey: dingibsmij0bzwbtyfrr
+  appSecret: JEtzUtRjXBN3yiF6v9bw0uF_jWAVmVvIWfoCqIyaRTK-TEWVQLGU-xsYu7Ni_GKB
+  corpId: ding6bd8f2716554297135c2f4657eb6378f
+  aesKey:
+  token:
+  operator: "81007710"   # 孙云嵩 [开头需要转一下字符串], OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_YH7W0E5637YUBU5UJ837
+  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9

+ 35 - 0
mjava-hangshi/src/test/resources/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-hangshi'
+if [ "$1" == "dev" ]; then
+  java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=dev
+else
+  if [ "$1" == "start" ]; then
+    nohup java -Xms256m -Xmx256m -jar $appname.jar &
+    echo "server prod is starting"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    else
+      if [ "$1" == "stop" ]; then
+        PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+        if [ -z "$PID" ]; then
+          echo "server is already stopped"
+        else
+          echo kill $PID
+          kill $PID
+        fi
+      else
+        if [ "$1" == "status" ]; then
+          PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+          if [ -z "$PID" ]; then
+            echo "server is stopped"
+          else
+            echo "server is running"
+            echo $PID
+          fi
+        fi
+      fi
+    fi
+  fi
+fi

+ 53 - 0
mjava-hangshi/target/classes/application-dev.yml

@@ -0,0 +1,53 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api/hangshi
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/server/_Tool/var/mjava/tmp/file/
+    image: /Users/malk/server/_Tool/var/mjava/tmp/image/
+    tmp: /Users/malk/server/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/server/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/server/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 2554541552
+  appKey: dingibsmij0bzwbtyfrr
+  appSecret: JEtzUtRjXBN3yiF6v9bw0uF_jWAVmVvIWfoCqIyaRTK-TEWVQLGU-xsYu7Ni_GKB
+  corpId: ding6bd8f2716554297135c2f4657eb6378f
+  aesKey:
+  token:
+  operator: "81007710"   # 孙云嵩 [开头需要转一下字符串], OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_YH7W0E5637YUBU5UJ837
+  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9
+
+

+ 39 - 0
mjava-hangshi/target/classes/application-prod.yml

@@ -0,0 +1,39 @@
+# 环境配置
+server:
+  port: 9009
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# ekuaibao
+ekuaibao:
+  corpId: -yQbjbywbc640011                # 易快报的 corpId
+  platformApi: https://app.ekuaibao.com   # 易快报不同平台获取前缀的方式不同
+
+# dingtalk
+dingtalk:
+  agentId: 2554541552
+  appKey: dingibsmij0bzwbtyfrr
+  appSecret: JEtzUtRjXBN3yiF6v9bw0uF_jWAVmVvIWfoCqIyaRTK-TEWVQLGU-xsYu7Ni_GKB
+  corpId: ding6bd8f2716554297135c2f4657eb6378f
+  aesKey:
+  token:
+  operator: "81007710"   # 孙云嵩 [开头需要转一下字符串], OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_YH7W0E5637YUBU5UJ837
+  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9

+ 35 - 0
mjava-hangshi/target/test-classes/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-hangshi'
+if [ "$1" == "dev" ]; then
+  java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=dev
+else
+  if [ "$1" == "start" ]; then
+    nohup java -Xms256m -Xmx256m -jar $appname.jar &
+    echo "server prod is starting"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    else
+      if [ "$1" == "stop" ]; then
+        PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+        if [ -z "$PID" ]; then
+          echo "server is already stopped"
+        else
+          echo kill $PID
+          kill $PID
+        fi
+      else
+        if [ "$1" == "status" ]; then
+          PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+          if [ -z "$PID" ]; then
+            echo "server is stopped"
+          else
+            echo "server is running"
+            echo $PID
+          fi
+        fi
+      fi
+    fi
+  fi
+fi

+ 113 - 0
mjava-mcli/pom.xml

@@ -0,0 +1,113 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>java-mcli</artifactId>
+        <groupId>com.malk</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>mjava-mcli</artifactId>
+    <description>java mcli 验证</description>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <repositories>
+        <!-- webService 依赖 -->
+        <repository>
+            <id>com.e-iceblue</id>
+            <name>e-iceblue</name>
+            <url>http://repo.e-iceblue.cn/repository/maven-public/</url>
+        </repository>
+    </repositories>
+
+    <dependencies>
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.malk</groupId>
+            <artifactId>mjava</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+
+        <!-- url转pdf -->
+        <dependency>
+            <groupId>org.xhtmlrenderer</groupId>
+            <artifactId>flying-saucer-pdf-itext5</artifactId>
+        </dependency>
+
+        <!-- jsp: tomcat-embed-jasper 需要在子项目内引用 -->
+        <dependency>
+            <groupId>org.apache.tomcat.embed</groupId>
+            <artifactId>tomcat-embed-jasper</artifactId>
+        </dependency>
+        <!-- servlet -->
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet.jsp</groupId>
+            <artifactId>javax.servlet.jsp-api</artifactId>
+        </dependency>
+
+        <!-- MongoDB 驱动 -->
+        <dependency>
+            <groupId>org.mongodb</groupId>
+            <artifactId>mongo-java-driver</artifactId>
+            <version>3.1.0</version>
+        </dependency>
+        <!-- MongoDB jpa 操作 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-mongodb</artifactId>
+            <version>2.2.13.RELEASE</version>
+        </dependency>
+
+        <!--    local test    -->
+
+        <!-- CXF webservice -->
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
+            <version>3.4.0</version>
+        </dependency>
+
+        <!-- 文档审阅, 转换依赖  -->
+        <dependency>
+            <groupId>e-iceblue</groupId>
+            <artifactId>spire.doc.free</artifactId>
+            <version>3.9.0</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                    <!-- 如果没有该配置,devtools不会生效: 打包时关闭 -->
+                    <fork>false</fork>
+                    <!-- 避免中文乱码 -->
+                    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
+                </configuration>
+                <!-- 允许生成可运行jar -->
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

+ 68 - 0
mjava-mcli/src/main/java/com/malk/mcli/config/CxfConfig.java

@@ -0,0 +1,68 @@
+package com.malk.mcli.config;
+
+import com.malk.mcli.service.IH3yunWebService;
+import com.malk.mcli.service.impl.H3yunWebServiceImpl;
+import org.apache.cxf.Bus;
+import org.apache.cxf.bus.spring.SpringBus;
+import org.apache.cxf.jaxws.EndpointImpl;
+import org.apache.cxf.phase.Phase;
+import org.apache.cxf.transport.servlet.CXFServlet;
+import org.springframework.boot.web.servlet.ServletRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.xml.ws.Endpoint;
+
+
+@Configuration
+public class CxfConfig {
+
+    /**
+     * 访问路径: http://localhost:9001/api/webService/api?wsdl
+     * -
+     * invoke: mc可自定义, test为方法名称, arg0第一次参数
+     * -
+     * <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mc="http://service.hangshi.malk.com">
+     *   <soap:Body>
+     *     <mc:test>
+     *       <arg0>[{"assetNo":"1","barCode":"1","belongDept":"1","boxBarCode":"1","cap":"1","chkDate"madeDate":158688000000}]</arg0>
+     *     </mc:test>
+     *   </soap:Body>
+     * </soap:Envelope>
+     * -
+     *
+     * @WebParam 自定义参数名称, 否则就是 arg0, arg1, ...
+     */
+
+    @Bean
+    public ServletRegistrationBean disServlet() {
+        return new ServletRegistrationBean(new CXFServlet(), "/hangshi/ws/*");
+    }
+
+    @Bean(name = Bus.DEFAULT_BUS_ID)
+    public SpringBus springBus() {
+        return new SpringBus();
+    }
+
+//    @Bean
+//    public InvoiceWebService demoService() {
+//        return new InvoiceWebServiceImpl();
+//    }
+
+    @Bean
+    public IH3yunWebService demoService() {
+        return new H3yunWebServiceImpl();
+    }
+
+    @Bean
+    public Endpoint endpoint() {
+        EndpointImpl endpoint = new EndpointImpl(springBus(), demoService());
+        // 请求拦截器
+        endpoint.getInInterceptors().add(new WsInInterceptor(Phase.RECEIVE));
+        // 响应拦截器
+        endpoint.getOutInterceptors().add(new WsOutInterceptor(Phase.PRE_STREAM));
+        endpoint.publish("/invoke.asmx");
+        return endpoint;
+    }
+
+}

+ 40 - 0
mjava-mcli/src/main/java/com/malk/mcli/config/WsInInterceptor.java

@@ -0,0 +1,40 @@
+package com.malk.mcli.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.cxf.binding.soap.SoapMessage;
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.phase.AbstractPhaseInterceptor;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+@Slf4j
+public class WsInInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
+
+    public WsInInterceptor(String phase) {
+        super(phase);
+    }
+
+    @Override
+    public void handleMessage(SoapMessage message) throws Fault {
+        try {
+            // 从流中获取请求消息体并以字符串形式输出,注意IOUtils是cxf的包;
+            String input = IOUtils.toString(message.getContent(InputStream.class), "UTF-8");
+            // 如果内容不为空(第一次连接也会被拦截,此时input为空)
+            if (StringUtils.isNotBlank(input)) {
+                // 修改请求消息体为webservice服务要求的格式
+                input = input.replace("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">", "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ser=\"http://server.dandelion.com\">")
+                        .replace("<esb:getData xmlns:esb=\"mdm.stardand.com\">", "<ser:getData>")
+                        .replace("</esb:getData>", "</ser:getData>").replace("ns2:InvokeResponse", "InvokeResponse");
+                log.info("ns2:InvokeResponse, {}", input);
+            }
+
+            // 重新写入
+            message.setContent(InputStream.class, new ByteArrayInputStream(input.getBytes()));
+        } catch (Exception e) {
+            System.out.println(String.format("解析报文异常: %s", e.getMessage()));
+        }
+    }
+}

+ 71 - 0
mjava-mcli/src/main/java/com/malk/mcli/config/WsOutInterceptor.java

@@ -0,0 +1,71 @@
+package com.malk.mcli.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.cxf.binding.soap.SoapMessage;
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.io.CachedOutputStream;
+import org.apache.cxf.phase.AbstractPhaseInterceptor;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+@Slf4j
+public class WsOutInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
+
+    public WsOutInterceptor(String phase) {
+        super(phase);
+    }
+
+    @Override
+    public void handleMessage(SoapMessage message) throws Fault {
+        try {
+            // 从流中获取返回内容
+            OutputStream os = message.getContent(OutputStream.class);
+            CachedStream cs = new CachedStream();
+            message.setContent(OutputStream.class, cs);
+            message.getInterceptorChain().doIntercept(message);
+            CachedOutputStream cachedOutputStream = (CachedOutputStream) message.getContent(OutputStream.class);
+            InputStream in = cachedOutputStream.getInputStream();
+            String output = IOUtils.toString(in, "UTF-8");
+            // 修改内容为集成平台要求的格式
+            output = output.replace("<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">", "<soapenv:Envelope xmlns:soapenv=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\">")
+                    .replace("</soap:Envelope>", "</soapenv:Envelope>")
+                    .replace("<soap:Body>", "<soapenv:Body>")
+                    .replace("</soap:Body>", "</soapenv:Body>")
+                    .replace("<ns2:getDataResponse xmlns:ns2=\"http://server.dandelion.com\">", "")
+                    .replace("</ns2:getDataResponse>", "").replace("ns2:InvokeResponse", "InvokeResponse");
+            ;
+            log.info("ns2:InvokeResponse, {}", output);
+            output = "<string xmlns=\"http://tempuri.org/\">{\"ResultCode\":\"0\",\"Message\":\"\",\"Schema\":{\"Code\":\"Student\",\"Items\":[]},\"Data\":{}}</string>";
+            // 处理完后写回流中
+            IOUtils.copy(new ByteArrayInputStream(output.getBytes()), os);
+            cs.close();
+            os.flush();
+            message.setContent(OutputStream.class, os);
+        } catch (Exception e) {
+            System.out.println(String.format("解析报文异常: %s", e.getMessage()));
+        }
+    }
+
+    private static class CachedStream extends CachedOutputStream {
+        public CachedStream() {
+            super();
+        }
+
+        @Override
+        protected void doFlush() throws IOException {
+            currentStream.flush();
+        }
+
+        @Override
+        protected void doClose() throws IOException {
+        }
+
+        @Override
+        protected void onWrite() throws IOException {
+        }
+    }
+}

+ 120 - 0
mjava-mcli/src/main/java/com/malk/mcli/controller/DocController.java

@@ -0,0 +1,120 @@
+package com.malk.mcli.controller;
+
+import com.malk.server.common.FilePath;
+import com.malk.server.common.McR;
+import com.spire.doc.Document;
+import com.spire.pdf.FileFormat;
+import com.spire.pdf.PdfDocument;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 错误抛出与拦截详见CatchException
+ */
+@Slf4j
+@RestController
+@RequestMapping("/doc")
+public class DocController {
+
+
+    @Autowired
+    private FilePath filePath;
+
+    @PostMapping("doc")
+    McR doc() {
+
+        //创建Document实例,加载第一个Word示例文档
+        com.spire.doc.Document doc1 = new com.spire.doc.Document();
+//        doc1.loadFromFile(filePath.getPath().getFile() + "工作确认单.docx");
+        doc1.loadFromFile(filePath.getPath().getFile() + "杉泰-太医管家产品购销合同(实体卡)V2.0.docx");
+
+        //创建Document实例,加载第二个Word示例文档
+        com.spire.doc.Document doc2 = new Document();
+//        doc2.loadFromFile(filePath.getPath().getFile() + "工作确认单(1).docx");
+        doc2.loadFromFile(filePath.getPath().getFile() + "杉泰-太医管家产品购销合同(实体卡)V2.0 2.docx");
+//        doc2.loadFromFile(filePath.getPath().getFile() + "杉泰-太医管家产品购销合同(实体卡)V2.0 2.pdf", FileFormat.PDF);
+
+        //比较两个示例文档的内容差异
+//        doc1.compare(doc2, "Host");
+        doc1.compare(doc2, "宁静");
+
+        //保存结果文档
+        doc1.saveToFile(filePath.getPath().getFile() + "diff-衫泰.docx");
+
+        return McR.success();
+    }
+
+    @PostMapping("doc2")
+    McR doc2() {
+
+        //加载PDF
+        PdfDocument pdf = new PdfDocument();
+        pdf.loadFromFile(filePath.getPath().getFile() + "杉泰-太医管家产品购销合同(实体卡)V2.0 2.pdf");
+
+        //保存为Word格式
+        pdf.saveToFile(filePath.getPath().getFile() + "杉泰-太医管家产品购销合同(实体卡)V2.0 pdf.docx", FileFormat.DOCX);
+
+        com.spire.doc.Document doc1 = new com.spire.doc.Document();
+        doc1.loadFromFile(filePath.getPath().getFile() + "杉泰-太医管家产品购销合同(实体卡)V2.0.docx");
+
+        //创建Document实例,加载第二个Word示例文档
+        com.spire.doc.Document doc2 = new Document();
+        doc2.loadFromFile(filePath.getPath().getFile() + "杉泰-太医管家产品购销合同(实体卡)V2.0 pdf.docx");
+
+        // 比对位置错乱
+        //比较两个示例文档的内容差异
+//        doc1.compare(doc2, "Host");
+        doc1.compare(doc2, "宁静");
+//
+//        //保存结果文档
+        doc1.saveToFile(filePath.getPath().getFile() + "diff-衫泰-pdf.docx");
+
+
+//        Comparer comparer = new Comparer(filePath.getPath().getFile() + "杉泰-太医管家产品购销合同(实体卡)V2.0.docx");
+//        try {
+//            comparer.add(filePath.getPath().getFile() + "杉泰-太医管家产品购销合同(实体卡)V2.0 2.docx");
+//            comparer.compare("grou-衫泰.docx");
+//        } finally {
+//            comparer.dispose();
+//        }
+        return McR.success();
+    }
+
+    @PostMapping("doc3")
+    McR doc3() {
+
+
+        // 乱码
+//        com.spire.doc.Document doc = new com.spire.doc.Document();
+//        doc.loadFromFile(filePath.getPath().getFile() + "杉泰-太医管家产品购销合同(实体卡)V2.0.docx");
+//        doc.saveToFile(filePath.getPath().getFile() + "WordToPDF.pdf", com.spire.doc.FileFormat.PDF);
+
+        com.spire.doc.Document doc1 = new com.spire.doc.Document();
+        doc1.loadFromFile(filePath.getPath().getFile() + "杉泰-太医管家产品购销合同(实体卡)V2.0.pdf", com.spire.doc.FileFormat.PDF);
+
+        //创建Document实例,加载第二个Word示例文档
+        com.spire.doc.Document doc2 = new Document();
+        doc2.loadFromFile(filePath.getPath().getFile() + "杉泰-太医管家产品购销合同(实体卡)V2.0 2.pdf", com.spire.doc.FileFormat.PDF);
+
+        //比较两个示例文档的内容差异
+//        doc1.compare(doc2, "Host");
+        doc1.compare(doc2, "宁静");
+//
+//        //保存结果文档
+        doc1.saveToFile(filePath.getPath().getFile() + "diff-衫泰-pdf-pdf.pdf");
+
+
+//        Comparer comparer = new Comparer(filePath.getPath().getFile() + "杉泰-太医管家产品购销合同(实体卡)V2.0.docx");
+//        try {
+//            comparer.add(filePath.getPath().getFile() + "杉泰-太医管家产品购销合同(实体卡)V2.0 2.docx");
+//            comparer.compare("grou-衫泰.docx");
+//        } finally {
+//            comparer.dispose();
+//        }
+        return McR.success();
+    }
+}
+

+ 11 - 0
mjava-mcli/src/main/java/com/malk/mcli/repository/dao/AyUserAttachmentRelRepository.java

@@ -0,0 +1,11 @@
+package com.malk.mcli.repository.dao;
+
+import com.malk.mcli.repository.entity.AyUserAttachmentRel;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+public interface AyUserAttachmentRelRepository extends MongoRepository<AyUserAttachmentRel, String> {
+
+    AyUserAttachmentRel findAllBy();
+}
+
+

+ 16 - 0
mjava-mcli/src/main/java/com/malk/mcli/repository/entity/AyUserAttachmentRel.java

@@ -0,0 +1,16 @@
+package com.malk.mcli.repository.entity;
+
+import lombok.Data;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import javax.persistence.Id;
+
+@Data
+@Document("organizations")
+public class AyUserAttachmentRel {
+
+    @Id
+    private String _id;
+    private String logo;
+    private String name;
+}

+ 41 - 0
mjava-mcli/src/main/java/com/malk/mcli/service/IH3yunWebService.java

@@ -0,0 +1,41 @@
+package com.malk.mcli.service;
+
+import javax.jws.WebMethod;
+import javax.jws.WebParam;
+import javax.jws.WebResult;
+import javax.jws.WebService;
+
+/**
+ * @author shinka
+ * @date 2021/03/26
+ */
+
+@WebService(name = "IH3yunWebService", // 暴露服务名称
+        targetNamespace = "http://service.example.com/h3yun" // 命名空间,一般是接口的包名倒序
+)
+// @BindingType(value = SOAPBinding.SOAP12HTTP_BINDING) // soap1.1
+public interface IH3yunWebService {
+
+    public static final String NAMESPACE = "http://service.example.com/h3yun";
+
+    @WebMethod(operationName = "GetSchema", action = NAMESPACE + "/GetSchema")
+    @WebResult(name = "GetSchemaResult")
+    public String GetSchema(@WebParam(name = "schemaCode", targetNamespace = NAMESPACE) String schemaCode);
+
+    @WebMethod(operationName = "GetSchemaList", action = NAMESPACE + "/GetSchemaList")
+    @WebResult(name = "GetSchemaListResult")
+    public String GetSchemaList();
+
+    @WebMethod(operationName = "GetList", action = NAMESPACE + "/GetList")
+    @WebResult(name = "GetListResult")
+    public String GetList(@WebParam(name = "userCode", targetNamespace = NAMESPACE) String userCode,
+                          @WebParam(name = "schemaCode", targetNamespace = NAMESPACE) String schemaCode,
+                          @WebParam(name = "filter", targetNamespace = NAMESPACE) String filter);
+
+    @WebMethod(operationName = "Invoke", action = NAMESPACE + "/Invoke")
+    @WebResult(name = "InvokeResult")
+    public String Invoke(@WebParam(name = "userCode", targetNamespace = NAMESPACE) String userCode,
+                         @WebParam(name = "schemaCode", targetNamespace = NAMESPACE) String schemaCode,
+                         @WebParam(name = "methodName", targetNamespace = NAMESPACE) String methodName,
+                         @WebParam(name = "param", targetNamespace = NAMESPACE) String param);
+}

+ 34 - 0
mjava-mcli/src/main/java/com/malk/mcli/service/InvoiceWebService.java

@@ -0,0 +1,34 @@
+package com.malk.mcli.service;
+
+import javax.jws.WebMethod;
+import javax.jws.WebParam;
+import javax.jws.WebResult;
+import javax.jws.WebService;
+
+@WebService(targetNamespace = "http://tempuri.org/")
+public interface InvoiceWebService {
+
+    @WebResult(name = "InvokeResult")
+    @WebMethod(operationName = "sayHello")
+    String sayHello(@WebParam(name = "name", targetNamespace = "http://tempuri.org/") String name);
+
+    @WebMethod(operationName = "test")
+    String test(String user);
+
+
+    // 氚云
+
+    @WebMethod(operationName = "GetSchema")
+    String GetSchema(@WebParam(name = "schemaCode") String schemaCode);
+
+    @WebMethod(operationName = "GetSchemaList")
+    String GetSchemaList();
+
+    @WebMethod(operationName = "GetList")
+    String GetList();
+
+    @WebResult(name = "InvokeResult")
+    @WebMethod(operationName = "Invoke")
+    String Invoke(@WebParam(name = "userCode", targetNamespace = "http://tempuri.org/") String userCode, @WebParam(name = "schemaCode", targetNamespace = "http://tempuri.org/") String schemaCode, @WebParam(name = "methodName", targetNamespace = "http://tempuri.org/") String methodName, @WebParam(name = "param", targetNamespace = "http://tempuri.org/") String param);
+}
+

+ 46 - 0
mjava-mcli/src/main/java/com/malk/mcli/service/impl/H3yunWebServiceImpl.java

@@ -0,0 +1,46 @@
+package com.malk.mcli.service.impl;
+
+import com.malk.mcli.service.IH3yunWebService;
+import org.springframework.stereotype.Component;
+
+import javax.jws.WebService;
+import javax.xml.ws.BindingType;
+import javax.xml.ws.soap.SOAPBinding;
+
+/**
+ * @author shinka
+ * @date 2021/03/26
+ */
+@WebService(serviceName = "H3yunWebService", // 与接口中指定的name一致
+        targetNamespace = "http://service.example.com/h3yun", // 与接口中的命名空间一致,一般是接口的包名倒
+        endpointInterface = "com.malk.mcli.service.IH3yunWebService" // 接口地址
+)
+@BindingType(value = SOAPBinding.SOAP12HTTP_BINDING)
+@Component
+public class H3yunWebServiceImpl implements IH3yunWebService {
+
+    @Override
+    public String GetSchema(String schemaCode) {
+        // 氚云在集成的时候会调用GetSchema方法,该方法返回值仅支持如下两种,业务逻辑请写在其它方法上
+        return "{\"code\":\"\"}";
+        // return "";
+    }
+
+    @Override
+    public String GetSchemaList() {
+        return "{\"schemaCode\":\"D001062ceshi2\"}";
+    }
+
+    @Override
+    public String GetList(String userCode, String schemaCode, String filter) {
+        return "{\"userCode\":\"" + userCode + "\",\"schemaCode\":\"" + schemaCode + "\",\"filter\":\"" + filter
+                + "\"}";
+    }
+
+    @Override
+    public String Invoke(String userCode, String schemaCode, String methodName, String param) {
+        return "{\"userCode\":\"" + userCode + "\",\"schemaCode\":\"" + schemaCode + "\",\"methodName\":\"" + methodName
+                + "\",\"param\":\"" + methodName + "\"}";
+    }
+
+}

Datei-Diff unterdrückt, da er zu groß ist
+ 56 - 0
mjava-mcli/src/main/java/com/malk/mcli/service/impl/InvoiceWebServiceImpl.java


+ 68 - 0
mjava-mcli/src/main/java/com/malk/mcli/test/JSPTestController.java

@@ -0,0 +1,68 @@
+package com.malk.mcli.test;
+
+import com.alibaba.fastjson.JSON;
+import com.malk.repository.dao.primary.McAuthorizationDao;
+import com.malk.server.common.McR;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Profile;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * JSP在SpringBoot内运行
+ * -
+ * 1. 在 file - project structure - facets 下, 添加web以及对应的路径. 注意 web.xml 直接添加, 完成后将 webapp 文件夹移动到 src/main 下面
+ * 2. 添加依赖, 注意 tomcat-embed-jasper 需要在子项目内引用才有效, 余下依赖引入主项目即可
+ * 3. 项目配置, (jsp为存放jsp文件夹) spring: mvc: view:  -->  prefix: /WEB-INF/jsp/  -->  suffix: .jsp
+ * 4. jsp文件有三种语法, JSP表达式 / EL表达式 / JSTL标签库; 正常书写 html, 数据获取通过 ModelAndView 传递进来 [c标签最实用]
+ * 5. 在controller内返回 ModelAndView, 渲染为jsp文件名称, 参数传递可用 request.setAttribute / modelAndView.addObject
+ * 6. 可选: 在启动配置内, environment - working directory 下填写 $MODULE_WORKING_DIR$
+ * 7. 进阶: 实现jsp效果后, 后续可通过 mvc 解耦视图和控制器, view 可使用模板依赖进行统一管理与继承, controller 可通过 servlet 统一接管
+ **/
+@Slf4j
+@Profile({"dev", "test"})
+@RestController
+@RequestMapping("/test/jsp")
+public class JSPTestController {
+
+    @Autowired
+    private McAuthorizationDao dao;
+
+    @RequestMapping("show")
+    ModelAndView showEmp() {
+        List<Map> list = JSON.parseArray(JSON.toJSONString(dao.findAll()), Map.class);
+        ModelAndView mav = new ModelAndView("/test");
+        mav.addObject("list", list);
+        return mav;
+    }
+
+    @RequestMapping("/index")
+    ModelAndView index(HttpServletRequest request) {
+        //将用户信息保存到Request对象中
+        request.setAttribute("name", "pan_junbiao的博客");
+        request.setAttribute("blog", "https://blog.csdn.net/pan_junbiao");
+        request.setAttribute("remark", "您好,欢迎访问 pan_junbiao的博客");
+        //返回首页
+        return new ModelAndView("/index");
+    }
+
+    @RequestMapping("/echarts")
+    ModelAndView echarts() {
+        return new ModelAndView("/echart");
+    }
+
+    /**
+     * test
+     */
+    @GetMapping("test")
+    McR test() {
+        return McR.success();
+    }
+}

+ 37 - 0
mjava-mcli/src/main/java/com/malk/mcli/test/MGTestController.java

@@ -0,0 +1,37 @@
+package com.malk.mcli.test;
+
+import com.malk.mcli.repository.dao.AyUserAttachmentRelRepository;
+import com.malk.server.common.McR;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Profile;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+/**
+ * 指定运行环境 [参考TestController]
+ * 1. # MongoDB配置 [yml文件]
+ * data: mongodb: uri: mongodb://tbread:Teambition999@192.168.31.201:27017/teambition   # 固定格式 [连接成功后, 需要为 teambition 库添加 admin 权限才可查询]
+ * 2. 添加pom依赖 [未全局添加, 仅当前项目使用市添加]
+ * 3. 添加对应的@entity与Dao
+ */
+@Profile({"dev", "test"})
+@Validated
+@RestController
+@Slf4j
+@RequestMapping("/test/mg")
+public class MGTestController {
+
+    @Autowired
+    private AyUserAttachmentRelRepository ayUserAttachmentRelRepository;
+
+
+    @PostMapping("test")
+    McR test() {
+
+        return McR.success(ayUserAttachmentRelRepository.findAll());
+    }
+}

+ 48 - 0
mjava-mcli/src/main/java/com/malk/mcli/utils/UtilVendor.java

@@ -0,0 +1,48 @@
+package com.malk.mcli.utils;
+
+import com.itextpdf.text.pdf.BaseFont;
+import com.malk.server.common.FilePath;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.xhtmlrenderer.pdf.ITextFontResolver;
+import org.xhtmlrenderer.pdf.ITextRenderer;
+
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+
+/**
+ * 引用了配置文件, 访问对象必须通过 @Autowired 进行注入, 否则识别到为空 [配置文件说明参考Setting]
+ */
+@Slf4j
+@Component
+public class UtilVendor {
+
+    @Autowired
+    private FilePath filePath;
+
+    /**
+     * 网页转存为PDF文件: http://www.lrfun.com/html/technology/java/2019/0509/137.html
+     */
+    public void urlToPdf(String url, String outputFileName) {
+        try {
+            String outputFile = filePath.getPath().getFile() + "/" + outputFileName;
+            java.io.File targetFile = new java.io.File(outputFile);
+            // 创建父级文件路径
+            if (!targetFile.getParentFile().exists()) {
+                targetFile.getParentFile().mkdirs();
+            }
+            log.info("PDF 存储路径, {}", outputFile);
+            OutputStream os = new FileOutputStream(outputFile);
+            ITextRenderer renderer = new ITextRenderer();
+            renderer.setDocument(url);
+            ITextFontResolver fontResolver = renderer.getFontResolver();
+            fontResolver.addFont(filePath.getSource().getFonts(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED); //Linux
+            renderer.layout();
+            renderer.createPDF(os);
+            os.close();
+        } catch (Exception e) {
+            log.error(e.getMessage(), e); // 记录错误日志
+        }
+    }
+}

+ 55 - 0
mjava-mcli/src/main/resources/application-dev.yml

@@ -0,0 +1,55 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api/mcli
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  # MongoDB配置
+  data:
+    mongodb:
+      uri: mongodb://tbread:Teambition999@192.168.31.201:27017/teambition   # 固定格式 [连接成功后, 需要为 teambition 库添加 admin 权限才可查询]
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQLDialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/server/_Tool/var/mjava/tmp/file/
+    image: /Users/malk/server/_Tool/var/mjava/tmp/image/
+    tmp: /Users/malk/server/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/server/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/server/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 2533464721
+  appKey: dingromjxexd1esgvwwg
+  appSecret: AcStrL5bdw69gqeUfTQiFoBsgqisL2g-egzaKyID9Q7d85f_z9EkuTSS9Vse6zDb
+  corpId: ding5e83ad92d917b47535c2f4657eb6378f
+  aesKey: NgBOhTTp38RmPYs3gz7xBRHGNhwLHAv3tZntZ6He54F
+  token: yLQuiiYIBvrzN3tmOduDn
+
+# aliwork
+aliwork:
+  appType: APP_IW1FN8PPGGYQBWVMXS69
+  systemToken: UT866MB1WGX8VU029U93IA9DIKEG2GE9UU7FLI5
+

+ 39 - 0
mjava-mcli/src/main/resources/application-prod.yml

@@ -0,0 +1,39 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /proxy/xintianlong
+
+# condition
+spel:
+  scheduling: false       # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+  # MongoDB配置
+  data:
+    mongodb:
+      uri: mongodb://tbread:Teambition999@192.168.31.201:27017/teambition   # 固定格式 [连接成功后, 需要为 teambition 库添加 admin 权限才可查询]
+
+# dingtalk
+dingtalk:
+  agentId: 2533464721
+  appKey: dingromjxexd1esgvwwg
+  appSecret: AcStrL5bdw69gqeUfTQiFoBsgqisL2g-egzaKyID9Q7d85f_z9EkuTSS9Vse6zDb
+  corpId: ding5e83ad92d917b47535c2f4657eb6378f
+  aesKey: NgBOhTTp38RmPYs3gz7xBRHGNhwLHAv3tZntZ6He54F
+  token: yLQuiiYIBvrzN3tmOduDn
+
+# aliwork
+aliwork:
+  appType: APP_IW1FN8PPGGYQBWVMXS69
+  systemToken: UT866MB1WGX8VU029U93IA9DIKEG2GE9UU7FLI5

+ 42 - 0
mjava-mcli/src/main/webapp/WEB-INF/jsp/echart.jsp

@@ -0,0 +1,42 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+<html>
+<head>
+    <title>echarts</title>
+    <!-- 引入 ECharts 文件 -->
+    <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.0/dist/echarts.min.js"></script>
+</head>
+<body>
+    <!-- 为 ECharts 准备一个定义了宽高的 DOM -->
+    <div id="main" style="width: 600px;height:400px;"></div>
+
+    <script type="text/javascript">
+        // 基于准备好的dom,初始化echarts实例
+        var myChart = echarts.init(document.getElementById('main'));
+
+        // 指定图表的配置项和数据
+        var option = {
+            title: {
+                text: 'ECharts 入门示例'
+            },
+            tooltip: {},
+            legend: {
+                data: ['销量']
+            },
+            xAxis: {
+                data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
+            },
+            yAxis: {},
+            series: [
+                {
+                    name: '销量',
+                    type: 'bar',
+                    data: [5, 20, 36, 10, 10, 20]
+                }
+            ]
+        };
+
+        // 使用刚指定的配置项和数据显示图表。
+        myChart.setOption(option);
+    </script>
+</body>
+</html>

+ 24 - 0
mjava-mcli/src/main/webapp/WEB-INF/jsp/index.jsp

@@ -0,0 +1,24 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<html>
+<head>
+    <title>首页</title>
+    <meta name="author" content="pan_junbiao的博客">
+</head>
+<body>
+<h3>使用JSP表达式:</h3>
+用户姓名:<%= request.getAttribute("name") %><br/>
+博客地址:<%= request.getAttribute("blog") %><br/>
+备注信息:<%= request.getAttribute("remark") %><br/>
+
+<h3>使用EL表达式语言:</h3>
+用户姓名:${requestScope.name}<br/>
+博客地址:${requestScope.blog}<br/>
+备注信息:${requestScope.remark}<br/>
+
+<h3>使用JSTL标签库:</h3>
+用户姓名:<c:out value="${requestScope.name}"/><br/>
+博客地址:<c:out value="${requestScope.blog}"/><br/>
+备注信息:<c:out value="${requestScope.remark}"/><br/>
+</body>
+</html>

+ 31 - 0
mjava-mcli/src/main/webapp/WEB-INF/jsp/test.jsp

@@ -0,0 +1,31 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<!DOCTYPE html>
+<html xmlns:th="http://www.thymeleaf.org">
+<head>
+    <title>learn Resources</title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+<body>
+
+<div style="text-align: center;margin:0 auto;width: 1000px; ">
+    <h1>Spring boot</h1>
+    <table width="100%" border="1" cellspacing="1" cellpadding="0">
+        <tr>
+            <td>编号</td>
+            <td>名称</td>
+            <td>描述</td>
+
+        </tr>
+        <% out.println("mc-details"); %>
+        <c:forEach var="emp" items="${list}">
+            <tr>
+                <td th:text="${emp.tName}">${emp.id}</td>
+                <td th:text="${emp}">${emp.tName}</td>
+                <td th:text="${emp}">${emp.tDesc}</td>
+            </tr>
+        </c:forEach>
+    </table>
+</div>
+</body>
+</html>

+ 6 - 0
mjava-mcli/src/main/webapp/WEB-INF/web.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
+         version="4.0">
+</web-app>

+ 41 - 0
mjava-mcli/src/test/java/com/malk/mcli/DDTest.java

@@ -0,0 +1,41 @@
+//package com.mcli;
+//
+//import cn.hutool.core.date.DateUtil;
+//import com.dingtalk.oapi.lib.aes.DingTalkEncryptException;
+//import com.dingtalk.oapi.lib.aes.DingTalkEncryptor;
+//import com.mcli.service.dingtalk.DDConf;
+//import com.mcli.service.dingtalk.crypto.DingCallbackCrypto;
+//import lombok.extern.slf4j.Slf4j;
+//import org.junit.Test;
+//import org.junit.runner.RunWith;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.boot.test.context.SpringBootTest;
+//import org.springframework.test.context.junit4.SpringRunner;
+//
+//import java.util.Date;
+//
+//@Slf4j
+//@RunWith(SpringRunner.class)
+//@SpringBootTest(classes = Boot.class)
+//public class DDTest {
+//
+//    @Autowired
+//    private DDClient ddClient;
+//
+//    @Autowired
+//    private DDConf ddConf;
+//
+//    @Test
+//    public void test() {
+//        log.info("test, {}", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
+//    }
+//
+//    @Test
+//    public void cryto() throws DingCallbackCrypto.DingTalkEncryptException, DingTalkEncryptException {
+//        DingCallbackCrypto callbackCrypto = new DingCallbackCrypto(ddConf.getToken(), ddConf.getAesKey(), ddConf.getAppKey());
+//        log.info("cryto 111, {}", callbackCrypto.getEncryptedMap(DDConf.CALLBACK_RESPONSE));
+//
+//        DingTalkEncryptor dingTalkEncryptor = new DingTalkEncryptor(ddConf.getToken(), ddConf.getAesKey(), ddConf.getAppKey());
+//        log.info("cryto 222, {}", dingTalkEncryptor.getEncryptedMap(DDConf.CALLBACK_RESPONSE, System.currentTimeMillis(), DingCallbackCrypto.Utils.getRandomStr(8)));
+//    }
+//}

+ 41 - 0
mjava-mcli/src/test/java/com/malk/mcli/JpaTest.java

@@ -0,0 +1,41 @@
+//package com.mcli;
+//
+//import com.mcli.com.mcli.rongzhi.repository.dao.mutual.McAuthorizationDao;
+//import com.mcli.com.mcli.rongzhi.repository.entity.mutual.McAuthorizationDTO;
+//import lombok.extern.slf4j.Slf4j;
+//import org.junit.Test;
+//import org.junit.runner.RunWith;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.boot.test.context.SpringBootTest;
+//import org.springframework.test.annotation.Rollback;
+//import org.springframework.test.context.junit4.SpringRunner;
+//
+//import javax.transaction.Transactional;
+//
+//@Slf4j
+//@Transactional
+//@RunWith(SpringRunner.class)
+//@SpringBootTest(classes = Boot.class)
+//public class JpaTest {
+//
+//    @Autowired
+//    private McAuthorizationDao useAuthDao;
+//
+//    @Test
+//    @Rollback(false)
+//    public void initSystemToken() {
+//
+////        log.info("查询token, {}", useAuthDao.findByAppType("APP_TGNBNDTLX5EYOKAZIM2E"));
+//        McAuthorizationDTO useAuthDo = new McAuthorizationDTO();
+//        useAuthDo.setAppType("APP_TGNBNDTLX5EYOKAZIM2E");
+//        useAuthDo.setSystemToken("1K766GD12Q7WCB0M250ZH428F55O37N1IL7XKU1");
+//        useAuthDo.setAppName("能力馆 4.0");
+//        useAuthDo.setCorpId("dingebe19bcf228f85ec35c2f4657eb6378f");
+//        useAuthDo.setCorpName("上海致拓");
+//        useAuthDo.setUserId("095358016621619612");
+//        useAuthDo.setUserName("燕江");
+//        useAuthDo.setDeptId("447396156");
+//        useAuthDo.setDeptName("业务运营部");
+//        useAuthDao.save(useAuthDo);
+//    }
+//}

+ 99 - 0
mjava-mcli/src/test/java/com/malk/mcli/McTest.java

@@ -0,0 +1,99 @@
+package com.malk.mcli;
+
+import cn.hutool.core.date.DateUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.malk.Boot;
+import com.malk.utils.UtilDateTime;
+import com.malk.utils.UtilString;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.math.BigDecimal;
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Unit 单元测试
+ *
+ * @RunWith(SpringRunner.class:若需要调用项目内方法,则需要添加,否则会报空指针错误。注解类
+ * @SpringBootTest(classes = Application.class):若需要调用项目内方法,则需要添加,否则会报空指针错误【Application为项目启动application类名称】。注解类
+ * @Test: 测试注解,添加可执行测试方法,不支持入参。注解方法。注解方法
+ * @ActiveProfiles("dev"}):一般用于注解测试类,加载指定环境配置,如dev、prod、test。多个环境配置@ActiveProfiles({"dev”})。注解类
+ * @Rollback,回滚注解,配合事务注解@Transactional,来回滚事务。可以定义在测试类上,对整个类起作用,也可以对方法单独定义。默认值true,若junit需要写入设置为false
+ */
+@Slf4j
+@ActiveProfiles({"dev"})
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Boot.class)
+public class McTest {
+
+    @Test
+    public void date() {
+
+        long startTime = DateUtil.parse(20220404 + " 060000", "yyyyMMdd HHmmss").getTime() / 1000;
+        long endTime = startTime + 24 * 60 * 60 - 1;
+
+        log.info("1111, {}, {}", startTime, endTime);
+
+        // NOTE: 必须使用 Long 类型, 或者用 L 修饰 long 类型, 否则就会java转为 int 类型, 导致溢出计算错误
+        long time = 1649123903 * 1000L;
+        log.info("222, {}, {}", DateUtil.date(time), DateUtil.format(DateUtil.date(time), "yyyyMMdd"));
+
+        JSONObject eventJson = new JSONObject();
+        eventJson.put("check_time", "1649123903");
+        String date = DateUtil.format(DateUtil.date(Long.valueOf(eventJson.getString("check_time")).longValue() * 1000), "yyyyMMdd");
+
+        log.info("xxx, {}", date);
+
+        log.info("333, {}, {}", System.currentTimeMillis(), DateUtil.date(1649160925434L));
+
+
+        log.info("444, {}", StringUtils.substring("20220311", 0, 4));
+    }
+
+
+    @Test
+    public void math() {
+        log.info("1111, {}, {}", String.format("%.2f", 1319.3214, 3213.2323));
+        log.info("2222, {}", UtilString.stringFormatFixed(01319.3214));
+
+
+        log.info("3333, {}", 3.31431f >= 3.31f);
+
+        log.info("4444, {}", new BigDecimal(0.25d).add(new BigDecimal(0.751d)));
+    }
+
+    @Test
+    public void dateTime() {
+
+        String sTime = "2022-05-24 09:30:00";
+        String eTime = "2022-05-24 18:30:00";
+
+
+        LocalDateTime cTime = UtilDateTime.parseLocalDateTime(eTime.split(" ")[0] + " 18:00:00");
+        LocalDateTime lTime = UtilDateTime.parseLocalDateTime(eTime);
+        if (lTime.isAfter(cTime)) {
+            long seconds = Duration.between(cTime, lTime).getSeconds();
+            eTime = UtilDateTime.formatLocalDateTime(lTime.minusSeconds(seconds));
+            sTime = UtilDateTime.formatLocalDateTime(UtilDateTime.parseLocalDateTime(sTime).minusSeconds(seconds));
+
+            log.info("11111, {}, {}", sTime, eTime);
+        }
+        Map map = new HashMap();
+        map.put("dateField_l9t7eqe9", "1669996800000");
+
+        log.info("xxxx, {}", UtilDateTime.formatDate(new Date(Long.valueOf(String.valueOf(map.get("dateField_l9t7eqe9"))))));
+
+
+//        String begin = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format();
+//        String finish = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(leaveDo.getEndTime());
+    }
+}

+ 31 - 0
mjava-mcli/src/test/java/com/malk/mcli/U8Test.java

@@ -0,0 +1,31 @@
+//package com.mcli;
+//
+//import com.mcli.service.aliwork.YDConf;
+//import com.mcli.service.u8open.U8Client;
+//import lombok.extern.slf4j.Slf4j;
+//import org.junit.Test;
+//import org.junit.runner.RunWith;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.boot.test.context.SpringBootTest;
+//import org.springframework.test.context.ActiveProfiles;
+//import org.springframework.test.context.junit4.SpringRunner;
+//
+//@Slf4j
+//@ActiveProfiles("dev")
+//@RunWith(SpringRunner.class)
+//@SpringBootTest(classes = Boot.class)
+//public class U8Test {
+//
+//    @Autowired
+//    private U8Client u8Client;
+//
+//    @Test
+//    public void token() {
+//        log.info("u8 token, {}", "xx");
+//    }
+//
+//    @Test
+//    public void test2() {
+//        log.info("xxx, {}", Math.ceil(4981 * 1.0 / YDConf.PAGE_SIZE_LIMIT));
+//    }
+//}

+ 97 - 0
mjava-mcli/src/test/java/com/malk/mcli/YDTest.java

@@ -0,0 +1,97 @@
+//package com.mcli;
+//
+//import com.alibaba.fastjson.JSON;
+//import com.alibaba.fastjson.JSONArray;
+//import com.alibaba.fastjson.JSONObject;
+//import com.mcli.service.aliwork.YDConf;
+//import com.mcli.service.aliwork.YDParam;
+//import lombok.extern.slf4j.Slf4j;
+//import org.junit.Test;
+//import org.junit.runner.RunWith;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.boot.test.context.SpringBootTest;
+//import org.springframework.test.context.ActiveProfiles;
+//import org.springframework.test.context.junit4.SpringRunner;
+//
+//@ActiveProfiles({"dev"})
+//@Slf4j
+//@RunWith(SpringRunner.class)
+//@SpringBootTest(classes = Boot.class)
+//public class YDTest {
+//
+//    @Autowired
+//    private YDService ydService;
+//
+//    @Autowired
+//    private YDClient ydClient;
+//
+//    @Test
+//    public void test2() {
+//        log.info("xxx, {}", Math.ceil(4981 * 1.0 / YDConf.PAGE_SIZE_LIMIT));
+//    }
+//
+//    // 申城
+//    @Test
+//    public void scUpdate() {
+//        YDParam ydParam = new YDParam();
+//        ydParam.setAppType("APP_QJKNHO0SAR3DDBRF5PBZ");
+//        ydParam.setSystemToken("9T566BD1GA2VGTBF4TJWZ5993SOX2AJ7X80WKZY1");
+//        ydParam.setFormUuid("FORM-MFA66S91ZZCVETYZ030N79FUG8VQ2GK7X80WK31");
+////        ydParam.setProcessInstanceId("f41a7516-6ec4-4deb-9968-eb3b842a017c");
+////        JSONObject updateFormDataJson = new JSONObject();
+////        updateFormDataJson.put("textareaField_krpv7d9t", "");
+////        ydParam.setUpdateFormDataJson(updateFormDataJson.toJSONString());
+//        log.info("2111, {}", ydClient.queryData(YDConf.API_FORM_QUERY_DATA, ydParam));
+//    }
+//
+//    // 查询实例
+//    @Test
+//    public void queryFormInstId() {
+//        YDParam ydParam = new YDParam();
+//
+//        // 远东
+////        ydParam.setAppType("APP_GXUUGZJ1ZPPBIJKLE9BH");
+////        ydParam.setSystemToken("KH766OB1OEFU141VX82MPV04ZS6R1M0WS8QUKD4");
+////        ydParam.setProcessInstanceId("3022651a-80c9-456e-860e-7cdfbe60db89");
+//
+//        // 镁信
+//        /**
+//         * 补充协议:15dafce9-0bf7-495d-9af7-c995d2306e46
+//         * 采购立项:a0ee6493-b657-4160-8f41-3c9ce744dd17
+//         * 采购结果:a2c915c3-6591-416b-a3b5-4dca07bdd81a
+//         * 采购合同:9a36abf7-2ced-424a-be76-4131cc268a0a
+//         */
+//        ydParam.setAppType("APP_X66J3HR5W8PGMOQ5S6N0");
+//        ydParam.setSystemToken("BP866V81LYVVMVOL5OQXD8MUY45N2UMAVGUWKII");
+//        ydParam.setProcessInstanceId("6a067967-fbaa-49df-a940-426a4f8f8bd7");
+//
+//        Object rsp = ydClient.operateData(YDConf.API_PROCESS_DETAIL, ydParam);
+//
+//        log.info("1111, {}", rsp);
+//    }
+//
+//    // 修改流程数据
+//    @Test
+//    public void updateProcessData() {
+//
+//        YDParam ydParam = new YDParam();
+//        ydParam.setAppType("APP_X66J3HR5W8PGMOQ5S6N0");
+//        ydParam.setSystemToken("BP866V81LYVVMVOL5OQXD8MUY45N2UMAVGUWKII");
+//        ydParam.setFormInstId("6a067967-fbaa-49df-a940-426a4f8f8bd7");
+//
+//        JSONObject object = new JSONObject();
+//        JSONArray array = new JSONArray();
+//        array.add("604392324");
+//        array.add("16044153158358656");
+//        object.put("employeeField_l60gz6kc", array);
+//        object.put("selectField_ktawz21s", "代办服务");
+//        ydParam.setUpdateFormDataJson(JSON.toJSONString(object));
+//
+//
+//        Object rsp = ydClient.operateData(YDConf.API_FORM_UPDATE, ydParam);
+//
+//        log.info("修改流程数据, {}", rsp);
+//
+//    }
+//
+//}

+ 66 - 0
mjava-mcli/src/test/java/com/malk/mcli/YSTest.java

@@ -0,0 +1,66 @@
+//package com.mcli;
+//
+//import cn.hutool.core.date.DateUtil;
+//import com.mcli.com.mcli.mcli.utils.UtilString;
+//import com.mcli.service.diwork.YSConf;
+//import com.mcli.service.diwork.YSClient;
+//import lombok.extern.slf4j.Slf4j;
+//import org.junit.Test;
+//import org.junit.runner.RunWith;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.boot.test.context.SpringBootTest;
+//import org.springframework.test.context.junit4.SpringRunner;
+//
+//import java.util.Date;
+//import java.util.HashMap;
+//import java.util.Map;
+//
+//@Slf4j
+//@RunWith(SpringRunner.class)
+//@SpringBootTest(classes = Boot.class)
+//public class YSTest {
+//
+//    @Autowired
+//    private YSClient ysClient;
+//
+//    @Test
+//    public void test() {
+//        log.info("math, {}", Math.ceil(149 * 1.0 / YSConf.PAGE_SIZE_LIMIT));
+//        log.info("date, {}", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
+//
+//        HashMap data = new HashMap<>();
+//        data.put("xxx", "11111");
+//        log.info("xxxxx, {}", UtilString.stringFormatNull(data, "xxx"));
+//    }
+//
+//    @Test
+//    public void token() {
+//        ysClient.getAccessToken();
+//    }
+//
+//    @Test
+//    public void shop() {
+//
+//        Map data = new HashMap();
+//        ysClient.queryStoreArchives(ysClient.getAccessToken(), (list, total) -> {
+//            for (Map map : list) {
+//                float coefficient = 1.0f;
+//                String shopCode = String.valueOf(map.get("shopCode"));
+//                if (shopCode.contains("-")) {
+//                    String[] arrStr = shopCode.split("-");
+//                    coefficient = Float.valueOf(arrStr[arrStr.length - 1]);
+//                }
+//                data.put(shopCode, coefficient);
+//            }
+//            log.info("shop test, {}, {}", list, total);
+//        });
+//        log.info("coefficient, {}", data);
+//    }
+//
+//    @Test
+//    public void financial() {
+//        ysClient.abandonApprove(ysClient.getAccessToken(), "2669748174591744", "2022-02-08 17:04:37", "钉钉审批拒绝", r -> {
+//            log.info("test, {}", r);
+//        });
+//    }
+//}

+ 35 - 0
mjava-mcli/src/test/resources/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-xintianlong'
+if [ "$1" == "dev" ]; then
+  java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=dev
+else
+  if [ "$1" == "start" ]; then
+    nohup java -Xms256m -Xmx256m -jar $appname.jar &
+    echo "server prod is starting"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    else
+      if [ "$1" == "stop" ]; then
+        PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+        if [ -z "$PID" ]; then
+          echo "server is already stopped"
+        else
+          echo kill $PID
+          kill $PID
+        fi
+      else
+        if [ "$1" == "status" ]; then
+          PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+          if [ -z "$PID" ]; then
+            echo "server is stopped"
+          else
+            echo "server is running"
+            echo $PID
+          fi
+        fi
+      fi
+    fi
+  fi
+fi

+ 56 - 0
mjava-mcli/src/test/resources/winsw.xml

@@ -0,0 +1,56 @@
+<!--
+  MIT License
+
+  Copyright (c) 2008-2020 Kohsuke Kawaguchi, Sun Microsystems, Inc., CloudBees,
+  Inc., Oleg Nenashev and other contributors
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in all
+  copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+-->
+
+<!--
+ This is an example of a minimal Windows Service Wrapper configuration, which includes only mandatory options.
+ 
+ This configuration file should be placed near the WinSW executable, the name should be the same.
+ E.g. for myapp.exe the configuration file name should be myapp.xml
+ 
+ You can find more information about the configuration options here: https://github.com/kohsuke/winsw/blob/master/doc/xmlConfigFile.md
+ Full example: https://github.com/kohsuke/winsw/blob/master/examples/sample-allOptions.xml
+-->
+
+<service>
+    <!-- 注册服务ID -->
+    <id>mjava</id>
+    <!-- 启动服务名称 -->
+    <name>mjava</name>
+    <!-- 对服务的描述 -->
+    <description>标准化后端接口, 自用脚手架封装</description>
+    <!-- 「jdk需要安装」启动的可执行文件:若未配置环境变量executable需要执行绝对路径 -->
+    <!-- <executable>java</executable> -->
+    <executable>C:\Program Files\DingTalkServer\jdk1.8.0_221\bin\java</executable>
+    <!-- Xmx256m 代表堆内存最大值为256MB -jar后面的是项目名 [-Dfile.encoding=UTF-8 Windows会乱码, 但Mac上VSCode正常] -->
+    <!-- <arguments>-Xms256m -Xmx256m -Dfile.encoding=UTF-8 -jar mjava-mcli.jar</arguments> -->
+    <arguments>-Xms256m -Xmx256m -jar mjava-mcli.jar</arguments>
+    <!-- 服务的启动模式:默认Automatic -->
+    <startmode>Automatic</startmode>
+    <!-- 日志地址 -->
+    <logpath>%BASE%\ws</logpath>
+    <!-- 日志模式 -->
+    <logmode>rotate</logmode>
+</service>
+

+ 55 - 0
mjava-mcli/target/classes/application-dev.yml

@@ -0,0 +1,55 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api/mcli
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  # MongoDB配置
+  data:
+    mongodb:
+      uri: mongodb://tbread:Teambition999@192.168.31.201:27017/teambition   # 固定格式 [连接成功后, 需要为 teambition 库添加 admin 权限才可查询]
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQLDialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/server/_Tool/var/mjava/tmp/file/
+    image: /Users/malk/server/_Tool/var/mjava/tmp/image/
+    tmp: /Users/malk/server/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/server/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/server/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 2533464721
+  appKey: dingromjxexd1esgvwwg
+  appSecret: AcStrL5bdw69gqeUfTQiFoBsgqisL2g-egzaKyID9Q7d85f_z9EkuTSS9Vse6zDb
+  corpId: ding5e83ad92d917b47535c2f4657eb6378f
+  aesKey: NgBOhTTp38RmPYs3gz7xBRHGNhwLHAv3tZntZ6He54F
+  token: yLQuiiYIBvrzN3tmOduDn
+
+# aliwork
+aliwork:
+  appType: APP_IW1FN8PPGGYQBWVMXS69
+  systemToken: UT866MB1WGX8VU029U93IA9DIKEG2GE9UU7FLI5
+

+ 39 - 0
mjava-mcli/target/classes/application-prod.yml

@@ -0,0 +1,39 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /proxy/xintianlong
+
+# condition
+spel:
+  scheduling: false       # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+  # MongoDB配置
+  data:
+    mongodb:
+      uri: mongodb://tbread:Teambition999@192.168.31.201:27017/teambition   # 固定格式 [连接成功后, 需要为 teambition 库添加 admin 权限才可查询]
+
+# dingtalk
+dingtalk:
+  agentId: 2533464721
+  appKey: dingromjxexd1esgvwwg
+  appSecret: AcStrL5bdw69gqeUfTQiFoBsgqisL2g-egzaKyID9Q7d85f_z9EkuTSS9Vse6zDb
+  corpId: ding5e83ad92d917b47535c2f4657eb6378f
+  aesKey: NgBOhTTp38RmPYs3gz7xBRHGNhwLHAv3tZntZ6He54F
+  token: yLQuiiYIBvrzN3tmOduDn
+
+# aliwork
+aliwork:
+  appType: APP_IW1FN8PPGGYQBWVMXS69
+  systemToken: UT866MB1WGX8VU029U93IA9DIKEG2GE9UU7FLI5

+ 35 - 0
mjava-mcli/target/test-classes/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-xintianlong'
+if [ "$1" == "dev" ]; then
+  java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=dev
+else
+  if [ "$1" == "start" ]; then
+    nohup java -Xms256m -Xmx256m -jar $appname.jar &
+    echo "server prod is starting"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    else
+      if [ "$1" == "stop" ]; then
+        PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+        if [ -z "$PID" ]; then
+          echo "server is already stopped"
+        else
+          echo kill $PID
+          kill $PID
+        fi
+      else
+        if [ "$1" == "status" ]; then
+          PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+          if [ -z "$PID" ]; then
+            echo "server is stopped"
+          else
+            echo "server is running"
+            echo $PID
+          fi
+        fi
+      fi
+    fi
+  fi
+fi

+ 56 - 0
mjava-mcli/target/test-classes/winsw.xml

@@ -0,0 +1,56 @@
+<!--
+  MIT License
+
+  Copyright (c) 2008-2020 Kohsuke Kawaguchi, Sun Microsystems, Inc., CloudBees,
+  Inc., Oleg Nenashev and other contributors
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in all
+  copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+-->
+
+<!--
+ This is an example of a minimal Windows Service Wrapper configuration, which includes only mandatory options.
+ 
+ This configuration file should be placed near the WinSW executable, the name should be the same.
+ E.g. for myapp.exe the configuration file name should be myapp.xml
+ 
+ You can find more information about the configuration options here: https://github.com/kohsuke/winsw/blob/master/doc/xmlConfigFile.md
+ Full example: https://github.com/kohsuke/winsw/blob/master/examples/sample-allOptions.xml
+-->
+
+<service>
+    <!-- 注册服务ID -->
+    <id>mjava</id>
+    <!-- 启动服务名称 -->
+    <name>mjava</name>
+    <!-- 对服务的描述 -->
+    <description>标准化后端接口, 自用脚手架封装</description>
+    <!-- 「jdk需要安装」启动的可执行文件:若未配置环境变量executable需要执行绝对路径 -->
+    <!-- <executable>java</executable> -->
+    <executable>C:\Program Files\DingTalkServer\jdk1.8.0_221\bin\java</executable>
+    <!-- Xmx256m 代表堆内存最大值为256MB -jar后面的是项目名 [-Dfile.encoding=UTF-8 Windows会乱码, 但Mac上VSCode正常] -->
+    <!-- <arguments>-Xms256m -Xmx256m -Dfile.encoding=UTF-8 -jar mjava-mcli.jar</arguments> -->
+    <arguments>-Xms256m -Xmx256m -jar mjava-mcli.jar</arguments>
+    <!-- 服务的启动模式:默认Automatic -->
+    <startmode>Automatic</startmode>
+    <!-- 日志地址 -->
+    <logpath>%BASE%\ws</logpath>
+    <!-- 日志模式 -->
+    <logmode>rotate</logmode>
+</service>
+

+ 54 - 0
mjava-suodisi/pom.xml

@@ -0,0 +1,54 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>java-mcli</artifactId>
+        <groupId>com.malk</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>mjava-suodisi</artifactId>
+    <description>索迪斯 poc 动态审批条件程序</description>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.malk</groupId>
+            <artifactId>mjava</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                    <!-- 如果没有该配置,devtools不会生效: 打包时关闭 -->
+                    <fork>false</fork>
+                    <!-- 避免中文乱码 -->
+                    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
+                </configuration>
+                <!-- 允许生成可运行jar -->
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

+ 32 - 0
mjava-suodisi/src/main/java/com/malk/suodisi/Boot.java

@@ -0,0 +1,32 @@
+package com.malk.suodisi;
+
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+import javax.persistence.EntityManager;
+
+/**
+ * corp项目: 扫描公共模块
+ * -
+ * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ */
+@EnableJpaAuditing
+@SpringBootApplication(scanBasePackages = {"com.malk"})
+public class Boot {
+
+    public static void main(String... args) {
+        SpringApplication.run(Boot.class, args);
+    }
+
+    /**
+     * 让Spring管理JPAQueryFactory [不使用Qualifier详见mjava-Boot]
+     */
+    @Bean
+    public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
+        return new JPAQueryFactory(entityManager);
+    }
+}

+ 106 - 0
mjava-suodisi/src/main/java/com/malk/suodisi/controller/SDSController.java

@@ -0,0 +1,106 @@
+package com.malk.suodisi.controller;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McException;
+import com.malk.service.aliwork.YDClient;
+import com.malk.utils.UtilServlet;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 错误抛出与拦截详见 CatchException
+ */
+@Slf4j
+@RestController
+@RequestMapping
+public class SDSController {
+    
+    @Autowired
+    private YDClient ydClient;
+
+    /**
+     * 动态审批人
+     */
+    @PostMapping("sds/test")
+    List<String> sdsTest(HttpServletRequest request) {
+        Map param = UtilServlet.getParamMap(request);
+        McException.assertParamException_Null(param, "finance");
+        Map condition = new HashMap();
+        condition.put("textField_lg52q035", param.get("finance"));
+        YDParam ydParam = YDParam.builder()
+                .appType("APP_Y75CEY3YR30YOLEWETJJ")
+                .systemToken("BY866R813JM8XVLGD7YELCPDH9IL29Z5BQQEL48")
+                .formUuid("FORM-8Y866XB1AXM9DFV3AW6D7AV2WWEK2F3OP25GLD")
+                .searchFieldJson(JSON.toJSONString(condition))
+                .build();
+        List<Map> list = (List<Map>) ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_search_form).getData();
+        Map formData = (Map) list.get(0).get("formData");
+        log.info("索迪斯动态审批人, {}, {}", param, formData);
+
+        return (List<String>) formData.get("employeeField_lg52q036_id");
+    }
+
+    /**
+     * 回写招聘子表
+     */
+    @PostMapping("sds/update")
+    Map sdsUpdate(HttpServletRequest request) {
+
+        // 查询招聘申请
+        Map param = UtilServlet.getParamMap(request);
+        McException.assertParamException_Null(param, "formInstId");
+        YDParam ydParam = YDParam.builder()
+                .appType("APP_Y75CEY3YR30YOLEWETJJ")
+                .systemToken("BY866R813JM8XVLGD7YELCPDH9IL29Z5BQQEL48")
+                .formInstId(String.valueOf(param.get("formInstId")))
+                .build();
+        Map rsp = (Map) ydClient.operateData(ydParam, YDConf.FORM_OPERATION.update);
+        Map formData = (Map) rsp.get("formData");
+        log.info("索迪斯回写子表, {}, {}", param, formData);
+
+        // 组装分发子表数据
+        Map detail = new HashMap();
+        detail.put("associationFormField_lf7pkag4", JSON.parse(String.valueOf(formData.get("associationFormField_lg54gbt9_id")))); // 职位组
+        detail.put("textField_lf7pkag5", formData.get("textField_lg54gbta")); // 新员工姓名
+        detail.put("dateField_lf7pkag6", formData.get("dateField_lg54gbtf")); // 入职日期
+
+        // todo: 成员, 附件, 关联表单
+        List<Map> association = JSON.parseArray(String.valueOf(JSON.parse(String.valueOf(formData.get("associationFormField_lg0gmbi8_id")))), Map.class);
+        String formInstId = String.valueOf(association.get(0).get("instanceId"));
+        ydParam.setFormInstId(formInstId);
+        Map rspSrc = (Map) ydClient.operateData(ydParam, YDConf.FORM_OPERATION.update);
+        Map formDataSrc = (Map) rspSrc.get("formData");
+        List<Map> list = new ArrayList<>();
+        if (ObjectUtil.isNotNull(formDataSrc.get("tableField_lf7pkag3"))) {
+            list = (List<Map>) formDataSrc.get("tableField_lf7pkag3");
+        }
+
+        // 更新流程数据
+        Map form = new HashMap();
+        list.add(detail);
+        form.put("tableField_lf7pkag3", list);
+        form.put("numberField_lfj9d501", 2);
+        ydParam.setUpdateFormDataJson(JSON.toJSONString(form));
+        ydClient.operateData(ydParam, YDConf.FORM_OPERATION.update);
+
+        log.info("更新, {}, {}", formInstId, form);
+
+        Map r = new HashMap();
+        r.put("success", true);
+        return r;
+    }
+}
+
+

+ 53 - 0
mjava-suodisi/src/main/resources/application-dev.yml

@@ -0,0 +1,53 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api/suodisi
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/server/_Tool/var/mjava/tmp/file/
+    image: /Users/malk/server/_Tool/var/mjava/tmp/image/
+    tmp: /Users/malk/server/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/server/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/server/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 1963716187
+  appKey: ding8qyulwwmad6j7k6c
+  appSecret: e_hRHuubw-Xi0OuPJOYdXSElVzOC0IPgMrHQTBuAM9BqW-DFnrcsSyBHi7Me3xSv
+  corpId: ding321c72787fffc78b35c2f4657eb6378f
+  aesKey:
+  token:
+  operator: "095358016629044412"   # 牧语[开头需要转一下字符串], OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_YH7W0E5637YUBU5UJ837
+  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9
+
+

+ 34 - 0
mjava-suodisi/src/main/resources/application-prod.yml

@@ -0,0 +1,34 @@
+# 环境配置
+server:
+  port: 9010
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# dingtalk
+dingtalk:
+  agentId: 1963716187
+  appKey: ding8qyulwwmad6j7k6c
+  appSecret: e_hRHuubw-Xi0OuPJOYdXSElVzOC0IPgMrHQTBuAM9BqW-DFnrcsSyBHi7Me3xSv
+  corpId: ding321c72787fffc78b35c2f4657eb6378f
+  aesKey:
+  token:
+  operator: "095358016629044412"   # 牧语[开头需要转一下字符串], OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_YH7W0E5637YUBU5UJ837
+  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9

+ 35 - 0
mjava-suodisi/src/test/resources/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-suodisi'
+if [ "$1" == "dev" ]; then
+  java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=dev
+else
+  if [ "$1" == "start" ]; then
+    nohup java -Xms256m -Xmx256m -jar $appname.jar &
+    echo "server prod is starting"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    else
+      if [ "$1" == "stop" ]; then
+        PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+        if [ -z "$PID" ]; then
+          echo "server is already stopped"
+        else
+          echo kill $PID
+          kill $PID
+        fi
+      else
+        if [ "$1" == "status" ]; then
+          PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+          if [ -z "$PID" ]; then
+            echo "server is stopped"
+          else
+            echo "server is running"
+            echo $PID
+          fi
+        fi
+      fi
+    fi
+  fi
+fi

+ 53 - 0
mjava-suodisi/target/classes/application-dev.yml

@@ -0,0 +1,53 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api/suodisi
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/server/_Tool/var/mjava/tmp/file/
+    image: /Users/malk/server/_Tool/var/mjava/tmp/image/
+    tmp: /Users/malk/server/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/server/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/server/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 1963716187
+  appKey: ding8qyulwwmad6j7k6c
+  appSecret: e_hRHuubw-Xi0OuPJOYdXSElVzOC0IPgMrHQTBuAM9BqW-DFnrcsSyBHi7Me3xSv
+  corpId: ding321c72787fffc78b35c2f4657eb6378f
+  aesKey:
+  token:
+  operator: "095358016629044412"   # 牧语[开头需要转一下字符串], OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_YH7W0E5637YUBU5UJ837
+  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9
+
+

+ 34 - 0
mjava-suodisi/target/classes/application-prod.yml

@@ -0,0 +1,34 @@
+# 环境配置
+server:
+  port: 9010
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# dingtalk
+dingtalk:
+  agentId: 1963716187
+  appKey: ding8qyulwwmad6j7k6c
+  appSecret: e_hRHuubw-Xi0OuPJOYdXSElVzOC0IPgMrHQTBuAM9BqW-DFnrcsSyBHi7Me3xSv
+  corpId: ding321c72787fffc78b35c2f4657eb6378f
+  aesKey:
+  token:
+  operator: "095358016629044412"   # 牧语[开头需要转一下字符串], OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_YH7W0E5637YUBU5UJ837
+  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9

+ 35 - 0
mjava-suodisi/target/test-classes/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-suodisi'
+if [ "$1" == "dev" ]; then
+  java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=dev
+else
+  if [ "$1" == "start" ]; then
+    nohup java -Xms256m -Xmx256m -jar $appname.jar &
+    echo "server prod is starting"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    else
+      if [ "$1" == "stop" ]; then
+        PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+        if [ -z "$PID" ]; then
+          echo "server is already stopped"
+        else
+          echo kill $PID
+          kill $PID
+        fi
+      else
+        if [ "$1" == "status" ]; then
+          PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+          if [ -z "$PID" ]; then
+            echo "server is stopped"
+          else
+            echo "server is running"
+            echo $PID
+          fi
+        fi
+      fi
+    fi
+  fi
+fi

+ 49 - 0
mjava/pom.xml

@@ -0,0 +1,49 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>java-mcli</artifactId>
+        <groupId>com.malk</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>mjava</artifactId>
+    <description>mjava framework</description>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                    <!-- 如果没有该配置,devtools不会生效: 打包时关闭 -->
+                    <fork>false</fork>
+                    <!-- 避免中文乱码 -->
+                    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
+                </configuration>
+                <!-- 允许生成可运行jar: 发布作为基础包提供, 注释 executions 再执行 install 到本地 maven. 若开启即可作为独立 jar 运行 -->
+                <executions>
+                    <execution>
+                        <goals>
+                            <!--                            <goal>repackage</goal>-->
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

+ 29 - 0
mjava/src/main/java/com/malk/Boot.java

@@ -0,0 +1,29 @@
+package com.malk;
+
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+import javax.persistence.EntityManager;
+
+@EnableJpaAuditing
+@SpringBootApplication
+public class Boot {
+
+    public static void main(String... args) {
+        SpringApplication.run(Boot.class, args);
+    }
+
+    /**
+     * 让Spring管理JPAQueryFactory [多数据源配置详见DataSourceConfig]
+     *
+     * @Qualifier("entityManagerFactory") 单数据源指向
+     * @Qualifier("entityManagerFactoryPrimary") 多数据源指向
+     */
+    @Bean
+    public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
+        return new JPAQueryFactory(entityManager);
+    }
+}

+ 215 - 0
mjava/src/main/java/com/malk/Filter/CatchException.java

@@ -0,0 +1,215 @@
+package com.malk.Filter;
+
+import com.alibaba.fastjson.JSONException;
+import com.malk.server.common.McException;
+import com.malk.server.common.McR;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.validation.BindException;
+import org.springframework.validation.FieldError;
+import org.springframework.web.HttpMediaTypeNotSupportedException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
+
+import javax.validation.ConstraintDeclarationException;
+import javax.validation.ConstraintViolationException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 统一错误拦截
+ * -
+ * 参数校验 @Validated【javax.validation】
+ * 1. @Validated 针对实体类进行字段入参校验,可做分组,实现不同接口请求下字段的校验规则
+ * 2. @RestControllerAdvice 搭配 @ExceptionHandler 注解进行错误统一捕获和拦截返回,无需 try…catch 即可格式化返回标准输出::注意类名
+ * 3. 若无分组验证需求,可将@Validated 置于类上,不需要在@requestBody前声明。分组验证,可以在实体类组合好,若是取并集,则可直接在@requestBody上设置多个即可
+ * -
+ * 拦截param自定义message: @RequestParam默认是required,若想使用该检验,请求方法无需添加@RequestParam,且需要在Controller上添加@Validated
+ * 参数@RequestParam,可以配置默认值,指定name,指定name后可以设置是否必填。若是要获取所有(@RequestParam MultiValueMap<String, String> paramMap),每一个字段的值是一个集合
+ * -
+ * 关于在Service上使用校验, 首先需要impl类上添加@Validated [和Controller一致]
+ * 建议注解到方法声明上, 抛出到ConstraintViolationException. 若校验注解到方法实现上, 则错误抛出到 ConstraintDeclarationException, 没有友好的提示
+ * -
+ * -
+ * 若入参是Body,需要使用@RequestBody解析到实体/Map内,校验错误抛出到MethodArgumentNotValidException。@RequestBody @Validated({YDParam.Retrieve_Condition.class}) YDParam param
+ * 如入参是formData,不能使用@RequestBody,参数会自动解析到实体; 若不是实体则需要通过方法转Map, 错会抛出到BindException. @Validated({YDParam.Retrieve_Condition.class}) YDParam param
+ * -
+ * 使用@RestController后,请求方法无需再使用@RequestBody,@RequestParam,直接可对入参进行修饰,效果类似解构,除了正常获取HttpServletRequest外,相关参数自动处理到注解内
+ * RESTFul 风格接口, 参数获取方式均相同, GET 没有 body, @PathVariable 获取 url 占位符, RequestParam 获取 url 参数, @RequestBody 获取 body 数据
+ * -
+ * 关于入参为JSONString类型: body内的json需要传入字符串, 若为对象会解析报错. 若是formData, 传入对象会自动转为字符串, 不会解析错误, 无需转为JSONString
+ * 注解@JsonInclude(JsonInclude.Include.NON_NULL):类注解过滤null字段,包含入参和返回值【参数类搭配 @Data,才可以实例化返回值以及ToString输出】
+ */
+@Slf4j
+@RestControllerAdvice(annotations = RestController.class)
+public class CatchException<T> {
+
+//    @Autowired
+//    private ExceptionNotice notice;
+
+    /**
+     * 通用错误类抛出
+     */
+    @ExceptionHandler(McException.class)
+    public McR McException(McException e) {
+        log.error(e.getMessage(), e);  // 记录错误日志
+        return McR.R(e.isSuccess(), e.getCode(), e.getMessage(), null, e.getSource());  // IGNORE_EXECUTE 为成功
+    }
+
+    /**************** validated不合法 ****************/
+
+    /**
+     * @validated 验证入参对象 @Validated({YDParam.Retrieve_Condition.class}) YDParam param
+     * -
+     * 如入参是formData,不能使用@RequestBody,参数会自动解析到实体; 若不是实体通过方法转Map .报错会抛出到BindException。@Validated({YDParam.Retrieve_Condition.class}) YDParam param
+     */
+    @ExceptionHandler(value = BindException.class)
+    public McR BindException(BindException e) {
+        List errorParam = new ArrayList();
+        e.getFieldErrors().forEach(fieldError -> {
+            errorParam.add(fieldError.getField() + ": " + fieldError.getDefaultMessage());
+        });
+        log.error(e.getMessage(), e);  // 记录错误日志
+        return McR.errorParam("formData参数 -> " + String.join(", ", errorParam));
+    }
+
+    /**
+     * @Validated 关于在Service上使用校验,
+     * -
+     * 首先需要impl类上添加@Validated [和Controller一致]
+     * 建议注解到方法声明上, 抛出到ConstraintViolationException. 若校验注解到方法实现上, 则错误抛出到 ConstraintDeclarationException, 没有友好的提示
+     */
+    @ExceptionHandler(ConstraintDeclarationException.class)
+    public McR ConstraintDeclarationException(ConstraintDeclarationException e) {
+        log.error(e.getMessage(), e);  // 记录错误日志
+        return McR.errorParam("param参数 -> " + e.getMessage());
+    }
+
+    /**
+     * @validated 验证入参字段 @NotNull(message = "cur不能为空") String cur
+     * -
+     * 若入参是Body,需要使用@RequestBody解析到实体内,校验错误抛出到MethodArgumentNotValidException。@RequestBody @Validated({YDParam.Retrieve_Condition.class}) YDParam param
+     * 如入参是formData,不能使用@RequestBody,参数会自动解析到实体; 若不是实体通过方法转Map .报错会抛出到BindException。@Validated({YDParam.Retrieve_Condition.class}) YDParam param
+     * 关于入参为JSONString类型: body内的json需要传入字符串, 若为对象会解析报错. 若是formData, 传入对象会自动转为字符串, 不会解析错误, 无需转为JSONString
+     */
+    @ExceptionHandler(ConstraintViolationException.class)
+    public McR ConstraintViolationException(ConstraintViolationException e) {
+        List errorParam = new ArrayList();
+        e.getConstraintViolations().forEach(fieldError -> {
+            errorParam.add(fieldError.getPropertyPath() + ": " + fieldError.getMessage());
+        });
+        log.error(e.getMessage(), e);  // 记录错误日志
+        return McR.errorParam("param参数 -> " + String.join(", ", errorParam));
+    }
+
+    /**
+     * @validated 验证入参对象 @RequestBody @Validated({YDParam.Retrieve_Condition.class}) YDParam param
+     * -
+     * 若入参是Body,需要使用@RequestBody解析到实体内,校验错误抛出到MethodArgumentNotValidException。@RequestBody @Validated({YDParam.Retrieve_Condition.class}) YDParam param
+     */
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public McR MethodArgumentNotValidException(MethodArgumentNotValidException e) {
+        List errorParam = new ArrayList();
+        e.getBindingResult().getAllErrors().forEach(err -> {
+            FieldError fieldError = (FieldError) err;
+            errorParam.add(fieldError.getField() + ": " + fieldError.getDefaultMessage());
+        });
+        log.error(e.getMessage(), e);  // 记录错误日志
+        return McR.errorParam("body参数 -> " + String.join(", ", errorParam));
+    }
+
+    /**************** 请求参数异常 ****************/
+
+    /**
+     * @RequestParam默认是required 验证入参字段 @RequestParam String cur
+     * -
+     * 参数@RequestParam,可以配置默认值,指定name,指定name后可以设置是否必填。若是要获取所有(@RequestParam MultiValueMap<String, String> param
+     */
+    @ExceptionHandler(MissingServletRequestParameterException.class)
+    public McR MissingServletRequestParameterException(MissingServletRequestParameterException e) {
+        log.error(e.getMessage(), e);  // 记录错误日志
+        return McR.errorParam("param参数 -> " + e.getMessage());
+    }
+
+    /**
+     * @RequestParam 参数类型解析异常
+     */
+    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
+    public McR MethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
+        log.error(e.getMessage(), e);  // 记录错误日志
+        return McR.errorParam("param参数 ->  " + e.getName() + "不合法: " + e.getMessage());
+    }
+
+    /**
+     * @RequestBody 序列化字段为非Sting类型
+     * -
+     * 关于入参为JSONString类型: body内的json需要传入字符串, 若为对象会解析报错. 若是formData, 传入对象会自动转为字符串, 不会解析错误, 无需转为JSONString
+     */
+    @ExceptionHandler(HttpMessageNotReadableException.class)
+    public McR HttpMessageNotReadableException(HttpMessageNotReadableException e) {
+        log.error(e.getMessage(), e);  // 记录错误日志
+        if (e.getMessage().contains("Required request body is missing")) {
+            return McR.errorParam("请求体参数不能为空");
+        }
+        return McR.errorParam("请求体参数格式不合法");
+    }
+
+    /**
+     * Content-Type不合法
+     */
+    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
+    public McR HttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
+        log.error(e.getMessage(), e);  // 记录错误日志
+        return McR.errorParam("Content-Type不合法: " + e.getMessage());
+    }
+
+    /**************** 网络请求异常 ****************/
+
+    /**
+     * http请求返回json解析异常
+     */
+    @ExceptionHandler(JSONException.class)
+    public McR JSONException(JSONException e) {
+        log.error(e.getMessage(), e);  // 记录错误日志
+        return McR.errorParam("返回JSON解析异常: " + e.getMessage());
+    }
+
+    /**************** 数据类型异常 ****************/
+
+    /**
+     * BigDecimal 非数值型字符串, 空字符串取值异常
+     */
+    @ExceptionHandler(NumberFormatException.class)
+    public McR NumberFormatException(NumberFormatException e) {
+        log.error(e.getMessage(), e);  // 记录错误日志
+        return McR.errorParam(e.getMessage() + ": 非数值型字符串, 空字符串取值异常");
+    }
+
+    /**
+     * 反射未匹配到路径
+     */
+    @ExceptionHandler(ClassNotFoundException.class)
+    public McR ClassNotFoundException(ClassNotFoundException e) {
+        log.error(e.getMessage(), e);  // 记录错误日志
+        return McR.errorParam("反射未匹配到路径: " + e.getMessage());
+    }
+
+    /**
+     * 系统错误抛出
+     * -
+     * NOTE: 空指针判定, 日志目前会记录在warn内, 不输出到error内, 做一层包装返回 (空指针message为null)
+     */
+    @ExceptionHandler(Exception.class)
+    public McR Exception(Exception e) {
+        log.error(e.getMessage(), e);       // 记录错误日志
+//        notice.noticeErrorByDingtalk(e);    // 上报错误日志
+        if (e instanceof NullPointerException) {
+            return McR.errorNullPointer();
+        }
+        return McR.errorUnknown(e.getMessage());
+    }
+}

+ 53 - 0
mjava/src/main/java/com/malk/Filter/ExceptionNotice.java

@@ -0,0 +1,53 @@
+//package com.mcli.Filter;
+//
+//import cn.hutool.core.util.ObjectUtil;
+//import com.alibaba.fastjson.JSONObject;
+//import com.mcli.com.mcli.mcli.utils.UtilDateTime;
+//import com.mcli.service.common.McConf;
+//import com.mcli.service.common.McException;
+//import com.mcli.service.dingtalk.DDConf;
+//import lombok.extern.slf4j.Slf4j;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.stereotype.Component;
+//
+//import java.util.Date;
+//
+///**
+// * 报错消息: 发送钉钉工作通知
+// */
+//@Slf4j
+//@Component
+//public class ExceptionNotice {
+//
+//    @Autowired
+//    private DDClient ddClient;
+//
+//    @Autowired
+//    private DDConf ddConf;
+//
+//    @Autowired
+//    private McConf mcConf;
+//
+//    /**
+//     * 上报错误日志 [未知错误]
+//     */
+//    public void noticeErrorByDingtalk(Exception e) {
+//        // 通知人为空为空则忽略
+//        if (ObjectUtil.isNull(mcConf.getEngineers()) || mcConf.getEngineers().isEmpty()) {
+//            return;
+//        }
+//        String content = e.getMessage();
+//        if (e instanceof McException) {
+//            McException mcE = (McException) e;
+//            content = mcE.toString();
+//        }
+//        log.warn("上报错误日志, {}, {}", mcConf.getEngineers(), content);
+//        content += " --> " + UtilDateTime.formatDateTime(new Date());
+//        JSONObject message = new JSONObject();
+//        message.put("msgtype", "text");
+//        JSONObject info = new JSONObject();
+//        info.put("content", content);
+//        message.put("text", info);
+//        ddClient.sendCorpConversationMessage(ddConf.getAgentId(), mcConf.getEngineers(), null, false, message);
+//    }
+//}

+ 32 - 0
mjava/src/main/java/com/malk/Filter/RequestFilter.java

@@ -0,0 +1,32 @@
+package com.malk.Filter;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.*;
+import java.io.IOException;
+
+@Component
+public class RequestFilter implements Filter {
+
+    // 指定类输出日志到指定文件夹
+    private static final Logger logger = LoggerFactory.getLogger("point");
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+        logger.info("过滤器 ▷ 初始化");
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        logger.trace("过滤器 ▷ 开始执行");
+        chain.doFilter(request, response);
+        logger.trace("过滤器 ▷ 执行结束");
+    }
+
+    @Override
+    public void destroy() {
+        logger.info("过滤器 ▷ 销毁");
+    }
+}

+ 41 - 0
mjava/src/main/java/com/malk/Filter/RequestInterceptor.java

@@ -0,0 +1,41 @@
+package com.malk.Filter;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 请求拦截器: 继承 HandlerInterceptor 或实现 HandlerInterceptor
+ */
+@Component
+public class RequestInterceptor extends HandlerInterceptorAdapter {
+
+    // 指定类输出日志到指定文件夹
+    private static final Logger logger = LoggerFactory.getLogger("point");
+
+    // 请求拦截
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        logger.info("拦截器 ▷ 收到请求: {}", request.getServletPath());
+        return super.preHandle(request, response, handler);
+    }
+
+    // 视图渲染
+    @Override
+    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
+        logger.trace("拦截器 ▷ 视图渲染");
+        super.postHandle(request, response, handler, modelAndView);
+    }
+
+    // 数据返回
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+        logger.trace("拦截器 ▷ 数据返回");
+        super.afterCompletion(request, response, handler, ex);
+    }
+}

+ 29 - 0
mjava/src/main/java/com/malk/base/BaseDao.java

@@ -0,0 +1,29 @@
+package com.malk.base;
+
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+/**
+ * @EntityListeners 且需要在启动类添加 @EnableJpaAuditing 注解, 即可在字段上添加 @CreatedDate & @LastModifiedDate 实现 [Date 类型数据 - 自动插入创建 & 更新时间]
+ * -
+ * 项目绑定数据库后,进行分配。即可消除@Table、 在 idea 下不能匹配到信息的报错提示
+ * @Table指定表【下划线和小驼峰都可】, 若使用驼峰则依然会有报错提示. 若类名从驼峰转为下划线和表名相同则可不需要注解
+ * -
+ * 自定义查询
+ * @Query 当设置nativeQuery=true即可以使用原生SQL进行查询, 默认为false, 使用JPQL语法 [JPQL不支持insert语法]
+ * - 索引参数: 索引值从1开始,查询中"?X"个数需要与方法定义的参数个数相一致,并且顺序也要一致
+ * - 命名参数: 可以定义好参数名,赋值时使用@Param("参数名"), 而不用管顺序. 对入参使用 @Param("email") 修饰, @Query内使用 :email 进行取值
+ * - 关于返回值: update 语法, 返回值为 void. select 语法, 返回单个可用集合接收; 若返回多个用对象接收就会异常
+ * @Modifying注解 编写JPQL实现DELETE和UPDATE操作的时候必须加上@modifying注解,以通知Spring Data 这是一个DELETE或UPDATE操作
+ * -
+ * 事务管理 @Transactional注解,可以修饰类或方法
+ * - 配置 jpa.database-platform: org.hibernate.dialect.MySQL57Dialect, JPA建表的默认引擎修改为:InNoDB
+ * - 在启动类添加 @EnableTransactionManagement 注解, 开启事务支持后,然后在访问数据库的Service方法上添加注解 @Transactional 即可 [Service指dao, 或调用dao的地方]
+ * -
+ * 动态匹配, 注解于类
+ * @DynamicInsert : 默认true,指定用于INSERT的 SQL 将会在运行时动态生成,并且只包含那些非空值字段。(如果是)
+ * @DynamicUpdate : 默认true, 指定用于UPDATE 的SQL将会在运行时动态生成,并且只更新那些改变过的字段
+ */
+public interface BaseDao extends JpaRepository<BasePo, Long> {
+
+}

+ 112 - 0
mjava/src/main/java/com/malk/base/BaseDto.java

@@ -0,0 +1,112 @@
+package com.malk.base;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.SneakyThrows;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.BeanWrapper;
+import org.springframework.beans.BeanWrapperImpl;
+
+import java.beans.PropertyDescriptor;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 基础对象
+ *
+ * @JsonInclude(JsonInclude.Include.NON_NULL):类注解过滤null字段,包含入参和返回值【参数类搭配 @Data,才可以实例化返回值以及ToString输出】
+ * -
+ * lombok
+ * @Data : 注在类上,提供类的get、set、equals、hashCode、canEqual、toString方法
+ * @AllArgsConstructor : 注在类上,提供类的全参构造
+ * @NoArgsConstructor : 注在类上,提供类的无参构造
+ * @Setter : 注在属性上,提供 set 方法
+ * @Getter : 注在属性上,提供 get 方法
+ * @EqualsAndHashCode : 注在类上,提供对应的 equals 和 hashCode 方法
+ * @Log4j/@Slf4j : 注在类上,提供对应的 Logger 对象,变量名为 log
+ * @Builder:为类生成相对略微复杂的构建器API。来初始化实例对象::类名.属性(值).属性(值).build()
+ * @Singular:在使用@Singular注释注释一个集合字段(使用@Builder注释类),lombok会将该构建器节点视为一个集合,并生成两个adder方法而不是setter方法::点一次集合增加一个元素
+ * @Builder.Default:在类中id和insertTime上都添加注解@Builder.Default,当在使用这个实体对象时,就不需要在为这两个字段进行初始化值
+ */
+@Data
+@NoArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public abstract class BaseDto {
+
+    /**
+     * 对象拷贝: 若是复制一个对象, 建议使用 cloneParam 避免性能问题
+     */
+    @Deprecated
+    @SneakyThrows
+    public BaseDto copyParam() {
+        BaseDto dto = this.getClass().newInstance();
+        BeanUtils.copyProperties(this, dto);
+        return dto;
+    }
+
+    /**
+     * * todo: 4.11 继承Serializable后执行深拷贝, 不能类型转换, 不继承Serializable则返回
+     * 对象拷贝: 复制一个新的对象, 避免条件被修改, 尤其并发下分页混乱情况
+     */
+    public BaseDto cloneParam() {
+        return ObjectUtil.clone(this);
+    }
+
+    /**
+     * 对象属性合并: jda之save接口会以传入数据为准,若传入为空或不传入,更新会置空。目前解决办法两种,通过注解实现JPQL/SQL,或者查询出数据,将未传入字段属性拷贝后再更新【性能消耗】
+     */
+    public void mergeParam(BaseDto modifyDo) {
+        BeanUtils.copyProperties(this, modifyDo, getNotNullPropertyNames(modifyDo));
+    }
+
+    // 忽略有值的字段
+    private static String[] getNotNullPropertyNames(Object target) {
+        final BeanWrapper src = new BeanWrapperImpl(target);
+        PropertyDescriptor[] pds = src.getPropertyDescriptors();
+        Set<String> emptyNames = new HashSet();
+        for (PropertyDescriptor pd : pds) {
+            Object srcValue = src.getPropertyValue(pd.getName());
+            if (srcValue != null) {
+                // 此处判断可根据需求修改, 目前过滤不为null
+                emptyNames.add(pd.getName());
+            }
+        }
+        String[] result = new String[emptyNames.size()];
+        return emptyNames.toArray(result);
+    }
+
+    /**
+     * 传入映射的Map, 将实体属性和Map的key转换, 返回Map
+     */
+    public Map convertEntity(Map<String, String> reflect) {
+        Map map = JSON.parseObject(JSON.toJSONString(this, SerializerFeature.WriteNullStringAsEmpty), Map.class);
+        Map<String, String> formData = new HashMap();
+        for (String key : reflect.keySet()) {
+            String content = String.valueOf(map.get(key));
+            // json序列化已经将空字符串过滤, 若转换还有null字符串, 可能是key为null或SerializerFeature未指定到类型, 如Date
+            if (StringUtils.isNotBlank(content) && !content.equals("null")) formData.put(reflect.get(key), content);
+        }
+        return formData;
+    }
+
+
+    /**
+     * Map时间格式化, 直接从数据库取值后Map会有市区差, 方法1见BasePo, @Temporal & @JsonFormat 注解
+     * -
+     * [单独时间格式化 [废弃]]
+     * * JSON.parseArray(JSON.toJSONString(data), Map.class).stream().map(item -> {
+     * *     item.put("tStoreInTime", UtilDateTime.formatDateTime(new Date(UtilMap.getLong(item, "tStoreInTime"))));
+     * *     return item;
+     * * });
+     */
+    public static final Object jsonFormatDateTime(Object data) {
+        return JSON.parse(JSON.toJSONString(data, SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteDateUseDateFormat));
+    }
+}

+ 55 - 0
mjava/src/main/java/com/malk/base/BasePo.java

@@ -0,0 +1,55 @@
+package com.malk.base;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.annotation.LastModifiedDate;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+
+import javax.persistence.*;
+import java.util.Date;
+
+/**
+ * 实体基类
+ *
+ * @MappedSuperclass 作为公共属性场景. 类注解, 标注后该类将不是一个完整的实体类,也不会映射到数据库表,但其的属性都将映射到其子类的数据库字段中
+ * @Cloumn java为小驼峰命名,数据库为下划线命名,若有差异,通过name指定表字段. 若相同则可不用指定name [直接设置字段值即可,无效额外注解]
+ * -
+ * 功能使用自带
+ * -
+ * @JsonFormat(pattern = "yyyy-MM-dd HH:smm:ss", timezone = "GMT+8"),数据库 Date 类型序列化后转到前台的指定格式【jackjson】
+ * @DateTimeFormat @DateTimeFormat(pattern = "yyyy-MM-dd"),使用和@jsonFormat差不多,前台传入的按照指定格式自动转为Date储存
+ * @JsonIgnoreProperties 类注解,作用是json序列化时将bean中的一些属性忽略掉,序列化和反序列化都受影响。支持多个属性 [也用于双向绑定解决循环序列化]
+ * @JsonIgnore 此注解用于属性或者方法上(最好是属性上),作用和上面的@JsonIgnoreProperties一样,屏蔽该字段在序列化和数据发挥会自动忽略
+ * @JsonGetter 用于序列化, 还可指定返回属性名,@JsonSetter 用于反序列化。注意@JsonGetter比@JsonProperty的优先级高,同时存在属性忽略会失效
+ * @Transient ORM框架将忽略该属性,不入库。如果一个属性并非数据库表的字段映射,就务必将其标示为@Transient,否则ORM框架默认其注解为@Basic
+ * @Temporal & @JsonFormat: fixme: 指定时区, new Date 会默认当前系统时区, 不添加 json 时区注解, 会出现序列化后的对象时间不是 GMT 时区 [方法2见BaseDto, jsonFormatDateTime]
+ */
+@MappedSuperclass
+@Data
+@NoArgsConstructor
+@EntityListeners(AuditingEntityListener.class)
+public abstract class BasePo extends BaseDto {
+
+    // 若是实体若不直接在 com.mcli 下, 可声明继承id, 避免编辑器提示 [不加也不影响编译以及运行]
+    @ExcelIgnore
+    @Id
+    @JsonIgnore
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    public Long id;
+
+    @ExcelIgnore
+    @CreatedDate
+    @Temporal(TemporalType.TIMESTAMP)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createTime;
+
+    @ExcelIgnore
+    @LastModifiedDate
+    @Temporal(TemporalType.TIMESTAMP)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updateTime;
+}

+ 9 - 0
mjava/src/main/java/com/malk/base/BaseRepository.java

@@ -0,0 +1,9 @@
+package com.malk.base;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.querydsl.QuerydslPredicateExecutor;
+
+public interface BaseRepository extends JpaRepository<BasePo, Long>, QuerydslPredicateExecutor<BasePo> {
+
+}
+

+ 73 - 0
mjava/src/main/java/com/malk/base/JpaMap.java

@@ -0,0 +1,73 @@
+package com.malk.base;
+
+
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.data.jpa.domain.Specification;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 查询map [不指定表名]
+ * 通过Map实现, 无需定义实体, 主键设置Long即可: public interface HSViewDao extends CrudRepository<JpaMap, Long>
+ * -
+ * 使用native查询,返回Map. 直接查询表名 + 列名 + 条件, 可不做实体映射场景
+ * 时间的时区处理: 方法1见BasePo, @Temporal & @JsonFormat 注解; 方法2见BaseDto, jsonFormatDateTime
+ * 空条件jpa实现, 查询全部数据, 通过 like LTRIM('%' + ?x + '%') 进行实现 [dsl适用于复杂场景, Specification谓词需要依赖于实体]
+ * -
+ * 多条件查询
+ * 1. sql + if [SqlServer不支持if条件]
+ * * @Query(value = "select * from vwpbCommonDataOrderPlan where if (?1 is not null, dPlanDate >= ?1, 1=1) and if (?2 is not null, dPlanDate <= ?2, 1=1) and sOrderNo like LTRIM('%' + ?3 + '%')", nativeQuery = true)
+ * * Page<Map> queryOrderPlan(Date start, Date end, String sOrderNo, Pageable pageable);
+ * 2. Specification, 谓词需要依赖于实体 [参考示例, 如下 test 方法实现]
+ */
+
+@Entity
+public class JpaMap {
+
+    @Id
+    private String id;
+
+    /**
+     * 时间的时区处理
+     */
+    public static final List<Map> jsonFormatDateTime(List<Map> data) {
+        return JSON.parseArray(JSON.toJSONString(data, SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteDateUseDateFormat), Map.class);
+    }
+
+    // 示例: Specification, 谓词需要依赖于实体
+    private void test() {
+        //Page<Map> findAll (Specification < T > spec, Pageable pageable);
+
+        String sOrderNo = "";
+        Date sTime = null;
+        Date eTime = null;
+
+        Specification spec = (root, criteriaQuery, criteriaBuilder) -> {
+            List<javax.persistence.criteria.Predicate> predicates = new ArrayList<>();
+            if (StringUtils.isNotBlank(sOrderNo)) {
+                javax.persistence.criteria.Predicate predicate = criteriaBuilder.like(root.get("sOrderNo"), "%" + sOrderNo + "%");
+                predicates.add(predicate);
+            }
+
+            if (ObjectUtil.isNotNull(sTime)) {
+//            javax.persistence.criteria.Predicate predicate = criteriaBuilder.greaterThanOrEqualTo(root.get("dPlanDate").as(String.class), "2023-06-03 00:00:00");
+                javax.persistence.criteria.Predicate predicate = criteriaBuilder.greaterThanOrEqualTo(root.get("dPlanDate"), sTime);
+                predicates.add(predicate);
+            }
+
+            if (ObjectUtil.isNotNull(eTime)) {
+                javax.persistence.criteria.Predicate predicate = criteriaBuilder.lessThanOrEqualTo(root.get("dPlanDate"), eTime);
+                predicates.add(predicate);
+            }
+            return criteriaBuilder.and(predicates.toArray(new javax.persistence.criteria.Predicate[predicates.size()]));
+        };
+    }
+}

+ 35 - 0
mjava/src/main/java/com/malk/config/JpaConfiguration.java

@@ -0,0 +1,35 @@
+package com.malk.config;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+
+/**
+ * JPA [错误抛出与拦截详见CatchException, 多数据源配置参考DataSourceConfig]
+ * -
+ * 1. 关键字语法: save find, exists, count [单表操作 - 若数据库列和对象属性字段一致, 直接使用 jpa 自带查询匹配不到启动报错]
+ * 2. 自定义查询: @Query, 通过 nativeQuery 区分 jpql 和 sql 语法 [简单查询]
+ * 3. 表关联关系: @OneToMany, @ManyToOne, @ManyToMany, @OneToOne [耦合关联]
+ * 4. Specification: Predicate 与 CriteriaBuilder 组合 [谓词, 需要依赖于实体]
+ * 5. QueryDSL: 基于ORM框架以及SQL之上的一个通用的查询框架, 分页, 关联查询原生支持 [查询框架] (通过查询关联, 而不是如 @OneToMany 等建立表关联)
+ * 6. DSL: 项目在 compile 会执行 apt-maven-plugin 插件, 将 @Entity 注解类, 添加 Q 前缀, 存放到 target 下 generated-source 目录
+ * 7. 配置: 扫描基础路径, 涉及子项目也能注册到, 避免启动报错. 子项目 Boot 配置 @SpringBootApplication(scanBasePackages = {"com.mcli"})
+ * 8. 查询: 使用native,查询列不匹配实体属性,会报错The column name xxx is not valid,返回Map可解决 (Map是Jpa的TupleBackedMap, 通过try取值)
+ * 9. 单数据源切换: 在dao与entity均添加mutual作为公共模块, 单数据源下服务于JpaConfiguration, 若是多数据源与PrimaryConfig一起作为主数据源配置
+ * 10 主子项目, 在单数据源情况下, 扫描全部. [需要注意的是, 在多数据源下同名dao是可以通过指定数据源使用, 此时若开启单数据源启动报错, 会扫描全部]
+ */
+@ConditionalOnProperty(name = "spel.multiSource", havingValue = "false")
+@Configuration
+// 单数据源, 扫描子项目与主项目primary [子项目可以访问到主项目primary]
+@EnableJpaRepositories(basePackages = {"com.malk.*.repository.dao", "com.malk.repository.dao.primary"})
+@EntityScan(basePackages = {"com.malk.*.repository.entity", "com.malk.repository.entity.primary"})
+public class JpaConfiguration {
+
+    @Bean
+    PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor() {
+        return new PersistenceExceptionTranslationPostProcessor();
+    }
+}

+ 52 - 0
mjava/src/main/java/com/malk/config/WebConfiguration.java

@@ -0,0 +1,52 @@
+package com.malk.config;
+
+import com.malk.Filter.RequestInterceptor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class WebConfiguration implements WebMvcConfigurer {
+
+    // 指定类输出日志到指定文件夹
+    private static final Logger logger = LoggerFactory.getLogger("point");
+
+    // 请求拦截
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        logger.info("拦截器 ▷ 初始化");
+        registry.addInterceptor(new RequestInterceptor())
+                .addPathPatterns("/**")
+                .excludePathPatterns("/assets/**", "/templates/**");
+    }
+
+    // 跨域支持: 端口不匹配也会报跨域, 若是单个控制器开放, 可使用 @CrossOrigin 注解
+    @Override
+    public void addCorsMappings(CorsRegistry registry) {
+        logger.info("拦截器 ▷ 开启CORS");
+        registry.addMapping("/**")  // 添加映射路径
+                .allowedOrigins("*")  // 放行哪些原始
+                .allowCredentials(true)  // 是否发送Cookie信息
+                .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH")  // 放行哪些原始域(请求方式)
+                .allowedHeaders("*")  // 放行哪些原始域(头部信息)
+                .allowCredentials(true);  // 放行证书
+    }
+
+    /**
+     * 静态资源映射
+     * -
+     * 默认的静态资源路径为: classpath:/META-INF/resources/, classpath:/resources/,classpath:/static/, classpath:/public [默认路径不会进拦截器]
+     * 读取的是target内容, 访问路径 assets: http://localhost:9001/dev/assets/logo/logo-text.png [自定义拦截器添加路径排除: excludePathPatterns]
+     * 当在SpringBoot项目内添加网页资源时,在windows服务器,需要C:\Windows\System32下添加tomcat-native-1.2.14-win32-bin.zip内x64下两个文件, 重启项目
+     */
+    @Override
+    public void addResourceHandlers(ResourceHandlerRegistry registry) {
+        registry.addResourceHandler("/mjs/**").addResourceLocations("classpath:/static/mjs/");
+        registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/assets/");
+        registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/");
+    }
+}

+ 41 - 0
mjava/src/main/java/com/malk/config/mutilSource/DataSourceConfig.java

@@ -0,0 +1,41 @@
+package com.malk.config.mutilSource;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+
+import javax.sql.DataSource;
+
+/**
+ * 数据源配置
+ * -
+ * AOP多数据源切换:
+ * - 1. pom文件添加spring-boot-starter-jdbc依赖
+ * - 2. yml配置多主从数据库, 数据库地址从url修改为jdbc-url
+ * - 3. 通过spel.multiSource控制是否多数据源, 屏蔽JpaConfiguration, 加载DataSourceConfig
+ * 不同数据源存在同名表:
+ * - 1. 实体只需要在dao层区分即可, 作用域下实体包路径是不同的
+ * - 2. 同名的dao通过@Repository("slaveMcTableDao")定义区分; 在Autowired引用时候属性上添加@Qualifier("slaveMcTableDao")注解
+ * -
+ * 单数据源切换: 在dao与entity均添加mutual作为公共模块, 单数据源下服务于JpaConfiguration, 若是多数据源与PrimaryConfig一起作为主数据源配置
+ */
+@ConditionalOnProperty(name = "spel.multiSource", havingValue = "true")
+@Configuration
+public class DataSourceConfig {
+
+    @Bean(name = "primaryDataSource")
+    @ConfigurationProperties(prefix = "spring.datasource.primary")
+    @Primary
+    public DataSource primaryDataSource() {
+        return DataSourceBuilder.create().build();
+    }
+
+    @Bean(name = "slaveDataSource")
+    @ConfigurationProperties(prefix = "spring.datasource.slave")
+    public DataSource slaveDataSource() {
+        return DataSourceBuilder.create().build();
+    }
+}

+ 80 - 0
mjava/src/main/java/com/malk/config/mutilSource/PrimaryConfig.java

@@ -0,0 +1,80 @@
+package com.malk.config.mutilSource;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
+import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
+import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
+import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.orm.jpa.JpaTransactionManager;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+import javax.persistence.EntityManager;
+import javax.sql.DataSource;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * 主数据源配置,多数据源必须设置一个主数据源, 通过 @Primary 注解 [包含公共部分]
+ * -
+ * 主子项目, 在多数据源情况下, 子项目需要匹配主项目目录结构, 且符合命名规范. 配置对应扫描 EnableJpaRepositories / EntityScan 添加子项目路径
+ */
+@ConditionalOnProperty(name = "spel.multiSource", havingValue = "true")
+@Configuration
+@EnableTransactionManagement
+@EnableJpaRepositories(
+        entityManagerFactoryRef = "entityManagerFactoryPrimary", // 配置连接工厂 entityManagerFactory
+        transactionManagerRef = "transactionManagerPrimary", // 配置事物管理器  transactionManager
+        basePackages = {"com.malk.repository.dao.primary", "com.malk.*.repository.dao"}  // dao层配置主数据 & 公共所在目录 [子项目可以访问到主项目primary]
+)
+public class PrimaryConfig {
+
+    @Autowired
+    @Qualifier("primaryDataSource")  // 指定这是主数据源,为了和从(其他)数据源区别开,因为@Autowired不能导入名称相同的是bean
+    private DataSource dataSourcePrimary;
+
+    @Autowired
+    private JpaProperties jpaProperties;
+
+    @Autowired
+    private HibernateProperties hibernateProperties;
+
+    @Primary
+    @Bean("entityManagerPrimary")
+    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
+        return Objects.requireNonNull(entityManagerFactoryBean(builder).getObject()).createEntityManager();
+    }
+
+    @Primary
+    @Bean("entityManagerFactoryPrimary")
+    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder) {
+        return builder.dataSource(dataSourcePrimary)
+                .properties(getVendorProperties())
+                // 设置实体类所在目录: 包含主数据源与公共 [子项目可以访问到主项目primary]
+                .packages("com.malk.repository.entity.primary", "com.malk.*.repository.entity")
+                // 持久化单元名称,当存在多个EntityManagerFactory时,需要制定此名称
+                .persistenceUnit("primaryPersistenceUnit")
+                .build();
+    }
+
+    private Map<String, Object> getVendorProperties() {
+        return hibernateProperties.determineHibernateProperties(
+                jpaProperties.getProperties(),
+                new HibernateSettings()
+        );
+    }
+
+    @Primary
+    @Bean("transactionManagerPrimary")
+    public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
+        return new JpaTransactionManager(Objects.requireNonNull(entityManagerFactoryBean(builder).getObject()));
+    }
+}
+

+ 0 - 0
mjava/src/main/java/com/malk/config/mutilSource/SlaveConfig.java


Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.