唐tag vor 1 Jahr
Commit
f778f71967
58 geänderte Dateien mit 5216 neuen und 0 gelöschten Zeilen
  1. 34 0
      .gitignore
  2. 36 0
      logss/dataService.log
  3. 530 0
      pom.xml
  4. 24 0
      src/main/java/com/zswl/dataservicestarter/DataServiceStarterApplication.java
  5. 67 0
      src/main/java/com/zswl/dataservicestarter/components/DataRecord.java
  6. 29 0
      src/main/java/com/zswl/dataservicestarter/config/GlobalResponseAdvice.java
  7. 13 0
      src/main/java/com/zswl/dataservicestarter/config/JpaConfig.java
  8. 28 0
      src/main/java/com/zswl/dataservicestarter/config/JpaDataConfiguration.java
  9. 102 0
      src/main/java/com/zswl/dataservicestarter/config/MongoConfiguration.java
  10. 26 0
      src/main/java/com/zswl/dataservicestarter/config/PaginationConfiguration.java
  11. 11 0
      src/main/java/com/zswl/dataservicestarter/config/SwaggerConfig.java
  12. 73 0
      src/main/java/com/zswl/dataservicestarter/config/SwaggerProperties.java
  13. 19 0
      src/main/java/com/zswl/dataservicestarter/config/WebMvcConfig.java
  14. 18 0
      src/main/java/com/zswl/dataservicestarter/config/converts/BigDecimalToDecimal128Converter.java
  15. 20 0
      src/main/java/com/zswl/dataservicestarter/config/converts/Decimal128ToBigDecimalConverter.java
  16. 50 0
      src/main/java/com/zswl/dataservicestarter/controller/OauthController.java
  17. 34 0
      src/main/java/com/zswl/dataservicestarter/controller/TestController.java
  18. 17 0
      src/main/java/com/zswl/dataservicestarter/dao/AppInfoDao.java
  19. 12 0
      src/main/java/com/zswl/dataservicestarter/dao/MongoDao.java
  20. 9 0
      src/main/java/com/zswl/dataservicestarter/dao/UserDao.java
  21. 38 0
      src/main/java/com/zswl/dataservicestarter/domain/AppInfo.java
  22. 43 0
      src/main/java/com/zswl/dataservicestarter/domain/SuperEntity.java
  23. 20 0
      src/main/java/com/zswl/dataservicestarter/domain/User.java
  24. 37 0
      src/main/java/com/zswl/dataservicestarter/helper/BatchQueryHelper.java
  25. 273 0
      src/main/java/com/zswl/dataservicestarter/helper/DBHelper.java
  26. 181 0
      src/main/java/com/zswl/dataservicestarter/helper/MongoQueryLanguageHelper.java
  27. 30 0
      src/main/java/com/zswl/dataservicestarter/helper/MongoTemplateNearest.java
  28. 284 0
      src/main/java/com/zswl/dataservicestarter/helper/ReIndexHelper.java
  29. 103 0
      src/main/java/com/zswl/dataservicestarter/helper/jpa/TransactionHelper.java
  30. 32 0
      src/main/java/com/zswl/dataservicestarter/model/AppInfoModel.java
  31. 26 0
      src/main/java/com/zswl/dataservicestarter/model/QueryModel.java
  32. 18 0
      src/main/java/com/zswl/dataservicestarter/model/TokenModel.java
  33. 23 0
      src/main/java/com/zswl/dataservicestarter/model/params/TokenParam.java
  34. 51 0
      src/main/java/com/zswl/dataservicestarter/service/AppInfoService.java
  35. 105 0
      src/main/java/com/zswl/dataservicestarter/service/RedisService.java
  36. 40 0
      src/main/java/com/zswl/dataservicestarter/service/UserService.java
  37. 18 0
      src/main/java/com/zswl/dataservicestarter/type/AppState.java
  38. 23 0
      src/main/java/com/zswl/dataservicestarter/type/ResultState.java
  39. 17 0
      src/main/java/com/zswl/dataservicestarter/utils/AppInfoUtil.java
  40. 8 0
      src/main/java/com/zswl/dataservicestarter/utils/ConfigDict.java
  41. 719 0
      src/main/java/com/zswl/dataservicestarter/utils/DateUtils.java
  42. 19 0
      src/main/java/com/zswl/dataservicestarter/utils/ITree.java
  43. 45 0
      src/main/java/com/zswl/dataservicestarter/utils/SecurityUtil.java
  44. 148 0
      src/main/java/com/zswl/dataservicestarter/utils/TreeUtil.java
  45. 687 0
      src/main/java/com/zswl/dataservicestarter/utils/bean/BeanUtil.java
  46. 216 0
      src/main/java/com/zswl/dataservicestarter/utils/bean/EntityObjectUtil.java
  47. 19 0
      src/main/java/com/zswl/dataservicestarter/utils/exception/BusinessException.java
  48. 19 0
      src/main/java/com/zswl/dataservicestarter/utils/exception/ServiceException.java
  49. 21 0
      src/main/java/com/zswl/dataservicestarter/utils/exception/UnauthorizedException.java
  50. 36 0
      src/main/java/com/zswl/dataservicestarter/utils/os/SystemUtil.java
  51. 237 0
      src/main/java/com/zswl/dataservicestarter/utils/page/PageEntityUtil.java
  52. 36 0
      src/main/java/com/zswl/dataservicestarter/utils/path/PathUtil.java
  53. 108 0
      src/main/java/com/zswl/dataservicestarter/utils/result/ResultContent.java
  54. 204 0
      src/main/java/com/zswl/dataservicestarter/utils/text/CodeCommentUtil.java
  55. 68 0
      src/main/java/com/zswl/dataservicestarter/utils/text/TextUtil.java
  56. 28 0
      src/main/resources/application-dev.yml
  57. 71 0
      src/main/resources/application.yml
  58. 13 0
      src/test/java/com/zswl/dataservicestarter/DataServiceStarterApplicationTests.java

+ 34 - 0
.gitignore

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

Datei-Diff unterdrückt, da er zu groß ist
+ 36 - 0
logss/dataService.log


+ 530 - 0
pom.xml

@@ -0,0 +1,530 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.zswl.dataService</groupId>
+    <artifactId>DataServiceStarter</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>DataServiceStarter</name>
+    <description>DataServiceStarter</description>
+    <properties>
+        <java.version>11</java.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <spring-boot.version>2.7.6</spring-boot.version>
+
+        <!--spring cloud 版本-->
+        <spring-mvc.version>5.3.26</spring-mvc.version>
+
+        <!-- auth2.0-->
+        <spring-security-core.version>5.8.2</spring-security-core.version>
+        <spring-security-oauth2.version>2.5.2.RELEASE</spring-security-oauth2.version>
+        <!--        <spring-security-oauth2.version>2.3.8.RELEASE</spring-security-oauth2.version>-->
+
+        <spring-boot-starter-security.version>3.0.5</spring-boot-starter-security.version>
+        <spring-security-oauth2-authorization-server.version>0.1.1</spring-security-oauth2-authorization-server.version>
+
+        <!-- jdk11 2021.0.x -->
+        <spring-cloud-dependencies.version>2021.0.7</spring-cloud-dependencies.version>
+        <spring-cloud.version>3.1.6</spring-cloud.version>
+        <spring-cloud-starter-stream.version>3.2.7</spring-cloud-starter-stream.version>
+        <spring-cloud-bus.version>3.1.2</spring-cloud-bus.version>
+        <spring-cloud-starter-config.version>3.1.6</spring-cloud-starter-config.version>
+        <spring-cloud-starter-consul-discovery.version>3.1.2</spring-cloud-starter-consul-discovery.version>
+
+        <spring-boot.version>2.7.12</spring-boot.version>
+        <spring-boot-starter-data-jpa.version>2.7.12</spring-boot-starter-data-jpa.version>
+
+        <spring-data-jpa.version>2.7.12</spring-data-jpa.version>
+
+        <spring-integration-core.version>5.5.17</spring-integration-core.version>
+
+        <!-- 依赖组件 -->
+        <!--        <ribbon.version>2.7.18.RELEASE</ribbon.version>-->
+        <!--        <netflix.version>3.0.3</netflix.version>-->
+        <netflix-zuul.version>2.2.10.RELEASE</netflix-zuul.version>
+        <netflix-hystrix.version>2.2.10.RELEASE</netflix-hystrix.version>
+        <netflix-ribbon.version>2.2.10.RELEASE</netflix-ribbon.version>
+
+
+        <feign.version>11.9</feign.version>
+
+
+        <!-- 其他工具版本 -->
+        <!--        <groovy.version>3.0.16</groovy.version> &lt;!&ndash; 3.0.10 拷贝方法注解会出现重复 &ndash;&gt;-->
+        <!--        <groovy.version>4.0.10</groovy.version>-->
+
+        <groovy.version>3.0.9</groovy.version>
+        <ehcache.version>3.10.8</ehcache.version>
+        <caffeine.version>3.1.5</caffeine.version>
+        <lombok.version>1.18.26</lombok.version>
+        <httpclient.version>4.5.14</httpclient.version>
+        <commons-lang3.version>3.12.0</commons-lang3.version>
+        <junit.version>4.13.2</junit.version>
+        <javax.servlet.jsp-api.version>2.3.3</javax.servlet.jsp-api.version>
+        <servlets-ssi.version>5.0.16</servlets-ssi.version>
+        <javax.servlet-api.version>4.0.1</javax.servlet-api.version>
+        <commons-fileupload.version>1.5</commons-fileupload.version>
+        <jstl.version>1.2</jstl.version>
+        <gson.version>2.10.1</gson.version>
+        <jackson.version>2.14.2</jackson.version>
+        <commons-beanutils.version>1.9.4</commons-beanutils.version>
+        <hibernate.version>6.1.7.Final</hibernate.version>
+        <jaxb-api.version>2.3.1</jaxb-api.version>
+        <javax.annotation-api.version>1.3.2</javax.annotation-api.version>
+
+
+        <!--链路追踪-->
+        <zipkin.version>2.2.8.RELEASE</zipkin.version>
+
+
+        <!-- 插件 -->
+        <maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
+
+        <groovy-eclipse-compiler.version>3.8.0</groovy-eclipse-compiler.version>
+        <!--        <groovy-eclipse-batch.version>4.0.11-02</groovy-eclipse-batch.version>-->
+
+        <!--        <groovy-eclipse-compiler.version>3.7.0</groovy-eclipse-compiler.version>-->
+        <groovy-eclipse-batch.version>3.0.8-01</groovy-eclipse-batch.version>
+
+
+        <maven-war-plugin.version>3.3.2</maven-war-plugin.version>
+        <maven-surefire-plugin.version>3.0.0</maven-surefire-plugin.version>
+
+        <mongo-java-driver.version>3.12.13</mongo-java-driver.version>
+        <mongodb-driver-sync.version>4.9.1</mongodb-driver-sync.version>
+        <spring-data-mongodb.version>3.4.12</spring-data-mongodb.version>
+
+        <Hsqldb.version>2.7.0</Hsqldb.version>
+        <JodaTime.version>2.11.1</JodaTime.version>
+        <mybatis.version>2.2.2</mybatis.version>
+    </properties>
+    <dependencies>
+
+        <!-- spring boot -->
+        <!--tomcat运行环境-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-tomcat</artifactId>
+            <version>${spring-boot.version}</version>
+        </dependency>
+        <!--自带web容器-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <version>${spring-boot.version}</version>
+        </dependency>
+        <!--日志-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-logging</artifactId>
+            <version>${spring-boot.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <version>${spring-boot.version}</version>
+            <optional>true</optional>
+        </dependency>
+        <!--测试-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <version>${spring-boot.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- gson -->
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <version>${gson.version}</version>
+        </dependency>
+
+        <!--Spring mvc-->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-orm</artifactId>
+            <version>${spring-mvc.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-core</artifactId>
+            <version>${spring-mvc.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-aop</artifactId>
+            <version>${spring-mvc.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-tx</artifactId>
+            <version>${spring-mvc.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+            <version>${spring-mvc.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context-support</artifactId>
+            <version>${spring-mvc.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-webmvc</artifactId>
+            <version>${spring-mvc.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-aspects</artifactId>
+            <version>${spring-mvc.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-beans</artifactId>
+            <version>${spring-mvc.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-expression</artifactId>
+            <version>${spring-mvc.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-oxm</artifactId>
+            <version>${spring-mvc.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-messaging</artifactId>
+            <version>${spring-mvc.version}</version>
+        </dependency>
+        <!--<dependency>-->
+        <!--<groupId>org.springframework</groupId>-->
+        <!--<artifactId>spring-expression</artifactId>-->
+        <!--<version>${spring-mvc.version}</version>-->
+        <!--</dependency>-->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-web</artifactId>
+            <version>${spring-mvc.version}</version>
+        </dependency>
+
+
+        <!-- 依赖包 -->
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>jstl</artifactId>
+            <version>${jstl.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-fileupload</groupId>
+            <artifactId>commons-fileupload</artifactId>
+            <version>${commons-fileupload.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>${javax.servlet-api.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>tomcat</groupId>
+            <artifactId>servlets-ssi</artifactId>
+            <version>${servlets-ssi.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.servlet.jsp</groupId>
+            <artifactId>javax.servlet.jsp-api</artifactId>
+            <version>${javax.servlet.jsp-api.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>${junit.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>${commons-lang3.version}</version>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>${httpclient.version}</version>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.codehaus.groovy</groupId>
+            <artifactId>groovy-all</artifactId>
+            <version>3.0.9</version>
+            <type>pom</type>
+        </dependency>
+
+        <!--        <dependency>-->
+        <!--            <groupId>org.apache.groovy</groupId>-->
+        <!--            <artifactId>groovy-all</artifactId>-->
+        <!--            <version>4.0.10</version>-->
+        <!--            <type>pom</type>-->
+        <!--        </dependency>-->
+
+
+        <!-- Get Set 需要IDE 安装 lombok plugin -->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>${lombok.version}</version>
+        </dependency>
+
+
+        <dependency>
+            <groupId>javax.annotation</groupId>
+            <artifactId>javax.annotation-api</artifactId>
+            <version>${javax.annotation-api.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- db -->
+        <dependency>
+            <groupId>org.springframework.data</groupId>
+            <artifactId>spring-data-mongodb</artifactId>
+            <version>${spring-data-mongodb.version}</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>spring-data-commons</artifactId>
+                    <groupId>org.springframework.data</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-mongodb</artifactId>
+            <version>${spring-boot.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.mongodb</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!--        驱动-->
+        <dependency>
+            <groupId>org.mongodb</groupId>
+            <artifactId>mongodb-driver-sync</artifactId>
+            <version>${mongodb-driver-sync.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mongodb</groupId>
+            <artifactId>mongodb-driver-core</artifactId>
+            <version>${mongodb-driver-sync.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mongodb</groupId>
+            <artifactId>bson-record-codec</artifactId>
+            <version>4.9.1</version>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mongodb</groupId>
+            <artifactId>bson</artifactId>
+            <version>4.9.1</version>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
+            <version>${spring-boot-starter-data-jpa.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.data</groupId>
+                    <artifactId>spring-data-jpa</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.springframework.data</groupId>
+            <artifactId>spring-data-jpa</artifactId>
+            <version>${spring-data-jpa.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.xml.bind</groupId>
+            <artifactId>jaxb-api</artifactId>
+            <version>${jaxb-api.version}</version>
+        </dependency>
+
+
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+            <version>${JodaTime.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.hsqldb</groupId>
+            <artifactId>hsqldb</artifactId>
+            <version>${Hsqldb.version}</version>
+        </dependency>
+
+        <!--        <dependency>-->
+        <!--            <groupId>org.hibernate</groupId>-->
+        <!--            <artifactId>hibernate-entitymanager</artifactId>-->
+        <!--            <version>5.6.11.Final</version>-->
+        <!--        </dependency>-->
+
+        <!--spring 数据源-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-autoconfigure</artifactId>
+            <version>${spring-boot.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>${mybatis.version}</version>
+        </dependency>
+
+        <!--    redis    -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>2.0.39</version>
+        </dependency>
+
+    </dependencies>
+
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring-boot.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <repositories>
+
+        <!-- 阿里-->
+        <repository>
+            <id>nexus</id>
+            <name>nexus</name>
+            <url>https://maven.aliyun.com/nexus/content/groups/public</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>true</enabled>
+                <updatePolicy>always</updatePolicy>
+            </snapshots>
+        </repository>
+
+
+        <repository>
+            <id>spring-snapshots</id>
+            <name>Spring Snapshots</name>
+            <url>https://repo.spring.io/snapshot</url>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+        </repository>
+
+        <repository>
+            <id>spring-milestones</id>
+            <name>Spring Milestones</name>
+            <url>https://repo.spring.io/milestone</url>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+
+
+    </repositories>
+
+
+    <pluginRepositories>
+
+        <pluginRepository>
+            <id>groovy-plugins-release</id>
+            <url>https://groovy.jfrog.io/artifactory/plugins-release</url>
+        </pluginRepository>
+
+    </pluginRepositories>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.8.1</version>
+                <configuration>
+                    <source>11</source>
+                    <target>11</target>
+                    <encoding>UTF-8</encoding>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring-boot.version}</version>
+                <configuration>
+                    <mainClass>com.zswl.dataservicestarter.DataServiceStarterApplication</mainClass>
+                    <skip>true</skip>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>repackage</id>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+
+        <!-- properties 取 pom 配置 -->
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+
+    </build>
+
+
+</project>

+ 24 - 0
src/main/java/com/zswl/dataservicestarter/DataServiceStarterApplication.java

@@ -0,0 +1,24 @@
+package com.zswl.dataservicestarter;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+//@SpringBootApplication
+@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
+@EnableAsync
+@EnableCaching
+@Configuration
+@EnableWebMvc
+public class DataServiceStarterApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(DataServiceStarterApplication.class, args);
+    }
+
+}

+ 67 - 0
src/main/java/com/zswl/dataservicestarter/components/DataRecord.java

@@ -0,0 +1,67 @@
+package com.zswl.dataservicestarter.components;
+
+import com.zswl.dataservicestarter.domain.SuperEntity;
+import lombok.*;
+import lombok.experimental.Delegate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * 数据记录集,可用于还原,适合完成业务补偿部分,建议配合事务使用
+ */
+@Component
+@NoArgsConstructor
+public class DataRecord {
+
+    @Getter
+    @Setter
+    @Autowired
+    private MongoTemplate mongoTemplate;
+
+
+    private interface ProxyMethod {
+        boolean add(RevertData data);
+
+        boolean addAll(Collection<? extends RevertData> datas);
+
+        void clear();
+
+        int size();
+    }
+
+
+    @Delegate(types = ProxyMethod.class)
+    private Collection<RevertData> list = new ArrayList<>();
+
+
+    @Data
+    @Builder
+    @AllArgsConstructor
+    @NoArgsConstructor
+    public static class RevertData {
+        private Class<? extends SuperEntity> entityClass;
+        private Query query;
+        private Update update;
+    }
+
+    public Collection<RevertData> list() {
+        return this.list;
+    }
+
+
+    /**
+     * 恢复数据
+     */
+    public void revert() {
+        for (RevertData data : this.list) {
+            this.mongoTemplate.updateFirst(data.query, data.update, data.entityClass);
+        }
+    }
+
+}

+ 29 - 0
src/main/java/com/zswl/dataservicestarter/config/GlobalResponseAdvice.java

@@ -0,0 +1,29 @@
+package com.zswl.dataservicestarter.config;
+
+import org.springframework.core.MethodParameter;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
+
+/**
+ * 暂时没用
+ *
+ * @author TRX
+ * @date 2024/3/21
+ */
+//@RestControllerAdvice(basePackages = "com.zswl.dataservicestarter.controller")
+public class GlobalResponseAdvice implements ResponseBodyAdvice<Object> {
+    @Override
+    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
+        return true;
+    }
+
+    @Override
+    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
+
+        return "11";
+    }
+}

+ 13 - 0
src/main/java/com/zswl/dataservicestarter/config/JpaConfig.java

@@ -0,0 +1,13 @@
+package com.zswl.dataservicestarter.config;
+
+import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+
+@Configuration
+@Import(JpaDataConfiguration.class)
+@EntityScan("com.zswl.dataservicestarter.domain")
+@EnableJpaRepositories("com.zswl.dataservicestarter.dao")
+public class JpaConfig {
+}

+ 28 - 0
src/main/java/com/zswl/dataservicestarter/config/JpaDataConfiguration.java

@@ -0,0 +1,28 @@
+package com.zswl.dataservicestarter.config;
+
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+/**
+ * JPA 配置
+ */
+
+@Configuration
+//允许自动装载数据源
+@Import({DataSourceAutoConfiguration.class, PaginationConfiguration.class})
+
+//允许使用jpa注解
+@EnableJpaAuditing
+
+//允许事务管理
+@EnableTransactionManagement
+
+@ComponentScan("com.zswl.dataservicestarter.helper.jpa")
+public class JpaDataConfiguration {
+
+
+}

+ 102 - 0
src/main/java/com/zswl/dataservicestarter/config/MongoConfiguration.java

@@ -0,0 +1,102 @@
+package com.zswl.dataservicestarter.config;
+
+import com.mongodb.ReadPreference;
+import com.zswl.dataservicestarter.config.converts.BigDecimalToDecimal128Converter;
+import com.zswl.dataservicestarter.config.converts.Decimal128ToBigDecimalConverter;
+import org.bson.Document;
+import org.bson.codecs.DocumentCodec;
+import org.springframework.beans.BeanInstantiationException;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.data.mongodb.MongoDatabaseFactory;
+import org.springframework.data.mongodb.MongoTransactionManager;
+import org.springframework.data.mongodb.config.EnableMongoAuditing;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
+import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
+import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
+import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
+import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 集成自动配置
+ */
+@Configuration
+@EnableMongoAuditing
+@ComponentScan({"com.zswl.dataservicestarter", "com.zswl.dataservicestarter.helper"})
+@EnableMongoRepositories("com.zswl.dataservicestarter.dao")
+@Import(PaginationConfiguration.class)
+public class MongoConfiguration {
+
+
+    static {
+        //jdk 11 以上,强制使用 TLSv1.3 ,  mongo 驱动目前兼容 TLSv1.2
+        System.setProperty("jdk.tls.client.protocols", "TLSv1.2");
+    }
+
+    /**
+     * 自定义转换器
+     *
+     * @param mongoDbFactory
+     * @param mongoMappingContext
+     * @return
+     * @throws Exception
+     */
+    @Bean
+    @ConditionalOnMissingBean
+    public MappingMongoConverter mappingMongoConverter(MongoDatabaseFactory mongoDbFactory, MongoMappingContext mongoMappingContext) throws Exception {
+        DefaultDbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory);
+        MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext);
+        List<Object> list = new ArrayList<>();
+        list.add(new BigDecimalToDecimal128Converter());//自定义的类型转换器
+        list.add(new Decimal128ToBigDecimalConverter());//自定义的类型转换器
+        converter.setCustomConversions(new MongoCustomConversions(list));
+
+        return converter;
+    }
+
+    /**
+     * 事务
+     *
+     * @param dbFactory
+     * @return
+     */
+    @Bean
+    MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
+        return new MongoTransactionManager(dbFactory);
+    }
+
+    /**
+     * 配置读写分离
+     *
+     * @return
+     */
+    @Bean
+    public ReadPreference readPreference(MongoTemplate mongoTemplate) {
+//        首选主节点,大多情况下读操作在主节点,如果主节点不可用,如故障转移,读操作在从节点。
+        ReadPreference readPreference = ReadPreference.primaryPreferred();
+        mongoTemplate.setReadPreference(readPreference);
+        return readPreference;
+    }
+
+    @Bean
+    public DocumentCodec documentCodec(MongoDatabaseFactory dbFactory) {
+        return new DocumentCodec(dbFactory.getCodecRegistry());
+    }
+
+
+// 	 @EventListener(ApplicationReadyEvent.class)
+//	 public void initIndicesAfterStartup() {
+//
+//	    IndexOperations indexOps = mongoTemplate.indexOps(DomainType.class);
+//
+//	     IndexResolver resolver = new MongoPersistentEntityIndexResolver(mongoMappingContext);
+//	     resolver.resolveIndexFor(DomainType.class).forEach(indexOps::ensureIndex);
+//	 }
+}

+ 26 - 0
src/main/java/com/zswl/dataservicestarter/config/PaginationConfiguration.java

@@ -0,0 +1,26 @@
+package com.zswl.dataservicestarter.config;
+
+import org.springframework.beans.factory.ObjectFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.convert.ConversionService;
+import org.springframework.data.web.PageableHandlerMethodArgumentResolver;
+import org.springframework.data.web.config.SpringDataWebConfiguration;
+
+@Configuration
+public class PaginationConfiguration extends SpringDataWebConfiguration {
+
+    public PaginationConfiguration(ApplicationContext context, ObjectFactory<ConversionService> conversionService) {
+        super(context, conversionService);
+    }
+
+    @Bean
+    @Override
+    public PageableHandlerMethodArgumentResolver pageableResolver() {
+        PageableHandlerMethodArgumentResolver pageableHandlerMethodArgumentResolver = new PageableHandlerMethodArgumentResolver(sortResolver());
+        pageableHandlerMethodArgumentResolver.setMaxPageSize(Integer.MAX_VALUE);
+        return pageableHandlerMethodArgumentResolver;
+    }
+
+}

+ 11 - 0
src/main/java/com/zswl/dataservicestarter/config/SwaggerConfig.java

@@ -0,0 +1,11 @@
+package com.zswl.dataservicestarter.config;
+
+import com.mongodb.MongoClientSettings;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ *
+ */
+//@Configuration
+public class SwaggerConfig {
+}

+ 73 - 0
src/main/java/com/zswl/dataservicestarter/config/SwaggerProperties.java

@@ -0,0 +1,73 @@
+package com.zswl.dataservicestarter.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConfigurationProperties("swagger")
+public class SwaggerProperties {
+    /**
+     * 是否开启swagger,生产环境一般关闭,所以这里定义一个变量
+     */
+    private Boolean enable;
+
+    /**
+     * 项目应用名
+     */
+    private String applicationName;
+
+    /**
+     * 项目版本信息
+     */
+    private String applicationVersion;
+
+    /**
+     * 项目描述信息
+     */
+    private String applicationDescription;
+
+    /**
+     * 接口调试地址
+     */
+    private String tryHost;
+
+    public Boolean getEnable() {
+        return enable;
+    }
+
+    public void setEnable(Boolean enable) {
+        this.enable = enable;
+    }
+
+    public String getApplicationName() {
+        return applicationName;
+    }
+
+    public void setApplicationName(String applicationName) {
+        this.applicationName = applicationName;
+    }
+
+    public String getApplicationVersion() {
+        return applicationVersion;
+    }
+
+    public void setApplicationVersion(String applicationVersion) {
+        this.applicationVersion = applicationVersion;
+    }
+
+    public String getApplicationDescription() {
+        return applicationDescription;
+    }
+
+    public void setApplicationDescription(String applicationDescription) {
+        this.applicationDescription = applicationDescription;
+    }
+
+    public String getTryHost() {
+        return tryHost;
+    }
+
+    public void setTryHost(String tryHost) {
+        this.tryHost = tryHost;
+    }
+}

+ 19 - 0
src/main/java/com/zswl/dataservicestarter/config/WebMvcConfig.java

@@ -0,0 +1,19 @@
+package com.zswl.dataservicestarter.config;
+
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.util.ReflectionUtils;
+import org.springframework.web.servlet.config.annotation.*;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+/**
+ * @author TRX
+ * @date 2024/3/21
+ */
+@Configuration
+public class WebMvcConfig implements WebMvcConfigurer {
+
+}

+ 18 - 0
src/main/java/com/zswl/dataservicestarter/config/converts/BigDecimalToDecimal128Converter.java

@@ -0,0 +1,18 @@
+package com.zswl.dataservicestarter.config.converts;
+
+import org.bson.types.Decimal128;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.data.convert.ReadingConverter;
+import org.springframework.data.convert.WritingConverter;
+
+import java.math.BigDecimal;
+
+@ReadingConverter
+@WritingConverter
+public class BigDecimalToDecimal128Converter implements Converter<BigDecimal, Decimal128> {
+
+    public Decimal128 convert(BigDecimal bigDecimal) {
+        return new Decimal128(bigDecimal);
+    }
+
+}

+ 20 - 0
src/main/java/com/zswl/dataservicestarter/config/converts/Decimal128ToBigDecimalConverter.java

@@ -0,0 +1,20 @@
+package com.zswl.dataservicestarter.config.converts;
+
+import org.bson.types.Decimal128;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.data.convert.ReadingConverter;
+import org.springframework.data.convert.WritingConverter;
+
+import java.math.BigDecimal;
+
+@ReadingConverter
+@WritingConverter
+public class Decimal128ToBigDecimalConverter implements Converter<Decimal128, BigDecimal> {
+
+    public BigDecimal convert(Decimal128 decimal128) {
+        return decimal128.bigDecimalValue();
+    }
+
+
+
+}

+ 50 - 0
src/main/java/com/zswl/dataservicestarter/controller/OauthController.java

@@ -0,0 +1,50 @@
+package com.zswl.dataservicestarter.controller;
+
+import com.zswl.dataservicestarter.model.TokenModel;
+import com.zswl.dataservicestarter.model.params.TokenParam;
+import com.zswl.dataservicestarter.service.AppInfoService;
+import com.zswl.dataservicestarter.utils.result.ResultContent;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 访问令牌 服务
+ *
+ * @author TRX
+ * @date 2024/3/21
+ */
+@RequestMapping("/oauth")
+@RestController
+@Validated
+public class OauthController {
+
+    @Autowired
+    AppInfoService appInfoService;
+
+    /**
+     * 得到Token
+     *
+     * @param param
+     * @return
+     */
+    @RequestMapping(value = "token", method = {RequestMethod.POST})
+    public ResultContent<TokenModel> token(@RequestBody TokenParam param) {
+        return appInfoService.getToken(param);
+    }
+
+    /**
+     * 生成一个 渠道
+     *
+     * @return
+     */
+    @RequestMapping(value = "addAppInfo", method = {RequestMethod.POST})
+    public ResultContent addAppInfo() {
+        return appInfoService.addAppInfo();
+    }
+
+
+}

+ 34 - 0
src/main/java/com/zswl/dataservicestarter/controller/TestController.java

@@ -0,0 +1,34 @@
+package com.zswl.dataservicestarter.controller;
+
+import com.zswl.dataservicestarter.service.UserService;
+import com.zswl.dataservicestarter.utils.result.ResultContent;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ */
+@RequestMapping("/test")
+@RestController
+@Validated
+public class TestController {
+
+    @Autowired
+    UserService userService;
+
+    @RequestMapping(value = "test", method = {RequestMethod.GET, RequestMethod.POST})
+    public ResultContent test(String name) {
+        Map map = new HashMap();
+        map.put("obj", name);
+        map.put("time", System.currentTimeMillis());
+
+        return userService.addUser(name);
+    }
+}
+

+ 17 - 0
src/main/java/com/zswl/dataservicestarter/dao/AppInfoDao.java

@@ -0,0 +1,17 @@
+package com.zswl.dataservicestarter.dao;
+
+import com.zswl.dataservicestarter.domain.AppInfo;
+import com.zswl.dataservicestarter.domain.SuperEntity;
+import com.zswl.dataservicestarter.domain.User;
+
+/**
+ * @author TRX
+ * @date 2024/3/21
+ */
+public interface AppInfoDao extends MongoDao<AppInfo> {
+
+    AppInfo findTopByEntIdAndAppSecret(String entId, String appSecret);
+
+    AppInfo findTopById(String id);
+
+}

+ 12 - 0
src/main/java/com/zswl/dataservicestarter/dao/MongoDao.java

@@ -0,0 +1,12 @@
+package com.zswl.dataservicestarter.dao;
+
+import com.zswl.dataservicestarter.domain.SuperEntity;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+/**
+ * Mongodb的一些通用方法
+ */
+public interface MongoDao<T extends SuperEntity> extends MongoRepository<T, String> {
+
+
+}

+ 9 - 0
src/main/java/com/zswl/dataservicestarter/dao/UserDao.java

@@ -0,0 +1,9 @@
+package com.zswl.dataservicestarter.dao;
+
+import com.zswl.dataservicestarter.domain.User;
+
+import java.util.List;
+
+public interface UserDao extends MongoDao<User> {
+    List<User> findByNameLike(String name);
+}

+ 38 - 0
src/main/java/com/zswl/dataservicestarter/domain/AppInfo.java

@@ -0,0 +1,38 @@
+package com.zswl.dataservicestarter.domain;
+
+import com.zswl.dataservicestarter.type.AppState;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.mongodb.core.mapping.DBRef;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+/**
+ * 用户认证账户信息
+ *
+ * @author TRX
+ * @date 2024/3/21
+ */
+@Data
+@Document
+@NoArgsConstructor
+@AllArgsConstructor
+public class AppInfo extends SuperEntity {
+    /**
+     * 渠道ID
+     */
+    @DBRef
+    private String entId;
+    /**
+     * appSecret
+     */
+    private String appSecret;
+    /**
+     * 应用ID
+     */
+    private String appId;
+    /**
+     * 账户状态
+     */
+    private AppState appState;
+}

+ 43 - 0
src/main/java/com/zswl/dataservicestarter/domain/SuperEntity.java

@@ -0,0 +1,43 @@
+package com.zswl.dataservicestarter.domain;
+
+import lombok.Data;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.annotation.LastModifiedDate;
+import org.springframework.data.jpa.domain.AbstractPersistable;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+import org.springframework.data.mongodb.core.index.Indexed;
+
+import javax.persistence.EntityListeners;
+import javax.persistence.MappedSuperclass;
+import java.io.Serializable;
+
+@Data
+@MappedSuperclass
+@EntityListeners(AuditingEntityListener.class)
+public abstract class SuperEntity extends AbstractPersistable<String> implements Serializable {
+
+
+    @Id
+    private String id;
+
+    /**
+     * 创建时间
+     */
+
+    @Indexed
+    @CreatedDate
+    private Long createTime;
+
+    /**
+     * 修改时间
+     */
+    @Indexed
+    @LastModifiedDate
+    private Long updateTime;
+
+    /**
+     * 备注
+     */
+    private String remark;
+}

+ 20 - 0
src/main/java/com/zswl/dataservicestarter/domain/User.java

@@ -0,0 +1,20 @@
+package com.zswl.dataservicestarter.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+/**
+ * @author TRX
+ * @date 2024/3/20
+ */
+@Data
+@Document
+@NoArgsConstructor
+@AllArgsConstructor
+public class User extends SuperEntity {
+    private String name;
+    private Integer age;
+    private String address;
+}

+ 37 - 0
src/main/java/com/zswl/dataservicestarter/helper/BatchQueryHelper.java

@@ -0,0 +1,37 @@
+package com.zswl.dataservicestarter.helper;
+
+import com.zswl.dataservicestarter.domain.SuperEntity;
+import com.zswl.dataservicestarter.utils.bean.EntityObjectUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Component;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 批量查询
+ */
+@Component
+public class BatchQueryHelper {
+
+    @Autowired
+    private MongoTemplate mongoTemplate;
+
+
+    /**
+     * 批量查询
+     *
+     * @param entityCls
+     * @param items
+     * @param <T>
+     * @return
+     */
+    public <T extends SuperEntity> List<T> batchQuery(Class<T> entityCls, Collection<Map<String, Object>> items) {
+        return this.mongoTemplate.find(Query.query(EntityObjectUtil.createQueryBatch(items)), entityCls);
+    }
+
+
+}

+ 273 - 0
src/main/java/com/zswl/dataservicestarter/helper/DBHelper.java

@@ -0,0 +1,273 @@
+package com.zswl.dataservicestarter.helper;
+
+import com.zswl.dataservicestarter.domain.SuperEntity;
+import com.zswl.dataservicestarter.helper.jpa.TransactionHelper;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Delegate;
+import org.bson.Document;
+import org.bson.codecs.DocumentCodec;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.aggregation.Aggregation;
+import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Component
+public class DBHelper {
+
+    @Autowired
+    private MongoTemplate mongoTemplate;
+
+    @Autowired
+    private DocumentCodec documentCodec;
+
+    //引用事务助手
+    @Autowired
+    @Delegate(types = TransactionHelper.class)
+    private TransactionHelper transactionHelper;
+
+
+    //引用mql查询助手
+    @Autowired
+    @Delegate(types = MongoQueryLanguageHelper.class)
+    private MongoQueryLanguageHelper mongoQueryLanguageHelper;
+
+
+    //引用批量查询
+    @Autowired
+    @Delegate(types = BatchQueryHelper.class)
+    private BatchQueryHelper batchQueryHelper;
+
+
+    //偏移数据
+    @Setter
+    @Getter
+    private long offsetTime = 0L;
+
+
+    // 缓存集合与类名
+    private Map<Class, String> collectionCache = new ConcurrentHashMap();
+
+
+    /**
+     * 设置更新时间
+     *
+     * @param entity
+     */
+    public void updateTime(SuperEntity entity) {
+        entity.setUpdateTime(getTime());
+    }
+
+    /**
+     * 设置创建时间
+     *
+     * @param entity
+     */
+    public void saveTime(SuperEntity entity) {
+        entity.setCreateTime(getTime());
+        updateTime(entity);
+    }
+
+
+    /**
+     * 设置更新时间
+     */
+    public void updateTime(Update update) {
+        update.set("updateTime", getTime());
+    }
+
+    /**
+     * 构建一个 update
+     *
+     * @return
+     */
+    public Update buildUpdate() {
+        Update update = new Update();
+        updateTime(update);
+        return update;
+    }
+
+
+    /**
+     * 设置创建时间
+     */
+    public void saveTime(Update update) {
+        update.setOnInsert("createTime", getTime());
+        updateTime(update);
+    }
+
+
+    /**
+     * 取时间
+     *
+     * @return
+     */
+    public long getTime() {
+        return this.offsetTime + System.currentTimeMillis();
+    }
+
+
+    /**
+     * 分页查询
+     *
+     * @param query
+     * @param pageable
+     * @param cls
+     * @param <T>
+     * @return
+     */
+    public <T> Page<T> pages(Query query, Pageable pageable, Class<T> cls) {
+        long total = this.mongoTemplate.count(query, cls);
+        query.with(pageable);
+        return new PageImpl<T>(this.mongoTemplate.find(query, cls), pageable, total);
+    }
+
+
+    /**
+     * 分页查询
+     *
+     * @param query
+     * @param pageable
+     * @param cls
+     * @param collectionName
+     * @param <T>
+     * @return
+     */
+    public <T> Page<T> pages(Query query, Pageable pageable, Class cls, String collectionName) {
+        long total = this.mongoTemplate.count(query, collectionName);
+        query.with(pageable);
+        return new PageImpl<T>(this.mongoTemplate.find(query, cls, collectionName), pageable, total);
+    }
+
+
+    /**
+     * 支持 aggregate 的分页查询语法
+     *
+     * @param pageable
+     * @param cls
+     * @return
+     */
+    public Page<Document> pages(Criteria criteria, Pageable pageable, Class<? extends SuperEntity> cls, AggregationOperation... aggregationOperations) {
+        //分页
+        AggregationOperation skip = Aggregation.skip(pageable.getOffset());
+        AggregationOperation limit = Aggregation.limit(pageable.getPageSize());
+
+
+        //排序
+        AggregationOperation sort = Aggregation.sort(pageable.getSort());
+        //分页模型
+        List<AggregationOperation> pageAggregationOperation = new ArrayList<AggregationOperation>() {{
+            //分页
+            add(skip);
+            add(limit);
+        }};
+
+
+        //总量
+        AggregationOperation count = Aggregation.count().as("count");
+
+
+        //构建分页查询条件
+        List<AggregationOperation> aggregations = new ArrayList<AggregationOperation>() {{
+
+            //查询条件
+            if (criteria != null) {
+                add(Aggregation.match(criteria));
+            }
+
+            //其他聚合业务
+            addAll(Arrays.asList(aggregationOperations));
+
+            //排序,必须放在分页模型外面,负责排序是分页排序
+            if (pageable.getSort() != null && !pageable.getSort().isEmpty()) {
+                add(sort);
+            }
+
+            //分页模型
+            add(Aggregation.facet().and(pageAggregationOperation.toArray(new AggregationOperation[0])).as("items").and(count).as("count"));
+        }};
+
+
+        //总量,用于分页, 移除外部的分页统计接口,用 facet 进行分页统计
+        Document result = this.mongoTemplate.aggregate(Aggregation.newAggregation(aggregations), this.getCollectionName(cls), Document.class).getMappedResults().get(0);
+
+        //转换输出类型
+        List items = result.getList("items", Document.class);
+
+        long total = 0;
+        List<Document> rets = result.getList("count", Document.class);
+        if (rets == null || rets.size() == 0) {
+            total = 0;
+        } else {
+            total = Long.parseLong(String.valueOf(rets.get(0).get("count")));
+        }
+
+
+        //记录的总数
+
+
+        //转换为分页模型
+        return new PageImpl<Document>(items, pageable, total);
+    }
+
+
+    /**
+     * 获取实体的名称
+     *
+     * @param cls
+     * @return
+     */
+    public String getCollectionName(Class cls) {
+        String name = this.collectionCache.get(cls);
+        if (name == null) {
+            name = this.mongoTemplate.getCollectionName(cls);
+            this.collectionCache.put(cls, name);
+        }
+        return name;
+    }
+
+
+    /**
+     * Document 转 json 对象
+     *
+     * @return
+     */
+    public String toJson(Document document) {
+        return document.toJson(documentCodec);
+    }
+
+
+    /**
+     * 支持查询对象转Json
+     *
+     * @param query
+     * @return
+     */
+    public String toJson(Query query) {
+        return toJson(query.getQueryObject());
+    }
+
+    /**
+     * 支持查询对象转Json
+     *
+     * @param update
+     * @return
+     */
+    public String toJson(Update update) {
+        return toJson(update.getUpdateObject());
+    }
+
+}

+ 181 - 0
src/main/java/com/zswl/dataservicestarter/helper/MongoQueryLanguageHelper.java

@@ -0,0 +1,181 @@
+package com.zswl.dataservicestarter.helper;
+
+import com.mongodb.client.FindIterable;
+import com.mongodb.client.MongoCollection;
+import com.zswl.dataservicestarter.model.QueryModel;
+import lombok.SneakyThrows;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Component
+public class MongoQueryLanguageHelper {
+
+
+    @Autowired
+    private MongoTemplate mongoTemplate;
+
+    @Autowired
+    @Lazy
+    private DBHelper dbHelper;
+
+
+    @SneakyThrows
+    public Criteria from(Document document) {
+        Criteria c = new Criteria();
+        Field _criteria = c.getClass().getDeclaredField("criteria");
+        _criteria.setAccessible(true);
+        LinkedHashMap<String, Object> criteria = (LinkedHashMap<String, Object>) _criteria.get(c);
+        for (Map.Entry<String, Object> set : document.entrySet()) {
+            criteria.put(set.getKey(), set.getValue());
+        }
+        Field _criteriaChain = c.getClass().getDeclaredField("criteriaChain");
+        _criteriaChain.setAccessible(true);
+        List<Criteria> criteriaChain = (List<Criteria>) _criteriaChain.get(c);
+        criteriaChain.add(c);
+        return c;
+    }
+
+    /**
+     * 通过 mongo的分页条件查询
+     *
+     * @param queryModel
+     * @param pageable
+     * @param entityClass
+     * @param <T>
+     * @return
+     */
+    @SneakyThrows
+    public <T> Page<T> queryByMql(QueryModel queryModel, Pageable pageable, Class<T> entityClass) {
+        Page<Document> page = this.queryByMql(queryModel, pageable, this.dbHelper.getCollectionName(entityClass));
+        //转换为数据库实体
+        List<T> resultSet = page.getContent().parallelStream().map((it) -> {
+            return (T) mongoTemplate.getConverter().read(entityClass, it);
+        }).collect(Collectors.toList());
+        return new PageImpl<T>(resultSet, pageable, page.getTotalElements());
+    }
+
+
+    @SneakyThrows
+    public Page<Document> queryByMql(QueryModel queryModel, Pageable pageable, String tableName) {
+        MongoCollection<Document> mongoCollection = this.mongoTemplate.getCollection(tableName);
+
+        final String mql = !StringUtils.hasText(queryModel.getMql()) ? "{}" : queryModel.getMql();
+        final Set<String> fields = queryModel.getFields() == null ? new HashSet<>() : queryModel.getFields();
+
+        //排序
+        Bson sort = sort(pageable.getSort());
+
+
+        //mql查询对象
+        Document mqlBson = Document.parse(mql);
+
+        //分页
+        long total = mongoCollection.countDocuments(mqlBson);
+        int skip = Integer.parseInt(String.valueOf(pageable.getOffset()));
+        int limit = pageable.getPageSize();
+
+
+        //构建查询语句
+        FindIterable<Document> findIterable = mongoCollection.find(mqlBson);
+
+        //过滤需要显示的字段
+        if (fields.size() > 0) {
+            findIterable = findIterable.projection(projection(fields));
+        }
+
+        //分页条件
+        findIterable = findIterable.skip(skip).limit(limit).sort(sort);
+
+
+        //结果集
+        List<Document> resultSet = new ArrayList<>();
+
+        //查询
+        for (Document document : findIterable) {
+            resultSet.add(document);
+        }
+
+        return new PageImpl<Document>(resultSet, pageable, total);
+    }
+
+    @SneakyThrows
+    public List<Document> queryByMql(QueryModel queryModel, Sort sort, String tableName) {
+        MongoCollection<Document> mongoCollection = this.mongoTemplate.getCollection(tableName);
+
+        final String mql = !StringUtils.hasText(queryModel.getMql()) ? "{}" : queryModel.getMql();
+        final Set<String> fields = queryModel.getFields() == null ? new HashSet<>() : queryModel.getFields();
+
+        //排序
+        Bson bsonSort = sort(sort);
+
+        //mql查询对象
+        Document mqlBson = Document.parse(mql);
+
+        //构建查询语句
+        FindIterable<Document> findIterable = mongoCollection.find(mqlBson);
+
+        //过滤需要显示的字段
+        if (fields.size() > 0) {
+            findIterable = findIterable.projection(projection(fields));
+        }
+
+        //分页条件
+        findIterable = findIterable.sort(bsonSort);
+
+        //结果集
+        List<Document> resultSet = new ArrayList<>();
+
+        //查询
+        for (Document document : findIterable) {
+            resultSet.add(document);
+        }
+
+        return resultSet;
+    }
+
+    /**
+     * 转换为sort
+     *
+     * @return
+     */
+    private static Document sort(Sort sort) {
+        Document bson = new Document();
+        if (sort.isUnsorted()) {
+            return bson;
+        }
+        sort.stream().forEach((order) -> {
+                    bson.put(order.getProperty(), order.getDirection() == Sort.Direction.DESC ? -1 : 1);
+                }
+        );
+        return bson;
+    }
+
+    /**
+     * 转换为过滤器
+     *
+     * @param fields
+     * @return
+     */
+    private static Document projection(Set<String> fields) {
+        Document bson = new Document();
+        fields.forEach((it) -> {
+            bson.put(it, 1);
+        });
+        return bson;
+    }
+
+}

+ 30 - 0
src/main/java/com/zswl/dataservicestarter/helper/MongoTemplateNearest.java

@@ -0,0 +1,30 @@
+package com.zswl.dataservicestarter.helper;
+
+import com.mongodb.ReadPreference;
+import lombok.experimental.Delegate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.stereotype.Component;
+
+@Component
+public class MongoTemplateNearest {
+
+
+    @Delegate(types = MongoTemplate.class)
+    private MongoTemplate mongoTemplate;
+
+
+    @Autowired
+    private void init(MongoTemplate mongoTemplate) {
+
+        //实例化 mongoTemplate
+        mongoTemplate = new MongoTemplate(
+                mongoTemplate.getMongoDatabaseFactory(),
+                mongoTemplate.getConverter()
+        );
+
+        //  最小的延迟,会从复制集中选择最低网络延迟的节点处理读请求,这种方式不能保证数据一致性,也不能保证减少IO以及CPU的负载
+        mongoTemplate.setReadPreference(ReadPreference.nearest());
+    }
+
+}

+ 284 - 0
src/main/java/com/zswl/dataservicestarter/helper/ReIndexHelper.java

@@ -0,0 +1,284 @@
+package com.zswl.dataservicestarter.helper;
+
+import com.zswl.dataservicestarter.domain.SuperEntity;
+import com.zswl.dataservicestarter.utils.bean.BeanUtil;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.index.Index;
+import org.springframework.data.mongodb.core.index.IndexInfo;
+import org.springframework.data.mongodb.core.index.IndexOperations;
+import org.springframework.data.mongodb.core.mapreduce.MapReduceResults;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 重置索引
+ */
+@Slf4j
+@Component
+public class ReIndexHelper {
+
+    @Autowired
+    private MongoTemplate mongoTemplate;
+
+    //每个索引里最大数量
+    private final static int MaxIndexCount = 24;
+
+
+    /**
+     * 重建索引
+     */
+    public void reIndexFromField(Class<? extends SuperEntity> entityClass, String fieldName, Class<?> cls) {
+        //构建索引
+        Set<Index> nowIndexNames = BeanUtil.readBeanType(cls).keySet()
+                .stream()
+                .map((it) -> {
+                    final String indexName = fieldName + "." + it;
+                    return new Index().named(indexName).on(indexName, Sort.Direction.ASC);
+                }).collect(Collectors.toSet());
+
+        //更新索引
+        updateIndex(entityClass, fieldName, nowIndexNames.toArray(new Index[0]));
+    }
+
+
+    /**
+     * 重置索引
+     */
+    public void reIndexFromMap(Class<? extends SuperEntity> entityClass, String fieldName) {
+        //构建索引
+        Set<Index> nowIndexNames = getIndexNamesFromMap(entityClass, fieldName)
+                .stream()
+                .map((it) -> {
+                    final String indexName = fieldName + "." + it;
+                    return new Index().named(indexName).on(indexName, Sort.Direction.ASC);
+                }).collect(Collectors.toSet());
+
+        //更新索引
+        updateIndex(entityClass, fieldName, nowIndexNames.toArray(new Index[0]));
+    }
+
+
+    /**
+     * 取出现有点索引
+     *
+     * @return
+     */
+    public Set<String> getIndexNames(String tableName) {
+        //现有索引
+        return this.mongoTemplate.indexOps(tableName)
+                .getIndexInfo()
+                .stream()
+                .map((it) -> {
+                    return it.getName();
+                }).collect(Collectors.toSet());
+    }
+
+
+    public void copyIndex(String tableName, String newTableName) {
+        final IndexOperations indexOperations = this.mongoTemplate.indexOps(tableName);
+        indexOperations.getIndexInfo().stream().filter(it -> !Set.of("_id_", "_id").contains(it.getName())).forEach((indexInfo) -> {
+            final String indexName = indexInfo.getName();
+            final IndexOperations newIndexOperations = this.mongoTemplate.indexOps(newTableName);
+
+            //删除索引
+            newIndexOperations.getIndexInfo().stream().filter(it -> indexName.equals(it.getName())).forEach((it) -> {
+                newIndexOperations.dropIndex(it.getName());
+            });
+            final Index newIndex = new Index();
+            newIndex.named(indexName);
+            indexInfo.getIndexFields().forEach((it) -> {
+                newIndex.on(it.getKey(), it.getDirection());
+            });
+
+            //创建索引
+            newIndexOperations.ensureIndex(newIndex);
+        });
+    }
+
+
+    /**
+     * 取出现有点索引
+     *
+     * @param entityClass
+     * @return
+     */
+    public Set<String> getIndexNames(Class<? extends SuperEntity> entityClass) {
+        return this.getIndexNames(this.mongoTemplate.getCollectionName(entityClass));
+    }
+
+
+    /**
+     * 更新索引
+     *
+     * @param tableName
+     * @param indexs
+     */
+    @SneakyThrows
+    public void updateIndex(String tableName, Index... indexs) {
+        //现有索引
+        final Set<String> nowIndexNames = getIndexNames(tableName);
+
+        //索引
+        final IndexOperations indexOperations = this.mongoTemplate.indexOps(tableName);
+
+        //索引不存在建索引
+        Arrays.stream(indexs).filter(it -> it.getIndexKeys().size() > 0).forEach((it) -> {
+            String indexName = getIndexName(it);
+            if ((nowIndexNames.contains(indexName))) {
+                indexOperations.dropIndex(indexName);
+            }
+            String ret = indexOperations.ensureIndex(it);
+            log.info("update index : " + ret);
+        });
+    }
+
+
+    @SneakyThrows
+    private String getIndexName(Index index) {
+        final Field field = FieldUtils.getDeclaredField(Index.class, "name", true);
+        if (field == null) {
+            return null;
+        }
+        Object val = field.get(index);
+        if (val == null) {
+            return null;
+        }
+        return String.valueOf(val);
+    }
+
+    /**
+     * 更新索引,独立的索引项
+     *
+     * @param entityClass
+     * @param indexs
+     */
+    @SneakyThrows
+    public void updateIndex(Class<? extends SuperEntity> entityClass, Index... indexs) {
+        this.updateIndex(this.mongoTemplate.getCollectionName(entityClass), indexs);
+    }
+
+
+    /**
+     * 更新索引,共用一个索引项
+     *
+     * @param entityClass
+     */
+    @SneakyThrows
+    public void updateIndex(Class<? extends SuperEntity> entityClass, String indexName, Index... indexs) {
+        boolean isUpdate = false;
+        List<IndexInfo> indexInfos = this.mongoTemplate.indexOps(entityClass)
+                .getIndexInfo()
+                .stream()
+                .filter((it) -> {
+                    return it.getName().length() > indexName.length() + 1 && it.getName().substring(0, indexName.length()).equals(indexName);
+                }).collect(Collectors.toList());
+        if (indexInfos != null && indexInfos.size() > 0) {
+            isUpdate = isNeedUpdateIndex(indexInfos, indexs);
+        } else {
+            isUpdate = true;
+        }
+
+        //进行更新索引
+        if (isUpdate) {
+            final IndexOperations indexOperations = this.mongoTemplate.indexOps(entityClass);
+
+            //如果存在则删除所有的和符合索引
+            indexOperations.getIndexInfo().stream().filter((it) -> {
+                return it.getName().length() > indexName.length() + 1 && it.getName().substring(0, indexName.length()).equals(indexName);
+            }).forEach((it) -> {
+                indexOperations.dropIndex(it.getName());
+            });
+
+            int size = (int) (indexs.length / MaxIndexCount);
+            for (int i = 0; i < size; i++) {
+                updateIndex(indexOperations, indexName + "_" + i, i, indexs);
+            }
+            if (indexs.length % MaxIndexCount != 0) {
+                updateIndex(indexOperations, indexName + "_" + size, size, indexs);
+            }
+        }
+    }
+
+    @SneakyThrows
+    private void updateIndex(IndexOperations indexOperations, String indexName, int page, final Index[] indexs) {
+        Index index = new Index();
+        index.named(indexName);
+
+        for (int j = 0; j < MaxIndexCount; j++) {
+            //索引
+            int i = page * MaxIndexCount + j;
+            if (i >= indexs.length) {
+                continue;
+            }
+            Index it = indexs[i];
+            Field field = it.getClass().getDeclaredField("name");
+            field.setAccessible(true);
+            String fieldName = String.valueOf(field.get(it));
+            index.on(fieldName, Sort.Direction.ASC);
+        }
+        log.info("update index : {}", indexName);
+        indexOperations.ensureIndex(index);
+
+    }
+
+
+    /**
+     * 需要更新的名字
+     *
+     * @return
+     */
+    private boolean isNeedUpdateIndex(List<IndexInfo> indexInfos, Index[] indexs) {
+        //取出需要更新的索引名
+        Set<String> newUpdateNames = Arrays.stream(indexs).map((it) -> {
+            return it.getIndexOptions().get("name");
+        }).filter((it) -> {
+            return it != null;
+        }).map((it) -> {
+            return String.valueOf(it);
+        }).collect(Collectors.toSet());
+
+        //取出现有的索引名
+        Set<String> nowIndexName = new HashSet<>();
+        indexInfos.forEach((it) -> {
+            nowIndexName.addAll(it.getIndexFields().stream().map((index) -> {
+                return index.getKey();
+            }).collect(Collectors.toSet()));
+        });
+
+
+        for (String updateName : newUpdateNames) {
+            if (!nowIndexName.contains(updateName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * 取出Map属性对应的所有key的集合
+     *
+     * @return
+     */
+    public Set<String> getIndexNamesFromMap(Class<? extends SuperEntity> entityClass, String fieldName) {
+        String collectionName = this.mongoTemplate.getCollectionName(entityClass);
+        String map = "function(){if(this." + fieldName + "==null){return}for(var key in this." + fieldName + "){emit(key,1)}};";
+        String reduce = "function(key,values){return values.length};";
+        Set<String> indexNames = new HashSet<>();
+        MapReduceResults<Map> mapReduceResults = this.mongoTemplate.mapReduce(collectionName, map, reduce, Map.class);
+        mapReduceResults.forEach((it) -> {
+            indexNames.add(String.valueOf(it.get("_id")));
+        });
+        return indexNames;
+    }
+
+
+}

+ 103 - 0
src/main/java/com/zswl/dataservicestarter/helper/jpa/TransactionHelper.java

@@ -0,0 +1,103 @@
+package com.zswl.dataservicestarter.helper.jpa;
+
+import com.zswl.dataservicestarter.utils.os.SystemUtil;
+import lombok.SneakyThrows;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.TransactionException;
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
+import org.springframework.transaction.support.TransactionCallback;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+@Component
+public class TransactionHelper {
+
+
+    @Autowired
+    private TransactionTemplate transactionTemplate;
+
+    //线程池
+    ExecutorService threadPool = Executors.newFixedThreadPool(SystemUtil.getCpuCoreCount() * 2);
+
+    @Autowired
+    private void init(ApplicationContext applicationContext) {
+        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+            threadPool.shutdownNow();
+        }));
+    }
+
+
+    /**
+     * 创建一个新事务
+     *
+     * @param action
+     * @param <T>
+     */
+    @SneakyThrows
+    public <T> T newTransaction(TransactionCallback<T> action) {
+        CountDownLatch countDownLatch = new CountDownLatch(1);
+        Object[] ts = new Object[1];
+        new Thread(() -> {
+            try {
+                ts[0] = transaction(action);
+            } catch (TransactionException e) {
+                e.printStackTrace();
+            }
+            countDownLatch.countDown();
+        }).start();
+        countDownLatch.await();
+        return ts[0] == null ? null : (T) ts[0];
+    }
+
+
+    /**
+     * 创建一个没有事务的操作执行环境
+     *
+     * @param runnable
+     */
+    @SneakyThrows
+    public void noTransaction(Runnable runnable) {
+        CountDownLatch countDownLatch = new CountDownLatch(1);
+        threadPool.execute(() -> {
+            try {
+                runnable.run();
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                countDownLatch.countDown();
+            }
+        });
+        countDownLatch.await();
+    }
+
+
+    /**
+     * 编程事务
+     */
+    public <T> T transaction(TransactionCallback<T> action) {
+        return transactionTemplate.execute(action);
+    }
+
+    /**
+     * 回滚事务
+     */
+    public void rollbackTransaction() {
+        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
+    }
+
+
+    /**
+     * 提交事务
+     * 注: 不可多次提交
+     */
+    public void commitTransaction() {
+        transactionTemplate.getTransactionManager().commit(TransactionAspectSupport.currentTransactionStatus());
+    }
+
+
+}

+ 32 - 0
src/main/java/com/zswl/dataservicestarter/model/AppInfoModel.java

@@ -0,0 +1,32 @@
+package com.zswl.dataservicestarter.model;
+
+import com.zswl.dataservicestarter.type.AppState;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author TRX
+ * @date 2024/3/21
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class AppInfoModel {
+    /**
+     * 渠道ID
+     */
+    private String entId;
+    /**
+     * appSecret
+     */
+    private String appSecret;
+    /**
+     * 应用ID
+     */
+    private String appId;
+    /**
+     * 账户状态
+     */
+    private AppState appState;
+}

+ 26 - 0
src/main/java/com/zswl/dataservicestarter/model/QueryModel.java

@@ -0,0 +1,26 @@
+package com.zswl.dataservicestarter.model;
+
+import lombok.*;
+import lombok.experimental.Accessors;
+
+import java.util.Set;
+
+/**
+ * 查询模型
+ */
+@Data
+@Builder
+@EqualsAndHashCode
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class QueryModel {
+
+    //mongo的查询语句
+    private String mql;
+
+    //关键词,如果为null则全部查询,否则只查询需要的字段
+    private Set<String> fields;
+
+
+}

+ 18 - 0
src/main/java/com/zswl/dataservicestarter/model/TokenModel.java

@@ -0,0 +1,18 @@
+package com.zswl.dataservicestarter.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author TRX
+ * @date 2024/3/21
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class TokenModel {
+    private String access_token;
+    private Long expires_at;
+    private Long auth_time;
+}

+ 23 - 0
src/main/java/com/zswl/dataservicestarter/model/params/TokenParam.java

@@ -0,0 +1,23 @@
+package com.zswl.dataservicestarter.model.params;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author TRX
+ * @date 2024/3/21
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class TokenParam {
+    /**
+     * 渠道ID
+     */
+    private String entId;
+    /**
+     * appSecret
+     */
+    private String appSecret;
+}

+ 51 - 0
src/main/java/com/zswl/dataservicestarter/service/AppInfoService.java

@@ -0,0 +1,51 @@
+package com.zswl.dataservicestarter.service;
+
+import com.zswl.dataservicestarter.dao.AppInfoDao;
+import com.zswl.dataservicestarter.domain.AppInfo;
+import com.zswl.dataservicestarter.model.TokenModel;
+import com.zswl.dataservicestarter.model.params.TokenParam;
+import com.zswl.dataservicestarter.type.AppState;
+import com.zswl.dataservicestarter.utils.AppInfoUtil;
+import com.zswl.dataservicestarter.utils.SecurityUtil;
+import com.zswl.dataservicestarter.utils.result.ResultContent;
+import com.zswl.dataservicestarter.dao.AppInfoDao;
+import com.zswl.dataservicestarter.model.TokenModel;
+import com.zswl.dataservicestarter.model.params.TokenParam;
+import com.zswl.dataservicestarter.utils.result.ResultContent;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author TRX
+ * @date 2024/3/21
+ */
+@Service
+public class AppInfoService {
+
+    @Autowired
+    AppInfoDao appInfoDao;
+
+
+    public ResultContent<TokenModel> getToken(TokenParam param) {
+        TokenModel model = new TokenModel();
+
+        return ResultContent.buildSuccess(model);
+    }
+
+    /**
+     * 添加客户端信息
+     *
+     * @return
+     */
+    public ResultContent addAppInfo() {
+        AppInfo appInfo = new AppInfo();
+        String enId = AppInfoUtil.generateRandomString();
+        String appSecret = SecurityUtil.passWord(enId);
+        appInfo.setEntId(enId);
+        appInfo.setAppSecret(appSecret);
+        appInfo.setAppState(AppState.Enable);
+        appInfoDao.save(appInfo);
+
+        return ResultContent.buildSuccess();
+    }
+}

+ 105 - 0
src/main/java/com/zswl/dataservicestarter/service/RedisService.java

@@ -0,0 +1,105 @@
+package com.zswl.dataservicestarter.service;
+
+import com.zswl.dataservicestarter.utils.exception.ServiceException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.TimeUnit;
+
+
+@Service
+public class RedisService {
+
+	@Autowired
+	private StringRedisTemplate template;
+
+	public void addExpireToken(String loginName,String token,long tokenExpirePeriod)
+	{
+		try
+		{
+			String[] tokens=token.split("\\.");
+			//template.boundValueOps(tokenKey).set(loginName, 10000, TimeUnit.MILLISECONDS);
+			template.opsForValue().set(tokens[1],loginName, tokenExpirePeriod, TimeUnit.MILLISECONDS);
+		}
+		catch(Exception e)
+		{
+			throw new ServiceException("系统故障,请联系服务商");
+		}
+	}
+
+	public void removeExpireToken(String loginName,String token)
+	{
+		try
+		{
+			String[] tokens=token.split("\\.");
+			//template.boundValueOps(tokenKey).set(loginName, 10000, TimeUnit.MILLISECONDS);
+			template.delete(tokens[1]);
+		}
+		catch(Exception e)
+		{
+			throw new ServiceException("系统故障,请联系服务商");
+		}
+	}
+
+	public boolean verifyExpireJwtToken(String loginName,String jwtToken)
+	{
+		try
+		{
+			String[] tokens=jwtToken.split("\\.");
+			//template.boundValueOps(tokenKey).set(loginName, 10000, TimeUnit.MILLISECONDS);
+			return template.hasKey(tokens[1]);
+		}
+		catch(Exception e)
+		{
+			throw new ServiceException("系统故障,请联系服务商");
+		}
+	}
+
+	public boolean verifyExpireCode(String code)
+	{
+		try
+		{
+			//template.boundValueOps(tokenKey).set(loginName, 10000, TimeUnit.MILLISECONDS);
+			return template.hasKey(code);
+		}
+		catch(Exception e)
+		{
+			throw new ServiceException("系统故障,请联系服务商");
+		}
+	}
+
+
+	public void setValue(String key, String value, long expirePeriod){
+		try
+		{
+			template.opsForValue().set(key, value, expirePeriod, TimeUnit.MILLISECONDS);
+		}
+		catch(Exception e)
+		{
+			throw new ServiceException("系统故障,请联系服务商");
+		}
+	}
+
+	public String getValue(String key){
+		try
+		{
+			return template.opsForValue().get(key);
+		}
+		catch(Exception e)
+		{
+			throw new ServiceException("系统故障,请联系服务商");
+		}
+	}
+	public void removeValue(String key){
+		try
+		{
+			template.delete(key);
+		}
+		catch(Exception e)
+		{
+			throw new ServiceException("系统故障,请联系服务商");
+		}
+	}
+
+}

+ 40 - 0
src/main/java/com/zswl/dataservicestarter/service/UserService.java

@@ -0,0 +1,40 @@
+package com.zswl.dataservicestarter.service;
+
+import com.zswl.dataservicestarter.dao.UserDao;
+import com.zswl.dataservicestarter.domain.User;
+import com.zswl.dataservicestarter.utils.AppInfoUtil;
+import com.zswl.dataservicestarter.utils.result.ResultContent;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author TRX
+ * @date 2024/3/20
+ */
+@Slf4j
+@Service
+public class UserService {
+    @Autowired
+    UserDao userDao;
+
+    @Autowired
+    RedisService redisService;
+
+    public ResultContent addUser(String name) {
+        User user = new User();
+        if (StringUtils.isEmpty(name)) {
+            name = "名称";
+        }
+//        name = name + Math.random();
+        user.setName(name);
+        user.setAge(1);
+        user.setAddress("重庆市渝北区");
+        userDao.save(user);
+        int code = user.hashCode();
+        log.info("名称: {} code {} redis: {}", name, code, AppInfoUtil.generateRandomString());
+        return ResultContent.buildSuccess(name + ": " + code);
+    }
+
+}

+ 18 - 0
src/main/java/com/zswl/dataservicestarter/type/AppState.java

@@ -0,0 +1,18 @@
+package com.zswl.dataservicestarter.type;
+
+import lombok.Getter;
+
+/**
+ */
+public enum AppState {
+    Enable("可用"),
+    Disable("不可用"),
+    ;
+
+    @Getter
+    private String remark;
+
+    AppState(String remark) {
+        this.remark = remark;
+    }
+}

+ 23 - 0
src/main/java/com/zswl/dataservicestarter/type/ResultState.java

@@ -0,0 +1,23 @@
+package com.zswl.dataservicestarter.type;
+
+import lombok.Getter;
+
+/**
+ * 结果状态模板
+ */
+public enum ResultState {
+
+    Success("成功"),
+    Fail("失败"),
+    Error("错误"),
+    Exception("异常"),
+
+    ;
+
+    @Getter
+    private String remark;
+
+    ResultState(String remark) {
+        this.remark = remark;
+    }
+}

+ 17 - 0
src/main/java/com/zswl/dataservicestarter/utils/AppInfoUtil.java

@@ -0,0 +1,17 @@
+package com.zswl.dataservicestarter.utils;
+
+import org.apache.commons.lang3.RandomStringUtils;
+
+/**
+ * @author TRX
+ * @date 2024/3/21
+ */
+public class AppInfoUtil {
+    /**
+     * 随机生成一个16位的字符串
+     * @return
+     */
+    public static String generateRandomString() {
+        return RandomStringUtils.randomAlphabetic(16);
+    }
+}

+ 8 - 0
src/main/java/com/zswl/dataservicestarter/utils/ConfigDict.java

@@ -0,0 +1,8 @@
+package com.zswl.dataservicestarter.utils;
+
+public class ConfigDict {
+
+    public static final String redis_issuer = "data-service";
+
+
+}

+ 719 - 0
src/main/java/com/zswl/dataservicestarter/utils/DateUtils.java

@@ -0,0 +1,719 @@
+package com.zswl.dataservicestarter.utils;
+
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import java.sql.Timestamp;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.temporal.WeekFields;
+import java.util.*;
+
+@Slf4j
+public class DateUtils {
+
+    public final static String FORMAT_LONG = "yyyy-MM-dd HH:mm:ss";
+
+    public static Long timeToLong(String time) {
+        return timeToLong(time, FORMAT_LONG);
+    }
+
+
+    public static Long timeToLong(String time, String format) {
+        if (!org.springframework.util.StringUtils.hasText(time)) {
+            return null;
+        }
+        try {
+            return new SimpleDateFormat(format).parse(time).getTime();
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    @SneakyThrows
+    public static Double timeToDouble(String time, String format) {
+        assert format != null;
+
+        Long timestamp = null;
+        if (StringUtils.isNotBlank(time)) {
+            timestamp = new SimpleDateFormat(format).parse(time).getTime();
+        }
+        if (timestamp != null) {
+            return timestamp.doubleValue();
+        }
+        return null;
+    }
+
+    public final static String pattern = "yyyy-MM-dd";
+
+    /**
+     * yyyyMMdd
+     */
+    public final static String pattern1 = "yyyyMMdd";
+
+    public final static String patternStr = "yyyy年MM月dd日";
+
+    public final static String patternyyyyMM = "yyyy-MM";
+
+    public final static String patternyyyyM = "yyyy-M";
+
+    public final static String patternHHmm = "HH:mm";
+
+    public final static String patternyyyyMis = "yyyy-MM-dd HH:mm";
+
+    public static String paresTime(Long time, String pattern) {
+        if (time == null || time <= 0) {
+            return "";
+        }
+        Date date = new Date(time);
+        SimpleDateFormat formatter = new SimpleDateFormat(pattern);
+        return formatter.format(date);
+    }
+
+    /**
+     * 获得本周的第一天,周一
+     *
+     * @return
+     */
+    public static Long getCurrentWeekDayStartTime() {
+        Calendar c = Calendar.getInstance();
+
+        int weekday = c.get(Calendar.DAY_OF_WEEK) - 2;
+        c.add(Calendar.DATE, -weekday);
+
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+
+        return c.getTimeInMillis();
+    }
+
+    /**
+     * 获得上周的第一天,周一
+     *
+     * @return
+     */
+    public static Long getBeforeWeekDayStartTime() {
+        Calendar c = Calendar.getInstance();
+
+        int weekday = c.get(Calendar.DAY_OF_WEEK) - 2 + 7;
+        c.add(Calendar.DATE, -weekday);
+
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+        return c.getTimeInMillis();
+    }
+
+
+    /**
+     * 获得上周的最后一天,周日
+     *
+     * @return
+     */
+    public static Long getBeforeWeekDayEndTime() {
+        Calendar c = Calendar.getInstance();
+
+        int weekday = c.get(Calendar.DAY_OF_WEEK);
+        c.add(Calendar.DATE, 8 - weekday - 7);
+
+        c.set(Calendar.HOUR_OF_DAY, 23);
+        c.set(Calendar.MINUTE, 59);
+        c.set(Calendar.SECOND, 59);
+
+        return c.getTimeInMillis();
+    }
+
+
+    /**
+     * 获得本周的最后一天,周日
+     *
+     * @return
+     */
+    public static Long getCurrentWeekDayEndTime() {
+        Calendar c = Calendar.getInstance();
+
+        int weekday = c.get(Calendar.DAY_OF_WEEK);
+        c.add(Calendar.DATE, 8 - weekday);
+
+        c.set(Calendar.HOUR_OF_DAY, 23);
+        c.set(Calendar.MINUTE, 59);
+        c.set(Calendar.SECOND, 59);
+
+        return c.getTimeInMillis();
+    }
+
+    /**
+     * 获得本天的开始时间
+     *
+     * @return
+     */
+    public static Date getCurrentDayStartTime() {
+        ZoneId zoneId = ZoneId.systemDefault();
+        LocalDateTime date = LocalDateTime.now();
+        LocalDateTime startOfTheDay = LocalDateTime.of(date.toLocalDate(), LocalTime.MIN);
+        Date beginTime = Date.from(startOfTheDay.atZone(zoneId).toInstant());
+        return beginTime;
+    }
+
+    /**
+     * 获得本天的结束时间
+     *
+     * @return
+     */
+    public static Date getCurrentDayEndTime() {
+        ZoneId zoneId = ZoneId.systemDefault();
+        LocalDateTime date = LocalDateTime.now();
+        LocalDateTime startOfTheDay = LocalDateTime.of(date.toLocalDate(), LocalTime.MAX);
+        Date beginTime = Date.from(startOfTheDay.atZone(zoneId).toInstant());
+        return beginTime;
+    }
+
+    /**
+     * 获得本小时的开始时间
+     *
+     * @return
+     */
+    public static Long getCurrentHourStartTime() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        return calendar.getTimeInMillis();
+    }
+
+    /**
+     * 获得本小时的结束时间
+     *
+     * @return
+     */
+    public static Long getCurrentHourEndTime() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.MINUTE, 59);
+        calendar.set(Calendar.SECOND, 59);
+        return calendar.getTimeInMillis();
+    }
+
+
+    /**
+     * 获得本月的开始时间
+     *
+     * @return
+     */
+    public static Long getCurrentMonthStartTime() {
+        Calendar c = Calendar.getInstance();
+
+        c.set(Calendar.DATE, 1);
+
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+
+        return c.getTimeInMillis();
+    }
+
+    /**
+     * 获得上个月的开始时间
+     *
+     * @return
+     */
+    public static Long getBeforeMonthStartTime() {
+        Calendar c = Calendar.getInstance();
+
+        c.add(Calendar.MONTH, -1);
+        c.set(Calendar.DATE, 1);
+
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+
+        return c.getTimeInMillis();
+    }
+
+
+    /**
+     * 本月的结束时间
+     *
+     * @return
+     */
+    public static Long getCurrentMonthEndTime() {
+        Calendar c = Calendar.getInstance();
+
+        c.set(Calendar.DATE, 1);
+        c.add(Calendar.MONTH, 1);
+        c.add(Calendar.DATE, -1);
+
+        c.set(Calendar.HOUR_OF_DAY, 23);
+        c.set(Calendar.MINUTE, 59);
+        c.set(Calendar.SECOND, 59);
+
+        return c.getTimeInMillis();
+    }
+
+    public static Long getBeforeMonthEndTime() {
+        Calendar c = Calendar.getInstance();
+
+        c.set(Calendar.DATE, 1);
+        c.add(Calendar.DATE, -1);
+
+        c.set(Calendar.HOUR_OF_DAY, 23);
+        c.set(Calendar.MINUTE, 59);
+        c.set(Calendar.SECOND, 59);
+        return c.getTimeInMillis();
+    }
+
+    /**
+     * 当前年的开始时间
+     *
+     * @return
+     */
+    public static Long getCurrentYearStartTime() {
+        Calendar c = Calendar.getInstance();
+
+        c.set(Calendar.MONTH, 0);
+        c.set(Calendar.DATE, 1);
+
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+
+        return c.getTimeInMillis();
+    }
+
+    /**
+     * 当前年的结束时间
+     *
+     * @return
+     */
+    public static Long getCurrentYearEndTime() {
+        Calendar c = Calendar.getInstance();
+        Date now = null;
+
+        c.set(Calendar.MONTH, 11);
+        c.set(Calendar.DATE, 31);
+
+        c.set(Calendar.HOUR_OF_DAY, 23);
+        c.set(Calendar.MINUTE, 59);
+        c.set(Calendar.SECOND, 59);
+
+        return c.getTimeInMillis();
+    }
+
+    /**
+     * 当前季度的开始时间
+     *
+     * @return
+     */
+    public static Long getCurrentQuarterStartTime() {
+        Calendar c = Calendar.getInstance();
+        int currentMonth = c.get(Calendar.MONTH) + 1;
+
+        if (currentMonth >= 1 && currentMonth <= 3)
+            c.set(Calendar.MONTH, 0);
+        else if (currentMonth >= 4 && currentMonth <= 6)
+            c.set(Calendar.MONTH, 3);
+        else if (currentMonth >= 7 && currentMonth <= 9)
+            c.set(Calendar.MONTH, 4);
+        else if (currentMonth >= 10 && currentMonth <= 12)
+            c.set(Calendar.MONTH, 9);
+        c.set(Calendar.DATE, 1);
+
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+
+        return c.getTimeInMillis();
+    }
+
+    /**
+     * 当前季度的结束时间
+     *
+     * @return
+     */
+    public static Long getCurrentQuarterEndTime() {
+        Calendar c = Calendar.getInstance();
+        int currentMonth = c.get(Calendar.MONTH) + 1;
+        Date now = null;
+        try {
+            if (currentMonth >= 1 && currentMonth <= 3) {
+                c.set(Calendar.MONTH, 2);
+                c.set(Calendar.DATE, 31);
+            } else if (currentMonth >= 4 && currentMonth <= 6) {
+                c.set(Calendar.MONTH, 5);
+                c.set(Calendar.DATE, 30);
+            } else if (currentMonth >= 7 && currentMonth <= 9) {
+                c.set(Calendar.MONTH, 8);
+                c.set(Calendar.DATE, 30);
+            } else if (currentMonth >= 10 && currentMonth <= 12) {
+                c.set(Calendar.MONTH, 11);
+                c.set(Calendar.DATE, 31);
+            }
+
+            c.set(Calendar.HOUR_OF_DAY, 23);
+            c.set(Calendar.MINUTE, 59);
+            c.set(Calendar.SECOND, 59);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return now.getTime();
+    }
+
+    /**
+     * 获取前/后半年的开始时间
+     *
+     * @return
+     */
+    public static Long getHalfYearStartTime() {
+        Calendar c = Calendar.getInstance();
+        int currentMonth = c.get(Calendar.MONTH) + 1;
+
+        if (currentMonth >= 1 && currentMonth <= 6) {
+            c.set(Calendar.MONTH, 0);
+        } else if (currentMonth >= 7 && currentMonth <= 12) {
+            c.set(Calendar.MONTH, 6);
+        }
+        c.set(Calendar.DATE, 1);
+
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+
+        return c.getTimeInMillis();
+    }
+
+    /**
+     * 获取前/后半年的结束时间
+     *
+     * @return
+     */
+    public static Long getHalfYearEndTime() {
+        Calendar c = Calendar.getInstance();
+        int currentMonth = c.get(Calendar.MONTH) + 1;
+
+        if (currentMonth >= 1 && currentMonth <= 6) {
+            c.set(Calendar.MONTH, 5);
+            c.set(Calendar.DATE, 30);
+        } else if (currentMonth >= 7 && currentMonth <= 12) {
+            c.set(Calendar.MONTH, 11);
+            c.set(Calendar.DATE, 31);
+        }
+
+        c.set(Calendar.HOUR_OF_DAY, 23);
+        c.set(Calendar.MINUTE, 59);
+        c.set(Calendar.SECOND, 59);
+
+        return c.getTimeInMillis();
+    }
+
+    public static Date parseStr2Date(String dateStr) {
+        SimpleDateFormat longSdf = new SimpleDateFormat(FORMAT_LONG);
+        try {
+            return longSdf.parse(dateStr);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public static String getShort2Str(Date date) {
+        if (date == null) {
+            return null;
+        }
+        SimpleDateFormat shortSdf = new SimpleDateFormat(pattern);
+        return shortSdf.format(date);
+    }
+
+
+    /**
+     * 毫秒数转时间
+     *
+     * @return
+     */
+    public static String millsToDuration(long mills) {
+        long dayBal = mills % (86400000);
+        int days = Long.valueOf(mills / 86400000).intValue();
+
+        long hourBal = dayBal % (3600000);
+        int hours = Long.valueOf(dayBal / (3600000)).intValue();
+
+        long minuteBal = hourBal % (60000);
+        int minutes = Long.valueOf(hourBal / (60000)).intValue();
+
+        int seconds = Long.valueOf(Long.valueOf(minuteBal / 1000).intValue()).intValue();
+        String str = "";
+        if (days > 0) {
+            str += days + "天";
+        }
+        if (hours > 0) {
+            str += hours + "小时";
+        }
+        if (minutes > 0) {
+            str += minutes + "分钟";
+        }
+        if (seconds > 0) {
+            str += seconds + "秒";
+        }
+        return str;
+    }
+
+
+    public static Long getDayStartTime(Long timestamp) {
+        ZoneId zoneId = ZoneId.systemDefault();
+        LocalDateTime date = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), zoneId);
+        LocalDateTime startOfTheDay = LocalDateTime.of(date.toLocalDate(), LocalTime.MIN);
+        return Timestamp.valueOf(startOfTheDay).getTime();
+    }
+
+    /**
+     * 获得本天的结束时间
+     *
+     * @return
+     */
+    public static Long getDayEndTime(Long timestamp) {
+        ZoneId zoneId = ZoneId.systemDefault();
+        LocalDateTime date = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), zoneId);
+        LocalDateTime endOfTheDay = LocalDateTime.of(date.toLocalDate(), LocalTime.MAX);
+        return Timestamp.valueOf(endOfTheDay).getTime();
+    }
+
+
+    /**
+     * 获得时间在当年的周数
+     *
+     * @return
+     */
+    public static Integer getWeekOfYear(Long timestamp) {
+        ZoneId zoneId = ZoneId.systemDefault();
+        LocalDateTime date = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), zoneId);
+        // WeekFields.ISO = 一星期从周一开始算, 其它的请自己摸索.
+        WeekFields weekFields = WeekFields.ISO;
+        int weekNumber = date.get(weekFields.weekOfWeekBasedYear());
+        return weekNumber;
+    }
+
+    public static Integer getYearWeekCount(Integer year) {
+        Calendar c = Calendar.getInstance();
+        c.set(Calendar.YEAR, year);
+        c.set(Calendar.MONTH, Calendar.DECEMBER);
+        c.set(Calendar.DATE, 31);
+        Integer weekCount = getWeekOfYear(c.getTimeInMillis());
+        //log.info("多少周:{}",weekCount);
+        return weekCount;
+    }
+
+    public static Long getWeekStartTime(Integer year, Integer week) {
+        Calendar c = new GregorianCalendar();
+        //获得指定年的第几周的开始日期(dayOfWeek是从周日开始排序的)
+        c.setWeekDate(year, week, 2);
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+        //获得Calendar的时间
+        Date starttime = c.getTime();
+        //log.info("{}年第{}周的开始日期为{}" ,year,week,paresTime(starttime.getTime(),FORMAT_LONG));
+        return starttime.getTime();
+    }
+
+    public static Long getWeekEndTime(Integer year, Integer week) {
+        Calendar c = new GregorianCalendar();
+        //获得指定年的第几周的结束日期
+        c.setWeekDate(year, week + 1, 1);
+        c.set(Calendar.HOUR_OF_DAY, 23);
+        c.set(Calendar.MINUTE, 59);
+        c.set(Calendar.SECOND, 59);
+
+        Date endtime = c.getTime();
+        //将时间戳格式化为指定格式
+        //log.info("{}年第{}周的结束日期为{}" ,year,week,paresTime(endtime.getTime(),FORMAT_LONG));
+        return endtime.getTime();
+    }
+
+    /**
+     * 本月的结束时间
+     *
+     * @return
+     */
+    public static Long getMonthStartTime(Integer year, Integer month) {
+        Calendar c = Calendar.getInstance();
+
+        c.set(Calendar.YEAR, year);
+        c.set(Calendar.MONTH, month - 1);
+        c.set(Calendar.DATE, 1);
+
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+
+        return c.getTimeInMillis();
+
+    }
+
+
+    /**
+     * 本月的结束时间
+     *
+     * @return
+     */
+    public static Long getMonthEndTime(Integer year, Integer month) {
+        Calendar c = Calendar.getInstance();
+
+        c.set(Calendar.YEAR, year);
+        c.set(Calendar.MONTH, month - 1);
+        c.add(Calendar.MONTH, 1);
+        c.set(Calendar.DAY_OF_MONTH, 0);
+
+        c.set(Calendar.HOUR_OF_DAY, 23);
+        c.set(Calendar.MINUTE, 59);
+        c.set(Calendar.SECOND, 59);
+        return c.getTimeInMillis();
+    }
+
+
+    /**
+     * 本年的开始时间
+     *
+     * @return
+     */
+    public static Long getYearStartTime(Integer year) {
+        Calendar c = Calendar.getInstance();
+
+        c.set(Calendar.YEAR, year);
+        c.set(Calendar.MONTH, Calendar.JANUARY);
+        c.set(Calendar.DATE, 1);
+
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+
+        return c.getTimeInMillis();
+    }
+
+
+    /**
+     * 本年的开始时间
+     *
+     * @return
+     */
+    public static Long getYearEndTime(Integer year) {
+        Calendar c = Calendar.getInstance();
+
+        c.set(Calendar.YEAR, year);
+        c.set(Calendar.MONTH, Calendar.DECEMBER);
+        c.set(Calendar.DATE, 31);
+
+        c.set(Calendar.HOUR_OF_DAY, 23);
+        c.set(Calendar.MINUTE, 59);
+        c.set(Calendar.SECOND, 59);
+
+        return c.getTimeInMillis();
+    }
+
+    /**
+     * 得到给定时间的 当天开始时间
+     *
+     * @param time
+     * @return
+     */
+    public static Long getDayStart(Long time) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTimeInMillis(time);
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        return calendar.getTimeInMillis();
+    }
+
+    /**
+     * 得到给定时间的 当天最大时间
+     *
+     * @param time
+     * @return
+     */
+    public static Long getDayEnd(Long time) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTimeInMillis(time);
+        calendar.set(Calendar.HOUR_OF_DAY, 23);
+        calendar.set(Calendar.MINUTE, 59);
+        calendar.set(Calendar.SECOND, 59);
+        return calendar.getTimeInMillis();
+    }
+
+    /**
+     * 转换日期为:2023-10-10 00:00:00  再加上天数
+     *
+     * @param time
+     * @param days
+     * @return
+     */
+    public static Calendar getCalendarDayAndDays(Long time, int days) {
+        Calendar calendar = Calendar.getInstance();
+        Date endDate = new Date(time);
+        calendar.setTime(endDate);
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        calendar.add(Calendar.DATE, days);
+        return calendar;
+    }
+
+    /**
+     * 日期加减天数,,中间跳过节假日 (不包括自己)
+     *
+     * @param time
+     * @param days
+     * @param holiday
+     * @return
+     */
+    public static Calendar getCalendarDayAndDays(Long time, int days, List<String> holiday) {
+        if (holiday == null) {
+            holiday = new ArrayList<>();
+        }
+        Calendar calendar = Calendar.getInstance();
+        Date endDate = new Date(time);
+        calendar.setTime(endDate);
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        if (days != 0) {
+            boolean isAdd = true;
+            if (days < 0) {
+                isAdd = false;
+            }
+            int count = Math.abs(days);
+            int sumCount = 0;
+            while (true) {
+                if (isAdd) {
+                    calendar.add(Calendar.DATE, 1);
+                } else {
+                    calendar.add(Calendar.DATE, -1);
+                }
+                String str = DateUtils.paresTime(calendar.getTimeInMillis(), DateUtils.pattern);
+                if (!holiday.contains(str)) {
+                    sumCount++;
+                } else {
+                    log.info("休息日:{}", str);
+                }
+                if (count == sumCount) {
+                    break;
+                }
+            }
+        }
+        return calendar;
+    }
+
+    public static void main(String[] args) {
+        log.info("本年开始时间:{},结束时间:{}", paresTime(getYearStartTime(2023), FORMAT_LONG), paresTime(getYearEndTime(2023), FORMAT_LONG));
+        log.info("本月开始时间:{},结束时间:{}", paresTime(getMonthStartTime(2023, 9), FORMAT_LONG), paresTime(getMonthEndTime(2023, 9), FORMAT_LONG));
+
+        Integer weekNumber = getWeekOfYear(System.currentTimeMillis());
+        log.info("本年一共{}周,本周是第{}周,本周时间区间:{}-{}", getYearWeekCount(2023), weekNumber, paresTime(getWeekStartTime(2023, weekNumber), FORMAT_LONG), paresTime(getWeekEndTime(2023, weekNumber), FORMAT_LONG));
+    }
+}

+ 19 - 0
src/main/java/com/zswl/dataservicestarter/utils/ITree.java

@@ -0,0 +1,19 @@
+package com.zswl.dataservicestarter.utils;
+
+import java.util.List;
+
+/**
+ *
+ */
+public interface ITree<T> {
+    public static final String ROOT_ID = "0";
+
+    public String getId();
+
+    public String getParentId();
+
+    public void setChildren(List<T> tree);
+
+    public List<T> getChildren();
+
+}

+ 45 - 0
src/main/java/com/zswl/dataservicestarter/utils/SecurityUtil.java

@@ -0,0 +1,45 @@
+package com.zswl.dataservicestarter.utils;
+
+import java.math.BigInteger;
+import java.security.MessageDigest;
+
+/**
+ * @author TRX
+ * @date 2024/3/21
+ */
+public class SecurityUtil {
+
+    public static String getMD5Str(String s) {
+        try {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] bytes = md.digest(s.getBytes("utf-8"));
+            return toHex(bytes);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static String toHex(byte[] bytes) {
+        final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();
+        StringBuilder ret = new StringBuilder(bytes.length * 2);
+        for (int i = 0; i < bytes.length; i++) {
+            ret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);
+            ret.append(HEX_DIGITS[bytes[i] & 0x0f]);
+        }
+        return ret.toString();
+    }
+
+    public static String passWord(String password) {
+        password = password + "--";
+        String encryptedPassword = "";
+        try {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] digest = md.digest(password.getBytes());
+            BigInteger no = new BigInteger(1, digest);
+            encryptedPassword = no.toString(16);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return encryptedPassword;
+    }
+}

+ 148 - 0
src/main/java/com/zswl/dataservicestarter/utils/TreeUtil.java

@@ -0,0 +1,148 @@
+package com.zswl.dataservicestarter.utils;
+
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.function.Function;
+
+/**
+ *
+ */
+public class TreeUtil {
+    private static final char[] constCode = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
+
+    public static <T extends ITree> List<T> buildTree(List<T> rows) {
+        return doBuildTree(rows, null);
+    }
+
+    public static <T extends ITree> List<T> buildTree(List<T> list, String parentId) {
+        if (ObjectUtils.isEmpty(list)) {
+            return new ArrayList<>(0);
+        }
+        if (StringUtils.isNotBlank(parentId)) {
+            //如果不是从根节点开始构建树,则需要把构建的父节点加入到树中
+
+            T parent = null;
+            for (T tree : list) {
+                if (tree.getId().equals(parentId)) {
+                    parent = tree;
+                    break;
+                }
+            }
+
+            if (parent != null) {
+                List<T> children = doBuildTree(list, parentId);
+                parent.setChildren(children);
+
+                List<T> ret = new ArrayList<>();
+
+                ret.add(parent);
+                return ret;
+            } else {
+                return doBuildTree(list, parentId);
+            }
+
+        } else {
+            return doBuildTree(list, null);
+        }
+    }
+
+    private static <T extends ITree> List<T> doBuildTree(List<T> list, String parentId) {
+        List<T> ret = null;
+        if (StringUtils.isBlank(parentId)) {
+            parentId = "";
+        }
+        for (T m : list) {
+            if (parentId.equals(m.getParentId())) {
+                if (ret == null) {
+                    ret = new ArrayList<>();
+                }
+                List tempList = doBuildTree(list, m.getId());
+                if (tempList == null || tempList.size() <= 0) {
+                    tempList = null;
+                }
+                m.setChildren(tempList);
+                ret.add(m);
+            }
+        }
+        if (ObjectUtils.isEmpty(ret)) {
+            return new ArrayList<>(0);
+        }
+        return ret;
+    }
+
+
+    public static String createSubCode() {
+        StringBuilder sb = new StringBuilder();
+        Random random = new Random();
+        random.nextInt(constCode.length - 1);
+        sb.append(constCode[random.nextInt(constCode.length)]).append(constCode[random.nextInt(constCode.length)]);
+        return sb.toString();
+    }
+
+
+    /**
+     * 分离部门代码
+     *
+     * @param code
+     * @return
+     */
+    public static List<String> splitCode(String code) {
+        List<String> ret = new ArrayList<>();
+        ret.add(code);
+        while (code != null && code.length() > 2) {
+            code = code.substring(0, code.length() - 2);
+            ret.add(code);
+        }
+
+        return ret;
+    }
+
+//    public static void main(String[] args) {
+//        /*List<String> list = splitCode("aabbccdd");
+//        for(String str : list){
+//            System.out.println(str);
+//        }*/
+//        System.out.println(createSubCode());
+//    }
+
+    public static void main(String[] args) {
+
+//        String accountId = "62e253756c21d410c0e0a0f5";
+////        String[] path =  new String[]{"BIM模型","其他","场布模型"};
+//        String[] parent =  new String[]{"BIM模型","其他","场布模型","场地模型及相关资料"};
+//        final String[] modelPath = new String[parent.length - 1];
+//        System.arraycopy(parent, 0, modelPath, 0, modelPath.length);
+//        System.out.println(DigestUtils.md5Hex(String.format("%s_%s",accountId ,String.join("/", modelPath))));
+
+        List<String> times = List.of("11:22", "次日11:22");
+        times.forEach(time -> {
+            try {
+                if (StringUtils.contains(time, "次日")) {
+                    time = StringUtils.substring(time, 2);
+                    System.out.println("时间=" + time + "   " + (new SimpleDateFormat("HH:mm").parse(time).getTime() + 24 * 60 * 60 * 1000L));
+                } else {
+                    System.out.println("时间=" + time + "   " + new SimpleDateFormat("HH:mm").parse(time).getTime());
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        });
+    }
+
+
+    public static List<? extends ITree> getAllChildren(String id, Function<String, List<? extends ITree>> getByParentId) {
+        List<? extends ITree> children = getByParentId.apply(id);
+        List<ITree> allChildren = new ArrayList<>();
+        children.forEach((child) -> {
+            allChildren.addAll(getAllChildren(child.getId(), getByParentId));
+        });
+        allChildren.addAll(children);
+        return allChildren;
+    }
+}

+ 687 - 0
src/main/java/com/zswl/dataservicestarter/utils/bean/BeanUtil.java

@@ -0,0 +1,687 @@
+package com.zswl.dataservicestarter.utils.bean;
+
+import com.zswl.dataservicestarter.utils.text.CodeCommentUtil;
+import com.zswl.dataservicestarter.utils.text.TextUtil;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.SneakyThrows;
+import org.springframework.beans.BeanWrapper;
+import org.springframework.beans.BeanWrapperImpl;
+import org.springframework.core.StandardReflectionParameterNameDiscoverer;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.beans.BeanInfo;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.*;
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static java.util.Locale.ENGLISH;
+
+/**
+ * Bean工具
+ */
+public class BeanUtil {
+
+    //默认的基础类型的实例化初始值
+    private static final Map<Class, Object> BaseType = new HashMap<>() {
+        {
+            put(int.class, 0);
+            put(long.class, 0l);
+            put(short.class, 0);
+            put(byte.class, 0);
+            put(float.class, 0f);
+            put(double.class, 0d);
+            put(boolean.class, false);
+            put(char.class, "");
+
+            put(Integer.class, 0);
+            put(Long.class, 0l);
+            put(Short.class, 0);
+            put(Byte.class, 0);
+            put(Float.class, 0f);
+            put(Double.class, 0d);
+            put(Boolean.class, false);
+
+            put(BigDecimal.class, 0);
+        }
+    };
+
+    // 参数名发现
+    private final static StandardReflectionParameterNameDiscoverer parameterNameDiscoverer = new StandardReflectionParameterNameDiscoverer();
+
+    /**
+     * javaBean转map
+     *
+     * @param obj
+     * @return
+     * @throws Exception
+     */
+    public static Map<String, Object> bean2Map(Object obj) {
+        Map<String, Object> map = new HashMap<>();
+        if (obj == null) {
+            return map;
+        }
+        try {
+            // 获取javaBean的BeanInfo对象
+            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass(), Object.class);
+            // 获取属性描述器
+            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
+            for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
+                // 获取属性名
+                String key = propertyDescriptor.getName();
+                // 获取该属性的值
+                Method readMethod = propertyDescriptor.getReadMethod();
+                // 通过反射来调用javaBean定义的getName()方法
+                Object value = readMethod.invoke(obj);
+                map.put(key, value);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return map;
+    }
+
+
+    /**
+     * 读取一个bean的类型
+     *
+     * @return
+     */
+    @SneakyThrows
+    public static Map<String, Class> readBeanType(Class<?> cls) {
+        Map<String, Class> ret = new HashMap<>();
+        // 获取javaBean的BeanInfo对象
+        BeanInfo beanInfo = Introspector.getBeanInfo(cls, Object.class);
+        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
+        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
+            ret.put(propertyDescriptor.getName(), propertyDescriptor.getPropertyType());
+        }
+        return ret;
+    }
+
+
+    /**
+     * 通过map设置bean对象
+     *
+     * @param obj
+     * @param map
+     */
+    @SneakyThrows
+    public static void setBean(final Object obj, final Map<String, Object> map) {
+        // 获取javaBean的BeanInfo对象
+        BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass(), Object.class);
+        // 获取属性描述器
+        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
+        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
+            // 获取属性名
+            String key = propertyDescriptor.getName();
+            if (!map.containsKey(key)) {
+                continue;
+            }
+
+
+            // 兼容 @Accessors(chain = true)
+            // 获取该属性的值
+            Method writeMethod = propertyDescriptor.getWriteMethod();
+
+            //如果为空则通过反射取出来
+            if (writeMethod == null) {
+                writeMethod = obj.getClass().getMethod(toMethodName(propertyDescriptor.getName()), propertyDescriptor.getPropertyType());
+            }
+
+            // 通过反射来调用javaBean定义的getName()方法
+            if (writeMethod == null) {
+                continue;
+            }
+
+            //调用方法
+            final Class propertyType = propertyDescriptor.getPropertyType();
+            Object sourceObj = map.get(key);
+            if (sourceObj == null) {
+                continue;
+            }
+
+            //递归类型 ( 当value 为 map)
+            if (propertyType != sourceObj.getClass() && sourceObj instanceof Map) {
+                Object ret = newClass(propertyType);
+                setBean(ret, (Map) sourceObj);
+                writeMethod.invoke(obj, ret);
+            } else if (sourceObj instanceof Collection || sourceObj.getClass().isArray()) {
+                writeMethod.invoke(obj, toTypeFromCollectionObject(propertyType, sourceObj));
+            } else {
+                writeMethod.invoke(obj, sourceObj);
+            }
+        }
+    }
+
+    /**
+     * 转换到目标类型
+     *
+     * @param <T>
+     * @return
+     */
+    private static <T> T toTypeFromCollectionObject(Class<T> targetCls, Object sourceObj) {
+
+        //处理集合类型
+        List items = null;
+        if (sourceObj instanceof Collection) {
+            items = (List) ((Collection) sourceObj).stream().collect(Collectors.toList());
+        } else if (targetCls.isArray()) {
+            items = Arrays.stream((Object[]) sourceObj).collect(Collectors.toList());
+        } else {
+            items = new ArrayList();
+        }
+
+
+        //目标类型
+        if (targetCls.isArray()) {
+            Object ret = Array.newInstance(targetCls.getComponentType(), items.size());
+            for (int i = 0; i < items.size(); i++) {
+                Array.set(ret, i, items.get(i));
+            }
+            return (T) ret;
+        }
+
+
+        if (targetCls == List.class) {
+            return (T) new ArrayList(items);
+        }
+        if (targetCls == Set.class) {
+            return (T) new HashSet<>(items);
+        }
+        if (targetCls == Vector.class) {
+            return (T) new Vector<>(items);
+        }
+//        sourceObj instanceof Map sourceObj instanceof Collections || sourceObj.getClass().isArray()
+
+        return null;
+    }
+
+    /**
+     * 转换到方法名
+     *
+     * @param name
+     * @return
+     */
+    private static String toMethodName(String name) {
+        return "set" + name.substring(0, 1).toUpperCase(ENGLISH) + name.substring(1);
+    }
+
+    /**
+     * Bean转到Map
+     *
+     * @param obj
+     * @return
+     */
+    public static Map<String, Object> toMap(Object obj) {
+        Map<String, Object> m = new HashMap<>();
+        setMap(m, obj);
+        return m;
+    }
+
+
+    @SneakyThrows
+    public static <T> T getBeanValue(Object obj, String name) {
+        // 获取javaBean的BeanInfo对象
+        BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass(), Object.class);
+        // 获取属性描述器
+        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
+        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
+            // 获取属性名
+            String key = propertyDescriptor.getName();
+            if (key.equals(name)) {
+                Method readMethod = propertyDescriptor.getReadMethod();
+                return (T) readMethod.invoke(obj, name);
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * bean转到Map
+     *
+     * @param map
+     * @param obj
+     */
+    @SneakyThrows
+    public static void setMap(final Map<String, Object> map, final Object obj) {
+        //如果对象为Map,直接拷贝到目标Map中
+        if (obj instanceof Map) {
+            map.putAll((Map) obj);
+            return;
+        }
+        // 获取javaBean的BeanInfo对象
+        BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass(), Object.class);
+        // 获取属性描述器
+        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
+        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
+            // 获取属性名
+            String key = propertyDescriptor.getName();
+            Method readMethod = propertyDescriptor.getReadMethod();
+            map.put(key, readMethod.invoke(obj));
+        }
+    }
+
+
+    /**
+     * 获取bean对象中为null的属性名
+     *
+     * @param source
+     * @return
+     */
+    public static void getNullPropertyNames(Object source, Set<String> sets) {
+        final BeanWrapper src = new BeanWrapperImpl(source);
+        PropertyDescriptor[] pds = src.getPropertyDescriptors();
+        for (PropertyDescriptor pd : pds) {
+            Object srcValue = src.getPropertyValue(pd.getName());
+            if (srcValue == null) sets.add(pd.getName());
+        }
+    }
+
+
+    /**
+     * 构建Bean对象
+     *
+     * @param cls
+     * @param componentType
+     * @param <T>
+     * @return
+     */
+    @SneakyThrows
+    private static <T> T buildBean(final Class<T> cls, final Class componentType, int currentDepth,
+                                   int maxDepthCount) {
+        //集合对象
+        Object items = null;
+        //单独的属性
+        Object item = null;
+        //处理数组与集合
+        if (cls.isArray()) {
+            items = Array.newInstance(componentType, 1);
+            item = newClass(componentType);
+            Array.set(items, 0, item);
+        } else if (Collection.class.isAssignableFrom(cls)) {
+            item = newClass(componentType);
+            if (cls == Collection.class) {
+                items = List.of(item);
+            } else {
+                //取出ofMethod 的方法
+                Method ofMethod = cls.getDeclaredMethod("of", Object.class);
+                if (ofMethod != null) {
+                    ofMethod.setAccessible(true);
+                    items = ofMethod.invoke(null, item);
+                }
+            }
+        } else if (Map.class.isAssignableFrom(cls)) {
+            items = new HashMap<>();
+        } else {
+            item = newClass(cls);
+        }
+
+        //深度执行 , 过滤基础类型与字符串类型
+        if (item != null && !(item instanceof String) && currentDepth < maxDepthCount && item.getClass() != Object.class && !item.getClass().isEnum()) {
+            depthSetBean(item, ++currentDepth, maxDepthCount);
+        }
+        //集合对象不为空则返回集合对象,否则返回单个的对象
+        return (T) (items != null ? items : item);
+    }
+
+
+    /**
+     * 获取方法上的参数名
+     *
+     * @param method
+     * @return
+     */
+    public static String[] getParameterNames(Method method) {
+        return parameterNameDiscoverer.getParameterNames(method);
+    }
+
+    /**
+     * 取方法名上的参数名,优先遵循是 RequestParam 注解
+     *
+     * @param method
+     * @param index
+     * @return
+     */
+    public static String getMethodParamName(Method method, final int index) {
+        String[] paramNames = getParameterNames(method);
+        //读取参数名,优先读取注解上的参数名
+        String paramName = null;
+        Annotation[] parameterAnnotations = method.getParameterAnnotations()[index];
+        for (Annotation parameterAnnotation : parameterAnnotations) {
+            if (parameterAnnotation instanceof RequestParam) {
+                RequestParam requestParam = (RequestParam) parameterAnnotation;
+                return requestParam.value();
+            }
+        }
+        if (paramName == null) {
+            paramName = paramNames[index];
+        }
+
+        return paramName;
+    }
+
+
+    /**
+     * 取出controller的方法的所有属性以及类型
+     *
+     * @param method
+     * @return
+     */
+    public static Map<String, BeanValueInfo> getControllerMethodParmaInfo(final Method method,
+                                                                          final int maxDepthCount) {
+        Map<String, String> fieldComment = new HashMap<>();
+        CodeCommentUtil.readMethodComment(method, fieldComment);
+        //当前深度
+        Map<String, BeanValueInfo> ret = new HashMap<>();
+        for (int i = 0; i < method.getParameterTypes().length; i++) {
+            String paramName = getMethodParamName(method, i);
+            Class paramType = method.getParameterTypes()[i];
+
+            //深度设置参数值
+            setDepthParmaInfo(ret, null, paramName, paramType, fieldComment.get(paramName), 0, maxDepthCount);
+        }
+        return ret;
+    }
+
+
+    /**
+     * 深度设置参数或bean的值
+     *
+     * @param ret
+     * @param spaceName
+     * @param paramName
+     * @param paramType
+     * @param currentDepthCount
+     * @param maxDepthCount
+     */
+    @SneakyThrows
+    private static void setDepthParmaInfo(final Map<String, BeanValueInfo> ret, final String spaceName,
+                                          final String paramName, final Class paramType, final String fieldCommentText, int currentDepthCount,
+                                          int maxDepthCount) {
+        //参数类型的名称
+        String paramTypeName = paramType.getName();
+
+        if (paramType == Class.class) {
+            //过滤不处理
+        } else if (BaseType.containsKey(paramType)) {
+            //基础类型
+            setBeanMapItem(ret, spaceName, paramName, fieldCommentText, BaseType.get(paramType));
+        } else if (paramType == String.class) {
+            //字符串
+            setBeanMapItem(ret, spaceName, paramName, fieldCommentText, new String());
+        } else if (paramType.isEnum()) {
+            //枚举类
+            String value = TextUtil.join(Arrays.stream(paramType.getFields()).map((it) -> {
+                it.setAccessible(true);
+                return it.getName();
+            }).collect(Collectors.toList()).toArray(new String[0]), ",");
+            setBeanMapItem(ret, spaceName, paramName, fieldCommentText, value);
+        } else if (paramTypeName.equals("org.springframework.data.domain.Pageable")) {
+            //分页模型
+            setBeanMapItem(ret, spaceName, "page", "分页查询: 当前页码,第一页为0", 0);
+            setBeanMapItem(ret, spaceName, "size", "分页查询: 每页显示数量", 10);
+            setBeanMapItem(ret, spaceName, "sort", "分页查询: 排序", "createTime,desc");
+        } else if (paramType.isArray() || Collection.class.isAssignableFrom(paramType)) {
+            //数组或集合
+            setBeanMapItem(ret, spaceName, paramName, fieldCommentText, "test1,test2");
+        } else if (Map.class.isAssignableFrom(paramType)) {
+            //处理Map
+            setBeanMapItem(ret, spaceName, paramName + "['key']", fieldCommentText, "test");
+        } else if (paramType.isInterface() || Modifier.isAbstract(paramType.getModifiers())) {
+            //不处理接口或抽象类
+        } else if (currentDepthCount < maxDepthCount) {
+            //自定义类型的处理,必须保证有至少一个默认的构造方法
+            int depthCount = ++currentDepthCount;
+            //当前对象的命名空间
+            final String objSpaceName = StringUtils.hasText(spaceName) ? spaceName + "." + paramName : paramName;
+            try {
+                //遍历所有属性
+                final BeanWrapper src = new BeanWrapperImpl(paramType);
+                PropertyDescriptor[] pds = src.getPropertyDescriptors();
+                for (PropertyDescriptor pd : pds) {
+                    Class beanType = pd.getPropertyType();
+                    if (beanType == Class.class) {
+                        continue;
+                    }
+                    String beanName = pd.getName();
+                    //深度识别类型
+                    setDepthParmaInfo(ret, objSpaceName, beanName, beanType, getFieldCommentText(paramType, beanName), depthCount, maxDepthCount);
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+    }
+
+    /**
+     * 设置BeanMap的项
+     *
+     * @param ret
+     * @param spaceName
+     * @param itemKey
+     * @param fieldCommentText
+     * @param value
+     */
+    private static void setBeanMapItem(final Map<String, BeanValueInfo> ret, final String spaceName,
+                                       final String itemKey, String fieldCommentText, Object value) {
+        String key = getItemKeyName(spaceName, itemKey);
+        if (StringUtils.hasText(key)) {
+            ret.put(key, new BeanValueInfo(key, fieldCommentText, value));
+        }
+    }
+
+    /**
+     * 获取项目的key
+     *
+     * @param spaceName
+     * @param itemKey
+     * @return
+     */
+    private static String getItemKeyName(String spaceName, String itemKey) {
+        String ret = StringUtils.hasText(spaceName) && StringUtils.hasText(itemKey) ? spaceName + "." + itemKey : itemKey;
+        if (ret.indexOf(".") < 0) {
+            return ret;
+        }
+        //根据spring controller的规则,如果有多级对象,则去掉首个
+        String[] items = ret.split("\\.");
+        if (items.length > 1) {
+            String[] newItems = new String[items.length - 1];
+            System.arraycopy(items, 1, newItems, 0, newItems.length);
+            ret = TextUtil.join(newItems, ".");
+        }
+        return ret;
+    }
+
+
+    /**
+     * 参数信息
+     */
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class BeanValueInfo {
+
+        //名称
+        private String name;
+
+        //类型
+        private String commentText;
+
+        //值
+        private Object value;
+
+//        //方法
+//        private String commentText;
+//
+//        //参数注释
+//        private Map<String,String> paramCommentText;
+
+    }
+
+
+    /**
+     * 构建bean,支持深度遍历构建
+     *
+     * @param cls
+     * @param <T>
+     * @return
+     */
+    public static <T> T buildBean(Class<T> cls, int maxDepthCount) {
+        return buildBean(cls, cls.getComponentType(), 0, maxDepthCount);
+    }
+
+
+    /**
+     * 通过属性构建bean对象
+     *
+     * @param field
+     * @param <T>
+     * @return
+     */
+    private static <T> T buildBean(Field field, int currentDepth, int maxDepthCount) {
+        Class type = field.getType();
+        Class[] cls = getGenericType(field);
+        Object ret = buildBean(type, (cls != null && cls.length > 0) ? cls[0] : type.getComponentType(), currentDepth, maxDepthCount);
+        return ret == null ? null : (T) ret;
+    }
+
+
+    /**
+     * 实例化对象
+     *
+     * @param cls
+     */
+    @SneakyThrows
+    public static <T> T newClass(Class<T> cls) {
+        //基础类型,则直接返回null
+        Object val = BaseType.get(cls);
+        if (val != null) {
+            return (T) val;
+        }
+        //枚举类
+        if (cls.isEnum()) {
+            return (T) cls.getFields()[0].get(null);
+        }
+
+        // 数组与集合
+        if (cls.isArray()) {
+            return (T) Array.newInstance(cls, 0);
+        } else if (cls == List.class) {
+            return (T) new ArrayList();
+        } else if (cls == Set.class) {
+            return (T) new HashSet<>();
+        } else if (cls == Map.class) {
+            return (T) new HashMap<>();
+        }
+
+
+        Constructor<?> newConstructor = null;
+        //遍历出所有的构造方法
+        for (Constructor<?> constructor : cls.getDeclaredConstructors()) {
+            if (constructor.getParameterCount() == 0) {
+                newConstructor = constructor;
+                break;
+            }
+        }
+        Assert.notNull(newConstructor, "未找到可用的构造方法 : " + cls);
+        return (T) newConstructor.newInstance();
+    }
+
+
+    /**
+     * 获取枚举类的class
+     *
+     * @param field
+     * @return
+     */
+    public static Class[] getGenericType(Field field) {
+        Type genericType = field.getGenericType();
+        if (null == genericType) {
+            return null;
+        }
+        if (genericType instanceof ParameterizedType) {
+            ParameterizedType pt = (ParameterizedType) genericType;
+            // 得到泛型里的class类型对象
+            return Arrays.stream(pt.getActualTypeArguments()).map((it) -> {
+                return (Class) it;
+            }).collect(Collectors.toList()).toArray(new Class[0]);
+        }
+        return null;
+    }
+
+    /**
+     * 深度设置Bean的默认值,调用Set方法进行赋值
+     *
+     * @param item
+     */
+    @SneakyThrows
+    private static <T> void depthSetBean(Object item, int currentDepth, int maxDepthCount) {
+        // 获取javaBean的BeanInfo对象
+        BeanInfo beanInfo = Introspector.getBeanInfo(item.getClass(), Object.class);
+        // 获取属性描述器
+        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
+        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
+            String name = propertyDescriptor.getName();
+            //属性
+            Field field = getField(item.getClass(), name);
+            if (field == null) {
+                continue;
+            }
+            // 根据类型进行构建Bean
+            Object val = buildBean(field, currentDepth, maxDepthCount);
+            if (val != null) {
+                // 获取该属性的值
+                Method readMethod = propertyDescriptor.getWriteMethod();
+                // 通过反射来调用javaBean定义的getName()方法
+                readMethod.invoke(item, val);
+            }
+        }
+    }
+
+
+    /**
+     * 获取class的属性
+     *
+     * @param cls
+     * @param fieldName
+     * @return
+     */
+    @SneakyThrows
+    private static Field getField(Class cls, String fieldName) {
+        for (Field field : cls.getDeclaredFields()) {
+            if (field.getName().equals(fieldName)) {
+                field.setAccessible(true);
+                return field;
+            }
+        }
+        Field field = null;
+        if (cls.getSuperclass() != null) {
+            field = getField(cls.getSuperclass(), fieldName);
+        }
+        return field;
+    }
+
+    /**
+     * 读取属性上面的注释
+     *
+     * @param cls
+     * @param fieldName
+     * @return
+     */
+    @SneakyThrows
+    private static String getFieldCommentText(Class cls, String fieldName) {
+        return CodeCommentUtil.readFieldComment(getField(cls, fieldName));
+    }
+
+
+}

+ 216 - 0
src/main/java/com/zswl/dataservicestarter/utils/bean/EntityObjectUtil.java

@@ -0,0 +1,216 @@
+package com.zswl.dataservicestarter.utils.bean;
+
+
+import com.zswl.dataservicestarter.domain.SuperEntity;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Update;
+
+import java.util.*;
+
+/**
+ * 实体工具类
+ */
+public class EntityObjectUtil {
+
+    /**
+     * 保存之前执行
+     *
+     * @param superEntity
+     */
+    public static void preInsert(SuperEntity superEntity) {
+        superEntity.setId(null);
+        superEntity.setCreateTime(getTime());
+        superEntity.setUpdateTime(getTime());
+    }
+
+    /**
+     * 更新之前执行
+     *
+     * @param superEntity
+     * @return
+     */
+    public static void preUpdate(SuperEntity superEntity) {
+        superEntity.setUpdateTime(getTime());
+    }
+
+    /**
+     * 更新之前
+     *
+     * @param update
+     */
+    public static void preUpdate(Update update) {
+        update.set("updateTime", getTime());
+    }
+
+    /**
+     * 创建查询_批量
+     *
+     * @param fieldName
+     * @param values
+     * @return
+     */
+    public static Criteria createQueryBatch(String fieldName, String... values) {
+        if (values == null || values.length < 1) {
+            return null;
+        }
+        List<Criteria> wheres = new ArrayList<Criteria>();
+        for (String value : values) {
+            Criteria where = Criteria.where(fieldName).is(value);
+            wheres.add(where);
+        }
+        return new Criteria().orOperator(wheres.toArray(new Criteria[wheres.size()]));
+    }
+
+    /**
+     * 创建批量查询
+     *
+     * @param items
+     * @return
+     */
+    public static Criteria createQueryBatch(Collection<Map<String, Object>> items) {
+        final Set<Criteria> criteriaSet = new HashSet<>();
+        items.stream().map((map) -> {
+            return map.entrySet();
+        }).forEach((entry) -> {
+            Criteria criteria = new Criteria();
+            entry.forEach((it) -> {
+                criteria.and(it.getKey()).is(it.getValue());
+            });
+            criteriaSet.add(criteria);
+        });
+        return new Criteria().orOperator(criteriaSet.toArray(new Criteria[0]));
+    }
+
+
+    /**
+     * 创建查询_批量
+     *
+     * @param fieldName
+     * @param values
+     * @return
+     */
+    public static Criteria createQueryBatch(String fieldName, Object[] values) {
+        if (values == null || values.length < 1) {
+            return null;
+        }
+        List<Criteria> wheres = new ArrayList<Criteria>();
+        for (Object value : values) {
+            Criteria where = Criteria.where(fieldName).is(value);
+            wheres.add(where);
+        }
+        return new Criteria().orOperator(wheres.toArray(new Criteria[wheres.size()]));
+    }
+
+    /**
+     * 取出时间
+     *
+     * @return
+     */
+    public static long getTime() {
+        return System.currentTimeMillis();
+    }
+
+
+    /**
+     * 实体到更新模型
+     *
+     * @param entity
+     * @param update
+     * @param ignore
+     */
+    public static void entity2Update(Object entity, Update update, String... ignore) {
+        Set<String> ignoreSet = null;
+        if (ignore != null) {
+            ignoreSet = new HashSet<>(Arrays.asList(ignore));
+        }
+        entity2Update(entity, entity.getClass(), update, ignoreSet);
+    }
+
+    /**
+     * 实体判断是否为null,非null并设置到update中的修改
+     *
+     * @param entity
+     * @param update
+     */
+    public static void entity2Update(Object entity, Update update, Set<String> ignore) {
+        entity2Update(entity, entity.getClass(), update, ignore);
+    }
+
+    /**
+     * 实体判断是否为null,非null并设置到update中的修改
+     *
+     * @param entity
+     * @param update
+     */
+    public static void entity2Update(Object entity, Update update) {
+        entity2Update(entity, entity.getClass(), update, null);
+    }
+
+    private static void entity2Update(Object entity, Class<?> meClass, Update update, Set<String> ignore) {
+        Map<String, Object> m = BeanUtil.bean2Map(entity);
+        m.entrySet().forEach((it) -> {
+            //没有value则不更新
+            if (it.getValue() == null) {
+                return;
+            }
+            //忽略列表
+            if (ignore == null) {
+                update.set(it.getKey(), it.getValue());
+            } else if (!ignore.contains(it.getKey())) {
+                update.set(it.getKey(), it.getValue());
+            }
+        });
+
+    }
+
+
+    public static Criteria buildCriteria(Criteria criteria, Object source, CriteriaType type, String... items) {
+        if (source == null) {
+            return null;
+        }
+        if (items == null || items.length == 0) {
+            return criteria;
+        }
+        Map<String, Object> objMap = BeanUtil.bean2Map(source);
+        for (String key : items) {
+            //取出value
+            Object value = objMap.get(key);
+            if (value == null) {
+                continue;
+            }
+            criteria = criteria.and(key);
+            switch (type) {
+                case Is:
+                    criteria = criteria.is(value);
+                    break;
+                case Like:
+                    criteria = criteria.regex(String.valueOf(value));
+                    break;
+                case In:
+                    criteria = criteria.in(value);
+                    break;
+            }
+        }
+        return criteria;
+    }
+
+    /**
+     * 条件
+     */
+    public static enum CriteriaType {
+        /**
+         * 模糊查询
+         */
+        Like,
+        /**
+         * 精准查询
+         */
+        Is,
+        /**
+         * 集合查询
+         */
+        In
+    }
+
+
+}

+ 19 - 0
src/main/java/com/zswl/dataservicestarter/utils/exception/BusinessException.java

@@ -0,0 +1,19 @@
+package com.zswl.dataservicestarter.utils.exception;
+
+/**
+ * 统一业务异常
+ */
+public class BusinessException extends RuntimeException{
+
+    public BusinessException(){}
+
+    public BusinessException(String message)
+    {
+        super(message);
+    }
+
+    public BusinessException(String message, Throwable throwable)
+    {
+        super(message,throwable);
+    }
+}

+ 19 - 0
src/main/java/com/zswl/dataservicestarter/utils/exception/ServiceException.java

@@ -0,0 +1,19 @@
+package com.zswl.dataservicestarter.utils.exception;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+@Setter
+@Getter
+@AllArgsConstructor
+@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) //, reason = ""
+public class ServiceException extends RuntimeException{
+
+	private static final long serialVersionUID = 552192089988571466L;
+
+	private String message;
+
+}

+ 21 - 0
src/main/java/com/zswl/dataservicestarter/utils/exception/UnauthorizedException.java

@@ -0,0 +1,21 @@
+package com.zswl.dataservicestarter.utils.exception;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+@Setter
+@Getter
+@AllArgsConstructor
+@ResponseStatus(value = HttpStatus.UNAUTHORIZED) //, reason = ""
+public class UnauthorizedException extends RuntimeException{
+
+	private static final long serialVersionUID = 7227904251082562156L;
+
+	private String message;
+
+	public UnauthorizedException(){}
+
+}

+ 36 - 0
src/main/java/com/zswl/dataservicestarter/utils/os/SystemUtil.java

@@ -0,0 +1,36 @@
+package com.zswl.dataservicestarter.utils.os;
+
+/**
+ * 系统工具
+ */
+public class SystemUtil {
+
+
+    /**
+     * 是否linux系统
+     *
+     * @return
+     */
+    public static boolean isLinux() {
+        return System.getProperty("os.name").toLowerCase().contains("linux");
+    }
+
+    /**
+     * 是否windows系统
+     *
+     * @return
+     */
+    public static boolean isWindows() {
+        return System.getProperty("os.name").toLowerCase().contains("windows");
+    }
+
+    /**
+     * 获取CPu核心数
+     *
+     * @return
+     */
+    public static int getCpuCoreCount() {
+        return Runtime.getRuntime().availableProcessors();
+    }
+
+}

+ 237 - 0
src/main/java/com/zswl/dataservicestarter/utils/page/PageEntityUtil.java

@@ -0,0 +1,237 @@
+package com.zswl.dataservicestarter.utils.page;
+
+import lombok.Cleanup;
+import lombok.SneakyThrows;
+import org.springframework.beans.BeanUtils;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
+
+/**
+ *
+ */
+public class PageEntityUtil {
+
+
+    /**
+     * 线程数
+     */
+    private final static int threadCount = Runtime.getRuntime().availableProcessors() * 2;
+
+
+    /**
+     * 集合转换
+     *
+     * @param collections
+     * @param <S>
+     * @param <T>
+     * @return
+     */
+    public static <S, T> Map<S, T> concurrentCollection(Collection<S> collections, DataClean<S, T> dataClean) {
+        return concurrentCollection(collections, dataClean, threadCount);
+    }
+
+    /**
+     * 集合转换
+     *
+     * @param collections
+     * @param <S>
+     * @param <T>
+     * @return
+     */
+    @SneakyThrows
+    public static <S, T> Map<S, T> concurrentCollection(Collection<S> collections, DataClean<S, T> dataClean, int threadCountSize) {
+        Map<S, T> contents = new ConcurrentHashMap<>();
+        @Cleanup("shutdownNow") ExecutorService executorService = Executors.newFixedThreadPool(threadCountSize);
+        CountDownLatch countDownLatch = new CountDownLatch(collections.size());
+        collections.forEach((it) -> {
+            executorService.execute(() -> {
+                try {
+                    contents.put(it, dataClean.execute(it));
+                } catch (Exception e) {
+                    e.printStackTrace();
+                } finally {
+                    countDownLatch.countDown();
+                }
+            });
+        });
+
+        countDownLatch.await();
+
+
+        return contents;
+    }
+
+
+    /**
+     * 并行分页模型转换
+     *
+     * @param pages
+     * @param dataClean
+     * @param threadCountSize
+     * @param <S>
+     * @param <T>
+     * @return
+     */
+    @SneakyThrows
+    @Deprecated
+    public static <S, T> Page<T> concurrent2PageModel(Page<S> pages, DataClean<S, T> dataClean, int threadCountSize) {
+        //数据源
+        List<S> sources = pages.getContent();
+        if (sources == null) {
+            return new PageImpl<T>(new ArrayList<>(), PageRequest.of(pages.getNumber(), pages.getSize(), pages.getSort()), pages.getTotalElements());
+        }
+
+        //容器,保留序号与数据
+        Map<Integer, S> sourcesContents = new ConcurrentHashMap<>();
+        for (int i = 0; i < sources.size(); i++) {
+            sourcesContents.put(i, sources.get(i));
+        }
+
+        //目标容器
+        Map<Integer, T> newContents = new ConcurrentHashMap<>();
+
+        //线程池与计数器
+        @Cleanup("shutdownNow") ExecutorService executorService = Executors.newFixedThreadPool(threadCountSize);
+        CountDownLatch countDownLatch = new CountDownLatch(sourcesContents.size());
+
+        //进行线程并发
+        sourcesContents.entrySet().forEach((it) -> {
+            executorService.execute(() -> {
+                try {
+                    newContents.put(it.getKey(), dataClean.execute(it.getValue()));
+                } catch (Exception e) {
+                    e.printStackTrace();
+                } finally {
+                    countDownLatch.countDown();
+                }
+            });
+        });
+        //阻塞多线直到结束
+        countDownLatch.await();
+
+        //转换为新的集合,且保证顺序
+        List<T> newList = new ArrayList<>();
+        for (int i = 0; i < newContents.entrySet().size(); i++) {
+            newList.add(newContents.get(i));
+        }
+
+        //转换模型
+        return new PageImpl<T>(newList, PageRequest.of(pages.getNumber(), pages.getSize(), pages.getSort()), pages.getTotalElements());
+    }
+
+    /**
+     * 并行分页模型转换
+     *
+     * @param pages
+     * @param dataClean
+     * @param <S>
+     * @param <T>
+     * @return
+     */
+    public static <S, T> Page<T> concurrent2PageModel(Page<S> pages, DataClean<S, T> dataClean) {
+        List<T> result = pages.getContent().parallelStream().map((it) -> {
+            return dataClean.execute(it);
+        }).collect(Collectors.toList());
+        return new PageImpl<T>(result, PageRequest.of(pages.getNumber(), pages.getSize(), pages.getSort()), pages.getTotalElements());
+    }
+
+
+    /**
+     * 转换到模型
+     *
+     * @param pages
+     * @return
+     */
+    public static <S, T> Page<T> toPageModel(Page<S> pages, DataClean<S, T> dataClean) {
+        List<T> result = pages.stream().map((it) -> {
+            return dataClean.execute(it);
+        }).collect(Collectors.toList());
+        //转换模型
+        return new PageImpl<T>(result, PageRequest.of(pages.getNumber(), pages.getSize(), pages.getSort()), pages.getTotalElements());
+    }
+
+
+    /**
+     * 数据处理
+     *
+     * @param <S>
+     * @param <T>
+     */
+    @FunctionalInterface
+    public interface DataClean<S, T> {
+
+        /**
+         * 数据处理
+         *
+         * @param data
+         * @return
+         */
+        T execute(S data);
+    }
+
+
+    /**
+     * 转换到模型
+     *
+     * @param pages
+     * @return
+     */
+    public static <S, T> Page<T> toPageModel(Page<S> pages, Class<T> cls) {
+        return toPageModel(pages, new DataClean<S, T>() {
+
+            @Override
+            public T execute(S data) {
+                try {
+                    Object o = cls.getDeclaredConstructor().newInstance();
+                    BeanUtils.copyProperties(data, o);
+                    return (T) o;
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+                return null;
+            }
+        });
+    }
+
+    /**
+     * 构建一个空分页对象
+     *
+     * @param pageable
+     * @return
+     */
+    public static Page buildEmptyPage(Pageable pageable) {
+        return new PageImpl<>(new ArrayList<>(), pageable, 0);
+    }
+
+    /**
+     * 构建一个空分页对象
+     *
+     * @return
+     */
+    public static Page buildEmptyPage() {
+        return new PageImpl<>(new ArrayList<>());
+    }
+
+
+    /**
+     * 构建一个空分页对象
+     *
+     * @return
+     */
+    public static <T> Page<T> buildPage(List<T> content, Pageable pageable, long total) {
+        return new PageImpl<T>(content, pageable, total);
+    }
+
+}

+ 36 - 0
src/main/java/com/zswl/dataservicestarter/utils/path/PathUtil.java

@@ -0,0 +1,36 @@
+package com.zswl.dataservicestarter.utils.path;
+
+
+import com.zswl.dataservicestarter.utils.text.TextUtil;
+
+public class PathUtil {
+
+
+    /**
+     * 取路径的父类
+     *
+     * @param path
+     * @param split
+     * @return
+     */
+    public static String getParent(String path, String split) {
+        String[] sources = path.split(split);
+        String[] newPath = new String[sources.length - 1];
+        System.arraycopy(sources, 0, newPath, 0, newPath.length);
+        return TextUtil.join(newPath, split);
+    }
+
+
+    /**
+     * 获取当前名称
+     *
+     * @param path
+     * @param split
+     * @return
+     */
+    public static String getName(String path, String split) {
+        String[] sources = path.split(split);
+        return sources[sources.length - 1];
+    }
+
+}

+ 108 - 0
src/main/java/com/zswl/dataservicestarter/utils/result/ResultContent.java

@@ -0,0 +1,108 @@
+package com.zswl.dataservicestarter.utils.result;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.zswl.dataservicestarter.type.ResultState;
+import lombok.*;
+
+import java.util.Optional;
+import java.util.function.Consumer;
+
+/**
+ * 结果
+ *
+ * @param <T>
+ */
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@ToString(callSuper = true)
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ResultContent<T> {
+
+    //内容
+    @Getter
+    @Setter
+    private T content;
+
+    //状态
+    @Getter
+    @Setter
+    private ResultState state;
+
+    //文本
+    @Getter
+    @Setter
+    private String msg;
+
+
+    /**
+     * 获取内容
+     *
+     * @return
+     */
+    public Optional<T> optionalContent() {
+        return Optional.ofNullable(this.content);
+    }
+
+    public static <T> ResultContent build(ResultState state, T content) {
+        return ResultContent.builder().state(state).content(content).msg(state.getRemark()).build();
+    }
+
+    public static <T> ResultContent build(ResultState state, T content, String msg) {
+        return ResultContent.builder().state(state).content(content).msg(msg).build();
+    }
+
+    public static <T> ResultContent build(ResultState state, String msg) {
+        return ResultContent.builder().state(state).msg(msg).build();
+    }
+
+    public static <T> ResultContent build(boolean bool) {
+        return build(bool ? ResultState.Success : ResultState.Fail, null);
+    }
+
+    public static <T> ResultContent buildFail(String msg) {
+        return ResultContent.builder().state(ResultState.Fail).msg(msg).build();
+    }
+
+    public static <T> ResultContent buildSuccess(String msg) {
+        return build(ResultState.Success, msg);
+    }
+
+    public static <T> ResultContent buildSuccess(T content) {
+        return build(ResultState.Success, content);
+    }
+
+    public static <T> ResultContent buildSuccess() {
+        return build(ResultState.Success, ResultState.Success.getRemark());
+    }
+
+    public static <T> ResultContent build(ResultState state) {
+        return build(state, state.getRemark());
+    }
+
+    public static <T> ResultContent buildContent(T content) {
+        return build(content == null ? ResultState.Fail : ResultState.Success, content);
+    }
+
+    public void ifSuccess(Consumer<? super T> action) {
+        if (isSuccess() && content != null) {
+            action.accept(content);
+        }
+    }
+
+    public void ifSucessOrElse(Consumer<? super T> action, Runnable emptyAction) {
+        if (isSuccess() && content != null) {
+            action.accept(content);
+        } else {
+            emptyAction.run();
+        }
+    }
+
+    public boolean isSuccess() {
+        return ResultState.Success.equals(this.state);
+    }
+
+    public boolean isFailed() {
+        return !ResultState.Success.equals(this.state);
+    }
+}

+ 204 - 0
src/main/java/com/zswl/dataservicestarter/utils/text/CodeCommentUtil.java

@@ -0,0 +1,204 @@
+package com.zswl.dataservicestarter.utils.text;
+
+import com.github.javaparser.JavaParser;
+import com.github.javaparser.ParseResult;
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.body.VariableDeclarator;
+import com.github.javaparser.ast.comments.Comment;
+import com.github.javaparser.ast.expr.SimpleName;
+import com.zswl.dataservicestarter.utils.path.PathUtil;
+import lombok.SneakyThrows;
+import org.springframework.util.StringUtils;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 代码注释工具类
+ */
+public class CodeCommentUtil {
+
+    private final static String ParamText = "@param";
+
+
+    @SneakyThrows
+    public static String readFieldComment(Field field) {
+        if (field == null) {
+            return null;
+        }
+        File sourceFile = toSourceFile(field.getDeclaringClass());
+        if (sourceFile == null) {
+            return null;
+        }
+        //用于存放方法上面的注释
+        String[] fieldComments = new String[1];
+        //取方法名
+        final String fieldName = field.getName();
+        JavaParser javaParser = new JavaParser();
+        ParseResult<CompilationUnit> result = javaParser.parse(sourceFile);
+        result.getResult().ifPresent((it) -> {
+            for (Comment comment : it.getAllContainedComments()) {
+                comment.getCommentedNode().ifPresent((node) -> {
+
+                    //取出方法注释
+                    String[] commentText = new String[1];
+                    node.getComment().ifPresent((comm) -> {
+                        commentText[0] = comm.getContent();
+                    });
+
+                    //过滤节点类型,,取属性名的子节点
+                    List<Node> codeNodes = node.getChildNodes().stream().filter((childNode) -> {
+                        return childNode instanceof VariableDeclarator;
+                    }).collect(Collectors.toList());
+                    if (codeNodes == null || codeNodes.size() == 0) {
+                        return;
+                    }
+                    //取出代码中的方法名
+                    VariableDeclarator variableDeclarator = (VariableDeclarator) codeNodes.get(0);
+                    //匹配方法名相同的
+                    if (fieldName.equals(variableDeclarator.getName().getIdentifier())) {
+                        fieldComments[0] = commentText[0];
+                    }
+
+                });
+
+            }
+        });
+        return StringUtils.hasText(fieldComments[0]) ? formatComment(fieldComments[0]) : null;
+    }
+
+
+    @SneakyThrows
+    public static String readMethodComment(Method method) {
+        return readMethodComment(method, null);
+    }
+
+    /**
+     * 读取方法上面的注释,并格式化(注:须在开发环境下使用)
+     *
+     * @return
+     */
+    @SneakyThrows
+    public static String readMethodComment(Method method, Map<String, String> paramCommentMap) {
+        File sourceFile = toSourceFile(method.getDeclaringClass());
+        if (sourceFile == null) {
+            return null;
+        }
+        //用于存放方法上面的注释
+        String[] methodComments = new String[1];
+        //取方法名
+        final String methodName = method.getName();
+        JavaParser javaParser = new JavaParser();
+        ParseResult<CompilationUnit> result = javaParser.parse(sourceFile);
+        result.getResult().ifPresent((it) -> {
+            for (Comment comment : it.getAllContainedComments()) {
+                comment.getCommentedNode().ifPresent((node) -> {
+
+                    //取出方法注释
+                    String[] commentText = new String[1];
+                    node.getComment().ifPresent((comm) -> {
+                        commentText[0] = comm.getContent();
+                    });
+
+                    //没有注释的每一个方法
+                    Node noCommentNode = node.removeComment();
+
+                    //过滤节点类型,,取方法名的子节点
+                    List<Node> codeNodes = noCommentNode.getChildNodes().stream().filter((childNode) -> {
+                        return childNode instanceof SimpleName;
+                    }).collect(Collectors.toList());
+                    if (codeNodes == null || codeNodes.size() == 0) {
+                        return;
+                    }
+
+                    //取出代码中的方法名
+                    SimpleName simpleName = (SimpleName) codeNodes.get(0);
+
+
+                    //匹配方法名相同的
+                    if (methodName.equals(simpleName.getIdentifier())) {
+                        methodComments[0] = commentText[0];
+                    }
+
+                });
+
+            }
+        });
+
+        return StringUtils.hasText(methodComments[0]) ? formatComment(methodComments[0], paramCommentMap) : null;
+    }
+
+
+    /**
+     * 取出源码文件
+     *
+     * @param cls
+     * @return
+     */
+    private static File toSourceFile(Class cls) {
+        String classesPath = cls.getProtectionDomain().getCodeSource().getLocation().getFile();
+        String projectPath = PathUtil.getParent(PathUtil.getParent(classesPath, "/"), "/");
+        String fileName = projectPath + "/src/main/java/" + TextUtil.join(cls.getPackageName().split("\\."), "/") + "/" + cls.getSimpleName();
+        if (new File(fileName + ".java").exists()) {
+            return new File(fileName + ".java");
+        } else if (new File(fileName + ".groovy").exists()) {
+            return new File(fileName + ".groovy");
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * 格式化注释文本
+     *
+     * @param textComment
+     * @return
+     */
+    private static String formatComment(String textComment) {
+        return formatComment(textComment, null);
+    }
+
+    /**
+     * 格式化注释文本
+     *
+     * @param textComment
+     * @return
+     */
+    private static String formatComment(String textComment, Map<String, String> paramCommentMap) {
+        //处理一些符号
+        String commentContent = textComment.replaceAll("//", "").replaceAll("\\*", "");
+
+
+        StringBuffer sb = new StringBuffer();
+        //过滤注解的注释
+        for (String line : commentContent.split("\n")) {
+            //取出左边所有的空格
+            if (StringUtils.hasText(line)) {
+                line = line.trim();
+            }
+            if (StringUtils.hasText(line) && line.indexOf("@") == -1) {
+                sb.append(line);
+            } else if (line.indexOf(ParamText) > -1 && line.length() > ParamText.length() + 1) {
+                String paramCommentText = line.substring(ParamText.length() + 1, line.length());
+                if (paramCommentMap != null) {
+                    int at = paramCommentText.indexOf(" ");
+                    if (at == -1) {
+                        paramCommentMap.put(paramCommentText, "");
+                    } else {
+                        paramCommentMap.put(paramCommentText.substring(0, at), paramCommentText.substring(at + 1, paramCommentText.length()).trim());
+                    }
+                }
+            }
+        }
+
+        //过滤空格与换行符
+        return sb.toString().replaceAll(" ", "").replaceAll("\n", "").replaceAll("\r", "");
+    }
+
+}

+ 68 - 0
src/main/java/com/zswl/dataservicestarter/utils/text/TextUtil.java

@@ -0,0 +1,68 @@
+package com.zswl.dataservicestarter.utils.text;
+
+/**
+ * 字符串工具集合
+ *
+ * @author 练书锋
+ */
+public class TextUtil {
+
+    /**
+     * 字符串
+     *
+     * @param source
+     * @param startText
+     * @param endText
+     * @return
+     */
+    public static String subText(String source, String startText, String endText, int offSet) {
+        int start = source.indexOf(startText, offSet) + 1;
+        if (start == -1) {
+            return null;
+        }
+        int end = source.indexOf(endText, start + offSet + startText.length() - 1);
+        if (end == -1) {
+            end = source.length();
+        }
+        return source.substring(start + startText.length() - 1, end);
+    }
+
+    /**
+     * 合并字符串数组到字符串,以关键词间隔
+     *
+     * @param arr
+     * @param keyword
+     * @return
+     */
+    public static String join(String[] arr, String keyword) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < arr.length - 1; i++) {
+            sb.append(arr[i]);
+            sb.append(keyword);
+        }
+        if (arr.length > 0) {
+            sb.append(arr[arr.length - 1]);
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * 填充文本
+     *
+     * @param fillText
+     * @param size
+     * @param source
+     * @return
+     */
+    public static String fill(char fillText, int size, Object source) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(String.valueOf(source));
+        while (sb.length() < size) {
+            sb.insert(0, fillText);
+        }
+        return sb.toString();
+    }
+
+
+}

+ 28 - 0
src/main/resources/application-dev.yml

@@ -0,0 +1,28 @@
+spring:
+  data:
+    mongodb:
+      uri: mongodb://admin:admin123@192.168.0.102:37017,192.168.0.102:47017,192.168.0.102:57107/dataDB?replicaSet=rs
+      auto-index-creation: true
+    redis:
+      host: localhost
+      port: 6379
+      database: 0
+      timeout: 5000
+      lettuce:
+        pool:
+          max-active: 32 # 最大连接
+          max-idle: 16   # 最大空闲连接
+          min-idle: 8   # 最小空闲连接
+          max-wait: 100ms # 连接等待时间
+
+logging:
+  file:
+    name: logs/dataServiceStarter.log
+  level:
+    org:
+      springframework:
+        boot:
+          autoconfigure:
+            logging: info
+
+

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

@@ -0,0 +1,71 @@
+server:
+  port: 9000
+
+debug: true
+
+spring:
+  application:
+    name: dataService
+  profiles:
+    active: dev
+  data:
+    mongodb:
+      uri: mongodb://admin:admin123@192.168.0.102:37017,192.168.0.102:47017,192.168.0.102:57107/dataDB?replicaSet=rs
+      auto-index-creation: true
+  # 允许beans循环引用
+  main:
+    allow-circular-references: true
+    allow-bean-definition-overriding: true
+  servlet:
+    multipart:
+      max-file-size: 20MB
+      max-request-size: 20MB
+#  mvc:
+#    pathmatch:
+#      matching-strategy: ant_path_matcher
+
+
+authsettings:
+  free-urls:
+    - path: /*/free/**
+      method: GET,POST
+    - path: /oauth/**
+      method: POST,GET
+  validateSsoSessionURL: http://114.55.105.47:8888/ylxs-pms/SsoLogin.action
+  tokenExpirePeriod: 86400000 #单位 ms
+  privateKey: "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrt4Ygv761NfAG\
+   QbafBGyAgje00TrI7QGRgf2qDSG7s7LZ0hD9k48us/miHxEynqbasFLM61RQNnWJ\
+   IoDiDxjKcq3NtiYbuRm52zI+QNSqPugNmbzXKGGIdR2cE1kPp9YFFDQr3Wvru8m4\
+   23E1hNb+7m5eZ2KjyFuSu6xKKLsDrhpNpB2ML+n88DflP2ZsdqjZ/QvfvtAATUbJ\
+   LlPdNNlR+lz2ffpqnSVBNo3vc0+A1oY1pk9EQpaQuyU430mrKsDwW/ytbOhfS3uK\
+   pE80XiUh6x4h02alpB0RhRy2Fgk+mSZdTF2wy4N0mYubHawaejGHN+vfs/l/PvjU\
+   V882Y6ARAgMBAAECggEAQhCDnAnpV1J/HAkgN6G+FNsEj56H3VHB7rdyXoBa4BpM\
+   zxzQyJ6C0dcQTd1iAnWjgDOiR5CqiYnKQo5xw4dHZGwmjiRsGPJoAWdhty2+JBm7\
+   sa/aRXUVwSg90hRniWxrHN0fDVlM8g73lxVmQs7u4HnfIJbqDlVBVfy6VnXBLbKm\
+   ePMqS2bKK+Fn/Uy33qUeIm2VMyEunsZRX+r4hs1xvZtCB17GUeFlcfULAyMI93kz\
+   rnOGDQap2FqOyDFliXHWrJOaJS8N8niDEM9W/os8V+WMcRC+YkNvdzlTebeHUH/8\
+   EYWE2YBFh+lxVjgZ4PhUj2hEYXtpytHAmU42bY7NgQKBgQDd4qnGUe2ncZllz3IN\
+   OENe40vylNY5Xu/Kgn6eo8aTqq7wyT+HHGlC1wEUfPBN0Dod957aqq1W6N7e8Oyg\
+   yjuGB0aegDvxdQNPfxuDEB43B6ToQDEf+my2pVJ2h08Tb5aCWZ4xFzP2kKebIly7\
+   49ECb7Q34UVaWE7fwlbH/rzh2QKBgQDGHj6Y8/KkzJEe+j1OCr7TN7xAK/VDEiLc\
+   KNUwSDbFEGjZlH4iPI86fUV8c2eczbpy2Hxp+WaOT79y0z8YSkTcLY2X61ixNXiW\
+   MT0jesrV7UGtw0jQB6bncQCbjVAENJbEu46YJsT8L8yQNBqrm74vcJGn1UDWr+hd\
+   /8LFq98U+QKBgBbPIya461ZILj2yCoZjX0GU2gzQ0gjJwpqtuXhzW4l4hU1JUtd/\
+   yy5MzdaeVVGacy77coAGBZWmkKqYV6rbvyyy+MZ4ZjEXF0UHyvs5H/IGPiSF3Mbt\
+   xlksO4Llu/JCiVVTAxkGypexHRmseZ3y+FxowTzxUmDMLSeBYcxjWmVZAoGAPpjh\
+   yGwTt5RXKgWBBz6H6q7KkTASb120nAFe0sGOZJd5uX2cmO6vhph8MwU3sKikB5N1\
+   Q/qkN8TkxcAPSHp25WaTPXQD8wHlFvd5zNMIca1kOiXgxLIWPzxKJ9vvc1S2anSk\
+   alidltz3cny0DJLJ9a1IqFHOCcdM0R51iQV0F+kCgYEA1DgiehJVJ5YQ4HhYY7EZ\
+   5RRwvJCel1mvgoO8VlyyKNxUfhMa5XKRjXgtwJOQ8sB2Rz172FxC5Bxso8aLzN66\
+   WeiA0dKnxMR5zU1onqjzgyenZ36EMntB2abvBRwb/fMbuuDzaeFN3CenJgITCxQO\
+   Xj/Eior+hYDbTMnuHg/Nkng="
+  publicKey: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq7eGIL++tTXwBkG2nwRs\
+   gII3tNE6yO0BkYH9qg0hu7Oy2dIQ/ZOPLrP5oh8RMp6m2rBSzOtUUDZ1iSKA4g8Y\
+   ynKtzbYmG7kZudsyPkDUqj7oDZm81yhhiHUdnBNZD6fWBRQ0K91r67vJuNtxNYTW\
+   /u5uXmdio8hbkrusSii7A64aTaQdjC/p/PA35T9mbHao2f0L377QAE1GyS5T3TTZ\
+   Ufpc9n36ap0lQTaN73NPgNaGNaZPREKWkLslON9JqyrA8Fv8rWzoX0t7iqRPNF4l\
+   IeseIdNmpaQdEYUcthYJPpkmXUxdsMuDdJmLmx2sGnoxhzfr37P5fz741FfPNmOg\
+   EQIDAQAB"
+  tokenHeaderName: accessToken
+
+

+ 13 - 0
src/test/java/com/zswl/dataservicestarter/DataServiceStarterApplicationTests.java

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

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