asen %!s(int64=2) %!d(string=hai) anos
achega
6e982555d7
Modificáronse 100 ficheiros con 3281 adicións e 0 borrados
  1. 10 0
      .idea/.gitignore
  2. 46 0
      .idea/compiler.xml
  3. 67 0
      .idea/encodings.xml
  4. 25 0
      .idea/jarRepositories.xml
  5. 12 0
      .idea/misc.xml
  6. 24 0
      README.md
  7. 108 0
      pom.xml
  8. 485 0
      tr-dependencies/pom.xml
  9. 78 0
      tr-framework/pom.xml
  10. 25 0
      tr-framework/src/main/java/cn/tr/core/annotation/ColumnDefaultValue.java
  11. 16 0
      tr-framework/src/main/java/cn/tr/core/annotation/Comment.java
  12. 24 0
      tr-framework/src/main/java/cn/tr/core/annotation/Mobile.java
  13. 25 0
      tr-framework/src/main/java/cn/tr/core/annotation/MobileValidator.java
  14. 18 0
      tr-framework/src/main/java/cn/tr/core/annotation/TenantIgnore.java
  15. 37 0
      tr-framework/src/main/java/cn/tr/core/constant/MybatisConstant.java
  16. 73 0
      tr-framework/src/main/java/cn/tr/core/context/SecurityContextHolder.java
  17. 15 0
      tr-framework/src/main/java/cn/tr/core/enums/CreateEnum.java
  18. 15 0
      tr-framework/src/main/java/cn/tr/core/enums/IEnum.java
  19. 17 0
      tr-framework/src/main/java/cn/tr/core/enums/UserTypeEnum.java
  20. 53 0
      tr-framework/src/main/java/cn/tr/core/enums/WebFilterOrderEnum.java
  21. 23 0
      tr-framework/src/main/java/cn/tr/core/exception/BaseCode.java
  22. 61 0
      tr-framework/src/main/java/cn/tr/core/exception/ServiceException.java
  23. 214 0
      tr-framework/src/main/java/cn/tr/core/exception/TRExcCode.java
  24. 96 0
      tr-framework/src/main/java/cn/tr/core/pojo/CommonResult.java
  25. 22 0
      tr-framework/src/main/java/cn/tr/core/pojo/KeyValue.java
  26. 28 0
      tr-framework/src/main/java/cn/tr/core/pojo/LoginResult.java
  27. 33 0
      tr-framework/src/main/java/cn/tr/core/pojo/PageDomain.java
  28. 41 0
      tr-framework/src/main/java/cn/tr/core/pojo/PageInfo.java
  29. 50 0
      tr-framework/src/main/java/cn/tr/core/pojo/TableDataInfo.java
  30. 55 0
      tr-framework/src/main/java/cn/tr/core/strategy/DeptDataPermissionStrategy.java
  31. 37 0
      tr-framework/src/main/java/cn/tr/core/strategy/ExceptionStrategy.java
  32. 43 0
      tr-framework/src/main/java/cn/tr/core/strategy/LoginUserStrategy.java
  33. 44 0
      tr-framework/src/main/java/cn/tr/core/strategy/PageStrategy.java
  34. 16 0
      tr-framework/src/main/java/cn/tr/core/strategy/auth/ILoginUser.java
  35. 51 0
      tr-framework/src/main/java/cn/tr/core/tree/TreeNode.java
  36. 126 0
      tr-framework/src/main/java/cn/tr/core/utils/CommonNetWorkInfoUtil.java
  37. 58 0
      tr-framework/src/main/java/cn/tr/core/utils/IpUtil.java
  38. 146 0
      tr-framework/src/main/java/cn/tr/core/utils/JsonUtils.java
  39. 111 0
      tr-framework/src/main/java/cn/tr/core/utils/MediaTypeUtils.java
  40. 164 0
      tr-framework/src/main/java/cn/tr/core/utils/Proxy.java
  41. 34 0
      tr-framework/src/main/java/cn/tr/core/utils/PswUtils.java
  42. 149 0
      tr-framework/src/main/java/cn/tr/core/utils/ServletUtils.java
  43. 124 0
      tr-framework/src/main/java/cn/tr/core/utils/TreeUtil.java
  44. 47 0
      tr-framework/src/main/java/cn/tr/core/utils/ValidationUtils.java
  45. 15 0
      tr-framework/src/main/java/cn/tr/core/validation/Insert.java
  46. 15 0
      tr-framework/src/main/java/cn/tr/core/validation/Update.java
  47. BIN=BIN
      tr-framework/src/main/resources/ip2region.xdb
  48. BIN=BIN
      tr-framework/target/classes/cn/tr/core/annotation/ColumnDefaultValue.class
  49. BIN=BIN
      tr-framework/target/classes/cn/tr/core/annotation/Comment.class
  50. BIN=BIN
      tr-framework/target/classes/cn/tr/core/annotation/Mobile.class
  51. BIN=BIN
      tr-framework/target/classes/cn/tr/core/annotation/MobileValidator.class
  52. BIN=BIN
      tr-framework/target/classes/cn/tr/core/annotation/TenantIgnore.class
  53. BIN=BIN
      tr-framework/target/classes/cn/tr/core/constant/MybatisConstant.class
  54. BIN=BIN
      tr-framework/target/classes/cn/tr/core/context/SecurityContextHolder.class
  55. BIN=BIN
      tr-framework/target/classes/cn/tr/core/enums/CreateEnum.class
  56. BIN=BIN
      tr-framework/target/classes/cn/tr/core/enums/IEnum.class
  57. BIN=BIN
      tr-framework/target/classes/cn/tr/core/enums/UserTypeEnum.class
  58. BIN=BIN
      tr-framework/target/classes/cn/tr/core/enums/WebFilterOrderEnum.class
  59. BIN=BIN
      tr-framework/target/classes/cn/tr/core/exception/BaseCode.class
  60. BIN=BIN
      tr-framework/target/classes/cn/tr/core/exception/ServiceException.class
  61. BIN=BIN
      tr-framework/target/classes/cn/tr/core/exception/TRExcCode.class
  62. BIN=BIN
      tr-framework/target/classes/cn/tr/core/pojo/CommonResult.class
  63. BIN=BIN
      tr-framework/target/classes/cn/tr/core/pojo/KeyValue.class
  64. BIN=BIN
      tr-framework/target/classes/cn/tr/core/pojo/LoginResult.class
  65. BIN=BIN
      tr-framework/target/classes/cn/tr/core/pojo/PageDomain.class
  66. BIN=BIN
      tr-framework/target/classes/cn/tr/core/pojo/PageInfo.class
  67. BIN=BIN
      tr-framework/target/classes/cn/tr/core/pojo/TableDataInfo.class
  68. BIN=BIN
      tr-framework/target/classes/cn/tr/core/strategy/DeptDataPermissionStrategy.class
  69. BIN=BIN
      tr-framework/target/classes/cn/tr/core/strategy/ExceptionStrategy.class
  70. BIN=BIN
      tr-framework/target/classes/cn/tr/core/strategy/LoginUserStrategy.class
  71. BIN=BIN
      tr-framework/target/classes/cn/tr/core/strategy/PageStrategy.class
  72. BIN=BIN
      tr-framework/target/classes/cn/tr/core/strategy/auth/ILoginUser.class
  73. BIN=BIN
      tr-framework/target/classes/cn/tr/core/tree/TreeNode.class
  74. BIN=BIN
      tr-framework/target/classes/cn/tr/core/utils/CommonNetWorkInfoUtil.class
  75. BIN=BIN
      tr-framework/target/classes/cn/tr/core/utils/IpUtil.class
  76. BIN=BIN
      tr-framework/target/classes/cn/tr/core/utils/JsonUtils.class
  77. BIN=BIN
      tr-framework/target/classes/cn/tr/core/utils/MediaTypeUtils$MediaType.class
  78. BIN=BIN
      tr-framework/target/classes/cn/tr/core/utils/MediaTypeUtils.class
  79. BIN=BIN
      tr-framework/target/classes/cn/tr/core/utils/Proxy$Task.class
  80. BIN=BIN
      tr-framework/target/classes/cn/tr/core/utils/Proxy.class
  81. BIN=BIN
      tr-framework/target/classes/cn/tr/core/utils/PswUtils.class
  82. BIN=BIN
      tr-framework/target/classes/cn/tr/core/utils/ServletUtils.class
  83. BIN=BIN
      tr-framework/target/classes/cn/tr/core/utils/TreeUtil.class
  84. BIN=BIN
      tr-framework/target/classes/cn/tr/core/utils/ValidationUtils.class
  85. BIN=BIN
      tr-framework/target/classes/cn/tr/core/validation/Insert.class
  86. BIN=BIN
      tr-framework/target/classes/cn/tr/core/validation/Update.class
  87. BIN=BIN
      tr-framework/target/classes/ip2region.xdb
  88. 20 0
      tr-modules-api/pom.xml
  89. 26 0
      tr-modules-api/tr-module-export-api/pom.xml
  90. 21 0
      tr-modules-api/tr-module-export-api/src/main/java/cn/tr/module/api/export/annotation/ExcelDict.java
  91. BIN=BIN
      tr-modules-api/tr-module-export-api/target/classes/cn/tr/module/api/export/annotation/ExcelDict.class
  92. 23 0
      tr-modules-api/tr-module-system-api/pom.xml
  93. 27 0
      tr-modules-api/tr-module-system-api/src/main/java/cn/tr/module/api/sys/dict/SysDictApi.java
  94. 45 0
      tr-modules-api/tr-module-system-api/src/main/java/cn/tr/module/api/sys/log/annotation/OperateLog.java
  95. 64 0
      tr-modules-api/tr-module-system-api/src/main/java/cn/tr/module/api/sys/log/bo/OperateLogBO.java
  96. 30 0
      tr-modules-api/tr-module-system-api/src/main/java/cn/tr/module/api/sys/log/enums/LoginType.java
  97. 25 0
      tr-modules-api/tr-module-system-api/src/main/java/cn/tr/module/api/sys/storage/SysStorageApi.java
  98. 24 0
      tr-modules-api/tr-module-system-api/src/main/java/cn/tr/module/api/sys/user/SysMenuApi.java
  99. BIN=BIN
      tr-modules-api/tr-module-system-api/target/classes/cn/tr/module/api/sys/dict/SysDictApi.class
  100. BIN=BIN
      tr-modules-api/tr-module-system-api/target/classes/cn/tr/module/api/sys/log/annotation/OperateLog.class

+ 10 - 0
.idea/.gitignore

@@ -0,0 +1,10 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Zeppelin ignored files
+/ZeppelinRemoteNotebooks/

+ 46 - 0
.idea/compiler.xml

@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <annotationProcessing>
+      <profile default="true" name="Default" enabled="true" />
+      <profile name="Annotation profile for tr-footstone" enabled="true">
+        <sourceOutputDir name="target/generated-sources/annotations" />
+        <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
+        <outputRelativeToContentRoot value="true" />
+        <processorPath useClasspath="false">
+          <entry name="$PROJECT_DIR$/../../../Maven/repository/org/springframework/boot/spring-boot-configuration-processor/2.7.8/spring-boot-configuration-processor-2.7.8.jar" />
+          <entry name="$PROJECT_DIR$/../../../Maven/repository/org/projectlombok/lombok/1.18.24/lombok-1.18.24.jar" />
+          <entry name="$PROJECT_DIR$/../../../Maven/repository/org/mapstruct/mapstruct-processor/1.5.3.Final/mapstruct-processor-1.5.3.Final.jar" />
+          <entry name="$PROJECT_DIR$/../../../Maven/repository/org/mapstruct/mapstruct/1.5.3.Final/mapstruct-1.5.3.Final.jar" />
+        </processorPath>
+        <module name="tr-spring-boot-starter-plugin-doc" />
+        <module name="tr-spring-boot-starter-plugin-websocket" />
+        <module name="tr-module-export-api" />
+        <module name="tr-spring-boot-starter-plugin-file" />
+        <module name="tr-test" />
+        <module name="tr-spring-boot-starter-plugin-eventbus" />
+        <module name="tr-spring-boot-starter-plugin-biz-data-permission" />
+        <module name="tr-spring-boot-starter-plugin-cache" />
+        <module name="tr-spring-boot-starter-plugin-import-export" />
+        <module name="tr-module-system-api" />
+        <module name="tr-module-gen" />
+        <module name="tr-spring-boot-starter-plugin-mp-enhance-actable" />
+        <module name="tr-framework" />
+        <module name="tr-spring-boot-starter-plugin-sms" />
+        <module name="tr-spring-boot-starter-plugin-biz-tenant" />
+        <module name="tr-spring-boot-starter-plugin-web" />
+        <module name="tr-spring-boot-starter-plugin-biz-bean-mapper" />
+        <module name="tr-spring-boot-starter-plugin-test" />
+        <module name="tr-module-system" />
+        <module name="tr-module-quartz" />
+        <module name="tr-spring-boot-starter-plugin-desensitize" />
+        <module name="tr-spring-boot-starter-plugin-mybatis" />
+        <module name="tr-spring-boot-starter-plugin-numbering-strategy" />
+        <module name="tr-spring-boot-starter-plugin-banner" />
+        <module name="tr-spring-boot-starter-plugin-biz-constant" />
+        <module name="tr-spring-boot-starter-plugin-satoken" />
+        <module name="tr-module-export" />
+      </profile>
+    </annotationProcessing>
+  </component>
+</project>

+ 67 - 0
.idea/encodings.xml

@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding">
+    <file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-framework/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-framework/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-modules-api/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-modules-api/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-modules-api/tr-module-export-api/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-modules-api/tr-module-export-api/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-modules-api/tr-module-system-api/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-modules-api/tr-module-system-api/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-modules/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-modules/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-modules/tr-module-export/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-modules/tr-module-export/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-modules/tr-module-gen/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-modules/tr-module-gen/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-modules/tr-module-quartz/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-modules/tr-module-quartz/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-modules/tr-module-system/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-modules/tr-module-system/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-banner/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-banner/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-biz-bean-mapper/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-biz-bean-mapper/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-biz-constant/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-biz-constant/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-biz-data-permission/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-biz-data-permission/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-biz-tenant/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-biz-tenant/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-cache/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-cache/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-desensitize/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-desensitize/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-doc/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-doc/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-eventbus/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-eventbus/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-file/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-file/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-import-export/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-import-export/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-mp-enhance-actable/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-mp-enhance-actable/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-mybatis/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-mybatis/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-numbering-strategy/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-numbering-strategy/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-satoken/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-satoken/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-sms/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-sms/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-test/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-test/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-web/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-web/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-websocket/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-plugins/tr-spring-boot-starter-plugin-websocket/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-test/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/tr-test/src/main/resources" charset="UTF-8" />
+  </component>
+</project>

+ 25 - 0
.idea/jarRepositories.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RemoteRepositoriesConfiguration">
+    <remote-repository>
+      <option name="id" value="central" />
+      <option name="name" value="Central Repository" />
+      <option name="url" value="https://repo.maven.apache.org/maven2" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="aliyunmaven" />
+      <option name="name" value="aliyun" />
+      <option name="url" value="https://maven.aliyun.com/repository/public" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="central" />
+      <option name="name" value="Maven Central repository" />
+      <option name="url" value="https://repo1.maven.org/maven2" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="jboss.community" />
+      <option name="name" value="JBoss Community repository" />
+      <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
+    </remote-repository>
+  </component>
+</project>

+ 12 - 0
.idea/misc.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ExternalStorageConfigurationManager" enabled="true" />
+  <component name="MavenProjectsManager">
+    <option name="originalFiles">
+      <list>
+        <option value="$PROJECT_DIR$/pom.xml" />
+      </list>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK" />
+</project>

+ 24 - 0
README.md

@@ -0,0 +1,24 @@
+|  框架   | 说明  |  版本 | 学习指南|
+|  ----  | ----  | ---- | ---- |
+| SpringBoot  | 基础手脚架 | 2.7.8 | [文档](https://spring.io/projects/spring-boot/) |
+| SaToken  | 权限框架 | 1.34.0 | [文档](https://sa-token.cc/index.html) |
+| MapStruct  | Bean转换器 | 1.5.3.Final | [文档](https://spring.io/projects/spring-boot/) |
+| Lombok  | 代码插件 | 1.18.20 | [文档](https://projectlombok.org/) |
+| Hutool  | 基础工具类 | 5.8.12 | [文档](https://hutool.mydoc.io/) |
+| Log4j2  | 日志框架 | 2.7.8 | [文档](https://logging.apache.org/log4j/2.x/) |
+|Druid| JDBC连接工具| 1.2.8 ||
+|Knife4j|Swagger 增强 UI 实现| 4.0.0|
+|Javassist|字节码增强| 3.25.0-GA|
+|Jackson| Json工具库|2.13.4 |
+| Mybatis-Plus  | MyBatis 增强工具包 | 3.5.3.1 | [文档](https://www.baomidou.com/pages/24112f/) |
+| PageHelper  | 分页插件 | 1.4.5 | [文档](https://pagehelper.github.io/) |
+| Mockito  | mock框架 | 4.11.0 | [文档](https://site.mockito.org/) |
+| JUnit  | 单元测试框架 | 4.11.0 | |
+| Redisson  | redis连接工具 | 3.17.7 | [文档](https://github.com/redisson/redisson) |
+| Tio  | 网络编程框架 | 3.6.0.v20200315-RELEASE | [文档](https://www.tiocloud.com/tio/) |
+|Quartz|任务调度框架| 2.3.2 |
+| SpringCloudStream  | 生产消费模型 | 3.2.6 |  |
+| SpringCloudBus  | 消息总线 | 3.1.2 |  |
+| RabbitMq  | 消息队列 | 3.8.5 | |
+| Mysql  | 基础手脚架 | 5.7/8.0+ |  |
+| Redis  | 基础手脚架 | 6.0.1 | |

+ 108 - 0
pom.xml

@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>cn.tr</groupId>
+    <artifactId>tr-footstone</artifactId>
+    <version>${revision}</version>
+    <packaging>pom</packaging>
+    <description>驼人通用型管理框架</description>
+
+    <modules>
+        <!--依赖包-->
+        <module>tr-dependencies</module>
+        <!--插件-->
+        <module>tr-plugins</module>
+        <!--一些框架公共服务-->
+        <module>tr-framework</module>
+        <!--系统、业务服务模块-->
+        <module>tr-modules</module>
+        <!--系统、业务服务对外提供api模块-->
+        <module>tr-modules-api</module>
+        <module>tr-test</module>
+    </modules>
+
+    <properties>
+        <revision>0.0.9</revision>
+        <java.version>1.8</java.version>
+        <maven.compiler.source>${java.version}</maven.compiler.source>
+        <maven.compiler.target>${java.version}</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <versions-maven-plugin.version>2.7</versions-maven-plugin.version>
+        <maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
+        <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
+        <skipTests>true</skipTests>
+        <lombok.version>1.18.24</lombok.version>
+        <mapstruct.version>1.5.3.Final</mapstruct.version>
+        <spring-boot.version>2.7.8</spring-boot.version>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-dependencies</artifactId>
+                <version>${revision}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+        </dependencies>
+    </dependencyManagement>
+
+
+
+    <build>
+        <pluginManagement>
+            <plugins>
+                <!-- maven-surefire-plugin 插件,用于运行单元测试。 -->
+                <!-- 注意,需要使用 3.0.X+,因为要支持 Junit 5 版本 -->
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-surefire-plugin</artifactId>
+                    <version>${maven-surefire-plugin.version}</version>
+                </plugin>
+                <!-- maven-compiler-plugin 插件,解决 Lombok + MapStruct 组合 -->
+                <!-- https://stackoverflow.com/questions/33483697/re-run-spring-boot-configuration-annotation-processor-to-update-generated-metada -->
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <version>${maven-compiler-plugin.version}</version>
+                    <configuration>
+                        <annotationProcessorPaths>
+                            <path>
+                                <groupId>org.springframework.boot</groupId>
+                                <artifactId>spring-boot-configuration-processor</artifactId>
+                                <version>${spring-boot.version}</version>
+                            </path>
+                            <path>
+                                <groupId>org.projectlombok</groupId>
+                                <artifactId>lombok</artifactId>
+                                <version>${lombok.version}</version>
+                            </path>
+                            <path>
+                                <groupId>org.mapstruct</groupId>
+                                <artifactId>mapstruct-processor</artifactId>
+                                <version>${mapstruct.version}</version>
+                            </path>
+                        </annotationProcessorPaths>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+
+    <!-- 使用 aliyun 的 Maven 源,提升下载速度 -->
+    <repositories>
+        <repository>
+            <id>aliyunmaven</id>
+            <name>aliyun</name>
+            <url>https://maven.aliyun.com/repository/public</url>
+        </repository>
+    </repositories>
+
+</project>

+ 485 - 0
tr-dependencies/pom.xml

@@ -0,0 +1,485 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+
+    <groupId>cn.tr</groupId>
+    <artifactId>tr-dependencies</artifactId>
+    <version>${revision}</version>
+    <packaging>pom</packaging>
+    <modelVersion>4.0.0</modelVersion>
+
+
+    <name>${project.artifactId}</name>
+    <description>基础 bom 文件,管理整个项目的依赖版本</description>
+
+    <properties>
+        <skip>true</skip>
+        <revision>0.0.9</revision>
+
+        <spring-boot.version>2.7.8</spring-boot.version>
+        <hutool.version>5.8.12</hutool.version>
+        <mapstruct.version>1.5.3.Final</mapstruct.version>
+        <lombok.version>1.18.20</lombok.version>
+        <ip2region.version>2.6.6</ip2region.version>
+
+        <!--数据库-->
+        <mybatis-plus.version>3.5.3.1</mybatis-plus.version>
+        <mybatis-plus-generator.version>3.5.3.1</mybatis-plus-generator.version>
+        <mysql-connector.version>8.0.27</mysql-connector.version>
+        <druid.version>1.2.8</druid.version>
+        <pagehelper.boot.version>1.4.5</pagehelper.boot.version>
+        <!--权限相关-->
+        <satoken.version>1.34.0</satoken.version>
+        <!--TEST测试相关-->
+        <podam.version>7.2.11.RELEASE</podam.version>
+        <mockito-inline.version>4.11.0</mockito-inline.version>
+
+        <caffeine.version>2.6.2</caffeine.version>
+        <!--redission-->
+        <redisson.version>3.17.7</redisson.version>
+
+        <!--文件存储-->
+        <aliyun-oss.version>3.15.0</aliyun-oss.version>
+        <minio.version>8.5.1</minio.version>
+        <qiniu.version>7.9.5</qiniu.version>
+        <!--文件导入导出-->
+        <poi.version>5.2.2</poi.version>
+        <!--websocket-->
+        <tio-websocket.version>3.6.0.v20200315-RELEASE</tio-websocket.version>
+
+        <!--字节码增强-->
+        <javassist.version>3.25.0-GA</javassist.version>
+
+        <!--flink版本-->
+        <flink.version>1.16.1</flink.version>
+
+        <!--在线文档-->
+        <knife4j.verison>4.0.0</knife4j.verison>
+
+        <!--阿里云短信-->
+        <ali.sms.version>2.0.23</ali.sms.version>
+
+        <!--渲染模板引擎-->
+        <beetl.version>1.2.40.Beetl.RELEASE</beetl.version>
+
+        <!--硬件信息-->
+        <oshi.core.version>6.2.2</oshi.core.version>
+
+        <stream-rabbit.version>3.2.6</stream-rabbit.version>
+
+        <bus-rabbit.version>3.1.2</bus-rabbit.version>
+
+        <easy-captcha.version>1.6.2</easy-captcha.version>
+
+        <easy-excel.version>3.3.1</easy-excel.version>
+    </properties>
+
+
+    <dependencyManagement>
+        <dependencies>
+            <!--springboot pom文件-->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring-boot.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <!--redis客户端-->
+            <dependency>
+                <groupId>org.redisson</groupId>
+                <artifactId>redisson-spring-boot-starter</artifactId>
+                <version>${redisson.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.springframework.boot</groupId>
+                        <artifactId>spring-boot-starter-logging</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+
+            <!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
+            <dependency>
+                <groupId>cn.dev33</groupId>
+                <artifactId>sa-token-spring-boot-starter</artifactId>
+                <version>${satoken.version}</version>
+            </dependency>
+
+            <!-- Sa-Token 整合 Redis (使用 jdk 默认序列化方式) -->
+            <dependency>
+                <groupId>cn.dev33</groupId>
+                <artifactId>sa-token-dao-redis</artifactId>
+                <version>${satoken.version}</version>
+            </dependency>
+
+            <!--使用mapstruct转换-->
+            <dependency>
+                <groupId>org.mapstruct</groupId>
+                <artifactId>mapstruct</artifactId>
+                <version>${mapstruct.version}</version>
+            </dependency>
+
+            <!--hutool工具类包-->
+            <dependency>
+                <groupId>cn.hutool</groupId>
+                <artifactId>hutool-all</artifactId>
+                <version>${hutool.version}</version>
+            </dependency>
+
+            <!--lombok-->
+            <dependency>
+                <groupId>org.projectlombok</groupId>
+                <artifactId>lombok</artifactId>
+                <version>${lombok.version}</version>
+            </dependency>
+
+            <!-- ip地址查询 -->
+            <dependency>
+                <groupId>org.lionsoul</groupId>
+                <artifactId>ip2region</artifactId>
+                <version>${ip2region.version}</version>
+            </dependency>
+
+            <!--mybatis-plus-->
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>mybatis-plus-boot-starter</artifactId>
+                <version>${mybatis-plus.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>mybatis-plus-extension</artifactId>
+                <version>${mybatis-plus.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>mybatis-plus-generator</artifactId> <!-- 代码生成器,使用它解析表结构 -->
+                <version>${mybatis-plus-generator.version}</version>
+            </dependency>
+            <!--mybatis-plus-->
+
+            <!--阿里数据库连接池 -->
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>druid-spring-boot-starter</artifactId>
+                <version>${druid.version}</version>
+            </dependency>
+
+            <!-- pagehelper 分页插件 -->
+            <dependency>
+                <groupId>com.github.pagehelper</groupId>
+                <artifactId>pagehelper-spring-boot-starter</artifactId>
+                <version>${pagehelper.boot.version}</version>
+            </dependency>
+
+
+            <!--Test测试自动填充对象属性-->
+            <dependency>
+                <groupId>uk.co.jemos.podam</groupId>
+                <artifactId>podam</artifactId>
+                <version>${podam.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.mockito</groupId>
+                <artifactId>mockito-inline</artifactId>
+                <version>${mockito-inline.version}</version> <!-- 支持 Mockito 的 final 类与 static 方法的 mock -->
+            </dependency>
+
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-test</artifactId>
+                <version>${spring-boot.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <artifactId>asm</artifactId>
+                        <groupId>org.ow2.asm</groupId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>org.mockito</groupId>
+                        <artifactId>mockito-core</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+
+            <!--缓存-->
+            <dependency>
+                <groupId>com.github.ben-manes.caffeine</groupId>
+                <artifactId>caffeine</artifactId>
+                <version>${caffeine.version}</version>
+            </dependency>
+
+
+            <!--OSS模块-->
+            <!--ali OSS存储-->
+            <dependency>
+                <groupId>com.aliyun.oss</groupId>
+                <artifactId>aliyun-sdk-oss</artifactId>
+                <version>${aliyun-oss.version}</version>
+            </dependency>
+            <!-- minio -->
+            <dependency>
+                <groupId>io.minio</groupId>
+                <artifactId>minio</artifactId>
+                <version>${minio.version}</version>
+            </dependency>
+            <!--七牛云-->
+            <dependency>
+                <groupId>com.qiniu</groupId>
+                <artifactId>qiniu-java-sdk</artifactId>
+                <version>${qiniu.version}</version>
+            </dependency>
+            <!--OSS模块-->
+
+
+
+            <!--系统硬件信息-->
+            <dependency>
+                <groupId>com.github.oshi</groupId>
+                <artifactId>oshi-core</artifactId>
+                <version>${oshi.core.version}</version>
+            </dependency>
+
+            <!-- excel导入导出工具 -->
+            <dependency>
+                <groupId>org.apache.poi</groupId>
+                <artifactId>poi-ooxml</artifactId>
+                <version>${poi.version}</version>
+            </dependency>
+
+            <!--websocket-->
+            <dependency>
+                <groupId>org.t-io</groupId>
+                <artifactId>tio-websocket-spring-boot-starter</artifactId>
+                <version>${tio-websocket.version}</version>
+            </dependency>
+
+            <!--字节码增强技术-->
+            <dependency>
+                <groupId>org.javassist</groupId>
+                <artifactId>javassist</artifactId>
+                <version>${javassist.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.github.whvcse</groupId>
+                <artifactId>easy-captcha</artifactId>
+                <version>${easy-captcha.version}</version>
+            </dependency>
+
+            <!--flink 组件-->
+            <dependency>
+                <groupId>org.apache.flink</groupId>
+                <artifactId>flink-streaming-java</artifactId>
+                <version>${flink.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.apache.flink</groupId>
+                <artifactId>flink-clients</artifactId>
+                <version>${flink.version}</version>
+            </dependency>
+
+            <!--在线文档-->
+            <dependency>
+                <groupId>com.github.xiaoymin</groupId>
+                <artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
+                <version>${knife4j.verison}</version>
+            </dependency>
+
+            <!--业务组件-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-framework</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-test</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-flink</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>mysql</groupId>
+                <artifactId>mysql-connector-java</artifactId>
+                <version>${mysql-connector.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-mybatis</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!--缓存插件-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-cache</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+
+            <!--文件插件-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-file</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!--消息总线-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-eventbus</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+
+            <!--satoken插件-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-satoken</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!--编号生成插件-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-numbering-strategy</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+
+            <!--对象转换插件-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-biz-bean-mapper</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!--在线文档插件-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-doc</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!--租户插件-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-biz-tenant</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!--常量业务插件-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-biz-constant</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!--websocket插件-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-websocket</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!--表结构自动更新插件-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-mp-enhance-actable</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!--打印banner插件-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-banner</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!--敏感词插件-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-desensitize</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!--web插件-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-web</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!--api模块-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-module-system-api</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!--导出api模块-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-module-export-api</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!--短信模块-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-sms</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!--阿里云短信-->
+            <dependency>
+                <groupId>com.aliyun</groupId>
+                <artifactId>dysmsapi20170525</artifactId>
+                <version>${ali.sms.version}</version>
+            </dependency>
+
+            <!--阿里云短信-->
+            <dependency>
+                <groupId>com.ibeetl</groupId>
+                <artifactId>beetl-framework-starter</artifactId>
+                <version>${beetl.version}</version>
+            </dependency>
+
+            <!--驱动式消息 订阅发布-->
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
+                <version>${stream-rabbit.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-starter-bus-amqp</artifactId>
+                <version>${bus-rabbit.version}</version>
+            </dependency>
+
+
+
+
+
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>easyexcel</artifactId>
+                <version>${easy-excel.version}</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+</project>

+ 78 - 0
tr-framework/pom.xml

@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>tr-footstone</artifactId>
+        <groupId>cn.tr</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>tr-framework</artifactId>
+    <packaging>jar</packaging>
+    <version>${revision}</version>
+
+    <description>系统内置的核心框架功能</description>
+    <modules>
+
+    </modules>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-log4j2</artifactId>
+        </dependency>
+
+        <!-- ip2region -->
+        <dependency>
+            <groupId>org.lionsoul</groupId>
+            <artifactId>ip2region</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.javassist</groupId>
+            <artifactId>javassist</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 25 - 0
tr-framework/src/main/java/cn/tr/core/annotation/ColumnDefaultValue.java

@@ -0,0 +1,25 @@
+package cn.tr.core.annotation;
+
+import java.lang.annotation.*;
+
+
+/**
+ * 字段的默认值
+ *
+ * @author sunchenbin
+ * @version 2020年11月09日 下午6:13:37
+ */
+// 该注解用于方法声明
+@Target(ElementType.FIELD)
+// VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息
+@Retention(RetentionPolicy.RUNTIME)
+// 将此注解包含在javadoc中
+@Documented
+public @interface ColumnDefaultValue {
+
+	/**
+	 * 字段的默认值
+	 * @return 字段的默认值
+	 */
+	String value();
+}

+ 16 - 0
tr-framework/src/main/java/cn/tr/core/annotation/Comment.java

@@ -0,0 +1,16 @@
+package cn.tr.core.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * @@interface : Comment
+ * @Description : 字段注释
+ * @Author : LF
+ * @Date: 2023年03月23日
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Comment {
+    String value() default "";
+}

+ 24 - 0
tr-framework/src/main/java/cn/tr/core/annotation/Mobile.java

@@ -0,0 +1,24 @@
+package cn.tr.core.annotation;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+@Target({
+        ElementType.METHOD,
+        ElementType.FIELD,
+        ElementType.ANNOTATION_TYPE,
+        ElementType.CONSTRUCTOR,
+        ElementType.PARAMETER,
+        ElementType.TYPE_USE
+})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Constraint(
+        validatedBy = MobileValidator.class
+)
+public @interface Mobile {
+
+    String value() default "手机号格式不正确";
+
+}

+ 25 - 0
tr-framework/src/main/java/cn/tr/core/annotation/MobileValidator.java

@@ -0,0 +1,25 @@
+package cn.tr.core.annotation;
+
+import cn.hutool.core.util.PhoneUtil;
+import cn.hutool.core.util.StrUtil;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+public class MobileValidator implements ConstraintValidator<Mobile, String> {
+
+    @Override
+    public void initialize(Mobile annotation) {
+    }
+
+    @Override
+    public boolean isValid(String value, ConstraintValidatorContext context) {
+        // 如果手机号为空,默认不校验,即校验通过
+        if (StrUtil.isEmpty(value)) {
+            return true;
+        }
+        // 校验手机
+        return PhoneUtil.isPhone(value);
+    }
+
+}

+ 18 - 0
tr-framework/src/main/java/cn/tr/core/annotation/TenantIgnore.java

@@ -0,0 +1,18 @@
+package cn.tr.core.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 忽略租户,标记指定方法不进行租户的自动过滤
+ *
+ * 注意,只有 DB 的场景会过滤,其它场景暂时不过滤:
+ * 1、Redis 场景:因为是基于 Key 实现多租户的能力,所以忽略没有意义,不像 DB 是一个 column 实现的
+ * 2、MQ 场景:有点难以抉择,目前可以通过 Consumer 手动在消费的方法上,添加 @TenantIgnore 进行忽略
+ *
+ * @author 芋道源码
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface TenantIgnore {
+}

+ 37 - 0
tr-framework/src/main/java/cn/tr/core/constant/MybatisConstant.java

@@ -0,0 +1,37 @@
+package cn.tr.core.constant;
+
+/**
+ * @ClassName : MybatisConstant
+ * @Description : mybatis常量
+ * @Author : LF
+ * @Date: 2023年02月21日
+ */
+
+public class MybatisConstant {
+    /**
+     * 创建时间字段名称
+     */
+    public static final String CREATE_TIME = "createTime";
+    /**
+     * 更新时间字段名称
+     */
+    public static final String UPDATE_TIME = "updateTime";
+    /**
+     * 创建人字段名称
+     */
+    public static final String CREATE_BY = "createBy";
+    /**
+     * 更新人字段名称
+     */
+    public static final String UPDATE_BY = "updateBy";
+
+    /**
+     * 租户id字段名称
+     */
+    public static final String TENANT_ID = "tenantId";
+
+    /**
+     * 分页信息缓存
+     */
+    public static final String PAGE_CACHE = "page_cache";
+}

+ 73 - 0
tr-framework/src/main/java/cn/tr/core/context/SecurityContextHolder.java

@@ -0,0 +1,73 @@
+package cn.tr.core.context;
+
+import cn.hutool.core.util.ObjectUtil;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 获取当前线程变量中的 用户id、用户名称、Token等信息 
+ * 注意: 必须在网关通过请求头的方法传入,同时在HeaderInterceptor拦截器设置值。 否则这里无法获取
+ *
+ * @author lifang
+ */
+public class SecurityContextHolder {
+    private static final ThreadLocal<Map<String, Object>> THREAD_LOCAL = new ThreadLocal<>();
+
+
+    public static void set(String key, Object value) {
+        if (ObjectUtil.isNull(value)) {
+            return;
+        }
+        Map<String, Object> map = getLocalMap();
+        map.put(key, value);
+    }
+
+    public static String getStr(String key)
+    {
+        return get(key,String.class);
+    }
+
+    public static <T> T get(String key, Class<T> clazz) {
+        Map<String,  Object> map = getLocalMap();
+        Object result = map.getOrDefault(key, null);
+        if(result==null){
+            return null;
+        }
+        if(result.getClass() .equals(clazz) ){
+            return (T) result;
+        }else {
+            return null;
+        }
+    }
+
+
+    public static <T> List<T> getList(String key,Class<T> clazz){
+        return (List<T>) getLocalMap().getOrDefault(key, null);
+    }
+
+    public static <T> Map getMap(String key){
+        return (Map) getLocalMap().getOrDefault(key, null);
+    }
+
+
+
+
+
+    private static Map<String, Object> getLocalMap() {
+        Map<String,  Object> map = THREAD_LOCAL.get();
+        if (map == null)
+        {
+            map = new ConcurrentHashMap<String,Object>();
+            THREAD_LOCAL.set(map);
+        }
+        return map;
+    }
+
+    public static void remove()
+    {
+        THREAD_LOCAL.remove();
+    }
+
+}

+ 15 - 0
tr-framework/src/main/java/cn/tr/core/enums/CreateEnum.java

@@ -0,0 +1,15 @@
+package cn.tr.core.enums;
+
+/**
+ * @ClassName : CreateEnum
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月21日
+ */
+
+public enum  CreateEnum {
+    //系统类型
+    sys,
+    //自定义类型
+    custom
+}

+ 15 - 0
tr-framework/src/main/java/cn/tr/core/enums/IEnum.java

@@ -0,0 +1,15 @@
+package cn.tr.core.enums;
+
+/**
+ * @ClassName : IEnum
+ * @Description :
+ * @Author : JR
+ * @Date: 2022年11月12日
+ */
+
+public interface IEnum<T> {
+    T getValue();
+
+    String getLabel();
+
+}

+ 17 - 0
tr-framework/src/main/java/cn/tr/core/enums/UserTypeEnum.java

@@ -0,0 +1,17 @@
+package cn.tr.core.enums;
+
+/**
+ * 全局用户类型枚举
+ */
+
+public interface UserTypeEnum {
+    /**
+     * 面向 b 端,管理后台
+     */
+    String ADMIN="admin";
+
+    /**
+     * 面向 c 端,普通用户
+     */
+    String MEMBER="member";
+}

+ 53 - 0
tr-framework/src/main/java/cn/tr/core/enums/WebFilterOrderEnum.java

@@ -0,0 +1,53 @@
+package cn.tr.core.enums;
+
+/**
+ * Web 过滤器顺序的枚举类,保证过滤器按照符合我们的预期
+ *
+ *  考虑到每个 starter 都需要用到该工具类,所以放到 common 模块下的 enum 包下
+ * order值越小越先执行
+ * @author 芋道源码
+ */
+public interface WebFilterOrderEnum {
+
+    int CORS_FILTER = Integer.MIN_VALUE;
+
+    int EXCEPTION_FILTER=CORS_FILTER+1;
+
+    int TRACE_FILTER = EXCEPTION_FILTER + 1;
+
+    int ENV_TAG_FILTER = TRACE_FILTER + 1;
+
+    int REQUEST_BODY_CACHE_FILTER = Integer.MIN_VALUE + 500;
+
+    /**
+     * 执行租户过滤器
+     */
+    int TENANT_CONTEXT_FILTER = - 104;
+
+    /**
+     * 租户接口安全,在租户过滤器之后
+     */
+    int TENANT_SECURITY_FILTER = -99;
+
+    /**
+     * 请求记录过滤器
+     */
+    int API_ACCESS_LOG_FILTER = -103;
+
+    int XSS_FILTER = -102;  // 需要保证在 RequestBodyCacheFilter 后面
+
+    // Spring Security Filter 默认为 -100,可见 org.springframework.boot.autoconfigure.security.SecurityProperties 配置属性类
+
+
+
+    int ACTIVITI_FILTER = -98; // 需要保证在 Spring Security 过滤后面
+
+    int FLOWABLE_FILTER = -98; // 需要保证在 Spring Security 过滤后面
+
+    /**
+     * 填充登录方式,放在最后
+     */
+    int FILL_LOGIN_TYPE=9999;
+    int DEMO_FILTER = Integer.MAX_VALUE;
+
+}

+ 23 - 0
tr-framework/src/main/java/cn/tr/core/exception/BaseCode.java

@@ -0,0 +1,23 @@
+package cn.tr.core.exception;
+
+/**
+ * @Enum : BaseCode
+ * @Description : 基础错误代码
+ * @Author : JR
+ * @Date: 2022年11月18日
+ */
+
+public interface BaseCode {
+
+    /**
+     * 错误码
+     * @return
+     */
+    String getErrCode();
+
+    /**
+     * 错误信息
+     * @return
+     */
+    String getErrMsg();
+}

+ 61 - 0
tr-framework/src/main/java/cn/tr/core/exception/ServiceException.java

@@ -0,0 +1,61 @@
+package cn.tr.core.exception;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 业务逻辑异常 Exception
+ * @author JR
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public final class ServiceException extends RuntimeException {
+
+    private static final long serialVersionUID = 7657422049507503668L;
+    /**
+     * 业务错误码
+     *
+     */
+    private TRExcCode code;
+
+    /**
+     * 错误提示
+     */
+    private String message;
+
+    /**
+     * 空构造方法,避免反序列化问题
+     */
+    public ServiceException() {
+    }
+
+    public ServiceException(TRExcCode errorCode) {
+        this.code = errorCode;
+        this.message = errorCode.getErrMsg();
+    }
+
+    public ServiceException(TRExcCode errCode, String message) {
+        this.code = errCode;
+        this.message = message;
+    }
+
+    public TRExcCode getCode() {
+        return code;
+    }
+
+    public ServiceException setCode(TRExcCode code) {
+        this.code = code;
+        return this;
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+
+    public ServiceException setMessage(String message) {
+        this.message = message;
+        return this;
+    }
+
+}

+ 214 - 0
tr-framework/src/main/java/cn/tr/core/exception/TRExcCode.java

@@ -0,0 +1,214 @@
+package cn.tr.core.exception;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @ClassName : TRExcCode
+ * @Description : 根据阿里巴巴编码规约(泰山版)整理的错误码
+ * @Author : JR
+ * @Date: 2022年11月18日
+ */
+@AllArgsConstructor
+@Getter
+public enum TRExcCode implements BaseCode {
+        SUCCESS("00000", "成功"),
+    USER_ERROR_0001("A0001", "用户端错误"),
+    USER_ERROR_A0100("A0100", "用户注册错误"),
+    USER_ERROR_A0101("A0101", "用户未同意隐私协议"),
+    USER_ERROR_A0102("A0102", "注册国家或地区受限"),
+    USER_ERROR_A0110("A0110", "用户名校验失败"),
+    USER_ERROR_A0111("A0111", "用户名已存在"),
+    USER_ERROR_A0112("A0112", "用户名包含敏感词"),
+    USER_ERROR_A0113("A0113", "用户名包含特殊字符"),
+    USER_ERROR_A0120("A0120", "密码校验失败"),
+    USER_ERROR_A0121("A0121", "密码长度不够"),
+    USER_ERROR_A0122("A0122", "密码强度不够"),
+    USER_ERROR_A0130("A0130", "校验码输入错误"),
+    USER_ERROR_A0131("A0131", "短信校验码输入错误"),
+    USER_ERROR_A0132("A0132", "邮件校验码输入错误"),
+    USER_ERROR_A0133("A0133", "语音校验码输入错误"),
+    USER_ERROR_A0140("A0140", "用户证件异常"),
+    USER_ERROR_A0141("A0141", "用户证件类型未选择"),
+    USER_ERROR_A0142("A0142", "大陆身份证编号校验非法"),
+    USER_ERROR_A0143("A0143", "护照编号校验非法"),
+    USER_ERROR_A0144("A0144", "军官证编号校验非法"),
+    USER_ERROR_A0150("A0150", "用户基本信息校验失败"),
+    USER_ERROR_A0151("A0151", "手机格式校验失败"),
+    USER_ERROR_A0152("A0152", "地址格式校验失败"),
+    USER_ERROR_A0153("A0153", "邮箱格式校验失败"),
+
+    /**** 登录 **/
+    USER_ERROR_A0200("A0200", "用户登陆异常"),
+    USER_ERROR_A0201("A0201", "用户账户不存在"),
+    USER_ERROR_A0202("A0202", "用户账户被禁用"),
+    USER_ERROR_A0203("A0203", "用户账户已作废"),
+    USER_ERROR_A0210("A0210", "用户密码错误"),
+    USER_ERROR_A0211("A0211", "用户输入密码次数超限"),
+    USER_ERROR_A0220("A0220", "用户身份校验失败"),
+    USER_ERROR_A0221("A0221", "用户指纹识别失败"),
+    USER_ERROR_A0222("A0222", "用户面容识别失败"),
+    USER_ERROR_A0223("A0223", "用户未获得第三方登陆授权"),
+    USER_ERROR_A0230("A0230", "用户登陆已过期"),
+    USER_ERROR_A0240("A0240", "用户验证码错误"),
+    USER_ERROR_A0241("A0241", "用户验证码尝试次数超限"),
+    USER_ERROR_A0242("A0242", "用户未登录"),
+
+    USER_ERROR_A0243("A0243", "OAuth2 认证失败"),
+    USER_ERROR_A0204("A0244", "租户被禁用"),
+    USER_ERROR_A0205("A0245", "租户已被删除"),
+    /**** 权限 **/
+    USER_ERROR_A0300("A0300", "访问权限异常"),
+    USER_ERROR_A0301("A0301", "访问未授权"),
+    USER_ERROR_A0302("A0302", "正在授权中"),
+    USER_ERROR_A0303("A0303", "用户授权申请被拒绝"),
+    USER_ERROR_A0310("A0310", "因访问对象隐私设置被拦截"),
+    USER_ERROR_A0311("A0311", "授权已过期"),
+    USER_ERROR_A0312("A0312", "无权限使用API"),
+    USER_ERROR_A0320("A0320", "用户访问被拦截"),
+    USER_ERROR_A0321("A0321", "黑名单用户"),
+    USER_ERROR_A0322("A0322", "账号被禁用"),
+    USER_ERROR_A0323("A0323", "非法IP地址"),
+    USER_ERROR_A0324("A0324", "网关访问受限"),
+    USER_ERROR_A0325("A0325", "地域黑名单"),
+    USER_ERROR_A0330("A0330", "服务已欠费"),
+    USER_ERROR_A0340("A0340", "用户签名异常"),
+    USER_ERROR_A0341("A0341", "RSA签名错误"),
+
+
+    /**** 输入错误 **/
+    USER_ERROR_A0400("A0400", "用户请求参数错误"),
+    USER_ERROR_A0401("A0401", "包含非法恶意跳转链接"),
+    USER_ERROR_A0402("A0402", "无效的用户输入"),
+    USER_ERROR_A0403("A0403", "权限不足"),
+    USER_ERROR_A0404("A0404", "用户请求地址不存在"),
+    USER_ERROR_A0410("A0410", "请求必填参数为空"),
+    USER_ERROR_A0411("A0411", "用户订单号为空"),
+    USER_ERROR_A0412("A0412", "订购数量为空"),
+    USER_ERROR_A0413("A0413", "缺少时间戳参数"),
+    USER_ERROR_A0414("A0414", "非法的时间戳参数"),
+    USER_ERROR_A0420("A0420", "请求参数值超出允许的范围"),
+    USER_ERROR_A0421("A0421", "参数格式不匹配"),
+    USER_ERROR_A0422("A0422", "地址不在服务范围"),
+    USER_ERROR_A0423("A0423", "时间不在服务范围"),
+    USER_ERROR_A0424("A0424", "金额超出限制"),
+    USER_ERROR_A0425("A0425", "数量超出限制"),
+    USER_ERROR_A0426("A0426", "请求批量处理总个数超出限制"),
+    USER_ERROR_A0427("A0427", "请求JSON解析失败"),
+    USER_ERROR_A0430("A0430", "用户输入内容非法"),
+    USER_ERROR_A0431("A0431", "包含违禁敏感词"),
+    USER_ERROR_A0432("A0432", "图片包含违禁信息"),
+    USER_ERROR_A0433("A0433", "文件侵犯版权"),
+    USER_ERROR_A0440("A0440", "用户操作异常"),
+    USER_ERROR_A0441("A0441", "用户支付超时"),
+    USER_ERROR_A0442("A0442", "确认订单超时"),
+    USER_ERROR_A0443("A0443", "订单已关闭"),
+    USER_ERROR_A0500("A0500", "用户请求服务异常"),
+    USER_ERROR_A0501("A0501", "请求次数超出限制"),
+    USER_ERROR_A0502("A0502", "请求并发数超出限制"),
+    USER_ERROR_A0503("A0503", "用户操作请等待"),
+    USER_ERROR_A0504("A0504", "WebSocket连接异常"),
+    USER_ERROR_A0505("A0505", "WebSocket连接断开"),
+    USER_ERROR_A0506("A0506", "用户重复请求"),
+    USER_ERROR_A0600("A0600", "用户资源异常"),
+    USER_ERROR_A0601("A0601", "账户余额不足"),
+    USER_ERROR_A0602("A0602", "用户磁盘空间不足"),
+    USER_ERROR_A0603("A0603", "用户内存空间不足"),
+    USER_ERROR_A0604("A0604", "用户OSS容量不足"),
+    USER_ERROR_A0605("A0605", "用户配额已用光"),
+    USER_ERROR_A0700("A0700", "用户上传文件异常"),
+    USER_ERROR_A0701("A0701", "用户上传文件类型不匹配"),
+    USER_ERROR_A0702("A0702", "用户上传文件太大"),
+    USER_ERROR_A0703("A0703", "用户上传图片太大"),
+    USER_ERROR_A0704("A0704", "用户上传视频太大"),
+    USER_ERROR_A0705("A0705", "用户上传压缩文件太大"),
+    USER_ERROR_A0706("A0706", "不支持预览该类型文件预览"),
+    USER_ERROR_A0800("A0800", "用户当前版本异常"),
+    USER_ERROR_A0801("A0801", "用户安装版本与系统不匹配"),
+    USER_ERROR_A0802("A0802", "用户安装版本过低"),
+    USER_ERROR_A0803("A0803", "用户安装版本过高"),
+    USER_ERROR_A0804("A0804", "用户安装版本已过期"),
+    USER_ERROR_A0805("A0805", "用户API请求版本不匹配"),
+    USER_ERROR_A0806("A0806", "用户API请求版本过高"),
+    USER_ERROR_A0807("A0807", "用户API请求版本过低"),
+    USER_ERROR_A0900("A0900", "用户隐私未授权"),
+    USER_ERROR_A0901("A0901", "用户隐私未签署"),
+    USER_ERROR_A0902("A0902", "用户摄像头未授权"),
+    USER_ERROR_A0903("A0903", "用户相机未授权"),
+    USER_ERROR_A0904("A0904", "用户图片库未授权"),
+    USER_ERROR_A0905("A0905", "用户文件未授权"),
+    USER_ERROR_A0906("A0906", "用户位置信息未授权"),
+    USER_ERROR_A0907("A0907", "用户通讯录未授权"),
+    USER_ERROR_A1000("A1000", "用户设备异常"),
+    USER_ERROR_A1001("A1001", "用户相机异常"),
+    USER_ERROR_A1002("A1002", "用户麦克风异常"),
+    USER_ERROR_A1003("A1003", "用户听筒异常"),
+    USER_ERROR_A1004("A1004", "用户扬声器异常"),
+    USER_ERROR_A1005("A1005", "用户GPS定位异常"),
+
+    /**** 服务端错误 **/
+    SYSTEM_ERROR_B0001("B0001", "系统执行出错"),
+    SYSTEM_ERROR_B0100("B0100", "系统执行超时"),
+    SYSTEM_ERROR_B0101("B0101", "系统订单处理超时"),
+    SYSTEM_ERROR_B0200("B0200", "系统容灾功能被触发"),
+    SYSTEM_ERROR_B0210("B0210", "系统限流"),
+    SYSTEM_ERROR_B0220("B0220", "系统功能降级"),
+    SYSTEM_ERROR_B0300("B0300", "系统资源异常"),
+    SYSTEM_ERROR_B0310("B0310", "系统资源耗尽"),
+    SYSTEM_ERROR_B0311("B0311", "系统磁盘空间耗尽"),
+    SYSTEM_ERROR_B0312("B0312", "系统内存耗尽"),
+    SYSTEM_ERROR_B0313("B0313", "文件句柄耗尽"),
+    SYSTEM_ERROR_B0314("B0314", "系统连接池耗尽"),
+    SYSTEM_ERROR_B0315("B0315", "系统线程池耗尽"),
+    SYSTEM_ERROR_B0320("B0320", "系统资源访问异常"),
+    SYSTEM_ERROR_B0321("B0321", "系统读取磁盘文件失败"),
+    SYSTEM_ERROR_B0404("B0321", "资源未找到"),
+
+    /**** 第三方服务错误 **/
+    SERVICE_ERROR_C0001("C0001", "调用第三方服务出错"),
+    SERVICE_ERROR_C0100("C0100", "中间件服务出错"),
+    SERVICE_ERROR_C0110("C0110", "RPC服务出错"),
+    SERVICE_ERROR_C0111("C0111", "RPC服务未找到"),
+    SERVICE_ERROR_C0112("C0112", "RPC服务未注册"),
+    SERVICE_ERROR_C0113("C0113", "接口不存在"),
+    SERVICE_ERROR_C0120("C0120", "消息服务出错"),
+    SERVICE_ERROR_C0121("C0121", "消息投递出错"),
+    SERVICE_ERROR_C0122("C0122", "消息消费出错"),
+    SERVICE_ERROR_C0123("C0123", "消息订阅出错"),
+    SERVICE_ERROR_C0124("C0124", "消息分组未查到"),
+    SERVICE_ERROR_C0130("C0130", "缓存服务出错"),
+    SERVICE_ERROR_C0131("C0131", "key长度超过限制"),
+    SERVICE_ERROR_C0132("C0132", "value长度超过限制"),
+    SERVICE_ERROR_C0133("C0133", "存储容量已满"),
+    SERVICE_ERROR_C0134("C0134", "不支持的数据格式"),
+    SERVICE_ERROR_C0140("C0140", "配置服务出错"),
+    SERVICE_ERROR_C0150("C0150", "网络资源服务出错"),
+    SERVICE_ERROR_C0151("C0151", "VPN服务出错"),
+    SERVICE_ERROR_C0152("C0152", "CDN服务出错"),
+    SERVICE_ERROR_C0153("C0153", "域名解析服务出错"),
+    SERVICE_ERROR_C0154("C0154", "网关服务出错"),
+    SERVICE_ERROR_C0200("C0200", "第三方系统执行超时"),
+    SERVICE_ERROR_C0210("C0210", "RPC执行超时"),
+    SERVICE_ERROR_C0220("C0220", "消息投递超时"),
+    SERVICE_ERROR_C0230("C0230", "缓存服务超时"),
+    SERVICE_ERROR_C0240("C0240", "配置服务超时"),
+    SERVICE_ERROR_C0250("C0250", "数据库服务超时"),
+    SERVICE_ERROR_C0300("C0300", "数据库服务出错"),
+    SERVICE_ERROR_C0311("C0311", "表不存在"),
+    SERVICE_ERROR_C0312("C0312", "列不存在"),
+    SERVICE_ERROR_C0321("C0321", "多表关联中存在多个相同名称的列"),
+    SERVICE_ERROR_C0331("C0331", "数据库死锁"),
+    SERVICE_ERROR_C0341("C0341", "主键冲突"),
+    SERVICE_ERROR_C0400("C0400", "第三方容灾系统被触发"),
+    SERVICE_ERROR_C0401("C0401", "第三方系统限流"),
+    SERVICE_ERROR_C0402("C0402", "第三方功能降级"),
+    SERVICE_ERROR_C0500("C0500", "通知服务出错"),
+    SERVICE_ERROR_C0501("C0501", "短信提醒服务失败"),
+    SERVICE_ERROR_C0502("C0502", "语音提醒服务失败"),
+    SERVICE_ERROR_C0503("C0503", "邮件提醒服务失败"),
+    ;
+    @Getter
+    private String errCode;
+    @Getter
+    private String errMsg;
+}

+ 96 - 0
tr-framework/src/main/java/cn/tr/core/pojo/CommonResult.java

@@ -0,0 +1,96 @@
+package cn.tr.core.pojo;
+
+import cn.hutool.core.util.StrUtil;
+import cn.tr.core.exception.BaseCode;
+import cn.tr.core.exception.ServiceException;
+import cn.tr.core.exception.TRExcCode;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Data;
+import lombok.experimental.Accessors;
+import org.springframework.util.Assert;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * 通用返回
+ *
+ * @param <T> 数据泛型
+ */
+@Data
+@Accessors(chain = true)
+public class CommonResult<T> implements Serializable {
+
+    private static final long serialVersionUID = -2619760277112039632L;
+
+    /**
+     * 错误码
+     *
+     * @see TRExcCode ()
+     */
+    private String code;
+    /**
+     * 返回数据
+     */
+    private T data;
+    /**
+     * 错误提示,用户可阅读
+     *
+     * @see TRExcCode#getErrMsg()
+     */
+    private String errorMsg;
+
+    public static <T> CommonResult<T> error(BaseCode excCode, String detailErrorMsg) {
+        String errCode = excCode.getErrCode();
+        Assert.isTrue(!TRExcCode.SUCCESS.getErrCode().equals(errCode), "type 必须是错误的!");
+        CommonResult<T> result = new CommonResult<>();
+        result.code = errCode;
+        result.errorMsg = StrUtil.isNotBlank(detailErrorMsg)?detailErrorMsg:excCode.getErrMsg();
+        return result;
+    }
+
+    public static <T> CommonResult<T> error(BaseCode errorCode) {
+        return error(errorCode, errorCode.getErrMsg());
+    }
+
+    public static <T> CommonResult<T> success() {
+        return CommonResult.success(null);
+    }
+
+    public static <T> CommonResult<T> success(T data) {
+        CommonResult<T> result = new CommonResult<>();
+        result.code = TRExcCode.SUCCESS.getErrCode();
+        result.data = data;
+        result.errorMsg = "";
+        return result;
+    }
+
+    public static boolean isSuccess(String code) {
+        return Objects.equals(code, TRExcCode.SUCCESS.getErrCode());
+    }
+
+    /**
+     *  避免 jackson 序列化
+     * @return
+     */
+    @JsonIgnore
+    public boolean isSuccess() {
+        return isSuccess(code);
+    }
+
+    /**
+     *  避免 jackson 序列化
+     * @return
+     */
+    @JsonIgnore
+    public boolean isError() {
+        return !isSuccess();
+    }
+
+    // ========= 和 Exception 异常体系集成 =========
+
+    public static <T> CommonResult<T> error(ServiceException serviceException) {
+        return error(TRExcCode.SYSTEM_ERROR_B0001, serviceException.getMessage());
+    }
+
+}

+ 22 - 0
tr-framework/src/main/java/cn/tr/core/pojo/KeyValue.java

@@ -0,0 +1,22 @@
+package cn.tr.core.pojo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * Key Value 的键值对
+ *
+ * @author tr
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor(staticName = "of")
+public class KeyValue<K,V> implements Serializable {
+
+    private K key;
+    private V value;
+
+}

+ 28 - 0
tr-framework/src/main/java/cn/tr/core/pojo/LoginResult.java

@@ -0,0 +1,28 @@
+package cn.tr.core.pojo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @ClassName : LoginResult
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年03月02日
+ */
+@Data
+public class LoginResult implements Serializable {
+    private static final long serialVersionUID = 6736183242095354849L;
+
+    /**
+     * 登录token
+     */
+    private String token;
+
+    /**
+     * token过期时间
+     */
+    private long expireTime;
+
+
+}

+ 33 - 0
tr-framework/src/main/java/cn/tr/core/pojo/PageDomain.java

@@ -0,0 +1,33 @@
+package cn.tr.core.pojo;
+
+import cn.hutool.db.sql.Order;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 分页数据
+ * 
+ * @author lifang
+ */
+@Data
+public class PageDomain
+{
+    /** 当前记录起始索引 */
+    private Integer current;
+
+    /** 每页显示记录数 */
+    private Integer size;
+
+    private List<Order> orders;
+
+    /** 分页参数合理化 */
+    private Boolean reasonable = true;
+
+
+    public PageDomain(Integer current, Integer size,List<Order> orders) {
+        this.current = current;
+        this.size = size;
+        this.orders=orders;
+    }
+}

+ 41 - 0
tr-framework/src/main/java/cn/tr/core/pojo/PageInfo.java

@@ -0,0 +1,41 @@
+package cn.tr.core.pojo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.Collection;
+
+/**
+ * @ClassName : PageInfo
+ * @Description :
+ * @Author : LF
+ * @Date: 2022年11月25日
+ */
+
+@AllArgsConstructor(staticName = "of")
+@NoArgsConstructor
+@Data
+public class PageInfo<T> implements Serializable {
+
+    /**
+     * 总条数
+     */
+    private Long total;
+
+    /**
+     * 当前记录起始索引
+     */
+    private Integer pageNum;
+
+    /**
+     * 每页显示记录数
+     */
+    private Integer pageSize;
+
+    /**
+     * 数据
+     */
+    private Collection<T> data;
+}

+ 50 - 0
tr-framework/src/main/java/cn/tr/core/pojo/TableDataInfo.java

@@ -0,0 +1,50 @@
+package cn.tr.core.pojo;
+
+
+import cn.tr.core.exception.TRExcCode;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 表格分页数据对象
+ * 
+ * @author lifang
+ */
+@Data
+public class TableDataInfo<T> implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /** 列表数据 */
+    private PageInfo<T> data;
+
+    /** 消息状态码 */
+    private String code;
+
+    /** 消息内容 */
+    private String errorMsg;
+
+
+    /**
+     * 表格数据对象
+     */
+    public TableDataInfo()
+    {
+    }
+
+    /**
+     * 分页
+     *
+     * @param page 分页数据
+     *
+     */
+    public TableDataInfo(PageInfo<T> page)
+    {
+        this.code= TRExcCode.SUCCESS.getErrCode();
+        this.data = page;
+    }
+
+    public String getErrorMsg() {
+        return errorMsg==null?"":errorMsg;
+    }
+}

+ 55 - 0
tr-framework/src/main/java/cn/tr/core/strategy/DeptDataPermissionStrategy.java

@@ -0,0 +1,55 @@
+package cn.tr.core.strategy;
+
+import java.util.*;
+import java.util.function.Supplier;
+
+/**
+ * @ClassName : DeptDataPermissionStrategy
+ * @Description : 数据权限策略
+ * @Author : LF
+ * @Date: 2023年03月03日
+ */
+
+public class DeptDataPermissionStrategy {
+    private DeptDataPermissionStrategy(){
+
+    }
+
+    public static DeptDataPermissionStrategy tr=new DeptDataPermissionStrategy();
+
+
+    /**
+     * 当前用户的部门id
+     */
+    public Supplier<Set<String>> currentUserDeptIdsSupplier=()->null;
+
+    /**
+     * 是否允许查看所有数据
+     */
+    public Supplier<Boolean> allowAllDataSupplier=()->false;
+
+    /**
+     * 是否允许查看自己的数据
+     */
+    public Supplier<Boolean> allowSelfDataSupplier=()->false;
+
+    public Set<String> getCurrentUserDeptIds(){
+        return currentUserDeptIdsSupplier==null?null:currentUserDeptIdsSupplier.get();
+    }
+
+    /**
+     * 查看所有数据
+     * @return
+     */
+    public Boolean getAll(){
+        return allowAllDataSupplier==null?null:allowAllDataSupplier.get();
+    }
+
+    /**
+     * 查看用户自身的数据
+     * @return
+     */
+    public Boolean getSelf(){
+        return allowSelfDataSupplier==null?null:allowSelfDataSupplier.get();
+    }
+}

+ 37 - 0
tr-framework/src/main/java/cn/tr/core/strategy/ExceptionStrategy.java

@@ -0,0 +1,37 @@
+package cn.tr.core.strategy;
+
+import cn.tr.core.exception.TRExcCode;
+import cn.tr.core.pojo.CommonResult;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiFunction;
+
+/**
+ * @ClassName : ExceptionStrategy
+ * @Description : 异常处理策略
+ * @Author : LF
+ * @Date: 2023年02月28日
+ */
+
+public class ExceptionStrategy {
+    private ExceptionStrategy(){
+
+    }
+    private Map<Class<? extends Throwable>,BiFunction<HttpServletRequest, Throwable,CommonResult>> exceptionHandlerMap=new HashMap<>();
+
+    public static ExceptionStrategy tr =new ExceptionStrategy();
+
+
+    public <T extends Throwable> void  registerThrowableHandler(Class<T> aClass,BiFunction<HttpServletRequest,Throwable,CommonResult> exceptionSupplier){
+        exceptionHandlerMap.put(aClass,exceptionSupplier);
+    }
+
+    public CommonResult<?> exceptionHandle(HttpServletRequest request, Throwable ex){
+        //兜底处理
+        return exceptionHandlerMap
+                .getOrDefault(ex.getClass(), ((re, t) -> CommonResult.error(TRExcCode.SYSTEM_ERROR_B0001, t.getLocalizedMessage())))
+                .apply(request,ex);
+    }
+}

+ 43 - 0
tr-framework/src/main/java/cn/tr/core/strategy/LoginUserStrategy.java

@@ -0,0 +1,43 @@
+package cn.tr.core.strategy;
+
+
+import cn.tr.core.strategy.auth.ILoginUser;
+import java.util.function.Supplier;
+
+/**
+ * @ClassName : LoginUserStrategy
+ * @Description : 登录用户策略
+ * @Author : LF
+ * @Date: 2023年02月21日
+ */
+
+public class LoginUserStrategy {
+    private LoginUserStrategy(){
+
+    }
+
+    public static LoginUserStrategy tr =new LoginUserStrategy();
+
+    public Supplier<? extends ILoginUser> loginUserSupplier;
+
+    /**
+     * 当前地址是否允许匿名登录,默认不允许
+     */
+    public Supplier<Boolean> anonymousLoginSupplier=()->true;
+
+    public String getCurrentUserId(){
+        return loginUserSupplier==null?null:loginUserSupplier.get().getUserId();
+    }
+
+    public String getCurrentUsername(){
+        return loginUserSupplier.get().getUsername();
+    }
+
+    public String getTenantId(){
+        return loginUserSupplier.get().getTenantId();
+    }
+
+    public boolean isAnonymous(){
+        return anonymousLoginSupplier==null||Boolean.TRUE.equals(anonymousLoginSupplier.get());
+    }
+}

+ 44 - 0
tr-framework/src/main/java/cn/tr/core/strategy/PageStrategy.java

@@ -0,0 +1,44 @@
+package cn.tr.core.strategy;
+
+import cn.tr.core.pojo.PageDomain;
+import com.github.pagehelper.Page;
+import com.github.pagehelper.PageHelper;
+
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * @ClassName : PageStrategy
+ * @Description : 分页策略
+ * @Author : LF
+ * @Date: 2023年02月21日
+ */
+
+public class PageStrategy {
+    private PageStrategy(){
+
+    }
+
+
+    public static final PageStrategy tr = new PageStrategy();
+
+
+    /**
+     * 从请求中创建分页参数
+     */
+    public Supplier<PageDomain> createPage=()-> new PageDomain(1,10,null);
+
+    /**
+     * 开始实现分页
+     */
+    public Consumer<PageDomain> startPage= page->{};
+
+    /**
+     * 获取当前最终分页参数
+     */
+    public Supplier<Page<?>> getPage=()-> new Page<>();
+
+    public void clear(){
+        PageHelper.clearPage();
+    }
+}

+ 16 - 0
tr-framework/src/main/java/cn/tr/core/strategy/auth/ILoginUser.java

@@ -0,0 +1,16 @@
+package cn.tr.core.strategy.auth;
+
+/**
+ * @ClassName : ILoginUser
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年02月21日
+ */
+
+public interface ILoginUser {
+    String getUserId();
+
+    String getUsername();
+
+    String getTenantId();
+}

+ 51 - 0
tr-framework/src/main/java/cn/tr/core/tree/TreeNode.java

@@ -0,0 +1,51 @@
+package cn.tr.core.tree;
+
+import cn.tr.core.validation.Insert;
+import cn.tr.core.validation.Update;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tree基类
+ * 
+ * @author ruoyi
+ */
+@Data
+public abstract class TreeNode<PK> implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 父节点
+     */
+    @NotNull(message = "父级id不能为空",groups = {Update.class, Insert.class})
+    private PK parentId;
+
+    /**
+     * 顺序
+     */
+    @NotNull(message = "排序不能为空",groups = {Update.class, Insert.class})
+    private Integer sort;
+
+    /**
+     * 子节点集合
+     */
+    @ApiModelProperty(readOnly = true)
+    private List<TreeNode<PK>> children = new ArrayList<>();
+
+    /**
+     * 节点路径
+     */
+    private String nodePath;
+
+    public abstract PK getId();
+
+    public abstract String getName();
+}

+ 126 - 0
tr-framework/src/main/java/cn/tr/core/utils/CommonNetWorkInfoUtil.java

@@ -0,0 +1,126 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.core.utils;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.NumberUtil;
+import cn.hutool.system.SystemUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.*;
+
+/**
+ * 通用获取当前网速工具类
+ *
+ * @author xuyuxiang
+ * @date 2022/9/1 23:45
+ */
+@Slf4j
+public class CommonNetWorkInfoUtil {
+
+    /**
+     * 网速测速时间2s
+     */
+    private static final int SLEEP_SECONDS = 2;
+
+    /**
+     * 获取网络上下行速率,格式{"UP": "123KB/S, "DOWN": "345KB/S"}
+     *
+     * @author xuyuxiang
+     * @date 2022/9/1 23:51
+     */
+    public static Map<String, String> getNetworkUpRate() {
+        Map<String, String> result = new HashMap<>();
+        Process pro = null;
+        Runtime r = Runtime.getRuntime();
+        BufferedReader input = null;
+        try {
+            boolean isWindows = SystemUtil.getOsInfo().isWindows();
+            String command = isWindows ? "netstat -e" : "ss";
+            pro = r.exec(command);
+            input = new BufferedReader(new InputStreamReader(pro.getInputStream()));
+            long[] result1 = readInLine(input, isWindows);
+            Thread.sleep(SLEEP_SECONDS * 1000);
+            pro.destroy();
+            input.close();
+            pro = r.exec(command);
+            input = new BufferedReader(new InputStreamReader(pro.getInputStream()));
+            long[] result2 = readInLine(input, isWindows);
+            String upSpeed = FileUtil.readableFileSize(Convert.toLong(NumberUtil
+                    .div(NumberUtil.sub(result2[0], result1[0]), SLEEP_SECONDS)));
+            String downSpeed = FileUtil.readableFileSize(Convert.toLong(NumberUtil
+                    .div(NumberUtil.sub(result2[1], result1[1]), SLEEP_SECONDS)));
+            result.put("UP", upSpeed + (upSpeed.endsWith("B")?"/S":"B/S"));
+            result.put("DOWN", downSpeed + (downSpeed.endsWith("B")?"/S":"B/S"));
+        } catch (Exception e) {
+            log.info(">>> 网络测速失败,原因:");
+            e.printStackTrace();
+        } finally {
+            if (input != null) {
+                try {
+                    input.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            Optional.ofNullable(pro).ifPresent(Process::destroy);
+        }
+        return result;
+    }
+
+    private static String formatNumber(double f) {
+        return new Formatter().format("%.2f", f).toString();
+    }
+
+    private static long[] readInLine(BufferedReader input, boolean isWindows) {
+        long[] arr = new long[2];
+        StringTokenizer tokenStat;
+        try {
+            if (isWindows) {
+                // 获取windows环境下的网口上下行速率
+                input.readLine();
+                input.readLine();
+                input.readLine();
+                input.readLine();
+                tokenStat = new StringTokenizer(input.readLine());
+                tokenStat.nextToken();
+                arr[0] = Long.parseLong(tokenStat.nextToken());
+                arr[1] = Long.parseLong(tokenStat.nextToken());
+            } else {
+                // 获取linux环境下的网口上下行速率
+                long rx = 0, tx = 0;
+                String line = null;
+                //RX packets:4171603 errors:0 dropped:0 overruns:0 frame:0
+                //TX packets:4171603 errors:0 dropped:0 overruns:0 carrier:0
+                while ((line = input.readLine()) != null) {
+                    if (line.contains("RX packets")) {
+                        rx += Long.parseLong(line.substring(line.indexOf("RX packets") + 11, line.indexOf(" ",
+                                line.indexOf("RX packets") + 11)));
+                    } else if (line.contains("TX packets")) {
+                        tx += Long.parseLong(line.substring(line.indexOf("TX packets") + 11, line.indexOf(" ",
+                                line.indexOf("TX packets") + 11)));
+                    }
+                }
+                arr[0] = rx;
+                arr[1] = tx;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return arr;
+    }
+}

+ 58 - 0
tr-framework/src/main/java/cn/tr/core/utils/IpUtil.java

@@ -0,0 +1,58 @@
+package cn.tr.core.utils;
+
+import cn.hutool.core.io.FileUtil;
+import org.lionsoul.ip2region.xdb.Searcher;
+
+import java.io.File;
+import java.io.InputStream;
+
+/**
+ * Ip地址查询类
+ */
+public class IpUtil {
+    private static Searcher searcher;
+
+    static {
+        String fileName = "/ip2region.xdb";
+        File existFile = FileUtil.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName);
+        if(!FileUtil.exist(existFile)) {
+            InputStream resourceAsStream = IpUtil.class.getResourceAsStream(fileName);
+            FileUtil.writeFromStream(resourceAsStream, existFile);
+        }
+
+        String dbPath = existFile.getPath();
+
+        // 1、从 dbPath 加载整个 xdb 到内存。
+        byte[] cBuff;
+        try {
+            cBuff = Searcher.loadContentFromFile(dbPath);
+        } catch (Exception e) {
+            throw new RuntimeException(String.format("IPUtil初始化失败,原因:%s", e.getMessage()));
+        }
+
+        // 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。
+        try {
+            searcher = Searcher.newWithBuffer(cBuff);
+        } catch (Exception e) {
+            throw new RuntimeException(String.format("IPUtil初始化失败,原因:%s", e.getMessage()));
+        }
+    }
+
+    /**
+     * 根据IP地址离线获取城市
+     *
+     * @author xuyuxiang
+     * @date 2022/4/27 23:14
+     */
+    public static String getCityInfo(String ip) {
+        try {
+            ip = ip.trim();
+            // 3、执行查询
+            String region = searcher.search(ip);
+            return region.replace("0|", "").replace("|0", "");
+        } catch (Exception e) {
+            return "未知";
+        }
+    }
+
+}

+ 146 - 0
tr-framework/src/main/java/cn/tr/core/utils/JsonUtils.java

@@ -0,0 +1,146 @@
+package cn.tr.core.utils;
+
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.experimental.UtilityClass;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * JSON 工具类
+ *
+ * @author 芋道源码
+ */
+@UtilityClass
+public class JsonUtils {
+
+    private static ObjectMapper objectMapper = new ObjectMapper();
+
+    /**
+     * 初始化 objectMapper 属性
+     * <p>
+     * 通过这样的方式,使用 Spring 创建的 ObjectMapper Bean
+     *
+     * @param objectMapper ObjectMapper 对象
+     */
+    public static void init(ObjectMapper objectMapper) {
+        JsonUtils.objectMapper = objectMapper;
+    }
+
+    public static String toJsonString(Object object) {
+        try {
+            return objectMapper.writeValueAsString(object);
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public static byte[] toJsonByte(Object object) throws JsonProcessingException {
+        return objectMapper.writeValueAsBytes(object);
+    }
+
+    public static String toJsonPrettyString(Object object) throws JsonProcessingException {
+        return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);
+    }
+
+    public static <T> T parseObject(String text, Class<T> clazz) {
+        if (StrUtil.isEmpty(text)) {
+            return null;
+        }
+        try {
+            return objectMapper.readValue(text, clazz);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public static <T> T parseObject(byte[] bytes, Class<T> clazz) {
+        if (ArrayUtil.isEmpty(bytes)) {
+            return null;
+        }
+        try {
+            return objectMapper.readValue(bytes, clazz);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static <T> T parseObject(String text, TypeReference<T> typeReference) throws JsonProcessingException {
+        if (!isJson(text)) {
+            return null;
+        }
+        try {
+            return objectMapper.readValue(text, typeReference);
+        } catch (IOException e) {
+            throw e;
+        }
+    }
+
+    public static Map<String,Object> parseMap(String text){
+        if (StrUtil.isEmpty(text)) {
+            return new HashMap<String,Object>();
+        }
+        try {
+            return objectMapper.readValue(text, Map.class);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static <T> List<T> parseArray(String text, Class<T> clazz){
+        if (StrUtil.isEmpty(text)) {
+            return new ArrayList<>();
+        }
+        try {
+            return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public static JsonNode parseTree(String text) throws JsonProcessingException {
+        try {
+            return objectMapper.readTree(text);
+        } catch (IOException e) {
+            throw e;
+        }
+    }
+
+    public static JsonNode parseTree(byte[] text) throws IOException {
+        try {
+            return objectMapper.readTree(text);
+        } catch (IOException e) {
+            throw e;
+        }
+    }
+
+    public static boolean isJson(String text) {
+        return JSONUtil.isTypeJSON(text);
+    }
+
+    /**
+     * 是否为JSONArray类型的字符串,首尾都为中括号判定为JSONArray字符串
+     *
+     * @param str 字符串
+     * @return 是否为JSONArray类型字符串
+     * @since 5.7.22
+     */
+    public static boolean isTypeJSONArray(String str) {
+        if (StrUtil.isBlank(str)) {
+            return false;
+        }
+        return StrUtil.isWrap(StrUtil.trim(str), '[', ']');
+    }
+}

+ 111 - 0
tr-framework/src/main/java/cn/tr/core/utils/MediaTypeUtils.java

@@ -0,0 +1,111 @@
+package cn.tr.core.utils;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @ClassName : MediaTypeUtils
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年03月13日
+ */
+@Slf4j
+public class MediaTypeUtils {
+    private static final Map<String,String> contentTypeMap=new HashMap<>();
+    /**
+     * 默认文件下载
+     */
+    private static final String DEFAULT_CONTENT_TYPE="application/octet-stream ";
+
+    static {
+        for (MediaType value : MediaType.values()) {
+            log.debug("[register]---->fileType:[{}],ContentType:[{}]",value.getFileType(),value.getContentType());
+            contentTypeMap.put(value.getFileType(),value.getContentType());
+        }
+    }
+
+    public static void registerContentType(String fileType,String contentType){
+        log.debug("[register]---->fileType:[{}],ContentType:[{}]",fileType,contentType);
+        contentTypeMap.put(fileType,contentType);
+    }
+
+    /**
+     *  解析文件锁对应的Content-Type
+     * @param fileName
+     * @return
+     */
+    public static String parseContentType(String fileName) {
+        if(!StrUtil.contains(fileName,".")){
+            return DEFAULT_CONTENT_TYPE;
+        }
+        String fileType= CollectionUtil.getLast(StrUtil.split(fileName,"."));
+        return contentTypeMap.getOrDefault(fileType,DEFAULT_CONTENT_TYPE);
+    }
+
+    @AllArgsConstructor
+    @Getter
+    private static enum MediaType{
+        DOC("doc","application/msword"),
+        DOCX("docx","application/vnd.openxmlformats-officedocument.wordprocessingml.document"),
+
+        RTF("rtf","application/rtf"),
+
+        XLS("xls","application/vnd.ms-excel application/x-excel"),
+        XLSX("xlsx","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
+
+        PPT("ppt","application/vnd.ms-powerpoint"),
+        PPTX("pptx","application/vnd.openxmlformats-officedocument.presentationml.presentation"),
+
+        PPS("pps","application/vnd.ms-powerpoint"),
+        PPSX("ppsx","application/vnd.openxmlformats-officedocument.presentationml.slideshow"),
+
+        PDF("pdf","application/pdf"),
+
+        SWF("swf","application/x-shockwave-flash"),
+
+        DDL("ddl","application/x-msdownload"),
+
+        TAR("tar","application/x-tar"),
+
+        TGZ("tgz","application/x-compressed"),
+
+        ZIP("zip","application/x-zip-compressed"),
+
+        z("z","application/x-compress"),
+
+        WAV("wav","audio/wav"),
+
+        WMA("wma","audio/x-ms-wma"),
+
+        WMV("wmv","video/x-ms-wmv"),
+
+
+        BMP("bmp","image/bmp"),
+
+        GIF("gif","image/gif"),
+
+        JPEG("jpeg","image/jpg"),
+        JPG("jpg","image/jpg"),
+        PNG("png","image/jpg"),
+
+        HTML("html","text/html"),
+
+        TXT("txt","text/plain"),
+
+        VSD("vsd","application/vnd.visio"),
+
+        XML("xml","text/xml"),
+
+
+
+        ;
+        private String fileType;
+        private String contentType;
+    }
+}

+ 164 - 0
tr-framework/src/main/java/cn/tr/core/utils/Proxy.java

@@ -0,0 +1,164 @@
+package cn.tr.core.utils;
+
+import cn.hutool.core.util.StrUtil;
+import javassist.*;
+import javassist.bytecode.AnnotationsAttribute;
+import javassist.bytecode.ConstPool;
+import javassist.bytecode.annotation.*;
+import lombok.Getter;
+import lombok.SneakyThrows;
+import org.springframework.util.ClassUtils;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Consumer;
+
+/**
+ * @author zhouhao
+ * @since 3.0
+ */
+public class Proxy<I> {
+    private static final AtomicLong counter = new AtomicLong(1);
+
+    public final CtClass ctClass;
+    @Getter
+    private final Class<I> superClass;
+    @Getter
+    private final String className;
+    @Getter
+    private final String classFullName;
+
+    private Class<I> targetClass;
+
+    @SneakyThrows
+    public static <I> Proxy<I> create(Class<I> superClass, String... classPathString) {
+        return new Proxy<>(superClass, classPathString);
+    }
+
+    public Proxy(Class<I> superClass, String... classPathString) throws Exception {
+        if (superClass == null) {
+            throw new NullPointerException("superClass can not be null");
+        }
+
+        className = superClass.getSimpleName() + "FastBeanCopier" + counter.getAndAdd(1);
+        classFullName = "cn.tr.plugin.eventbus"+ "." + className;
+
+        this.superClass = superClass;
+        ClassPool classPool = ClassPool.getDefault();
+
+        classPool.insertClassPath(new ClassClassPath(this.getClass()));
+        classPool.insertClassPath(new LoaderClassPath(ClassUtils.getDefaultClassLoader()));
+
+        if (classPathString != null) {
+            for (String path : classPathString) {
+                classPool.insertClassPath(path);
+            }
+        }
+
+
+        ctClass = classPool.makeClass(classFullName);
+        if (superClass != Object.class) {
+            if (superClass.isInterface()) {
+                ctClass.setInterfaces(new CtClass[]{classPool.get(superClass.getName())});
+            } else {
+                ctClass.setSuperclass(classPool.get(superClass.getName()));
+            }
+        }
+        addConstructor("public " + className + "(){}");
+    }
+
+    public Proxy<I> addMethod(String code) {
+        return handleException(() -> ctClass.addMethod(CtNewMethod.make(code, ctClass)));
+    }
+
+    public Proxy<I> addConstructor(String code) {
+        return handleException(() -> ctClass.addConstructor(CtNewConstructor.make(code, ctClass)));
+    }
+
+    public Proxy<I> addField(String code) {
+        return addField(code, null);
+    }
+
+    public Proxy<I> addField(String code, Class<? extends java.lang.annotation.Annotation> annotation) {
+        return addField(code, annotation, null);
+    }
+
+    @SuppressWarnings("all")
+    public static MemberValue createMemberValue(Object value, ConstPool constPool) {
+        MemberValue memberValue = null;
+        if (value instanceof Integer) {
+            memberValue = new IntegerMemberValue(constPool, ((Integer) value));
+        } else if (value instanceof Boolean) {
+            memberValue = new BooleanMemberValue((Boolean) value, constPool);
+        } else if (value instanceof Long) {
+            memberValue = new LongMemberValue((Long) value, constPool);
+        } else if (value instanceof String) {
+            memberValue = new StringMemberValue((String) value, constPool);
+        } else if (value instanceof Class) {
+            memberValue = new ClassMemberValue(((Class) value).getName(), constPool);
+        } else if (value instanceof Object[]) {
+            Object[] arr = ((Object[]) value);
+            ArrayMemberValue arrayMemberValue = new ArrayMemberValue(new ClassMemberValue(arr[0].getClass().getName(), constPool), constPool);
+            arrayMemberValue.setValue(Arrays.stream(arr)
+                    .map(o -> createMemberValue(o, constPool))
+                    .toArray(MemberValue[]::new));
+            memberValue = arrayMemberValue;
+
+        }
+        return memberValue;
+    }
+
+    public Proxy<I> custom(Consumer<CtClass> ctClassConsumer) {
+        ctClassConsumer.accept(ctClass);
+        return this;
+    }
+
+    @SneakyThrows
+    public Proxy<I> addField(String code, Class<? extends java.lang.annotation.Annotation> annotation, Map<String, Object> annotationProperties) {
+        return handleException(() -> {
+            CtField ctField = CtField.make(code, ctClass);
+            if (null != annotation) {
+                ConstPool constPool = ctClass.getClassFile().getConstPool();
+                AnnotationsAttribute attributeInfo = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
+                Annotation ann = new javassist.bytecode.annotation.Annotation(annotation.getName(), constPool);
+                if (null != annotationProperties) {
+                    annotationProperties.forEach((key, value) -> {
+                        MemberValue memberValue = createMemberValue(value, constPool);
+                        if (memberValue != null) {
+                            ann.addMemberValue(key, memberValue);
+                        }
+                    });
+                }
+                attributeInfo.addAnnotation(ann);
+                ctField.getFieldInfo().addAttribute(attributeInfo);
+            }
+            ctClass.addField(ctField);
+        });
+    }
+
+    @SneakyThrows
+    private Proxy<I> handleException(Task task) {
+        task.run();
+        return this;
+    }
+
+
+    @SneakyThrows
+    public I newInstance() {
+        return getTargetClass().newInstance();
+    }
+
+    @SneakyThrows
+    public Class<I> getTargetClass() {
+        if (targetClass == null) {
+            targetClass = (Class<I>) ctClass.toClass(ClassUtils.getDefaultClassLoader(), null);
+        }
+        return targetClass;
+    }
+
+    interface Task {
+        void run() throws Exception;
+    }
+}

+ 34 - 0
tr-framework/src/main/java/cn/tr/core/utils/PswUtils.java

@@ -0,0 +1,34 @@
+package cn.tr.core.utils;
+
+import cn.hutool.crypto.digest.BCrypt;
+import lombok.experimental.UtilityClass;
+
+/**
+ * @ClassName : PswUtils
+ * @Description : 密码工具类
+ * @Author : LF
+ * @Date: 2023年03月24日
+ */
+@UtilityClass
+public class PswUtils {
+    /**
+     * 生成BCryptPasswordEncoder密码
+     *
+     * @param password 密码
+     * @return 加密字符串
+     */
+    public static String encryptPassword(String password) {
+        return BCrypt.hashpw(password);
+    }
+
+    /**
+     * 判断密码是否相同
+     *
+     * @param rawPassword     真实密码
+     * @param encodedPassword 加密后字符
+     * @return 结果
+     */
+    public static boolean matchesPassword(String rawPassword, String encodedPassword) {
+        return BCrypt.checkpw(rawPassword, encodedPassword);
+    }
+}

+ 149 - 0
tr-framework/src/main/java/cn/tr/core/utils/ServletUtils.java

@@ -0,0 +1,149 @@
+package cn.tr.core.utils;
+
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.servlet.ServletUtil;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.URLEncoder;
+
+/**
+ * 客户端工具类
+ *
+ * @author 芋道源码
+ */
+public class ServletUtils {
+
+    /**
+     * 获取String参数
+     */
+    public static String getParameter(String name)
+    {
+        return getRequest().getParameter(name);
+    }
+
+    /**
+     * 获取String参数
+     */
+    public static String getHeader(String name)
+    {
+        return getRequest().getHeader(name);
+    }
+    /**
+     * 返回 JSON 字符串
+     *
+     * @param response 响应
+     * @param object 对象,会序列化成 JSON 字符串
+     */
+    @SuppressWarnings("deprecation") // 必须使用 APPLICATION_JSON_UTF8_VALUE,否则会乱码
+    public static void writeJSON(HttpServletResponse response, Object object) throws JsonProcessingException {
+        response.setStatus(HttpStatus.OK.value());
+        String content = JsonUtils.toJsonString(object);
+        ServletUtil.write(response, content, MediaType.APPLICATION_JSON_UTF8_VALUE);
+    }
+
+    /**
+     * 返回附件
+     *
+     * @param response 响应
+     * @param filename 文件名
+     * @param content 附件内容
+     * @throws IOException
+     */
+    public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException {
+        writeAttachment(response,filename,content,false);
+    }
+
+    /**
+     * 返回附件
+     *
+     * @param response 响应
+     * @param filename 文件名
+     * @param content 附件内容
+     * @param close 是否关闭流
+     * @throws IOException
+     */
+    public static void writeAttachment(HttpServletResponse response, String filename, byte[] content, boolean close) throws IOException {
+        // 设置 header 和 contentType
+        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
+        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
+        // 输出附件
+        IoUtil.write(response.getOutputStream(), close, content);
+    }
+
+    /**
+     * @param request 请求
+     * @return ua
+     */
+    public static String getUserAgent(HttpServletRequest request) {
+        String ua = request.getHeader("User-Agent");
+        return ua != null ? ua : "";
+    }
+
+    /**
+     * 获得请求
+     *
+     * @return HttpServletRequest
+     */
+    public static HttpServletRequest getRequest() {
+        try {
+            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
+            if (!(requestAttributes instanceof ServletRequestAttributes)) {
+                return null;
+            }
+            return ((ServletRequestAttributes) requestAttributes).getRequest();
+        }catch (Exception e){
+            return null;
+        }
+    }
+
+    /**
+     * 获取ua
+     * @return
+     */
+    public static String getUserAgent() {
+        HttpServletRequest request = getRequest();
+        if (request == null) {
+            return null;
+        }
+        return getUserAgent(request);
+    }
+
+    /**
+     * 获取客户端ip地址
+     * @return
+     */
+    public static String getClientIP() {
+        return getClientIP(getRequest());
+    }
+
+    /**
+     * 获取客户端ip地址
+     * @return
+     */
+    public static String getClientIP(  HttpServletRequest request ) {
+        if (request == null) {
+            return null;
+        }
+        return ServletUtil.getClientIP(request);
+    }
+
+    /**
+     * 判断请求内容类型是为json
+     * @param request
+     * @return
+     */
+    public static boolean isJsonRequest(ServletRequest request) {
+        return StrUtil.startWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE);
+    }
+
+}

+ 124 - 0
tr-framework/src/main/java/cn/tr/core/utils/TreeUtil.java

@@ -0,0 +1,124 @@
+package cn.tr.core.utils;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.tr.core.tree.TreeNode;
+import javafx.util.Pair;
+import lombok.experimental.UtilityClass;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @ClassName : TreeUtil
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月01日
+ */
+@UtilityClass
+public class TreeUtil {
+    /**
+     * 获取ID对应的节点,如果有多个ID相同的节点,只返回第一个。<br>
+     * 此方法只查找此节点及子节点,采用递归深度优先遍历。
+     *
+     * @param <T>  ID类型
+     * @param node 节点
+     * @param id   ID
+     * @return 节点
+     * @since 5.2.4
+     */
+    public static <T> TreeNode<T> getNode(TreeNode<T> node, T id) {
+        if (ObjectUtil.equal(id, node.getId())) {
+            return node;
+        }
+        final List<TreeNode<T>> children = node.getChildren();
+        if (null == children) {
+            return null;
+        }
+
+        // 查找子节点
+        TreeNode<T> childNode;
+        for (TreeNode<T> child : children) {
+            childNode = getNode(child, id);
+            if(childNode!=null){
+                return childNode;
+            }
+        }
+
+        // 未找到节点
+        return null;
+    }
+    /**
+     * 将传入的数组转变为树状结构
+     * @param sources
+     * @return
+     */
+    public static <Node extends TreeNode> List<Node> buildTree(Collection<Node> sources){
+        return buildTree(sources,null);
+    };
+
+    public static  <Node extends TreeNode> List<Node> buildTree(Collection<Node > sources, List<String> excludeNodeIds){
+        if(CollectionUtil.isNotEmpty(excludeNodeIds)){
+            sources=sources.stream()
+                    .filter(source->!excludeNodeIds.contains(source.getId()))
+                    .collect(Collectors.toList());
+        }
+        //找到顶级节点
+        sources.stream()
+                .peek(node->node.setParentId(ObjectUtil.isEmpty(node.getParentId())?"0":node.getParentId()))
+                .filter(source-> ObjectUtil.isNull(source.getSort())).forEach(source->source.setSort(999));
+        List<Node> result = sources.stream()
+                .filter(node -> StrUtil.equals("0",String.valueOf(node.getParentId())))
+                .collect(Collectors.toList());
+        if(CollectionUtil.isEmpty(result)){
+            return result;
+        }
+        Map<Object, List<TreeNode>> groupByParentId = sources.stream()
+                .filter(node ->!StrUtil.equals("0",String.valueOf(node.getParentId())))
+                .collect(Collectors.groupingBy(TreeNode::getParentId));
+        result.forEach(topNode->{
+            topNode.setNodePath(topNode.getName());
+            fillChildNode(topNode,groupByParentId);
+        });
+        CollectionUtil.sort(result, Comparator.comparing(TreeNode::getSort));
+        return result;
+    }
+
+    /**
+     * 填充叶子子节点
+     */
+    private static void fillChildNode(TreeNode source, Map<Object, List<TreeNode>> groupByParentIdMap){
+        Object parentId = source.getId();
+        List<TreeNode> children = groupByParentIdMap.get(parentId);
+        if(CollectionUtil.isEmpty(children)){
+            return;
+        }
+        source.setChildren(children);
+        children.forEach(child->{
+            child.setNodePath(Optional.ofNullable(source.getName()).orElse("")+"/"+child.getName());
+            fillChildNode(child,groupByParentIdMap);
+        });
+        CollectionUtil.sort(children,Comparator.comparing(TreeNode::getSort));
+    }
+
+    public static <T extends TreeNode> List<T> flatTree(Collection<T> sources) {
+        List<T> result = new ArrayList<>();
+        for (T source : sources) {
+            flatTree(source,result);
+        }
+        return result;
+    }
+
+    private static  <T extends TreeNode>  void flatTree(T source,Collection<T> result){
+        if(source==null){
+            return;
+        }
+        result.add(source);
+        if(CollectionUtil.isNotEmpty(source.getChildren())){
+            for (Object child : source.getChildren()) {
+                flatTree((T) child,result);
+            }
+        }
+    }
+}

+ 47 - 0
tr-framework/src/main/java/cn/tr/core/utils/ValidationUtils.java

@@ -0,0 +1,47 @@
+package cn.tr.core.utils;
+
+import cn.hutool.core.collection.CollUtil;
+import org.springframework.util.StringUtils;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import javax.validation.Validator;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * 校验工具类
+ *
+ * @author 芋道源码
+ */
+public class ValidationUtils {
+
+    private static final Pattern PATTERN_MOBILE = Pattern.compile("^(?:(?:\\+|00)86)?1(?:(?:3[\\d])|(?:4[0,1,4-9])|(?:5[0-3,5-9])|(?:6[2,5-7])|(?:7[0-8])|(?:8[\\d])|(?:9[0-3,5-9]))\\d{8}$");
+
+    private static final Pattern PATTERN_URL = Pattern.compile("^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]");
+
+    private static final Pattern PATTERN_XML_NCNAME = Pattern.compile("[a-zA-Z_][\\-_.0-9_a-zA-Z$]*");
+
+    public static boolean isMobile(String mobile) {
+        return StringUtils.hasText(mobile)
+                && PATTERN_MOBILE.matcher(mobile).matches();
+    }
+
+    public static boolean isURL(String url) {
+        return StringUtils.hasText(url)
+                && PATTERN_URL.matcher(url).matches();
+    }
+
+    public static boolean isXmlNCName(String str) {
+        return StringUtils.hasText(str)
+                && PATTERN_XML_NCNAME.matcher(str).matches();
+    }
+
+    public static void validate(Validator validator, Object object, Class<?>... groups) {
+        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
+        if (CollUtil.isNotEmpty(constraintViolations)) {
+            throw new ConstraintViolationException(constraintViolations);
+        }
+    }
+
+}

+ 15 - 0
tr-framework/src/main/java/cn/tr/core/validation/Insert.java

@@ -0,0 +1,15 @@
+package cn.tr.core.validation;
+
+import java.lang.annotation.*;
+
+/**
+ * @@interface : Insert
+ * @Description : 数据新增时校验
+ * @Author : LF
+ * @Date: 2023年03月27日
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Insert {
+}

+ 15 - 0
tr-framework/src/main/java/cn/tr/core/validation/Update.java

@@ -0,0 +1,15 @@
+package cn.tr.core.validation;
+
+import java.lang.annotation.*;
+
+/**
+ * @@interface : Update
+ * @Description : 数据更新时校验
+ * @Author : LF
+ * @Date: 2023年03月27日
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Update {
+}

BIN=BIN
tr-framework/src/main/resources/ip2region.xdb


BIN=BIN
tr-framework/target/classes/cn/tr/core/annotation/ColumnDefaultValue.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/annotation/Comment.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/annotation/Mobile.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/annotation/MobileValidator.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/annotation/TenantIgnore.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/constant/MybatisConstant.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/context/SecurityContextHolder.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/enums/CreateEnum.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/enums/IEnum.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/enums/UserTypeEnum.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/enums/WebFilterOrderEnum.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/exception/BaseCode.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/exception/ServiceException.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/exception/TRExcCode.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/pojo/CommonResult.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/pojo/KeyValue.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/pojo/LoginResult.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/pojo/PageDomain.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/pojo/PageInfo.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/pojo/TableDataInfo.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/strategy/DeptDataPermissionStrategy.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/strategy/ExceptionStrategy.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/strategy/LoginUserStrategy.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/strategy/PageStrategy.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/strategy/auth/ILoginUser.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/tree/TreeNode.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/utils/CommonNetWorkInfoUtil.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/utils/IpUtil.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/utils/JsonUtils.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/utils/MediaTypeUtils$MediaType.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/utils/MediaTypeUtils.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/utils/Proxy$Task.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/utils/Proxy.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/utils/PswUtils.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/utils/ServletUtils.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/utils/TreeUtil.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/utils/ValidationUtils.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/validation/Insert.class


BIN=BIN
tr-framework/target/classes/cn/tr/core/validation/Update.class


BIN=BIN
tr-framework/target/classes/ip2region.xdb


+ 20 - 0
tr-modules-api/pom.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>tr-footstone</artifactId>
+        <groupId>cn.tr</groupId>
+        <version>0.0.9</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>tr-modules-api</artifactId>
+    <packaging>pom</packaging>
+    <modules>
+        <module>tr-module-system-api</module>
+        <module>tr-module-export-api</module>
+    </modules>
+
+
+</project>

+ 26 - 0
tr-modules-api/tr-module-export-api/pom.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>tr-modules-api</artifactId>
+        <groupId>cn.tr</groupId>
+        <version>0.0.9</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>tr-module-export-api</artifactId>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.tr</groupId>
+            <artifactId>tr-framework</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>easyexcel</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 21 - 0
tr-modules-api/tr-module-export-api/src/main/java/cn/tr/module/api/export/annotation/ExcelDict.java

@@ -0,0 +1,21 @@
+package cn.tr.module.api.export.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * @@interface : ExcelDict
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年05月19日
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface ExcelDict {
+    /**
+     * 字典码
+     * 1、导出时会根据字典码自动生成下拉菜单
+     * 2、导出时会根据字段值自动返回字典值
+     */
+    String dictCode() default "";
+}

BIN=BIN
tr-modules-api/tr-module-export-api/target/classes/cn/tr/module/api/export/annotation/ExcelDict.class


+ 23 - 0
tr-modules-api/tr-module-system-api/pom.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>tr-modules-api</artifactId>
+        <groupId>cn.tr</groupId>
+        <version>0.0.9</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>tr-module-system-api</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.tr</groupId>
+            <artifactId>tr-framework</artifactId>
+        </dependency>
+
+
+    </dependencies>
+
+</project>

+ 27 - 0
tr-modules-api/tr-module-system-api/src/main/java/cn/tr/module/api/sys/dict/SysDictApi.java

@@ -0,0 +1,27 @@
+package cn.tr.module.api.sys.dict;
+
+import cn.hutool.core.lang.Pair;
+import java.util.*;
+/**
+ * @ClassName : SysDictApi
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年05月19日
+ */
+
+public interface SysDictApi {
+    /**
+     * 查找字典值
+     * @param dictCode 字典编码
+     * @param itemKey  键值对key
+     * @return
+     */
+    String findDictItem(String dictCode,String itemKey);
+
+    /**
+     * 找到字典码下的所有字典值
+     * @param dictCode
+     * @return
+     */
+    List<Pair<String,String>> findAllDictItemsByCode(String dictCode);
+}

+ 45 - 0
tr-modules-api/tr-module-system-api/src/main/java/cn/tr/module/api/sys/log/annotation/OperateLog.java

@@ -0,0 +1,45 @@
+package cn.tr.module.api.sys.log.annotation;
+
+import cn.tr.module.api.sys.log.enums.LoginType;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 操作日志注解
+ *
+ * @author 芋道源码
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface OperateLog {
+
+    // ========== 模块字段 ==========
+
+    /**
+     * 操作名
+     *
+     * 为空时,会尝试读取 {@link io.swagger.annotations.ApiOperation#value()} ()} 属性
+     */
+    String name() default "";
+
+    LoginType loginType() default  LoginType.oper;
+
+    // ========== 开关字段 ==========
+
+    /**
+     * 是否记录操作日志
+     */
+    boolean enable() default true;
+    /**
+     * 是否记录方法参数
+     */
+    boolean logArgs() default true;
+    /**
+     * 是否记录方法结果的数据
+     */
+    boolean logResultData() default true;
+
+}

+ 64 - 0
tr-modules-api/tr-module-system-api/src/main/java/cn/tr/module/api/sys/log/bo/OperateLogBO.java

@@ -0,0 +1,64 @@
+package cn.tr.module.api.sys.log.bo;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 操作日志
+ *
+ * @author 芋道源码
+ */
+@Data
+public class OperateLogBO {
+    /**
+     * 操作名称
+     */
+    private String opName;
+    /**
+     * 用户IP
+     */
+    private String userIp;
+    /**
+     * 用户地址
+     */
+    private String loginLocation;
+    /**
+     * 类名称
+     */
+    private String javaClass;
+    /**
+     * 方法名称
+     */
+    private String javaMethod;
+    /**
+     * 操作时间
+     */
+    private Date opTime;
+    /**
+     * 执行时长
+     */
+    private Integer duration;
+    /**
+     * 操作用户
+     */
+    private String opUser;
+    /**
+     * 请求参数
+     */
+    private String requestArgs;
+    /**
+     * 浏览器UserAgent
+     */
+    private String userAgent;
+    /**
+     * 响应结果
+     */
+    private String resultJson;
+
+    /**
+     * 日志类型
+     * {@link cn.tr.module.api.sys.log.enums.LoginType}
+     */
+    private String type;
+}

+ 30 - 0
tr-modules-api/tr-module-system-api/src/main/java/cn/tr/module/api/sys/log/enums/LoginType.java

@@ -0,0 +1,30 @@
+package cn.tr.module.api.sys.log.enums;
+
+import lombok.Getter;
+
+/**
+ * 操作日志的操作类型
+ *
+ * @author ruoyi
+ */
+@Getter
+public enum LoginType {
+
+    /**
+     * 操作日志
+     */
+    oper,
+    /**
+     * 异常日志
+     */
+    exception,
+    /**
+     * 登录日志
+     */
+    login,
+    /**
+     * 登出日志
+     */
+    logout;
+
+}

+ 25 - 0
tr-modules-api/tr-module-system-api/src/main/java/cn/tr/module/api/sys/storage/SysStorageApi.java

@@ -0,0 +1,25 @@
+package cn.tr.module.api.sys.storage;
+
+/**
+ * @ClassName : SysStorageApi
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年05月18日
+ */
+
+public interface SysStorageApi {
+    /**
+     * 上传文件
+     * @param content 文件内容
+     * @param filename 上传文件名称
+     * @return  文件id
+     */
+    String upload(byte[] content,String filename) throws Exception;
+
+    /**
+     * 获取文件
+     * @param recordId 文件记录id
+     * @return
+     */
+    byte[] obtainContent(String recordId) throws Exception;
+}

+ 24 - 0
tr-modules-api/tr-module-system-api/src/main/java/cn/tr/module/api/sys/user/SysMenuApi.java

@@ -0,0 +1,24 @@
+package cn.tr.module.api.sys.user;
+
+
+import cn.hutool.core.lang.Pair;
+
+/**
+ * @Interface : SysMenuApi
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月14日
+ */
+
+public interface SysMenuApi {
+    /**
+     * 代码生成菜单插入
+     * @param parentId          父级菜单id
+     * @param busName           业务名称
+     * @param frontModuleName   前端模块名称
+     * @param functionName      功能名称
+     * @param permissionPrefix  权限前缀
+     * @return <menuId,componentPath> <菜单id,组件路径>
+     */
+    Pair<String,String> addForGenMenu(String parentId, String busName, String frontModuleName,String backModuleName,String permissionPrefix, String functionName);
+}

BIN=BIN
tr-modules-api/tr-module-system-api/target/classes/cn/tr/module/api/sys/dict/SysDictApi.class


BIN=BIN
tr-modules-api/tr-module-system-api/target/classes/cn/tr/module/api/sys/log/annotation/OperateLog.class


Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio