浏览代码

pigx-weixin

zhoutao 5 年之前
当前提交
d8213954ad
共有 100 个文件被更改,包括 8828 次插入0 次删除
  1. 18 0
      .editorconfig
  2. 62 0
      .gitignore
  3. 16 0
      .gogs/ISSUE_TEMPLATE.md
  4. 21 0
      LICENSE
  5. 32 0
      README.md
  6. 20 0
      db/1schema.sql
  7. 756 0
      db/2pigxx.sql
  8. 697 0
      db/3pigxx_ac.sql
  9. 478 0
      db/4pigxx_job.sql
  10. 124 0
      db/5pigxx_mp.sql
  11. 239 0
      db/6pigxx_config.sql
  12. 159 0
      db/7pigxx_pay.sql
  13. 51 0
      db/8pigxx_codegen.sql
  14. 23 0
      db/Dockerfile
  15. 162 0
      docker-compose.yml
  16. 17 0
      pigx-auth/Dockerfile
  17. 121 0
      pigx-auth/pom.xml
  18. 39 0
      pigx-auth/src/main/java/com/pig4cloud/pigx/auth/PigxAuthApplication.java
  19. 105 0
      pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfig.java
  20. 111 0
      pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/WebSecurityConfigurer.java
  21. 213 0
      pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/PigxTokenEndpoint.java
  22. 50 0
      pigx-auth/src/main/java/com/pig4cloud/pigx/auth/handler/PigxAuthenticationFailureEvenHandler.java
  23. 49 0
      pigx-auth/src/main/java/com/pig4cloud/pigx/auth/handler/PigxAuthenticationSuccessEventHandler.java
  24. 17 0
      pigx-auth/src/main/resources/bootstrap.yml
  25. 87 0
      pigx-auth/src/main/resources/logback-spring.xml
  26. 6 0
      pigx-auth/src/main/resources/static/css/bootstrap.min.css
  27. 67 0
      pigx-auth/src/main/resources/static/css/signin.css
  28. 51 0
      pigx-auth/src/main/resources/templates/ftl/confirm.ftl
  29. 34 0
      pigx-auth/src/main/resources/templates/ftl/login.ftl
  30. 210 0
      pigx-common/pigx-common-bom/pom.xml
  31. 70 0
      pigx-common/pigx-common-core/pom.xml
  32. 38 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/config/JacksonConfig.java
  33. 41 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/config/MessageSourceConfig.java
  34. 35 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/config/RestTemplateConfig.java
  35. 75 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/CacheConstants.java
  36. 94 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/CommonConstants.java
  37. 17 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/PaginationConstants.java
  38. 191 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java
  39. 42 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/ServiceNameConstants.java
  40. 33 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/DictTypeEnum.java
  41. 74 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/LoginTypeEnum.java
  42. 39 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/MenuTypeEnum.java
  43. 49 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/ProcessStatusEnum.java
  44. 49 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/ResourceTypeEnum.java
  45. 33 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/StyleTypeEnum.java
  46. 59 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/TaskStatusEnum.java
  47. 48 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/exception/CheckedException.java
  48. 35 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/exception/ValidateCodeException.java
  49. 35 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/jackson/PigxJavaTimeModule.java
  50. 60 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/Sensitive.java
  51. 105 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveSerialize.java
  52. 70 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveTypeEnum.java
  53. 114 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/ClassUtils.java
  54. 181 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/DesensitizedUtils.java
  55. 96 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/R.java
  56. 102 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/SpringContextHolder.java
  57. 240 0
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/WebUtils.java
  58. 5 0
      pigx-common/pigx-common-core/src/main/resources/META-INF/spring.factories
  59. 16 0
      pigx-common/pigx-common-core/src/main/resources/banner.txt
  60. 0 0
      pigx-common/pigx-common-core/src/main/resources/i18n/messages_zh_CN.properties
  61. 58 0
      pigx-common/pigx-common-data/pom.xml
  62. 275 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/DefaultRedisCacheWriter.java
  63. 86 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisAutoCacheManager.java
  64. 110 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisCacheAutoConfiguration.java
  65. 43 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisCacheManagerConfig.java
  66. 86 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisTemplateConfig.java
  67. 49 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScope.java
  68. 37 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScopeHandle.java
  69. 131 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScopeInterceptor.java
  70. 88 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/PigxDefaultDatascopeHandle.java
  71. 60 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/enums/DataScopeTypeEnum.java
  72. 57 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/handler/JsonStringArrayTypeHandler.java
  73. 101 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/mybatis/MybatisPlusConfiguration.java
  74. 115 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/resolver/SqlFilterArgumentResolver.java
  75. 36 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/resolver/WebMvcConfig.java
  76. 35 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/PigxFeignTenantConfiguration.java
  77. 39 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/PigxFeignTenantInterceptor.java
  78. 31 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/PigxTenantConfigProperties.java
  79. 82 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/PigxTenantHandler.java
  80. 55 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/TenantContextHolder.java
  81. 62 0
      pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/TenantContextHolderFilter.java
  82. 9 0
      pigx-common/pigx-common-data/src/main/resources/META-INF/spring.factories
  83. 86 0
      pigx-common/pigx-common-datasource/pom.xml
  84. 56 0
      pigx-common/pigx-common-datasource/src/main/java/com/pig4cloud/pigx/common/datasource/DynamicDataSourceAutoConfiguration.java
  85. 23 0
      pigx-common/pigx-common-datasource/src/main/java/com/pig4cloud/pigx/common/datasource/annotation/EnableDynamicDataSource.java
  86. 26 0
      pigx-common/pigx-common-datasource/src/main/java/com/pig4cloud/pigx/common/datasource/config/DruidDataSourceProperties.java
  87. 75 0
      pigx-common/pigx-common-datasource/src/main/java/com/pig4cloud/pigx/common/datasource/config/JdbcDynamicDataSourceProvider.java
  88. 57 0
      pigx-common/pigx-common-datasource/src/main/java/com/pig4cloud/pigx/common/datasource/config/LastParamDsProcessor.java
  89. 35 0
      pigx-common/pigx-common-datasource/src/main/java/com/pig4cloud/pigx/common/datasource/support/DataSourceConstants.java
  90. 22 0
      pigx-common/pigx-common-feign/pom.xml
  91. 40 0
      pigx-common/pigx-common-feign/src/main/java/com/pig4cloud/pigx/common/feign/PigxFeignAutoConfiguration.java
  92. 83 0
      pigx-common/pigx-common-feign/src/main/java/com/pig4cloud/pigx/common/feign/annotation/EnablePigxFeignClients.java
  93. 231 0
      pigx-common/pigx-common-feign/src/main/java/org/springframework/cloud/openfeign/PigxFeignClientsRegistrar.java
  94. 2 0
      pigx-common/pigx-common-feign/src/main/resources/META-INF/spring.factories
  95. 58 0
      pigx-common/pigx-common-gateway/pom.xml
  96. 37 0
      pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/annotation/EnablePigxDynamicRoute.java
  97. 106 0
      pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/configuration/DynamicRouteAutoConfiguration.java
  98. 57 0
      pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/configuration/GrayLoadBalancerClientConfiguration.java
  99. 108 0
      pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/filter/GrayReactiveLoadBalancerClientFilter.java
  100. 0 0
      pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/rule/GrayLoadBalancer.java

+ 18 - 0
.editorconfig

@@ -0,0 +1,18 @@
+# 开发组IDE 编辑器标准 V2.1.0
+root = true
+
+[*.{adoc, bat, groovy, html, java, js, jsp, kt, kts, md, properties, py, rb, sh, sql, svg, txt, xml, xsd}]
+charset = utf-8
+
+[*.{groovy, java, kt, kts, xml, xsd}]
+indent_style = tab
+indent_size = 4
+continuation_indent_size = 8
+end_of_line = lf
+
+[*.{js, html}]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true

+ 62 - 0
.gitignore

@@ -0,0 +1,62 @@
+# 忽略匹配下列规则的Git 提交 V2.1.0
+### gradle ###
+.gradle
+/build/
+!gradle/wrapper/gradle-wrapper.jar
+
+### STS ###
+.settings/
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+bin/
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+*.lock
+rebel.xml
+
+### NetBeans ###
+nbproject/private/
+build/
+nbbuild/
+nbdist/
+.nb-gradle/
+
+### maven ###
+target/
+*.war
+*.ear
+*.zip
+*.tar
+*.tar.gz
+
+### logs ####
+/logs/
+*.log
+
+### temp ignore ###
+*.cache
+*.diff
+*.patch
+*.tmp
+*.java~
+*.properties~
+*.xml~
+
+### system ignore ###
+.DS_Store
+Thumbs.db
+Servers
+.metadata
+upload
+gen_code
+
+### node ###
+node_modules

+ 16 - 0
.gogs/ISSUE_TEMPLATE.md

@@ -0,0 +1,16 @@
+### 环境信息  (必填)
+
+- pigx版本:      
+- 是否修改包名:  
+
+### 描述(无法理解工单,将直接关闭)
+
+日志、截图、回显步骤
+
+
+
+
+
+
+
+

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+    Copyright (c) 2018-2025, lengleng All rights reserved.
+
+协议和授权
+pigX并非一个开源软件,作者保留全部的权利。
+擅自窃用,即属严重侵权行为,与盗窃无异。产生的一切任何后果责任由侵权者自负。
+
+
+
+🌹权益
+个人学习、毕设
+
+
+🚫禁止
+将本项目的部分或全部代码和资源进行任何形式的再发行(尤其上传GitHub、Gitee )
+利用本项目的部分或全部代码和资源进行任何商业行为
+
+免责声明
+
+PigX 未对任何组织、团队,书面授权商业使用。如若出现任何商业后果、纠纷和本人无关,特此声明
+
+    Author: lengleng (wangiegie@gmail.com)

+ 32 - 0
README.md

@@ -0,0 +1,32 @@
+## 协议和授权
+
+pigX并非一个开源软件,作者保留全部的权利。
+擅自窃用,即属严重侵权行为,与盗窃无异。产生的一切任何后果责任由侵权者自负。
+
+### 🌹权益
+
+1. 个人使用
+2. 允许用于学习、毕设等。
+
+### 🚫禁止  
+
+1. 将本项目的部分或全部代码和资源进行任何形式的再发行(尤其上传GitHub、Gitee )
+2. 利用本项目的部分或全部代码和资源进行`任何商业行为`
+
+### 免责声明
+
+PigX 未对任何组织、团队,书面授权商业使用。如若出现任何商业后果、纠纷和本人无关,特此声明
+
+## 贡献代码
+
+pigX并非一个开源项目,也不是社区共同创造,其全部功能由作者独立完成。
+
+如果你愿意放弃所有权利,并将权利无条件转让给pigX作者,欢迎您贡献代码,当然会给予不等金额奖励。
+
+## 提交反馈
+
+1. 欢迎提交 issue,请写清楚遇到问题的原因,浏览器和操作系统环境,重现的流程。
+如果有开发能力,建议在本地调试出出错的代码。
+
+2. 不接受`功能请求`的 issue,功能请求可能会被直接关闭,请谅解(正确的方式是打赏并附言)。
+

+ 20 - 0
db/1schema.sql

@@ -0,0 +1,20 @@
+-- pigx 核心表
+create database `pigxx` default character set utf8mb4 collate utf8mb4_general_ci;
+
+-- pigx 工作流相关库
+create database `pigxx_ac` default character set utf8mb4 collate utf8mb4_general_ci;
+
+-- pigx 任务相关库
+create database `pigxx_job` default character set utf8mb4 collate utf8mb4_general_ci;
+
+-- pigx 公众号管理相关库
+create database `pigxx_mp` default character set utf8mb4 collate utf8mb4_general_ci;
+
+-- pigx nacos配置相关库
+create database `pigxx_config` default character set utf8mb4 collate utf8mb4_general_ci;
+
+-- pigx pay配置相关库
+create database `pigxx_pay` default character set utf8mb4 collate utf8mb4_general_ci;
+
+-- pigx codegen相关库
+create database `pigxx_codegen` default character set utf8mb4 collate utf8mb4_general_ci;

+ 756 - 0
db/2pigxx.sql

@@ -0,0 +1,756 @@
+USE pigxx;
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for sys_dept
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_dept`;
+CREATE TABLE `sys_dept` (
+  `dept_id` int(20) NOT NULL AUTO_INCREMENT,
+  `name` varchar(50) DEFAULT NULL,
+  `sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序',
+  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+  `del_flag` char(1) DEFAULT '0',
+  `parent_id` int(11) DEFAULT NULL,
+  `tenant_id` int(11) DEFAULT NULL,
+  PRIMARY KEY (`dept_id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COMMENT='部门管理';
+
+-- ----------------------------
+-- Records of sys_dept
+-- ----------------------------
+BEGIN;
+INSERT INTO `sys_dept` VALUES (1, '山东', 1, '2018-01-22 19:00:23', '2019-05-18 14:56:06', '0', 0, 1);
+INSERT INTO `sys_dept` VALUES (2, '沙县国际', 2, '2018-01-22 19:00:38', '2019-05-18 14:12:07', '0', 0, 1);
+INSERT INTO `sys_dept` VALUES (3, '潍坊', 3, '2018-01-22 19:00:44', '2019-05-18 14:56:11', '0', 1, 1);
+INSERT INTO `sys_dept` VALUES (4, '高新', 4, '2018-01-22 19:00:52', '2019-05-18 14:56:09', '0', 3, 1);
+INSERT INTO `sys_dept` VALUES (5, '院校', 5, '2018-01-22 19:00:57', '2019-05-18 14:56:13', '0', 4, 1);
+INSERT INTO `sys_dept` VALUES (6, '潍院', 6, '2018-01-22 19:01:06', '2019-05-18 14:56:16', '1', 5, 1);
+INSERT INTO `sys_dept` VALUES (7, '山东沙县', 7, '2018-01-22 19:01:57', '2019-05-18 14:12:17', '0', 2, 1);
+INSERT INTO `sys_dept` VALUES (8, '潍坊沙县', 8, '2018-01-22 19:02:03', '2019-05-18 14:12:19', '0', 7, 1);
+COMMIT;
+
+-- ----------------------------
+-- Table structure for sys_dept_relation
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_dept_relation`;
+CREATE TABLE `sys_dept_relation` (
+  `ancestor` int(11) NOT NULL COMMENT '祖先节点',
+  `descendant` int(11) NOT NULL COMMENT '后代节点',
+  PRIMARY KEY (`ancestor`,`descendant`) USING BTREE,
+  KEY `idx1` (`ancestor`) USING BTREE,
+  KEY `idx2` (`descendant`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='部门关系表';
+
+-- ----------------------------
+-- Records of sys_dept_relation
+-- ----------------------------
+BEGIN;
+INSERT INTO `sys_dept_relation` VALUES (1, 1);
+INSERT INTO `sys_dept_relation` VALUES (1, 3);
+INSERT INTO `sys_dept_relation` VALUES (1, 4);
+INSERT INTO `sys_dept_relation` VALUES (1, 5);
+INSERT INTO `sys_dept_relation` VALUES (2, 2);
+INSERT INTO `sys_dept_relation` VALUES (2, 7);
+INSERT INTO `sys_dept_relation` VALUES (2, 8);
+INSERT INTO `sys_dept_relation` VALUES (2, 11);
+INSERT INTO `sys_dept_relation` VALUES (2, 12);
+INSERT INTO `sys_dept_relation` VALUES (3, 3);
+INSERT INTO `sys_dept_relation` VALUES (3, 4);
+INSERT INTO `sys_dept_relation` VALUES (3, 5);
+INSERT INTO `sys_dept_relation` VALUES (4, 4);
+INSERT INTO `sys_dept_relation` VALUES (4, 5);
+INSERT INTO `sys_dept_relation` VALUES (5, 5);
+INSERT INTO `sys_dept_relation` VALUES (7, 7);
+INSERT INTO `sys_dept_relation` VALUES (7, 8);
+INSERT INTO `sys_dept_relation` VALUES (7, 11);
+INSERT INTO `sys_dept_relation` VALUES (7, 12);
+INSERT INTO `sys_dept_relation` VALUES (8, 8);
+COMMIT;
+
+
+-- ----------------------------
+-- Table structure for sys_dict
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_dict`;
+CREATE TABLE `sys_dict` (
+  `id` int(64) NOT NULL AUTO_INCREMENT COMMENT '编号',
+  `type` varchar(100) DEFAULT NULL,
+  `description` varchar(100) DEFAULT NULL,
+  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `remarks` varchar(255) DEFAULT NULL,
+  `system` char(1) DEFAULT '0',
+  `del_flag` char(1) DEFAULT '0',
+  `tenant_id` int(11) NOT NULL DEFAULT '0' COMMENT '所属租户',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `sys_dict_del_flag` (`del_flag`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COMMENT='字典表';
+
+-- ----------------------------
+-- Records of sys_dict
+-- ----------------------------
+BEGIN;
+INSERT INTO `sys_dict` VALUES (1, 'log_type', '日志类型', '2019-03-19 11:06:44', '2019-03-19 11:06:44', '异常、正常', '1', '0', 1);
+INSERT INTO `sys_dict` VALUES (2, 'social_type', '社交登录', '2019-03-19 11:09:44', '2019-03-19 11:09:44', '微信、QQ', '1', '0', 1);
+INSERT INTO `sys_dict` VALUES (3, 'leave_status', '请假状态', '2019-03-19 11:09:44', '2019-03-19 11:09:44', '未提交、审批中、完成、驳回', '1', '0', 1);
+INSERT INTO `sys_dict` VALUES (4, 'job_type', '定时任务类型', '2019-03-19 11:22:21', '2019-03-19 11:22:21', 'quartz', '1', '0', 1);
+INSERT INTO `sys_dict` VALUES (5, 'job_status', '定时任务状态', '2019-03-19 11:24:57', '2019-03-19 11:24:57', '发布状态、运行状态', '1', '0', 1);
+INSERT INTO `sys_dict` VALUES (6, 'job_execute_status', '定时任务执行状态', '2019-03-19 11:26:15', '2019-03-19 11:26:15', '正常、异常', '1', '0', 1);
+INSERT INTO `sys_dict` VALUES (7, 'misfire_policy', '定时任务错失执行策略', '2019-03-19 11:27:19', '2019-03-19 11:27:19', '周期', '1', '0', 1);
+INSERT INTO `sys_dict` VALUES (8, 'gender', '性别', '2019-03-27 13:44:06', '2019-03-27 13:44:06', '微信用户性别', '1', '0', 1);
+INSERT INTO `sys_dict` VALUES (9, 'subscribe', '订阅状态', '2019-03-27 13:48:33', '2019-03-27 13:48:33', '公众号订阅状态', '1', '0', 1);
+INSERT INTO `sys_dict` VALUES (10, 'response_type', '回复', '2019-03-28 21:29:21', '2019-03-28 21:29:21', '微信消息是否已回复', '1', '0', 1);
+INSERT INTO `sys_dict` VALUES (11, 'param_type', '参数配置', '2019-04-29 18:20:47', '2019-04-29 18:20:47', '检索、原文、报表、安全、文档、消息、其他', '1', '0', 1);
+INSERT INTO `sys_dict` VALUES (12, 'status_type', '租户状态', '2019-05-15 16:31:08', '2019-05-15 16:31:08', '租户状态', '1', '0', 1);
+INSERT INTO `sys_dict` VALUES (13, 'dict_type', '字典类型', '2019-05-16 14:16:20', '2019-05-16 14:20:16', '系统类不能修改', '1', '0', 1);
+INSERT INTO `sys_dict` VALUES (14, 'channel_status', '支付渠道状态', '2019-05-30 16:14:43', '2019-05-30 16:14:43', '支付渠道状态(0-正常,1-冻结)', '1', '0', 1);
+INSERT INTO `sys_dict` VALUES (15, 'channel_id', '渠道编码ID', '2019-05-30 18:59:12', '2019-05-30 18:59:12', '不同的支付方式', '1', '0', 1);
+INSERT INTO `sys_dict` VALUES (16, 'order_status', '订单状态', '2019-06-27 08:17:40', '2019-06-27 08:17:40', '支付订单状态', '1', '0', 1);
+INSERT INTO `sys_dict` VALUES (17, 'grant_types', '授权类型', '2019-08-13 07:34:10', '2019-08-13 07:34:10', NULL, '1', '0', 1);
+INSERT INTO `sys_dict` VALUES (18, 'style_type', '前端风格', '2020-02-07 03:49:28', '2020-02-07 03:50:40', '0-Avue 1-element', '1', '0', 1);
+COMMIT;
+
+-- ----------------------------
+-- Table structure for sys_dict_item
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_dict_item`;
+CREATE TABLE `sys_dict_item` (
+  `id` int(64) NOT NULL AUTO_INCREMENT COMMENT '编号',
+  `dict_id` int(11) NOT NULL,
+  `value` varchar(100) DEFAULT NULL,
+  `label` varchar(100) DEFAULT NULL,
+  `type` varchar(100) DEFAULT NULL,
+  `description` varchar(100) DEFAULT NULL,
+  `sort` int(10) NOT NULL DEFAULT '0' COMMENT '排序(升序)',
+  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `remarks` varchar(255) DEFAULT NULL,
+  `del_flag` char(1) DEFAULT '0',
+  `tenant_id` int(11) NOT NULL DEFAULT '0' COMMENT '所属租户',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `sys_dict_value` (`value`) USING BTREE,
+  KEY `sys_dict_label` (`label`) USING BTREE,
+  KEY `sys_dict_del_flag` (`del_flag`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=58 DEFAULT CHARSET=utf8mb4 COMMENT='字典项';
+
+-- ----------------------------
+-- Records of sys_dict_item
+-- ----------------------------
+BEGIN;
+INSERT INTO `sys_dict_item` VALUES (1, 1, '9', '异常', 'log_type', '日志异常', 1, '2019-03-19 11:08:59', '2019-03-25 12:49:13', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (2, 1, '0', '正常', 'log_type', '日志正常', 0, '2019-03-19 11:09:17', '2019-03-25 12:49:18', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (3, 2, 'WX', '微信', 'social_type', '微信登录', 0, '2019-03-19 11:10:02', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (4, 2, 'QQ', 'QQ', 'social_type', 'QQ登录', 1, '2019-03-19 11:10:14', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (5, 3, '0', '未提交', 'leave_status', '未提交', 0, '2019-03-19 11:18:34', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (6, 3, '1', '审批中', 'leave_status', '审批中', 1, '2019-03-19 11:18:45', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (7, 3, '2', '完成', 'leave_status', '完成', 2, '2019-03-19 11:19:02', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (8, 3, '9', '驳回', 'leave_status', '驳回', 9, '2019-03-19 11:19:20', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (9, 4, '1', 'java类', 'job_type', 'java类', 1, '2019-03-19 11:22:37', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (10, 4, '2', 'spring bean', 'job_type', 'spring bean容器实例', 2, '2019-03-19 11:23:05', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (11, 4, '9', '其他', 'job_type', '其他类型', 9, '2019-03-19 11:23:31', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (12, 4, '3', 'Rest 调用', 'job_type', 'Rest 调用', 3, '2019-03-19 11:23:57', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (13, 4, '4', 'jar', 'job_type', 'jar类型', 4, '2019-03-19 11:24:20', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (14, 5, '1', '未发布', 'job_status', '未发布', 1, '2019-03-19 11:25:18', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (15, 5, '2', '运行中', 'job_status', '运行中', 2, '2019-03-19 11:25:31', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (16, 5, '3', '暂停', 'job_status', '暂停', 3, '2019-03-19 11:25:42', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (17, 6, '0', '正常', 'job_execute_status', '正常', 0, '2019-03-19 11:26:27', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (18, 6, '1', '异常', 'job_execute_status', '异常', 1, '2019-03-19 11:26:41', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (19, 7, '1', '错失周期立即执行', 'misfire_policy', '错失周期立即执行', 1, '2019-03-19 11:27:45', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (20, 7, '2', '错失周期执行一次', 'misfire_policy', '错失周期执行一次', 2, '2019-03-19 11:27:57', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (21, 7, '3', '下周期执行', 'misfire_policy', '下周期执行', 3, '2019-03-19 11:28:08', '2019-03-25 12:49:36', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (22, 8, '1', '男', 'gender', '微信-男', 0, '2019-03-27 13:45:13', '2019-03-27 13:45:13', '微信-男', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (23, 8, '2', '女', 'gender', '女-微信', 1, '2019-03-27 13:45:34', '2019-03-27 13:45:34', '女-微信', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (24, 8, '0', '未知', 'gender', 'x性别未知', 3, '2019-03-27 13:45:57', '2019-03-27 13:45:57', 'x性别未知', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (25, 9, '0', '未关注', 'subscribe', '公众号-未关注', 0, '2019-03-27 13:49:07', '2019-03-27 13:49:07', '公众号-未关注', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (26, 9, '1', '已关注', 'subscribe', '公众号-已关注', 1, '2019-03-27 13:49:26', '2019-03-27 13:49:26', '公众号-已关注', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (27, 10, '0', '未回复', 'response_type', '微信消息-未回复', 0, '2019-03-28 21:29:47', '2019-03-28 21:29:47', '微信消息-未回复', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (28, 10, '1', '已回复', 'response_type', '微信消息-已回复', 1, '2019-03-28 21:30:08', '2019-03-28 21:30:08', '微信消息-已回复', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (29, 11, '1', '检索', 'param_type', '检索', 0, '2019-04-29 18:22:17', '2019-04-29 18:22:17', '检索', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (30, 11, '2', '原文', 'param_type', '原文', 0, '2019-04-29 18:22:27', '2019-04-29 18:22:27', '原文', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (31, 11, '3', '报表', 'param_type', '报表', 0, '2019-04-29 18:22:36', '2019-04-29 18:22:36', '报表', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (32, 11, '4', '安全', 'param_type', '安全', 0, '2019-04-29 18:22:46', '2019-04-29 18:22:46', '安全', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (33, 11, '5', '文档', 'param_type', '文档', 0, '2019-04-29 18:22:56', '2019-04-29 18:22:56', '文档', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (34, 11, '6', '消息', 'param_type', '消息', 0, '2019-04-29 18:23:05', '2019-04-29 18:23:05', '消息', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (35, 11, '9', '其他', 'param_type', '其他', 0, '2019-04-29 18:23:16', '2019-04-29 18:23:16', '其他', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (36, 11, '0', '默认', 'param_type', '默认', 0, '2019-04-29 18:23:30', '2019-04-29 18:23:30', '默认', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (37, 12, '0', '正常', 'status_type', '状态正常', 0, '2019-05-15 16:31:34', '2019-05-16 22:30:46', '状态正常', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (38, 12, '9', '冻结', 'status_type', '状态冻结', 1, '2019-05-15 16:31:56', '2019-05-16 22:30:50', '状态冻结', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (39, 13, '1', '系统类', 'dict_type', '系统类字典', 0, '2019-05-16 14:20:40', '2019-05-16 14:20:40', '不能修改删除', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (40, 13, '0', '业务类', 'dict_type', '业务类字典', 0, '2019-05-16 14:20:59', '2019-05-16 14:20:59', '可以修改', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (41, 14, '0', '正常', 'channel_status', '支付渠道状态正常', 0, '2019-05-30 16:16:51', '2019-05-30 16:16:51', NULL, '0', 1);
+INSERT INTO `sys_dict_item` VALUES (42, 14, '1', '冻结', 'channel_status', '支付渠道冻结', 0, '2019-05-30 16:17:08', '2019-05-30 16:17:08', NULL, '0', 1);
+INSERT INTO `sys_dict_item` VALUES (43, 15, 'ALIPAY_WAP', '支付宝wap支付', 'channel_id', '支付宝扫码支付', 0, '2019-05-30 19:03:16', '2019-06-18 13:51:42', '支付宝wap支付', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (44, 15, 'WEIXIN_MP', '微信公众号支付', 'channel_id', '微信公众号支付', 1, '2019-05-30 19:08:08', '2019-06-18 13:51:53', '微信公众号支付', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (45, 16, '1', '支付成功', 'order_status', '支付成功', 1, '2019-06-27 08:18:26', '2019-06-27 08:18:26', '订单支付成功', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (46, 16, '2', '支付完成', 'order_status', '订单支付完成', 2, '2019-06-27 08:18:44', '2019-06-27 08:18:44', '订单支付完成', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (47, 16, '0', '待支付', 'order_status', '订单待支付', 0, '2019-06-27 08:19:02', '2019-06-27 08:19:02', '订单待支付', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (48, 16, '-1', '支付失败', 'order_status', '订单支付失败', 3, '2019-06-27 08:19:37', '2019-06-27 08:19:37', '订单支付失败', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (49, 2, 'GITEE', '码云', 'social_type', '码云', 2, '2019-06-28 09:59:12', '2019-06-28 09:59:12', '码云', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (50, 2, 'OSC', '开源中国', 'social_type', '开源中国登录', 0, '2019-06-28 10:04:32', '2019-06-28 10:04:32', 'http://gitee.huaxiadaowei.com/#/authredirect', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (51, 17, 'password', '密码模式', 'grant_types', '支持oauth密码模式', 0, '2019-08-13 07:35:28', '2019-08-13 07:35:28', NULL, '0', 1);
+INSERT INTO `sys_dict_item` VALUES (52, 17, 'authorization_code', '授权码模式', 'grant_types', 'oauth2 授权码模式', 1, '2019-08-13 07:36:07', '2019-08-13 07:36:07', NULL, '0', 1);
+INSERT INTO `sys_dict_item` VALUES (53, 17, 'client_credentials', '客户端模式', 'grant_types', 'oauth2 客户端模式', 2, '2019-08-13 07:36:30', '2019-08-13 07:36:30', NULL, '0', 1);
+INSERT INTO `sys_dict_item` VALUES (54, 17, 'refresh_token', '刷新模式', 'grant_types', 'oauth2 刷新token', 3, '2019-08-13 07:36:54', '2019-08-13 07:36:54', NULL, '0', 1);
+INSERT INTO `sys_dict_item` VALUES (55, 17, 'implicit', '简化模式', 'grant_types', 'oauth2 简化模式', 4, '2019-08-13 07:39:32', '2019-08-13 07:39:32', NULL, '0', 1);
+INSERT INTO `sys_dict_item` VALUES (56, 18, '0', 'Avue', 'style_type', 'Avue风格', 0, '2020-02-07 03:52:52', '2020-02-07 03:52:52', '', '0', 1);
+INSERT INTO `sys_dict_item` VALUES (57, 18, '1', 'element', 'style_type', 'element-ui', 1, '2020-02-07 03:53:12', '2020-02-07 03:53:12', '', '0', 1);
+COMMIT;
+
+-- ----------------------------
+-- Table structure for sys_file
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_file`;
+CREATE TABLE `sys_file` (
+  `id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '编号',
+  `file_name` varchar(100) DEFAULT NULL,
+  `bucket_name` varchar(200) DEFAULT NULL,
+  `original` varchar(100) DEFAULT NULL,
+  `type` varchar(50) DEFAULT NULL,
+  `file_size` bigint(50) DEFAULT NULL COMMENT '文件大小',
+  `create_user` varchar(32) DEFAULT NULL,
+  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '上传时间',
+  `update_user` varchar(32) DEFAULT NULL,
+  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `del_flag` char(1) DEFAULT '0',
+  `tenant_id` int(11) DEFAULT NULL COMMENT '所属租户',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件管理表';
+
+-- ----------------------------
+-- Table structure for sys_log
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_log`;
+CREATE TABLE `sys_log` (
+  `id` bigint(64) NOT NULL AUTO_INCREMENT COMMENT '编号',
+  `type` char(1) DEFAULT '0',
+  `title` varchar(255) DEFAULT NULL,
+  `service_id` varchar(32) DEFAULT NULL,
+  `create_by` varchar(64) DEFAULT NULL,
+  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `remote_addr` varchar(255) DEFAULT NULL,
+  `user_agent` varchar(1000) DEFAULT NULL,
+  `request_uri` varchar(255) DEFAULT NULL,
+  `method` varchar(10) DEFAULT NULL,
+  `params` text,
+  `time` mediumtext CHARACTER SET utf8 COMMENT '执行时间',
+  `del_flag` char(1) DEFAULT '0',
+  `exception` text,
+  `tenant_id` int(11) DEFAULT '0' COMMENT '所属租户',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `sys_log_create_by` (`create_by`) USING BTREE,
+  KEY `sys_log_request_uri` (`request_uri`) USING BTREE,
+  KEY `sys_log_type` (`type`) USING BTREE,
+  KEY `sys_log_create_date` (`create_time`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日志表';
+
+-- ----------------------------
+-- Table structure for sys_menu
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_menu`;
+CREATE TABLE `sys_menu` (
+  `menu_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '菜单ID',
+  `name` varchar(32) DEFAULT NULL,
+  `permission` varchar(32) DEFAULT NULL,
+  `path` varchar(128) DEFAULT NULL,
+  `parent_id` int(11) DEFAULT NULL COMMENT '父菜单ID',
+  `icon` varchar(32) DEFAULT NULL,
+  `sort` int(11) DEFAULT '1' COMMENT '排序值',
+  `keep_alive` char(1) DEFAULT '0',
+  `type` char(1) DEFAULT '0',
+  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `del_flag` char(1) DEFAULT '0',
+  PRIMARY KEY (`menu_id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=10013 DEFAULT CHARSET=utf8mb4 COMMENT='菜单权限表';
+
+-- ----------------------------
+-- Records of sys_menu
+-- ----------------------------
+BEGIN;
+INSERT INTO `sys_menu` VALUES (1000, '权限管理', NULL, '/user', -1, 'icon-quanxianguanli', 0, '0', '0', '2018-09-28 08:29:53', '2018-09-28 08:53:01', '0');
+INSERT INTO `sys_menu` VALUES (1100, '用户管理', NULL, '/admin/user/index', 1000, 'icon-yonghuguanli', 1, '1', '0', '2017-11-02 22:24:37', '2019-06-24 14:36:36', '0');
+INSERT INTO `sys_menu` VALUES (1101, '用户新增', 'sys_user_add', NULL, 1100, NULL, NULL, '0', '1', '2017-11-08 09:52:09', '2018-09-28 09:06:34', '0');
+INSERT INTO `sys_menu` VALUES (1102, '用户修改', 'sys_user_edit', NULL, 1100, NULL, NULL, '0', '1', '2017-11-08 09:52:48', '2018-09-28 09:06:37', '0');
+INSERT INTO `sys_menu` VALUES (1103, '用户删除', 'sys_user_del', NULL, 1100, NULL, NULL, '0', '1', '2017-11-08 09:54:01', '2018-09-28 09:06:42', '0');
+INSERT INTO `sys_menu` VALUES (1200, '菜单管理', NULL, '/admin/menu/index', 1000, 'icon-caidanguanli', 2, '0', '0', '2017-11-08 09:57:27', '2019-06-24 14:42:07', '0');
+INSERT INTO `sys_menu` VALUES (1201, '菜单新增', 'sys_menu_add', NULL, 1200, NULL, NULL, '0', '1', '2017-11-08 10:15:53', '2018-09-28 09:07:16', '0');
+INSERT INTO `sys_menu` VALUES (1202, '菜单修改', 'sys_menu_edit', NULL, 1200, NULL, NULL, '0', '1', '2017-11-08 10:16:23', '2018-09-28 09:07:18', '0');
+INSERT INTO `sys_menu` VALUES (1203, '菜单删除', 'sys_menu_del', NULL, 1200, NULL, NULL, '0', '1', '2017-11-08 10:16:43', '2018-09-28 09:07:22', '0');
+INSERT INTO `sys_menu` VALUES (1300, '角色管理', NULL, '/admin/role/index', 1000, 'icon-jiaoseguanli', 3, '0', '0', '2017-11-08 10:13:37', '2018-09-28 09:00:48', '0');
+INSERT INTO `sys_menu` VALUES (1301, '角色新增', 'sys_role_add', NULL, 1300, NULL, NULL, '0', '1', '2017-11-08 10:14:18', '2018-09-28 09:07:46', '0');
+INSERT INTO `sys_menu` VALUES (1302, '角色修改', 'sys_role_edit', NULL, 1300, NULL, NULL, '0', '1', '2017-11-08 10:14:41', '2018-09-28 09:07:49', '0');
+INSERT INTO `sys_menu` VALUES (1303, '角色删除', 'sys_role_del', NULL, 1300, NULL, NULL, '0', '1', '2017-11-08 10:14:59', '2018-09-28 09:07:53', '0');
+INSERT INTO `sys_menu` VALUES (1304, '分配权限', 'sys_role_perm', NULL, 1300, NULL, NULL, '0', '1', '2018-04-20 07:22:55', '2018-09-28 09:13:23', '0');
+INSERT INTO `sys_menu` VALUES (1400, '部门管理', NULL, '/admin/dept/index', 1000, 'icon-web-icon-', 4, '0', '0', '2018-01-20 13:17:19', '2018-12-09 16:35:12', '0');
+INSERT INTO `sys_menu` VALUES (1401, '部门新增', 'sys_dept_add', NULL, 1400, NULL, NULL, '0', '1', '2018-01-20 14:56:16', '2018-09-28 09:08:13', '0');
+INSERT INTO `sys_menu` VALUES (1402, '部门修改', 'sys_dept_edit', NULL, 1400, NULL, NULL, '0', '1', '2018-01-20 14:56:59', '2018-09-28 09:08:16', '0');
+INSERT INTO `sys_menu` VALUES (1403, '部门删除', 'sys_dept_del', NULL, 1400, NULL, NULL, '0', '1', '2018-01-20 14:57:28', '2018-09-28 09:08:18', '0');
+INSERT INTO `sys_menu` VALUES (1500, '租户管理', '', '/admin/tenant/index', 1000, 'icon-erji-zuhushouye', 5, '0', '0', '2018-01-20 13:17:19', '2019-05-17 15:36:11', '0');
+INSERT INTO `sys_menu` VALUES (1501, '租户新增', 'admin_systenant_add', NULL, 1500, '1', 0, '0', '1', '2018-05-15 21:35:18', '2019-05-17 15:36:34', '0');
+INSERT INTO `sys_menu` VALUES (1502, '租户修改', 'admin_systenant_edit', NULL, 1500, '1', 1, '0', '1', '2018-05-15 21:35:18', '2019-05-17 15:36:53', '0');
+INSERT INTO `sys_menu` VALUES (1503, '租户删除', 'admin_systenant_del', NULL, 1500, '1', 2, '0', '1', '2018-05-15 21:35:18', '2019-05-17 15:37:00', '0');
+INSERT INTO `sys_menu` VALUES (2000, '系统管理', NULL, '/admin', -1, 'icon-xitongguanli', 1, '0', '0', '2017-11-07 20:56:00', '2018-09-28 08:53:18', '0');
+INSERT INTO `sys_menu` VALUES (2100, '日志管理', NULL, '/admin/log/index', 2000, 'icon-rizhiguanli', 5, '0', '0', '2017-11-20 14:06:22', '2018-09-28 09:01:52', '0');
+INSERT INTO `sys_menu` VALUES (2101, '日志删除', 'sys_log_del', NULL, 2100, NULL, NULL, '0', '1', '2017-11-20 20:37:37', '2018-09-28 09:08:44', '0');
+INSERT INTO `sys_menu` VALUES (2200, '字典管理', NULL, '/admin/dict/index', 2000, 'icon-navicon-zdgl', 6, '0', '0', '2017-11-29 11:30:52', '2018-09-28 09:01:47', '0');
+INSERT INTO `sys_menu` VALUES (2201, '字典删除', 'sys_dict_del', NULL, 2200, NULL, NULL, '0', '1', '2017-11-29 11:30:11', '2018-09-28 09:09:10', '0');
+INSERT INTO `sys_menu` VALUES (2202, '字典新增', 'sys_dict_add', NULL, 2200, NULL, NULL, '0', '1', '2018-05-11 22:34:55', '2018-09-28 09:09:12', '0');
+INSERT INTO `sys_menu` VALUES (2203, '字典修改', 'sys_dict_edit', NULL, 2200, NULL, NULL, '0', '1', '2018-05-11 22:36:03', '2018-09-28 09:09:16', '0');
+INSERT INTO `sys_menu` VALUES (2210, '参数管理', NULL, '/admin/param/index', 2000, 'icon-canshu', 7, '1', '0', '2019-04-29 22:16:50', '2019-06-24 14:52:00', '0');
+INSERT INTO `sys_menu` VALUES (2211, '参数新增', 'admin_syspublicparam_add', NULL, 2210, NULL, 1, '0', '1', '2019-04-29 22:17:36', NULL, '0');
+INSERT INTO `sys_menu` VALUES (2212, '参数删除', 'admin_syspublicparam_del', NULL, 2210, NULL, 1, '0', '1', '2019-04-29 22:17:55', NULL, '0');
+INSERT INTO `sys_menu` VALUES (2213, '参数编辑', 'admin_syspublicparam_edit', NULL, 2210, NULL, 1, '0', '1', '2019-04-29 22:18:14', '2019-04-29 22:19:25', '0');
+INSERT INTO `sys_menu` VALUES (2300, '代码生成', '', '/gen/index', 10006, 'icon-weibiaoti46', 1, '0', '0', '2018-01-20 13:17:19', '2019-08-12 10:28:44', '0');
+INSERT INTO `sys_menu` VALUES (2400, '终端管理', '', '/admin/client/index', 2000, 'icon-shouji', 9, '0', '0', '2018-01-20 13:17:19', '2018-09-28 09:01:43', '0');
+INSERT INTO `sys_menu` VALUES (2401, '客户端新增', 'sys_client_add', NULL, 2400, '1', NULL, '0', '1', '2018-05-15 21:35:18', '2018-09-28 09:10:25', '0');
+INSERT INTO `sys_menu` VALUES (2402, '客户端修改', 'sys_client_edit', NULL, 2400, NULL, NULL, '0', '1', '2018-05-15 21:37:06', '2018-09-28 09:10:27', '0');
+INSERT INTO `sys_menu` VALUES (2403, '客户端删除', 'sys_client_del', NULL, 2400, NULL, NULL, '0', '1', '2018-05-15 21:39:16', '2018-09-28 09:10:30', '0');
+INSERT INTO `sys_menu` VALUES (2500, '密钥管理', '', '/admin/social/index', 2000, 'icon-miyue', 10, '0', '0', '2018-01-20 13:17:19', '2018-09-28 09:01:41', '0');
+INSERT INTO `sys_menu` VALUES (2501, '密钥新增', 'sys_social_details_add', NULL, 2500, '1', 0, '0', '1', '2018-05-15 21:35:18', '2019-03-25 11:52:18', '0');
+INSERT INTO `sys_menu` VALUES (2502, '密钥修改', 'sys_social_details_edit', NULL, 2500, '1', 1, '0', '1', '2018-05-15 21:35:18', '2019-03-25 11:51:36', '0');
+INSERT INTO `sys_menu` VALUES (2503, '密钥删除', 'sys_social_details_del', NULL, 2500, '1', 2, '0', '1', '2018-05-15 21:35:18', '2019-03-25 11:51:30', '0');
+INSERT INTO `sys_menu` VALUES (2600, '令牌管理', NULL, '/admin/token/index', 2000, 'icon-denglvlingpai', 11, '0', '0', '2018-09-04 05:58:41', '2018-09-28 09:01:38', '0');
+INSERT INTO `sys_menu` VALUES (2601, '令牌删除', 'sys_token_del', NULL, 2600, NULL, 1, '0', '1', '2018-09-04 05:59:50', '2018-09-28 09:11:24', '0');
+INSERT INTO `sys_menu` VALUES (2700, '动态路由', NULL, '/admin/route/index', 2000, 'icon-luyou', 12, '0', '0', '2018-09-04 05:58:41', '2019-06-24 15:14:28', '0');
+INSERT INTO `sys_menu` VALUES (2800, 'Quartz管理', '', '/daemon/job-manage/index', 2000, 'icon-guanwangfangwen', 8, '0', '0', '2018-01-20 13:17:19', '2019-03-25 13:52:14', '0');
+INSERT INTO `sys_menu` VALUES (2810, '任务新增', 'job_sys_job_add', NULL, 2800, '1', 0, '0', '1', '2018-05-15 21:35:18', '2019-03-25 11:50:23', '0');
+INSERT INTO `sys_menu` VALUES (2820, '任务修改', 'job_sys_job_edit', NULL, 2800, '1', 0, '0', '1', '2018-05-15 21:35:18', '2019-03-25 11:50:26', '0');
+INSERT INTO `sys_menu` VALUES (2830, '任务删除', 'job_sys_job_del', NULL, 2800, '1', 0, '0', '1', '2018-05-15 21:35:18', '2019-03-25 11:50:30', '0');
+INSERT INTO `sys_menu` VALUES (2840, '任务暂停', 'job_sys_job_shutdown_job', NULL, 2800, '1', 0, '0', '1', '2018-05-15 21:35:18', '2019-03-25 11:50:18', '0');
+INSERT INTO `sys_menu` VALUES (2850, '任务开始', 'job_sys_job_start_job', NULL, 2800, '1', 0, '0', '1', '2018-05-15 21:35:18', '2019-03-25 11:50:35', '0');
+INSERT INTO `sys_menu` VALUES (2860, '任务刷新', 'job_sys_job_refresh_job', NULL, 2800, '1', 0, '0', '1', '2018-05-15 21:35:18', '2019-03-25 11:50:39', '0');
+INSERT INTO `sys_menu` VALUES (2870, '执行任务', 'job_sys_job_run_job', NULL, 2800, '1', 0, '0', '1', '2019-08-08 15:35:18', '2019-08-08 15:50:35', '0');
+INSERT INTO `sys_menu` VALUES (3000, '系统监控', NULL, '/daemon', -1, 'icon-msnui-supervise', 2, '0', '0', '2018-07-27 01:13:21', '2018-09-28 08:53:24', '0');
+INSERT INTO `sys_menu` VALUES (3100, '服务监控', NULL, 'http://127.0.0.1:5001', 3000, 'icon-server', 0, '0', '0', '2018-06-26 10:50:32', '2019-05-01 23:54:05', '0');
+INSERT INTO `sys_menu` VALUES (3110, '缓存监控', NULL, '/monitor/redis/index', 3000, 'icon-qingchuhuancun', 1, '1', '0', '2019-05-08 23:51:27', '2019-06-24 15:17:45', '0');
+INSERT INTO `sys_menu` VALUES (3200, '接口文档', NULL, 'http://127.0.0.1:9999/swagger-ui.html', 3000, 'icon-wendang', 1, '0', '0', '2018-06-26 10:50:32', '2019-05-01 23:57:11', '0');
+INSERT INTO `sys_menu` VALUES (3300, '事务监控', NULL, '/tx/index', 3000, 'icon-gtsquanjushiwufuwuGTS', 5, '0', '0', '2018-08-19 11:02:39', '2019-06-24 15:18:04', '0');
+INSERT INTO `sys_menu` VALUES (3400, '在线事务', NULL, '/tx/model', 3000, 'icon-online', 6, '0', '0', '2018-08-19 11:32:04', '2019-06-24 15:18:13', '0');
+INSERT INTO `sys_menu` VALUES (3500, '文档扩展', NULL, 'http://127.0.0.1:9999/doc.html', 3000, 'icon-wendang', 2, '0', '0', '2018-06-26 10:50:32', '2019-05-01 23:57:42', '0');
+INSERT INTO `sys_menu` VALUES (3600, '任务轨迹', '', '/daemon/status-trace-log/index', 3000, 'icon-guiji', 8, '0', '0', '2018-01-20 13:17:19', '2019-06-24 15:18:41', '0');
+INSERT INTO `sys_menu` VALUES (3601, '删除轨迹', 'daemon_status_trace_log_del', NULL, 3600, '1', 2, '0', '1', '2018-05-15 21:35:18', '2019-03-30 09:31:06', '0');
+INSERT INTO `sys_menu` VALUES (3620, 'Quartz日志', '', '/daemon/job-log/index', 3000, 'icon-gtsquanjushiwufuwuGTS', 8, '0', '0', '2018-01-20 13:17:19', '2019-06-24 15:18:54', '0');
+INSERT INTO `sys_menu` VALUES (3630, '任务日志', '', '/daemon/execution-log/index', 3000, 'icon-wendang', 7, '0', '0', '2018-01-20 13:17:19', '2019-06-24 15:19:07', '0');
+INSERT INTO `sys_menu` VALUES (3631, '删除日志', 'daemon_execution_log_del', NULL, 3900, '1', 2, '0', '1', '2018-05-15 21:35:18', '2019-03-30 09:30:45', '0');
+INSERT INTO `sys_menu` VALUES (3700, '注册配置', NULL, '', 3000, 'icon-line', 10, '0', '0', '2018-01-25 11:08:52', '2019-06-24 15:35:10', '1');
+INSERT INTO `sys_menu` VALUES (4000, '协同管理', NULL, '/activti', -1, 'icon-kuaisugongzuoliu_o', 3, '0', '0', '2018-09-26 01:38:13', '2018-09-28 08:58:24', '0');
+INSERT INTO `sys_menu` VALUES (4100, '模型管理', NULL, '/activiti/index', 4000, 'icon-weibiaoti13', 1, '0', '0', '2018-09-26 01:39:07', '2019-06-24 15:20:00', '0');
+INSERT INTO `sys_menu` VALUES (4101, '模型管理', 'act_model_manage', NULL, 4100, '1', 0, '0', '1', '2018-05-15 21:35:18', '2018-09-28 09:12:07', '0');
+INSERT INTO `sys_menu` VALUES (4200, '流程管理', '/activiti/process', '/activiti/process', 4000, 'icon-liucheng', 2, '0', '0', '2018-09-26 06:41:05', '2019-06-24 08:31:07', '0');
+INSERT INTO `sys_menu` VALUES (4201, '流程管理', 'act_process_manage', NULL, 4200, '1', 0, '0', '1', '2018-05-15 21:35:18', '2018-09-28 09:12:07', '0');
+INSERT INTO `sys_menu` VALUES (4300, '请假管理', '/activiti/leave', '/activiti/leave', 4000, 'icon-qingjia', 3, '0', '0', '2018-01-20 13:17:19', '2019-06-24 08:31:11', '0');
+INSERT INTO `sys_menu` VALUES (4301, '请假新增', 'act_leavebill_add', NULL, 4300, '1', 0, '0', '1', '2018-05-15 21:35:18', '2018-09-28 09:12:07', '0');
+INSERT INTO `sys_menu` VALUES (4302, '请假修改', 'act_leavebill_edit', NULL, 4300, '1', 1, '0', '1', '2018-05-15 21:35:18', '2018-09-28 09:12:09', '0');
+INSERT INTO `sys_menu` VALUES (4303, '请假删除', 'act_leavebill_del', NULL, 4300, '1', 2, '0', '1', '2018-05-15 21:35:18', '2018-09-28 09:12:14', '0');
+INSERT INTO `sys_menu` VALUES (4400, '待办任务', '/activiti/task', '/activiti/task', 4000, 'icon-renwu', 4, '0', '0', '2018-09-27 09:52:31', '2019-06-24 08:31:18', '0');
+INSERT INTO `sys_menu` VALUES (4401, '流程管理', 'act_task_manage', NULL, 4400, '1', 0, '0', '1', '2018-05-15 21:35:18', '2018-09-28 09:12:07', '0');
+INSERT INTO `sys_menu` VALUES (5000, '支付管理', NULL, '/pay', -1, 'icon-pay6zhifu', 4, '1', '0', '2019-05-30 15:28:03', '2019-06-20 16:13:23', '0');
+INSERT INTO `sys_menu` VALUES (5100, '渠道管理', NULL, '/pay/paychannel/index', 5000, 'icon-zhifuqudaoguanli', 1, '1', '0', '2019-05-30 15:32:17', '2019-05-30 19:43:27', '0');
+INSERT INTO `sys_menu` VALUES (5110, '增加渠道', 'pay_paychannel_add', NULL, 5100, NULL, 1, '0', '1', '2019-05-30 15:46:14', NULL, '0');
+INSERT INTO `sys_menu` VALUES (5120, '编辑渠道', 'pay_paychannel_edit', NULL, 5100, NULL, 1, '0', '1', '2019-05-30 15:46:35', NULL, '0');
+INSERT INTO `sys_menu` VALUES (5130, '删除渠道', 'pay_paychannel_del', NULL, 5100, NULL, 1, '0', '1', '2019-05-30 15:47:08', NULL, '0');
+INSERT INTO `sys_menu` VALUES (5200, '收银台', NULL, '/pay/cd/index', 5000, 'icon-shouyintai', 0, '1', '0', '2019-05-30 19:44:00', '2019-05-30 19:45:05', '0');
+INSERT INTO `sys_menu` VALUES (5300, '商品订单', '', '/pay/goods/index', 5000, 'icon-dingdan', 2, '0', '0', '2018-01-20 13:17:19', '2019-06-16 18:02:21', '0');
+INSERT INTO `sys_menu` VALUES (5310, '商品订单新增', 'generator_paygoodsorder_add', NULL, 5300, '1', 0, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (5320, '商品订单修改', 'generator_paygoodsorder_edit', NULL, 5300, '1', 1, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (5330, '商品订单删除', 'generator_paygoodsorder_del', NULL, 5300, '1', 2, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (5400, '支付订单', '', '/pay/orders/index', 5000, 'icon-zhifu', 3, '0', '0', '2018-01-20 13:17:19', '2019-06-16 18:02:06', '0');
+INSERT INTO `sys_menu` VALUES (5410, '支付订单新增', 'generator_paytradeorder_add', NULL, 5400, '1', 0, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (5420, '支付订单修改', 'generator_paytradeorder_edit', NULL, 5400, '1', 1, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (5430, '支付订单删除', 'generator_paytradeorder_del', NULL, 5400, '1', 2, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (5500, '回调记录', '', '/pay/notify/index', 5000, 'icon-huitiao', 4, '0', '0', '2018-01-20 13:17:19', '2019-06-16 18:01:49', '0');
+INSERT INTO `sys_menu` VALUES (5510, '记录新增', 'generator_paynotifyrecord_add', NULL, 5500, '1', 0, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (5520, '记录修改', 'generator_paynotifyrecord_edit', NULL, 5500, '1', 1, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (5530, '记录删除', 'generator_paynotifyrecord_del', NULL, 5500, '1', 2, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (6000, '微信管理', NULL, '/mp', -1, 'icon-gongzhonghao', 4, '0', '0', '2018-09-26 01:38:13', '2018-09-28 08:58:24', '0');
+INSERT INTO `sys_menu` VALUES (6100, '账号管理', '', '/mp/wxaccount/index', 6000, 'icon-weixincaidan', 8, '0', '0', '2018-01-20 13:17:19', '2019-06-24 15:24:36', '0');
+INSERT INTO `sys_menu` VALUES (6101, '公众号新增', 'mp_wxaccount_add', '', 6100, '1', 0, '0', '1', '2018-05-15 21:35:18', '2019-06-24 15:24:33', '0');
+INSERT INTO `sys_menu` VALUES (6102, '公众号修改', 'mp_wxaccount_edit', NULL, 6100, '1', 1, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (6103, '公众号删除', 'mp_wxaccount_del', NULL, 6100, '1', 2, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (6200, '粉丝管理', '', '/mp/wxaccountfans/index', 6000, 'icon-fensiguanli', 8, '0', '0', '2018-01-20 13:17:19', '2019-06-24 15:24:46', '0');
+INSERT INTO `sys_menu` VALUES (6201, '粉丝新增', 'mp_wxaccountfans_add', NULL, 6200, '1', 0, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (6202, '粉丝修改', 'mp_wxaccountfans_edit', NULL, 6200, '1', 1, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (6203, '粉丝删除', 'mp_wxaccountfans_del', NULL, 6200, '1', 2, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (6300, '消息管理', '', '/mp/wxfansmsg/index', 6000, 'icon-xiaoxiguanli', 8, '0', '0', '2018-01-20 13:17:19', '2019-06-24 15:24:57', '0');
+INSERT INTO `sys_menu` VALUES (6301, '消息新增', 'mp_wxfansmsg_add', NULL, 6300, '1', 0, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (6302, '消息修改', 'mp_wxfansmsg_edit', NULL, 6300, '1', 1, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (6303, '消息删除', 'mp_wxfansmsg_del', NULL, 6300, '1', 2, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (6304, '消息回复', 'mp_wxfansmsgres_add', NULL, 6300, '1', 3, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (6305, '回复删除', 'mp_wxfansmsgres_del', NULL, 6300, NULL, 1, '0', '1', '2019-03-28 22:53:49', NULL, '0');
+INSERT INTO `sys_menu` VALUES (6400, '菜单设置', NULL, '/mp/wxmenu/index', 6000, 'icon-anniu_weixincaidanlianjie', 6, '1', '0', '2019-03-29 15:20:12', '2019-06-24 15:25:07', '0');
+INSERT INTO `sys_menu` VALUES (6401, '保存', 'mp_wxmenu_add', NULL, 6400, NULL, 1, '0', '1', '2019-03-29 15:43:22', '2019-03-29 15:43:30', '0');
+INSERT INTO `sys_menu` VALUES (6402, '发布', 'mp_wxmenu_push', NULL, 6400, NULL, 1, '0', '1', '2019-03-29 15:43:54', NULL, '0');
+INSERT INTO `sys_menu` VALUES (6500, '运营数据', NULL, '/mp/wxstatistics/index', 6000, 'icon-zhexiantu', 7, '1', '0', '2019-04-14 00:15:35', '2019-06-24 15:25:15', '0');
+INSERT INTO `sys_menu` VALUES (10000, '文件管理', NULL, '/admin/file/index', 2000, 'icon-wenjianguanli', 6, '1', '0', '2019-06-25 12:44:46', NULL, '0');
+INSERT INTO `sys_menu` VALUES (10001, '删除文件', 'sys_file_del', NULL, 10000, NULL, 1, '0', '1', '2019-06-25 13:41:41', NULL, '0');
+INSERT INTO `sys_menu` VALUES (10002, '表单管理', '', '/gen/form', 10006, 'icon-record', 3, '0', '0', '2018-01-20 13:17:19', '2019-08-12 09:36:09', '0');
+INSERT INTO `sys_menu` VALUES (10003, '表单新增', 'gen_form_add', NULL, 10002, '1', 0, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (10004, '表单修改', 'gen_form_edit', NULL, 10002, '1', 1, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (10005, '表单删除', 'gen_form_del', NULL, 10002, '1', 2, '0', '1', '2018-05-15 21:35:18', '2018-07-29 13:38:59', '0');
+INSERT INTO `sys_menu` VALUES (10006, '开发平台', NULL, '/gen', -1, 'icon-shejiyukaifa-', 9, '1', '0', '2019-08-12 09:35:16', '2019-08-12 10:28:35', '0');
+INSERT INTO `sys_menu` VALUES (10007, '数据源管理', NULL, '/gen/datasource', 10006, 'icon-mysql', 0, '1', '0', '2019-08-12 09:42:11', '2019-08-12 10:33:30', '0');
+INSERT INTO `sys_menu` VALUES (10008, '表单设计', NULL, '/gen/design', 10006, 'icon-biaodanbiaoqian', 2, '1', '0', '2019-08-16 10:08:56', NULL, '0');
+COMMIT;
+
+-- ----------------------------
+-- Table structure for sys_oauth_client_details
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_oauth_client_details`;
+CREATE TABLE `sys_oauth_client_details` (
+  `client_id` varchar(32) NOT NULL,
+  `resource_ids` varchar(256) DEFAULT NULL,
+  `client_secret` varchar(256) DEFAULT NULL,
+  `scope` varchar(256) DEFAULT NULL,
+  `authorized_grant_types` varchar(256) DEFAULT NULL,
+  `web_server_redirect_uri` varchar(256) DEFAULT NULL,
+  `authorities` varchar(256) DEFAULT NULL,
+  `access_token_validity` int(11) DEFAULT NULL,
+  `refresh_token_validity` int(11) DEFAULT NULL,
+  `additional_information` varchar(4096) DEFAULT NULL,
+  `autoapprove` varchar(256) DEFAULT NULL,
+  `tenant_id` int(11) NOT NULL DEFAULT '0' COMMENT '所属租户',
+  PRIMARY KEY (`client_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='终端信息表';
+
+-- ----------------------------
+-- Records of sys_oauth_client_details
+-- ----------------------------
+BEGIN;
+INSERT INTO `sys_oauth_client_details` VALUES ('app', NULL, 'app', 'server', 'password,refresh_token,authorization_code,client_credentials,implicit', NULL, NULL, 43200, 2592001, NULL, 'true', 1);
+INSERT INTO `sys_oauth_client_details` VALUES ('daemon', NULL, 'daemon', 'server', 'password,refresh_token', NULL, NULL, NULL, NULL, NULL, 'true', 1);
+INSERT INTO `sys_oauth_client_details` VALUES ('gen', NULL, 'gen', 'server', 'password,refresh_token', NULL, NULL, NULL, NULL, NULL, 'true', 1);
+INSERT INTO `sys_oauth_client_details` VALUES ('mp', NULL, 'mp', 'server', 'password,refresh_token', NULL, NULL, NULL, NULL, NULL, 'true', 1);
+INSERT INTO `sys_oauth_client_details` VALUES ('pig', NULL, 'pig', 'server', 'password,refresh_token,authorization_code,client_credentials', 'http://localhost:4040/sso1/login,http://localhost:4041/sso1/login,http://localhost:8080/renren-admin/sys/oauth2-sso,http://localhost:8090/sys/oauth2-sso', NULL, NULL, NULL, NULL, 'false', 1);
+INSERT INTO `sys_oauth_client_details` VALUES ('qwe', NULL, 'qwe', 'qwe', 'implicit', NULL, NULL, NULL, NULL, NULL, 'false', 0);
+INSERT INTO `sys_oauth_client_details` VALUES ('test', NULL, 'test', 'server', 'password,refresh_token', NULL, NULL, NULL, NULL, NULL, 'true', 1);
+COMMIT;
+
+-- ----------------------------
+-- Table structure for sys_public_param
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_public_param`;
+CREATE TABLE `sys_public_param` (
+  `public_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
+  `public_name` varchar(128) DEFAULT NULL,
+  `public_key` varchar(128) DEFAULT NULL,
+  `public_value` varchar(128) DEFAULT NULL,
+  `status` char(1) DEFAULT '0',
+  `validate_code` varchar(64) DEFAULT NULL,
+  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+  `public_type` char(1) DEFAULT '0',
+  `system` char(1) DEFAULT '0',
+  `del_flag` char(1) DEFAULT '0',
+  `tenant_id` int(11) DEFAULT NULL COMMENT '租户ID',
+  PRIMARY KEY (`public_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='公共参数配置表';
+
+-- ----------------------------
+-- Table structure for sys_role
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_role`;
+CREATE TABLE `sys_role` (
+  `role_id` int(11) NOT NULL AUTO_INCREMENT,
+  `role_name` varchar(64) DEFAULT NULL,
+  `role_code` varchar(64) DEFAULT NULL,
+  `role_desc` varchar(255) DEFAULT NULL,
+  `ds_type` char(1) DEFAULT '2',
+  `ds_scope` varchar(255) DEFAULT NULL,
+  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `update_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
+  `del_flag` char(1) DEFAULT '0',
+  `tenant_id` int(11) DEFAULT NULL,
+  PRIMARY KEY (`role_id`) USING BTREE,
+  KEY `role_idx1_role_code` (`role_code`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='系统角色表';
+
+-- ----------------------------
+-- Records of sys_role
+-- ----------------------------
+BEGIN;
+INSERT INTO `sys_role` VALUES (1, '管理员', 'ROLE_ADMIN', '管理员', '0', '2', '2017-10-29 15:45:51', '2018-12-26 14:09:11', '0', 1);
+COMMIT;
+
+-- ----------------------------
+-- Table structure for sys_role_menu
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_role_menu`;
+CREATE TABLE `sys_role_menu` (
+  `role_id` int(11) NOT NULL COMMENT '角色ID',
+  `menu_id` int(11) NOT NULL COMMENT '菜单ID',
+  PRIMARY KEY (`role_id`,`menu_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色菜单表';
+
+-- ----------------------------
+-- Records of sys_role_menu
+-- ----------------------------
+BEGIN;
+INSERT INTO `sys_role_menu` VALUES (1, 1000);
+INSERT INTO `sys_role_menu` VALUES (1, 1100);
+INSERT INTO `sys_role_menu` VALUES (1, 1101);
+INSERT INTO `sys_role_menu` VALUES (1, 1102);
+INSERT INTO `sys_role_menu` VALUES (1, 1103);
+INSERT INTO `sys_role_menu` VALUES (1, 1200);
+INSERT INTO `sys_role_menu` VALUES (1, 1201);
+INSERT INTO `sys_role_menu` VALUES (1, 1202);
+INSERT INTO `sys_role_menu` VALUES (1, 1203);
+INSERT INTO `sys_role_menu` VALUES (1, 1300);
+INSERT INTO `sys_role_menu` VALUES (1, 1301);
+INSERT INTO `sys_role_menu` VALUES (1, 1302);
+INSERT INTO `sys_role_menu` VALUES (1, 1303);
+INSERT INTO `sys_role_menu` VALUES (1, 1304);
+INSERT INTO `sys_role_menu` VALUES (1, 1400);
+INSERT INTO `sys_role_menu` VALUES (1, 1401);
+INSERT INTO `sys_role_menu` VALUES (1, 1402);
+INSERT INTO `sys_role_menu` VALUES (1, 1403);
+INSERT INTO `sys_role_menu` VALUES (1, 1500);
+INSERT INTO `sys_role_menu` VALUES (1, 1501);
+INSERT INTO `sys_role_menu` VALUES (1, 1502);
+INSERT INTO `sys_role_menu` VALUES (1, 1503);
+INSERT INTO `sys_role_menu` VALUES (1, 2000);
+INSERT INTO `sys_role_menu` VALUES (1, 2100);
+INSERT INTO `sys_role_menu` VALUES (1, 2101);
+INSERT INTO `sys_role_menu` VALUES (1, 2200);
+INSERT INTO `sys_role_menu` VALUES (1, 2201);
+INSERT INTO `sys_role_menu` VALUES (1, 2202);
+INSERT INTO `sys_role_menu` VALUES (1, 2203);
+INSERT INTO `sys_role_menu` VALUES (1, 2210);
+INSERT INTO `sys_role_menu` VALUES (1, 2211);
+INSERT INTO `sys_role_menu` VALUES (1, 2212);
+INSERT INTO `sys_role_menu` VALUES (1, 2213);
+INSERT INTO `sys_role_menu` VALUES (1, 2300);
+INSERT INTO `sys_role_menu` VALUES (1, 2400);
+INSERT INTO `sys_role_menu` VALUES (1, 2401);
+INSERT INTO `sys_role_menu` VALUES (1, 2402);
+INSERT INTO `sys_role_menu` VALUES (1, 2403);
+INSERT INTO `sys_role_menu` VALUES (1, 2500);
+INSERT INTO `sys_role_menu` VALUES (1, 2501);
+INSERT INTO `sys_role_menu` VALUES (1, 2502);
+INSERT INTO `sys_role_menu` VALUES (1, 2503);
+INSERT INTO `sys_role_menu` VALUES (1, 2600);
+INSERT INTO `sys_role_menu` VALUES (1, 2601);
+INSERT INTO `sys_role_menu` VALUES (1, 2700);
+INSERT INTO `sys_role_menu` VALUES (1, 2800);
+INSERT INTO `sys_role_menu` VALUES (1, 2810);
+INSERT INTO `sys_role_menu` VALUES (1, 2820);
+INSERT INTO `sys_role_menu` VALUES (1, 2830);
+INSERT INTO `sys_role_menu` VALUES (1, 2840);
+INSERT INTO `sys_role_menu` VALUES (1, 2850);
+INSERT INTO `sys_role_menu` VALUES (1, 2860);
+INSERT INTO `sys_role_menu` VALUES (1, 2870);
+INSERT INTO `sys_role_menu` VALUES (1, 3000);
+INSERT INTO `sys_role_menu` VALUES (1, 3100);
+INSERT INTO `sys_role_menu` VALUES (1, 3110);
+INSERT INTO `sys_role_menu` VALUES (1, 3200);
+INSERT INTO `sys_role_menu` VALUES (1, 3300);
+INSERT INTO `sys_role_menu` VALUES (1, 3400);
+INSERT INTO `sys_role_menu` VALUES (1, 3500);
+INSERT INTO `sys_role_menu` VALUES (1, 3600);
+INSERT INTO `sys_role_menu` VALUES (1, 3601);
+INSERT INTO `sys_role_menu` VALUES (1, 3620);
+INSERT INTO `sys_role_menu` VALUES (1, 3630);
+INSERT INTO `sys_role_menu` VALUES (1, 4000);
+INSERT INTO `sys_role_menu` VALUES (1, 4100);
+INSERT INTO `sys_role_menu` VALUES (1, 4101);
+INSERT INTO `sys_role_menu` VALUES (1, 4200);
+INSERT INTO `sys_role_menu` VALUES (1, 4201);
+INSERT INTO `sys_role_menu` VALUES (1, 4300);
+INSERT INTO `sys_role_menu` VALUES (1, 4301);
+INSERT INTO `sys_role_menu` VALUES (1, 4302);
+INSERT INTO `sys_role_menu` VALUES (1, 4303);
+INSERT INTO `sys_role_menu` VALUES (1, 4400);
+INSERT INTO `sys_role_menu` VALUES (1, 4401);
+INSERT INTO `sys_role_menu` VALUES (1, 5000);
+INSERT INTO `sys_role_menu` VALUES (1, 5100);
+INSERT INTO `sys_role_menu` VALUES (1, 5110);
+INSERT INTO `sys_role_menu` VALUES (1, 5120);
+INSERT INTO `sys_role_menu` VALUES (1, 5130);
+INSERT INTO `sys_role_menu` VALUES (1, 5200);
+INSERT INTO `sys_role_menu` VALUES (1, 5300);
+INSERT INTO `sys_role_menu` VALUES (1, 5310);
+INSERT INTO `sys_role_menu` VALUES (1, 5320);
+INSERT INTO `sys_role_menu` VALUES (1, 5330);
+INSERT INTO `sys_role_menu` VALUES (1, 5400);
+INSERT INTO `sys_role_menu` VALUES (1, 5410);
+INSERT INTO `sys_role_menu` VALUES (1, 5420);
+INSERT INTO `sys_role_menu` VALUES (1, 5430);
+INSERT INTO `sys_role_menu` VALUES (1, 5500);
+INSERT INTO `sys_role_menu` VALUES (1, 5510);
+INSERT INTO `sys_role_menu` VALUES (1, 5520);
+INSERT INTO `sys_role_menu` VALUES (1, 5530);
+INSERT INTO `sys_role_menu` VALUES (1, 6000);
+INSERT INTO `sys_role_menu` VALUES (1, 6100);
+INSERT INTO `sys_role_menu` VALUES (1, 6101);
+INSERT INTO `sys_role_menu` VALUES (1, 6102);
+INSERT INTO `sys_role_menu` VALUES (1, 6103);
+INSERT INTO `sys_role_menu` VALUES (1, 6200);
+INSERT INTO `sys_role_menu` VALUES (1, 6201);
+INSERT INTO `sys_role_menu` VALUES (1, 6202);
+INSERT INTO `sys_role_menu` VALUES (1, 6203);
+INSERT INTO `sys_role_menu` VALUES (1, 6300);
+INSERT INTO `sys_role_menu` VALUES (1, 6301);
+INSERT INTO `sys_role_menu` VALUES (1, 6302);
+INSERT INTO `sys_role_menu` VALUES (1, 6303);
+INSERT INTO `sys_role_menu` VALUES (1, 6304);
+INSERT INTO `sys_role_menu` VALUES (1, 6305);
+INSERT INTO `sys_role_menu` VALUES (1, 6400);
+INSERT INTO `sys_role_menu` VALUES (1, 6401);
+INSERT INTO `sys_role_menu` VALUES (1, 6402);
+INSERT INTO `sys_role_menu` VALUES (1, 6500);
+INSERT INTO `sys_role_menu` VALUES (1, 10000);
+INSERT INTO `sys_role_menu` VALUES (1, 10001);
+INSERT INTO `sys_role_menu` VALUES (1, 10002);
+INSERT INTO `sys_role_menu` VALUES (1, 10003);
+INSERT INTO `sys_role_menu` VALUES (1, 10004);
+INSERT INTO `sys_role_menu` VALUES (1, 10005);
+INSERT INTO `sys_role_menu` VALUES (1, 10006);
+INSERT INTO `sys_role_menu` VALUES (1, 10007);
+INSERT INTO `sys_role_menu` VALUES (1, 10008);
+COMMIT;
+
+-- ----------------------------
+-- Table structure for sys_route_conf
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_route_conf`;
+CREATE TABLE `sys_route_conf` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
+  `route_name` varchar(30) DEFAULT NULL,
+  `route_id` varchar(30) DEFAULT NULL,
+  `predicates` json DEFAULT NULL COMMENT '断言',
+  `filters` json DEFAULT NULL COMMENT '过滤器',
+  `uri` varchar(50) DEFAULT NULL,
+  `order` int(2) DEFAULT '0' COMMENT '排序',
+  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+  `del_flag` char(1) DEFAULT '0',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COMMENT='路由配置表';
+
+-- ----------------------------
+-- Records of sys_route_conf
+-- ----------------------------
+BEGIN;
+INSERT INTO `sys_route_conf` VALUES (1, '工作流管理模块', 'pigx-oa-platform', '[{\"args\": {\"_genkey_0\": \"/act/**\"}, \"name\": \"Path\"}]', '[]', 'lb://pigx-oa-platform', 0, '2019-10-16 16:44:41', '2019-11-05 22:36:56', '0');
+INSERT INTO `sys_route_conf` VALUES (2, '认证中心', 'pigx-auth', '[{\"args\": {\"_genkey_0\": \"/auth/**\"}, \"name\": \"Path\"}]', '[{\"args\": {}, \"name\": \"ValidateCodeGatewayFilter\"}, {\"args\": {}, \"name\": \"PasswordDecoderFilter\"}]', 'lb://pigx-auth', 0, '2019-10-16 16:44:41', '2019-11-05 22:36:57', '0');
+INSERT INTO `sys_route_conf` VALUES (3, '代码生成模块', 'pigx-codegen', '[{\"args\": {\"_genkey_0\": \"/gen/**\"}, \"name\": \"Path\"}]', '[]', 'lb://pigx-codegen', 0, '2019-10-16 16:44:41', '2019-11-05 22:36:58', '0');
+INSERT INTO `sys_route_conf` VALUES (4, 'elastic-job定时任务模块', 'pigx-daemon-elastic-job', '[{\"args\": {\"_genkey_0\": \"/daemon/**\"}, \"name\": \"Path\"}]', '[]', 'lb://pigx-daemon-elastic-job', 0, '2019-10-16 16:44:41', '2019-11-05 22:36:59', '0');
+INSERT INTO `sys_route_conf` VALUES (5, 'quartz定时任务模块', 'pigx-daemon-quartz', '[{\"args\": {\"_genkey_0\": \"/job/**\"}, \"name\": \"Path\"}]', '[]', 'lb://pigx-daemon-quartz', 0, '2019-10-16 16:44:41', '2019-11-05 22:37:02', '0');
+INSERT INTO `sys_route_conf` VALUES (6, '分布式事务模块', 'pigx-tx-manager', '[{\"args\": {\"_genkey_0\": \"/tx/**\"}, \"name\": \"Path\"}]', '[]', 'lb://pigx-tx-manager', 0, '2019-10-16 16:44:41', '2019-11-05 22:37:04', '0');
+INSERT INTO `sys_route_conf` VALUES (7, '通用权限模块', 'pigx-upms-biz', '[{\"args\": {\"_genkey_0\": \"/admin/**\"}, \"name\": \"Path\"}]', '[{\"args\": {\"key-resolver\": \"#{@remoteAddrKeyResolver}\", \"redis-rate-limiter.burstCapacity\": \"1000\", \"redis-rate-limiter.replenishRate\": \"1000\"}, \"name\": \"RequestRateLimiter\"}]', 'lb://pigx-upms-biz', 0, '2019-10-16 16:44:41', '2019-11-05 22:37:05', '0');
+INSERT INTO `sys_route_conf` VALUES (8, '工作流长链接支持1', 'pigx-oa-platform-ws-1', '[{\"args\": {\"_genkey_0\": \"/act/ws/info/**\"}, \"name\": \"Path\"}]', '[]', 'lb://pigx-oa-platform', 0, '2019-10-16 16:44:41', '2019-11-05 22:37:07', '0');
+INSERT INTO `sys_route_conf` VALUES (9, '工作流长链接支持2', 'pigx-oa-platform-ws-2', '[{\"args\": {\"_genkey_0\": \"/act/ws/**\"}, \"name\": \"Path\"}]', '[]', 'lb:ws://pigx-oa-platform', 100, '2019-10-16 16:44:41', '2019-11-05 22:37:09', '0');
+INSERT INTO `sys_route_conf` VALUES (10, '微信公众号管理', 'pigx-mp-platform', '[{\"args\": {\"_genkey_0\": \"/mp/**\"}, \"name\": \"Path\"}]', '[]', 'lb://pigx-mp-platform', 0, '2019-10-16 16:44:41', '2019-11-05 22:37:12', '0');
+INSERT INTO `sys_route_conf` VALUES (11, '支付管理', 'pigx-pay-platform', '[{\"args\": {\"_genkey_0\": \"/pay/**\"}, \"name\": \"Path\"}]', '[]', 'lb://pigx-pay-platform', 0, '2019-10-16 16:44:41', '2019-11-05 22:37:13', '0');
+INSERT INTO `sys_route_conf` VALUES (12, '监控管理', 'pigx-monitor', '[{\"args\": {\"_genkey_0\": \"/monitor/**\"}, \"name\": \"Path\"}]', '[]', 'lb://pigx-monitor', 0, '2019-10-16 16:44:41', '2019-11-05 22:37:17', '0');
+COMMIT;
+
+-- ----------------------------
+-- Table structure for sys_social_details
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_social_details`;
+CREATE TABLE `sys_social_details` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
+  `type` varchar(16) DEFAULT NULL,
+  `remark` varchar(64) DEFAULT NULL,
+  `app_id` varchar(64) DEFAULT NULL,
+  `app_secret` varchar(64) DEFAULT NULL,
+  `redirect_url` varchar(128) DEFAULT NULL,
+  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `del_flag` char(1) DEFAULT '0',
+  `tenant_id` int(11) NOT NULL DEFAULT '0' COMMENT '所属租户',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COMMENT='系统社交登录账号表';
+
+-- ----------------------------
+-- Records of sys_social_details
+-- ----------------------------
+BEGIN;
+INSERT INTO `sys_social_details` VALUES (1, 'WX', '微信互联参数', 'wxd1678d3f83b1d83a', '6ddb043f94da5d2172926abe8533504f', 'daoweicloud.com', '2018-08-16 14:24:25', '2019-03-02 09:43:13', '0', 1);
+INSERT INTO `sys_social_details` VALUES (2, 'GITEE', '码云登录', '8fc54e0e76e7842cf767c3ae3b9fdc48c03cefed27aa565ff7b2a39d142d9892', 'c544469ce78a67d9fcf9b28cd9f310b73f5cbc46a1b993e0802ad61517deb221', 'http://gitee.huaxiadaowei.com/#/authredirect', '2019-06-28 09:59:55', '2019-06-28 09:59:55', '0', 1);
+INSERT INTO `sys_social_details` VALUES (3, 'OSC', '开源中国', 'neIIqlwGsjsfsA6uxNqD', 'aOPhRuOOJNXV1x7JrTJ9qIyRCAPXoO0l', 'http://gitee.huaxiadaowei.com/#/authredirect', '2019-06-28 10:05:37', '2019-06-28 10:05:37', '0', 1);
+INSERT INTO `sys_social_details` VALUES (4, 'MINI', '小程序', 'wx6832be859d0e1cf5', '08036aef810dcb2f8ae31510910ba631', NULL, '2019-11-02 22:08:03', '2019-11-02 22:10:53', '0', 1);
+COMMIT;
+
+-- ----------------------------
+-- Table structure for sys_tenant
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_tenant`;
+CREATE TABLE `sys_tenant` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '租户id',
+  `name` varchar(255) DEFAULT NULL,
+  `code` varchar(64) DEFAULT NULL,
+  `start_time` timestamp NULL DEFAULT NULL COMMENT '开始时间',
+  `end_time` timestamp NULL DEFAULT NULL COMMENT '结束时间',
+  `status` char(1) DEFAULT '0',
+  `del_flag` char(1) DEFAULT '0',
+  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建',
+  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='租户表';
+
+-- ----------------------------
+-- Records of sys_tenant
+-- ----------------------------
+BEGIN;
+INSERT INTO `sys_tenant` VALUES (1, '北京分公司', '1', '2019-05-15 00:00:00', '2029-05-15 00:00:00', '0', '0', '2019-05-15 15:44:57', '2019-05-18 14:47:30');
+COMMIT;
+
+-- ----------------------------
+-- Table structure for sys_user
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_user`;
+CREATE TABLE `sys_user` (
+  `user_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+  `username` varchar(64) DEFAULT NULL,
+  `password` varchar(255) DEFAULT NULL,
+  `salt` varchar(255) DEFAULT NULL,
+  `phone` varchar(20) DEFAULT NULL,
+  `avatar` varchar(255) DEFAULT NULL,
+  `dept_id` int(11) DEFAULT NULL COMMENT '部门ID',
+  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+  `lock_flag` char(1) DEFAULT '0',
+  `del_flag` char(1) DEFAULT '0',
+  `wx_openid` varchar(32) DEFAULT NULL COMMENT '微信登录openId',
+  `mini_openid` varchar(32) DEFAULT NULL COMMENT '小程序openId',
+  `qq_openid` varchar(32) DEFAULT NULL COMMENT 'QQ openId',
+  `gitee_login` varchar(100) DEFAULT NULL COMMENT '码云 标识',
+  `osc_id` varchar(100) DEFAULT NULL COMMENT '开源中国 标识',
+  `tenant_id` int(11) NOT NULL DEFAULT '0' COMMENT '所属租户',
+  PRIMARY KEY (`user_id`) USING BTREE,
+  KEY `user_wx_openid` (`wx_openid`) USING BTREE,
+  KEY `user_qq_openid` (`qq_openid`) USING BTREE,
+  KEY `user_idx1_username` (`username`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
+
+-- ----------------------------
+-- Records of sys_user
+-- ----------------------------
+BEGIN;
+INSERT INTO `sys_user` VALUES (1, 'admin', '$2a$10$IVzj1Wd.ZQdOIWdb1htQjexU94uoNeuk1crlQ9ExVupPi0Iy1uv.C', '', '17034642888', '/admin/sys-file/lengleng/c5a85e0770cd4fe78bc14b63b3bd05ae.jpg', 1, '2018-04-20 07:15:18', '2019-11-02 22:12:11', '0', '0', 'o_0FT0uyg_H1vVy2H0JpSwlVGhWQ', 'oBxPy5E-v82xWGsfzZVzkD3wEX64', NULL, 'log4j', '2303656', 1);
+COMMIT;
+
+-- ----------------------------
+-- Table structure for sys_user_role
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_user_role`;
+CREATE TABLE `sys_user_role` (
+  `user_id` int(11) NOT NULL COMMENT '用户ID',
+  `role_id` int(11) NOT NULL COMMENT '角色ID',
+  PRIMARY KEY (`user_id`,`role_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户角色表';
+
+-- ----------------------------
+-- Records of sys_user_role
+-- ----------------------------
+BEGIN;
+INSERT INTO `sys_user_role` VALUES (1, 1);
+COMMIT;
+
+SET FOREIGN_KEY_CHECKS = 1;

文件差异内容过多而无法显示
+ 697 - 0
db/3pigxx_ac.sql


文件差异内容过多而无法显示
+ 478 - 0
db/4pigxx_job.sql


+ 124 - 0
db/5pigxx_mp.sql

@@ -0,0 +1,124 @@
+USE pigxx_mp;
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for wx_account
+-- ----------------------------
+DROP TABLE IF EXISTS `wx_account`;
+CREATE TABLE `wx_account` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
+  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `account` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `appid` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `appsecret` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `url` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `token` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `aeskey` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `qr_url` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',
+  `tenant_id` int(11) DEFAULT NULL COMMENT '租户Id',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='公众号账户表';
+
+-- ----------------------------
+-- Records of wx_account
+-- ----------------------------
+BEGIN;
+INSERT INTO `wx_account` VALUES (1, 'pigx测试', 'gh_16138b09b5f9', 'wxeb4543e2d692ec5a', '2e3d89a95aa55a63df11eecdea973662', 'http://pigx.huaxiadaowei.com', 'pigx', 'pigx', 'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=gQF88TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyWm1EOXNPWEdlS0MxMDAwMGcwM2MAAgQEzslcAwQAAAAA', '2019-05-02 22:14:35', '2019-05-02 22:14:35', '0', 1);
+COMMIT;
+
+-- ----------------------------
+-- Table structure for wx_account_fans
+-- ----------------------------
+DROP TABLE IF EXISTS `wx_account_fans`;
+CREATE TABLE `wx_account_fans` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
+  `openid` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `subscribe_status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',
+  `subscribe_time` datetime DEFAULT NULL COMMENT '订阅时间',
+  `nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `gender` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `language` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `country` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `province` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `city` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `headimg_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `wx_account_id` int(11) DEFAULT NULL COMMENT '微信公众号ID',
+  `wx_account_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `wx_account_appid` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',
+  `tenant_id` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `idx_1` (`openid`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='微信公众号粉丝表';
+
+-- ----------------------------
+-- Table structure for wx_fans_msg
+-- ----------------------------
+DROP TABLE IF EXISTS `wx_fans_msg`;
+CREATE TABLE `wx_fans_msg` (
+  `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键',
+  `openid` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `nickname` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `headimg_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `wx_account_appid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `wx_account_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `wx_account_id` int(11) DEFAULT NULL COMMENT '微信账号ID',
+  `msg_id` bigint(20) DEFAULT NULL COMMENT '消息ID',
+  `msg_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `content` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `res_content` varchar(3000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `is_res` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',
+  `media_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `pic_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `pic_path` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',
+  `tenant_id` int(11) DEFAULT NULL COMMENT '租户',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='粉丝消息表 ';
+
+-- ----------------------------
+-- Table structure for wx_fans_msg_res
+-- ----------------------------
+DROP TABLE IF EXISTS `wx_fans_msg_res`;
+CREATE TABLE `wx_fans_msg_res` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
+  `fans_msg_id` int(11) DEFAULT NULL COMMENT '粉丝消息ID',
+  `res_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
+  `user_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `user_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',
+  `tenant_id` int(11) DEFAULT NULL COMMENT '租户表',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='回复粉丝消息历史表 ';
+
+-- ----------------------------
+-- Table structure for wx_mp_menu
+-- ----------------------------
+DROP TABLE IF EXISTS `wx_mp_menu`;
+CREATE TABLE `wx_mp_menu` (
+  `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键',
+  `menu` json DEFAULT NULL COMMENT '菜单',
+  `wx_account_id` int(11) DEFAULT NULL,
+  `wx_account_appid` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `wx_account_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',
+  `tenant_id` int(11) DEFAULT NULL COMMENT '租户ID',
+  `pub_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='微信菜单表';
+
+SET FOREIGN_KEY_CHECKS = 1;

文件差异内容过多而无法显示
+ 239 - 0
db/6pigxx_config.sql


文件差异内容过多而无法显示
+ 159 - 0
db/7pigxx_pay.sql


+ 51 - 0
db/8pigxx_codegen.sql

@@ -0,0 +1,51 @@
+USE pigxx_codegen;
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for gen_datasource_conf
+-- ----------------------------
+DROP TABLE IF EXISTS `gen_datasource_conf`;
+CREATE TABLE `gen_datasource_conf` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
+  `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `password` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `create_date` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_date` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新',
+  `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',
+  `tenant_id` int(11) DEFAULT NULL COMMENT '租户ID',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='数据源表';
+
+-- ----------------------------
+-- Records of gen_datasource_conf
+-- ----------------------------
+BEGIN;
+INSERT INTO `gen_datasource_conf` VALUES (1, 'master', 'jdbc:mysql://pigx-mysql:3306/pigxx_codegen?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&allowMultiQueries=true', 'root', 'hyxlg2iaqpDLOe9qEcv2xQ==', '2019-08-12 15:47:39', '2019-08-12 15:47:39', '0', 1);
+INSERT INTO `gen_datasource_conf` VALUES (2, 'pigxx_core', 'jdbc:mysql://pigx-mysql:3306/pigxx?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&allowMultiQueries=true', 'root', 'Cx+ocw0iFCpae4Qo4IoFmQ==', '2019-03-31 16:40:43', '2019-06-13 03:07:24', '0', 1);
+INSERT INTO `gen_datasource_conf` VALUES (3, 'pigxx_ac', 'jdbc:mysql://pigx-mysql:3306/pigxx_ac?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8', 'root', 'Cx+ocw0iFCpae4Qo4IoFmQ==', '2019-03-31 17:53:25', '2019-06-13 03:07:25', '0', 1);
+INSERT INTO `gen_datasource_conf` VALUES (4, 'pigxx_job', 'jdbc:mysql://pigx-mysql:3306/pigxx_job?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8', 'root', 'Cx+ocw0iFCpae4Qo4IoFmQ==', '2019-03-31 17:53:25', '2019-06-13 03:07:26', '0', 1);
+INSERT INTO `gen_datasource_conf` VALUES (5, 'pigxx_mp', 'jdbc:mysql://pigx-mysql:3306/pigxx_mp?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8', 'root', 'Cx+ocw0iFCpae4Qo4IoFmQ==', '2019-03-31 17:53:25', '2019-06-13 03:07:28', '0', 1);
+INSERT INTO `gen_datasource_conf` VALUES (6, 'pigxx_pay', 'jdbc:mysql://pigx-mysql:3306/pigxx_pay?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8', 'root', 'Cx+ocw0iFCpae4Qo4IoFmQ==', '2019-03-31 17:53:25', '2019-06-13 03:07:30', '0', 1);
+COMMIT;
+
+-- ----------------------------
+-- Table structure for gen_form_conf
+-- ----------------------------
+DROP TABLE IF EXISTS `gen_form_conf`;
+CREATE TABLE `gen_form_conf` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `table_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+  `form_info` json NOT NULL COMMENT '表单信息',
+  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+  `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',
+  `tenant_id` int(11) DEFAULT NULL COMMENT '所属租户',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `table_name` (`table_name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='表单配置';
+
+SET FOREIGN_KEY_CHECKS = 1;

+ 23 - 0
db/Dockerfile

@@ -0,0 +1,23 @@
+FROM mysql:8.0.19
+
+MAINTAINER lengleng(wangiegie@gmail.com)
+
+ENV TZ=Asia/Shanghai
+
+RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+COPY ./1schema.sql /docker-entrypoint-initdb.d
+
+COPY ./2pigxx.sql /docker-entrypoint-initdb.d
+
+COPY ./3pigxx_ac.sql /docker-entrypoint-initdb.d
+
+COPY ./4pigxx_job.sql /docker-entrypoint-initdb.d
+
+COPY ./5pigxx_mp.sql /docker-entrypoint-initdb.d
+
+COPY ./6pigxx_config.sql /docker-entrypoint-initdb.d
+
+COPY ./7pigxx_pay.sql /docker-entrypoint-initdb.d
+
+COPY ./8pigxx_codegen.sql /docker-entrypoint-initdb.d

+ 162 - 0
docker-compose.yml

@@ -0,0 +1,162 @@
+# 使用说明 V3.7.0
+# 1. 使用docker-compose  宿主机不需要配置host来发现
+# 2. 无需修改源码,根目录  docker-compose up 即可
+# 3. 静静等待服务启动
+
+version: '2'
+services:
+  pigx-mysql:
+    build:
+      context: ./db
+    environment:
+      MYSQL_ROOT_PASSWORD: root
+    restart: always
+    container_name: pigx-mysql
+    image: pigx-mysql
+    ports:
+      - 3306:3306
+    volumes:
+      - ./pigx-mysql:/var/lib/mysql
+    command: --lower_case_table_names=1
+
+  pigx-zookeeper:
+    container_name: pigx-zookeeper
+    image: zookeeper:3.4.13
+    restart: always
+
+  pigx-xxl:
+    container_name: pigx-xxl
+    image: pig4cloud/xxl-job-admin:2.1.1
+    restart: always
+    environment:
+      PARAMS: "--server.port=9080 --spring.datasource.url=jdbc:mysql://pigx-mysql:3306/pigxx_job?Unicode=true&characterEncoding=UTF-8 --spring.datasource.username=root --spring.datasource.password=root"
+    ports:
+      - 9080:9080
+
+  pigx-redis:
+    container_name: pigx-redis
+    image: redis:5.0.7
+    restart: always
+    ports:
+      - 6379:6379
+
+  pigx-minio:
+    container_name: pigx-minio
+    image: minio/minio
+    command: server /data
+    ports:
+      - 9000:9000
+    volumes:
+      - ./data:/data
+      - ./config:/root/.minio
+    environment:
+      - MINIO_DOMAIN=pigx-minio
+      - MINIO_ACCESS_KEY=lengleng
+      - MINIO_SECRET_KEY=lengleng
+
+  pigx-register:
+    build:
+      context: ./pigx-register
+    restart: always
+    container_name: pigx-register
+    image: pigx-register
+    ports:
+      - 8848:8848
+
+  pigx-gateway:
+    build:
+      context: ./pigx-gateway
+    restart: always
+    container_name: pigx-gateway
+    image: pigx-gateway
+    ports:
+      - 9999:9999
+
+  pigx-auth:
+    build:
+      context: ./pigx-auth
+    restart: always
+    container_name: pigx-auth
+    image: pigx-auth
+
+  pigx-upms:
+    build:
+      context: ./pigx-upms/pigx-upms-biz
+    restart: always
+    container_name: pigx-upms
+    image: pigx-upms
+  pigx-inventory:
+    build:
+      context: ./pigx-inventory/pigx-inventory-biz
+    restart: always
+    container_name: pigx-inventory
+    image: pigx-inventory
+  pigx-monitor:
+    build:
+      context: ./pigx-visual/pigx-monitor
+    restart: always
+    image: pigx-monitor
+    container_name: pigx-monitor
+    ports:
+      - 5001:5001
+
+  pigx-daemon-quartz:
+    build:
+      context: ./pigx-visual/pigx-daemon-quartz
+    restart: always
+    image: pigx-daemon-quartz
+    container_name: pigx-daemon-quartz
+
+  pigx-daemon-elastic-job:
+    build:
+      context: ./pigx-visual/pigx-daemon-elastic-job
+    restart: always
+    image: pigx-daemon-elastic-job
+    container_name: pigx-daemon-elastic-job
+
+  pigx-codegen:
+    build:
+      context: ./pigx-visual/pigx-codegen
+    restart: always
+    image: pigx-codegen
+    container_name: pigx-codegen
+
+  pigx-mp-platform:
+    build:
+      context: ./pigx-visual/pigx-mp-platform
+    restart: always
+    image: pigx-mp-platform
+    container_name: pigx-mp-platform
+
+  pigx-pay-platform:
+    build:
+      context: ./pigx-visual/pigx-pay-platform
+    restart: always
+    image: pigx-pay-platform
+    container_name: pigx-pay-platform
+
+  pigx-oa-platform:
+    build:
+      context: ./pigx-visual/pigx-oa-platform
+    restart: always
+    image: pigx-oa-platform
+    container_name: pigx-oa-platform
+
+  pigx-tx-manager:
+    build:
+      context: ./pigx-visual/pigx-tx-manager
+    restart: always
+    image: pigx-tx-manager
+    container_name: pigx-tx-manager
+    ports:
+      - 5004:5004
+      - 9998:9998
+
+  pigx-sentinel:
+    build:
+      context: ./pigx-visual/pigx-sentinel-dashboard
+    restart: always
+    image: pigx-sentinel
+    container_name: pigx-sentinel
+    ports:
+      - 5020:5020

+ 17 - 0
pigx-auth/Dockerfile

@@ -0,0 +1,17 @@
+FROM java:8-jre
+
+MAINTAINER wangiegie@gmail.com
+
+ENV TZ=Asia/Shanghai
+
+RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+RUN mkdir -p /pigx-auth
+
+WORKDIR /pigx-auth
+
+EXPOSE 3000
+
+ADD ./target/pigx-auth.jar ./
+
+CMD sleep 120;java -Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom -jar pigx-auth.jar

+ 121 - 0
pigx-auth/pom.xml

@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~
+  ~      Copyright (c) 2018-2025, lengleng All rights reserved.
+  ~
+  ~  Redistribution and use in source and binary forms, with or without
+  ~  modification, are permitted provided that the following conditions are met:
+  ~
+  ~ Redistributions of source code must retain the above copyright notice,
+  ~  this list of conditions and the following disclaimer.
+  ~  Redistributions in binary form must reproduce the above copyright
+  ~  notice, this list of conditions and the following disclaimer in the
+  ~  documentation and/or other materials provided with the distribution.
+  ~  Neither the name of the pig4cloud.com developer nor the names of its
+  ~  contributors may be used to endorse or promote products derived from
+  ~  this software without specific prior written permission.
+  ~  Author: lengleng (wangiegie@gmail.com)
+  ~
+  -->
+
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+		 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>
+	<parent>
+		<groupId>com.pig4cloud</groupId>
+		<artifactId>pigx</artifactId>
+		<version>3.7.0</version>
+	</parent>
+
+	<artifactId>pigx-auth</artifactId>
+	<packaging>jar</packaging>
+
+	<description>pigx 认证授权中心,基于 spring security oAuth2</description>
+
+	<dependencies>
+		<!--注册中心客户端-->
+		<dependency>
+			<groupId>com.alibaba.cloud</groupId>
+			<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+		</dependency>
+		<!--配置中心客户端-->
+		<dependency>
+			<groupId>com.alibaba.cloud</groupId>
+			<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+		</dependency>
+		<!--upms api、model 模块-->
+		<dependency>
+			<groupId>com.pig4cloud</groupId>
+			<artifactId>pigx-upms-api</artifactId>
+		</dependency>
+		<!--security-->
+		<dependency>
+			<groupId>com.pig4cloud</groupId>
+			<artifactId>pigx-common-security</artifactId>
+		</dependency>
+		<!--feign 依赖-->
+		<dependency>
+			<groupId>com.pig4cloud</groupId>
+			<artifactId>pigx-common-feign</artifactId>
+		</dependency>
+		<!--mysql 驱动-->
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+		</dependency>
+		<!--缓存操作-->
+		<dependency>
+			<groupId>com.pig4cloud</groupId>
+			<artifactId>pigx-common-data</artifactId>
+		</dependency>
+		<!--sentinel 依赖-->
+		<dependency>
+			<groupId>com.pig4cloud</groupId>
+			<artifactId>pigx-common-sentinel</artifactId>
+		</dependency>
+		<!--路由控制-->
+		<dependency>
+			<groupId>com.pig4cloud</groupId>
+			<artifactId>pigx-common-gray</artifactId>
+		</dependency>
+		<!--JDBC相关-->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-jdbc</artifactId>
+		</dependency>
+		<!-- druid 连接池 -->
+		<dependency>
+			<groupId>com.alibaba</groupId>
+			<artifactId>druid-spring-boot-starter</artifactId>
+		</dependency>
+		<!--freemarker-->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-freemarker</artifactId>
+		</dependency>
+		<!--web 模块-->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-web</artifactId>
+		</dependency>
+		<!--undertow容器-->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-undertow</artifactId>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+			</plugin>
+			<plugin>
+				<groupId>io.fabric8</groupId>
+				<artifactId>docker-maven-plugin</artifactId>
+			</plugin>
+		</plugins>
+	</build>
+
+</project>

+ 39 - 0
pigx-auth/src/main/java/com/pig4cloud/pigx/auth/PigxAuthApplication.java

@@ -0,0 +1,39 @@
+/*
+ *
+ *      Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the pig4cloud.com developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: lengleng (wangiegie@gmail.com)
+ *
+ */
+
+package com.pig4cloud.pigx.auth;
+
+
+import com.pig4cloud.pigx.common.feign.annotation.EnablePigxFeignClients;
+import org.springframework.boot.SpringApplication;
+import org.springframework.cloud.client.SpringCloudApplication;
+
+/**
+ * @author lengleng
+ * @date 2020-02-08
+ * 认证授权中心
+ */
+@SpringCloudApplication
+@EnablePigxFeignClients
+public class PigxAuthApplication {
+
+	public static void main(String[] args) {
+		SpringApplication.run(PigxAuthApplication.class, args);
+	}
+}

+ 105 - 0
pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfig.java

@@ -0,0 +1,105 @@
+/*
+ *
+ *      Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the pig4cloud.com developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: lengleng (wangiegie@gmail.com)
+ *
+ */
+
+package com.pig4cloud.pigx.auth.config;
+
+import cn.hutool.core.util.StrUtil;
+import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
+import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
+import com.pig4cloud.pigx.common.security.component.PigxWebResponseExceptionTranslator;
+import com.pig4cloud.pigx.common.security.service.PigxClientDetailsService;
+import com.pig4cloud.pigx.common.security.service.PigxUserDetailsService;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
+import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
+import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
+import org.springframework.security.oauth2.provider.OAuth2Authentication;
+import org.springframework.security.oauth2.provider.token.DefaultAuthenticationKeyGenerator;
+import org.springframework.security.oauth2.provider.token.TokenEnhancer;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
+
+import javax.sql.DataSource;
+
+/**
+ * @author lengleng
+ * @date 2018/6/22
+ * 认证服务器配置
+ */
+@Configuration
+@AllArgsConstructor
+@EnableAuthorizationServer
+public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
+	private final DataSource dataSource;
+	private final TokenEnhancer pigxTokenEnhancer;
+	private final PigxUserDetailsService pigxUserDetailsService;
+	private final AuthenticationManager authenticationManagerBean;
+	private final RedisConnectionFactory redisConnectionFactory;
+
+	@Override
+	@SneakyThrows
+	public void configure(ClientDetailsServiceConfigurer clients) {
+		PigxClientDetailsService clientDetailsService = new PigxClientDetailsService(dataSource);
+		clientDetailsService.setSelectClientDetailsSql(SecurityConstants.DEFAULT_SELECT_STATEMENT);
+		clientDetailsService.setFindClientDetailsSql(SecurityConstants.DEFAULT_FIND_STATEMENT);
+		clients.withClientDetails(clientDetailsService);
+	}
+
+	@Override
+	public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
+		oauthServer
+				.allowFormAuthenticationForClients()
+				.checkTokenAccess("isAuthenticated()");
+	}
+
+	@Override
+	public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
+		endpoints
+				.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
+				.tokenStore(tokenStore())
+				.tokenEnhancer(pigxTokenEnhancer)
+				.userDetailsService(pigxUserDetailsService)
+				.authenticationManager(authenticationManagerBean)
+				.reuseRefreshTokens(false)
+				.pathMapping("/oauth/confirm_access", "/token/confirm_access")
+				.exceptionTranslator(new PigxWebResponseExceptionTranslator());
+	}
+
+
+	@Bean
+	public TokenStore tokenStore() {
+		RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);
+		tokenStore.setPrefix(SecurityConstants.PIGX_PREFIX + SecurityConstants.OAUTH_PREFIX);
+		tokenStore.setAuthenticationKeyGenerator(new DefaultAuthenticationKeyGenerator() {
+			@Override
+			public String extractKey(OAuth2Authentication authentication) {
+				return super.extractKey(authentication) + StrUtil.COLON + TenantContextHolder.getTenantId();
+			}
+		});
+		return tokenStore;
+	}
+}

+ 111 - 0
pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/WebSecurityConfigurer.java

@@ -0,0 +1,111 @@
+/*
+ *
+ *      Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the pig4cloud.com developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: lengleng (wangiegie@gmail.com)
+ *
+ */
+
+package com.pig4cloud.pigx.auth.config;
+
+import com.pig4cloud.pigx.common.security.handler.FormAuthenticationFailureHandler;
+import com.pig4cloud.pigx.common.security.handler.MobileLoginSuccessHandler;
+import com.pig4cloud.pigx.common.security.mobile.MobileSecurityConfigurer;
+import lombok.SneakyThrows;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.core.annotation.Order;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.crypto.factory.PasswordEncoderFactories;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.authentication.AuthenticationFailureHandler;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+
+/**
+ * @author lengleng
+ * @date 2018/6/22
+ * 认证相关配置
+ */
+@Primary
+@Order(90)
+@Configuration
+public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
+	@Override
+	@SneakyThrows
+	protected void configure(HttpSecurity http) {
+		http
+				.formLogin()
+				.loginPage("/token/login")
+				.loginProcessingUrl("/token/form")
+				.failureHandler(authenticationFailureHandler())
+				.and()
+				.authorizeRequests()
+				.antMatchers(
+						"/token/**",
+						"/actuator/**",
+						"/mobile/**").permitAll()
+				.anyRequest().authenticated()
+				.and().csrf().disable()
+				.apply(mobileSecurityConfigurer());
+	}
+
+	/**
+	 * 不拦截静态资源
+	 *
+	 * @param web
+	 */
+	@Override
+	public void configure(WebSecurity web) {
+		web.ignoring().antMatchers("/css/**");
+	}
+
+	@Bean
+	@Override
+	@SneakyThrows
+	public AuthenticationManager authenticationManagerBean() {
+		return super.authenticationManagerBean();
+	}
+
+	@Bean
+	public AuthenticationFailureHandler authenticationFailureHandler() {
+		return new FormAuthenticationFailureHandler();
+	}
+
+	@Bean
+	public AuthenticationSuccessHandler mobileLoginSuccessHandler() {
+		return new MobileLoginSuccessHandler();
+	}
+
+	@Bean
+	public MobileSecurityConfigurer mobileSecurityConfigurer() {
+		return new MobileSecurityConfigurer();
+	}
+
+
+	/**
+	 * https://spring.io/blog/2017/11/01/spring-security-5-0-0-rc1-released#password-storage-updated
+	 * Encoded password does not look like BCrypt
+	 *
+	 * @return PasswordEncoder
+	 */
+	@Bean
+	public PasswordEncoder passwordEncoder() {
+		return PasswordEncoderFactories.createDelegatingPasswordEncoder();
+	}
+
+}

+ 213 - 0
pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/PigxTokenEndpoint.java

@@ -0,0 +1,213 @@
+/*
+ *
+ *      Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the pig4cloud.com developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: lengleng (wangiegie@gmail.com)
+ *
+ */
+
+package com.pig4cloud.pigx.auth.endpoint;
+
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.pig4cloud.pigx.common.core.constant.CacheConstants;
+import com.pig4cloud.pigx.common.core.constant.PaginationConstants;
+import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
+import com.pig4cloud.pigx.common.core.util.R;
+import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
+import com.pig4cloud.pigx.common.security.annotation.Inner;
+import com.pig4cloud.pigx.common.security.util.SecurityUtils;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cache.CacheManager;
+import org.springframework.data.redis.core.ConvertingCursor;
+import org.springframework.data.redis.core.Cursor;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ScanOptions;
+import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.http.HttpHeaders;
+import org.springframework.security.oauth2.common.OAuth2AccessToken;
+import org.springframework.security.oauth2.common.OAuth2RefreshToken;
+import org.springframework.security.oauth2.provider.AuthorizationRequest;
+import org.springframework.security.oauth2.provider.ClientDetails;
+import org.springframework.security.oauth2.provider.ClientDetailsService;
+import org.springframework.security.oauth2.provider.OAuth2Authentication;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author lengleng
+ * @date 2018/6/24
+ * 删除token端点
+ */
+@Slf4j
+@RestController
+@AllArgsConstructor
+@RequestMapping("/token")
+public class PigxTokenEndpoint {
+	private static final String PIGX_OAUTH_ACCESS = SecurityConstants.PIGX_PREFIX + SecurityConstants.OAUTH_PREFIX + "auth_to_access:";
+	private final ClientDetailsService clientDetailsService;
+	private final RedisTemplate redisTemplate;
+	private final TokenStore tokenStore;
+	private final CacheManager cacheManager;
+
+	/**
+	 * 认证页面
+	 *
+	 * @param modelAndView
+	 * @param error        表单登录失败处理回调的错误信息
+	 * @return ModelAndView
+	 */
+	@GetMapping("/login")
+	public ModelAndView require(ModelAndView modelAndView, @RequestParam(required = false) String error) {
+		modelAndView.setViewName("ftl/login");
+		modelAndView.addObject("error", error);
+		return modelAndView;
+	}
+
+	/**
+	 * 确认授权页面
+	 *
+	 * @param request
+	 * @param session
+	 * @param modelAndView
+	 * @return
+	 */
+	@GetMapping("/confirm_access")
+	public ModelAndView confirm(HttpServletRequest request, HttpSession session, ModelAndView modelAndView) {
+		Map<String, Object> scopeList = (Map<String, Object>) request.getAttribute("scopes");
+		modelAndView.addObject("scopeList", scopeList.keySet());
+
+		Object auth = session.getAttribute("authorizationRequest");
+		if (auth != null) {
+			AuthorizationRequest authorizationRequest = (AuthorizationRequest) auth;
+			ClientDetails clientDetails = clientDetailsService.loadClientByClientId(authorizationRequest.getClientId());
+			modelAndView.addObject("app", clientDetails.getAdditionalInformation());
+			modelAndView.addObject("user", SecurityUtils.getUser());
+		}
+
+		modelAndView.setViewName("ftl/confirm");
+		return modelAndView;
+	}
+
+	/**
+	 * 退出token
+	 *
+	 * @param authHeader Authorization
+	 */
+	@DeleteMapping("/logout")
+	public R logout(@RequestHeader(value = HttpHeaders.AUTHORIZATION, required = false) String authHeader) {
+		if (StrUtil.isBlank(authHeader)) {
+			return R.ok(Boolean.FALSE, "退出失败,token 为空");
+		}
+
+		String tokenValue = authHeader.replace(OAuth2AccessToken.BEARER_TYPE, StrUtil.EMPTY).trim();
+		return delToken(tokenValue);
+	}
+
+	/**
+	 * 令牌管理调用
+	 *
+	 * @param token token
+	 * @return
+	 */
+	@Inner
+	@DeleteMapping("/{token}")
+	public R<Boolean> delToken(@PathVariable("token") String token) {
+		OAuth2AccessToken accessToken = tokenStore.readAccessToken(token);
+		if (accessToken == null || StrUtil.isBlank(accessToken.getValue())) {
+			return R.ok(Boolean.TRUE, "退出失败,token 无效");
+		}
+
+		OAuth2Authentication auth2Authentication = tokenStore.readAuthentication(accessToken);
+		// 清空用户信息
+		cacheManager.getCache(CacheConstants.USER_DETAILS)
+				.evict(auth2Authentication.getName());
+
+		// 清空access token
+		tokenStore.removeAccessToken(accessToken);
+
+		// 清空 refresh token
+		OAuth2RefreshToken refreshToken = accessToken.getRefreshToken();
+		tokenStore.removeRefreshToken(refreshToken);
+		return R.ok();
+	}
+
+
+	/**
+	 * 查询token
+	 *
+	 * @param params 分页参数
+	 * @return
+	 */
+	@Inner
+	@PostMapping("/page")
+	public R<Page> tokenList(@RequestBody Map<String, Object> params) {
+		//根据分页参数获取对应数据
+		String key = String.format("%s*:%s", PIGX_OAUTH_ACCESS, TenantContextHolder.getTenantId());
+		List<String> pages = findKeysForPage(key, MapUtil.getInt(params, PaginationConstants.CURRENT)
+				, MapUtil.getInt(params, PaginationConstants.SIZE));
+
+		redisTemplate.setKeySerializer(new StringRedisSerializer());
+		redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
+		Page result = new Page(MapUtil.getInt(params, PaginationConstants.CURRENT), MapUtil.getInt(params, PaginationConstants.SIZE));
+		result.setRecords(redisTemplate.opsForValue().multiGet(pages));
+		result.setTotal(redisTemplate.keys(key).size());
+		return R.ok(result);
+	}
+
+
+	private List<String> findKeysForPage(String patternKey, int pageNum, int pageSize) {
+		ScanOptions options = ScanOptions.scanOptions().count(1000L)
+				.match(patternKey).build();
+		RedisSerializer<String> redisSerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer();
+		Cursor cursor = (Cursor) redisTemplate.executeWithStickyConnection(redisConnection -> new ConvertingCursor<>(redisConnection.scan(options), redisSerializer::deserialize));
+		List<String> result = new ArrayList<>();
+		int tmpIndex = 0;
+		int startIndex = (pageNum - 1) * pageSize;
+		int end = pageNum * pageSize;
+
+		assert cursor != null;
+		while (cursor.hasNext()) {
+			if (tmpIndex >= startIndex && tmpIndex < end) {
+				result.add(cursor.next().toString());
+				tmpIndex++;
+				continue;
+			}
+			if (tmpIndex >= end) {
+				break;
+			}
+			tmpIndex++;
+			cursor.next();
+		}
+
+		try {
+			cursor.close();
+		} catch (IOException e) {
+			log.error("关闭cursor 失败");
+		}
+		return result;
+	}
+}

+ 50 - 0
pigx-auth/src/main/java/com/pig4cloud/pigx/auth/handler/PigxAuthenticationFailureEvenHandler.java

@@ -0,0 +1,50 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.auth.handler;
+
+import com.pig4cloud.pigx.common.security.handler.AbstractAuthenticationFailureEvenHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @author lengleng
+ * @date 2018/10/8
+ */
+@Slf4j
+@Component
+public class PigxAuthenticationFailureEvenHandler extends AbstractAuthenticationFailureEvenHandler {
+
+	/**
+	 * 处理登录失败方法
+	 * <p>
+	 *
+	 * @param authenticationException 登录的authentication 对象
+	 * @param authentication          登录的authenticationException 对象
+	 * @param request                 请求
+	 * @param response                响应
+	 */
+	@Override
+	public void handle(AuthenticationException authenticationException, Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
+		log.info("用户:{} 登录失败,异常:{}", authentication.getPrincipal(), authenticationException.getLocalizedMessage());
+	}
+}

+ 49 - 0
pigx-auth/src/main/java/com/pig4cloud/pigx/auth/handler/PigxAuthenticationSuccessEventHandler.java

@@ -0,0 +1,49 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.auth.handler;
+
+import com.pig4cloud.pigx.common.security.handler.AbstractAuthenticationSuccessEventHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.core.Authentication;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @author lengleng
+ * @date 2018/10/8
+ */
+@Slf4j
+@Component
+public class PigxAuthenticationSuccessEventHandler extends AbstractAuthenticationSuccessEventHandler {
+
+	/**
+	 * 处理登录成功方法
+	 * <p>
+	 * 获取到登录的authentication 对象
+	 *
+	 * @param authentication 登录对象
+	 * @param request        请求
+	 * @param response       返回
+	 */
+	@Override
+	public void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
+		log.info("用户:{} 登录成功", authentication.getPrincipal());
+	}
+}

+ 17 - 0
pigx-auth/src/main/resources/bootstrap.yml

@@ -0,0 +1,17 @@
+server:
+  port: 3000
+
+spring:
+  application:
+    name: @artifactId@
+  cloud:
+    nacos:
+      discovery:
+        server-addr: ${NACOS-HOST:pigx-register}:${NACOS-PORT:8848}
+      config:
+        server-addr: ${spring.cloud.nacos.discovery.server-addr}
+        file-extension: yml
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
+  profiles:
+    active: @profiles.active@

+ 87 - 0
pigx-auth/src/main/resources/logback-spring.xml

@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~    Copyright (c) 2018-2025, lengleng All rights reserved.
+  ~
+  ~ Redistribution and use in source and binary forms, with or without
+  ~ modification, are permitted provided that the following conditions are met:
+  ~
+  ~ Redistributions of source code must retain the above copyright notice,
+  ~ this list of conditions and the following disclaimer.
+  ~ Redistributions in binary form must reproduce the above copyright
+  ~ notice, this list of conditions and the following disclaimer in the
+  ~ documentation and/or other materials provided with the distribution.
+  ~ Neither the name of the pig4cloud.com developer nor the names of its
+  ~ contributors may be used to endorse or promote products derived from
+  ~ this software without specific prior written permission.
+  ~ Author: lengleng (wangiegie@gmail.com)
+  -->
+
+<!--
+    小技巧: 在根pom里面设置统一存放路径,统一管理方便维护
+    <properties>
+        <log-path>/Users/lengleng</log-path>
+    </properties>
+    1. 其他模块加日志输出,直接copy本文件放在resources 目录即可
+    2. 注意修改 <property name="${log-path}/log.path" value=""/> 的value模块
+-->
+<configuration debug="false" scan="false">
+	<property name="log.path" value="logs/${project.artifactId}"/>
+	<!-- 彩色日志格式 -->
+	<property name="CONSOLE_LOG_PATTERN"
+			  value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
+	<!-- 彩色日志依赖的渲染类 -->
+	<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
+	<conversionRule conversionWord="wex"
+					converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
+	<conversionRule conversionWord="wEx"
+					converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
+	<!-- Console log output -->
+	<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+		<encoder>
+			<pattern>${CONSOLE_LOG_PATTERN}</pattern>
+		</encoder>
+	</appender>
+
+	<!-- Log file debug output -->
+	<appender name="debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
+		<file>${log.path}/debug.log</file>
+		<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+			<fileNamePattern>${log.path}/%d{yyyy-MM, aux}/debug.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
+			<maxFileSize>50MB</maxFileSize>
+			<maxHistory>30</maxHistory>
+		</rollingPolicy>
+		<encoder>
+			<pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
+		</encoder>
+	</appender>
+
+	<!-- Log file error output -->
+	<appender name="error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+		<file>${log.path}/error.log</file>
+		<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+			<fileNamePattern>${log.path}/%d{yyyy-MM}/error.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
+			<maxFileSize>50MB</maxFileSize>
+			<maxHistory>30</maxHistory>
+		</rollingPolicy>
+		<encoder>
+			<pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
+		</encoder>
+		<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+			<level>ERROR</level>
+		</filter>
+	</appender>
+
+	<logger name="org.activiti.engine.impl.db" level="DEBUG">
+		<appender-ref ref="debug"/>
+	</logger>
+
+	<!--nacos 心跳 INFO 屏蔽-->
+	<logger name="com.alibaba.nacos" level="OFF">
+		<appender-ref ref="error"/>
+	</logger>
+	<!-- Level: FATAL 0  ERROR 3  WARN 4  INFO 6  DEBUG 7 -->
+	<root level="INFO">
+		<appender-ref ref="console"/>
+		<appender-ref ref="debug"/>
+	</root>
+</configuration>

文件差异内容过多而无法显示
+ 6 - 0
pigx-auth/src/main/resources/static/css/bootstrap.min.css


+ 67 - 0
pigx-auth/src/main/resources/static/css/signin.css

@@ -0,0 +1,67 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+.sign_body {
+  padding-top: 40px;
+  padding-bottom: 40px;
+  background-color: #eee;
+}
+
+.form-signin {
+  max-width: 330px;
+  padding: 15px;
+  margin: 0 auto;
+}
+.form-margin-top {
+  margin-top: 50px;
+}
+.form-signin .form-signin-heading,
+.form-signin .checkbox {
+  margin-bottom: 10px;
+}
+.form-signin .checkbox {
+  font-weight: normal;
+}
+.form-signin .form-control {
+  position: relative;
+  height: auto;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+  padding: 10px;
+  font-size: 16px;
+}
+.form-signin .form-control:focus {
+  z-index: 2;
+}
+.form-signin input[type="email"] {
+  margin-bottom: -1px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.form-signin input[type="password"] {
+  margin-bottom: 10px;
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+footer{
+  text-align: center;
+  position:absolute;
+  bottom:0;
+  width:100%;
+  height:100px;
+}

+ 51 - 0
pigx-auth/src/main/resources/templates/ftl/confirm.ftl

@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<html>
+<head>
+    <meta charset="UTF-8"/>
+    <meta name="viewport"
+          content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
+    <title>PigX第三方授权</title>
+    <link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css"/>
+    <link rel="stylesheet" type="text/css" href="/css/signin.css"/>
+</head>
+
+<body>
+<nav class="navbar navbar-default container-fluid">
+    <div class="container">
+        <div class="navbar-header">
+            <a class="navbar-brand" href="#">开放平台</a>
+        </div>
+        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-5">
+            <p class="navbar-text navbar-right">
+                <a target="_blank" href="https://pig4cloud.com">技术支持</a>
+            </p>
+            <p class="navbar-text navbar-right">
+                <a target="_blank" href="https://pig4cloud.com">${user.username}</a>
+            </p>
+        </div>
+    </div>
+</nav>
+<div style="padding-top: 80px;width: 300px; color: #555; margin:0px auto;">
+    <form id='confirmationForm' name='confirmationForm' action="/oauth/authorize" method='post'>
+        <input name='user_oauth_approval' value='true' type='hidden'/>
+        <p>
+            <a href="${app.website!''}" target="_blank">${app.appName!'未定义应用名称'}</a> 将获得以下权限:</p>
+        <ul class="list-group">
+            <li class="list-group-item"> <span>
+              <#list scopeList as scope>
+                  <input type="hidden" name="${scope}" value="true"/>
+                  <input type="checkbox" disabled checked="checked"/><label>${scope}</label>
+              </#list>
+        </ul>
+        <p class="help-block">授权后表明你已同意 <a>服务协议</a></p>
+        <button class="btn btn-success pull-right" type="submit" id="write-email-btn">授权</button>
+        </p>
+    </form>
+</div>
+<footer>
+    <p>support by: pig4cloud.com</p>
+    <p>email: <a href="mailto:wangiegie@gmail.com">wangiegie@gmail.com</a>.</p>
+</footer>
+</body>
+</html>

+ 34 - 0
pigx-auth/src/main/resources/templates/ftl/login.ftl

@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
+    <meta name="description" content="">
+    <meta name="author" content="">
+
+    <title>PigX微服务统一认证</title>
+
+    <link href="/css/bootstrap.min.css" rel="stylesheet">
+    <link href="/css/signin.css" rel="stylesheet">
+</head>
+
+<body class="sign_body">
+<div class="container form-margin-top">
+    <form class="form-signin" action="/token/form" method="post">
+        <h2 class="form-signin-heading" align="center">统一认证系统</h2>
+        <input type="text" name="username" class="form-control form-margin-top" placeholder="账号" required autofocus>
+        <input type="password" name="password" class="form-control" placeholder="密码" required>
+        <button class="btn btn-lg btn-primary btn-block" type="submit">sign in</button>
+        <#if error??>
+            <span style="color: red; ">${error}</span>
+        </#if>
+    </form>
+</div>
+<footer>
+    <p>support by: pig4cloud</p>
+    <p>email: <a href="mailto:pig4cloud@qq.com">pig4cloud@qq.com</a>.</p>
+</footer>
+</body>
+</html>

+ 210 - 0
pigx-common/pigx-common-bom/pom.xml

@@ -0,0 +1,210 @@
+<?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>
+	<parent>
+		<artifactId>pigx-cloud-dependencies-parent</artifactId>
+		<groupId>com.pig4cloud</groupId>
+		<version>Hoxton.SR2</version>
+		<relativePath/>
+	</parent>
+
+	<groupId>com.pig4cloud</groupId>
+	<artifactId>pigx-common-bom</artifactId>
+	<packaging>pom</packaging>
+	<version>${pigx.version}</version>
+	<description>pigx 公共版本控制</description>
+
+	<properties>
+		<pigx.version>3.7.0</pigx.version>
+		<mybatis-plus.version>3.3.1</mybatis-plus.version>
+		<dynamic-ds.version>3.0.0</dynamic-ds.version>
+		<druid.version>1.1.21</druid.version>
+		<mysql.connector.version>8.0.19</mysql.connector.version>
+		<swagger.core.version>1.5.22</swagger.core.version>
+		<mp.weixin.version>3.6.0</mp.weixin.version>
+		<ijpay.version>1.2.0</ijpay.version>
+		<fastjson.version>1.2.62</fastjson.version>
+		<aliyun.version>3.0.52.ALL</aliyun.version>
+	</properties>
+
+	<dependencyManagement>
+		<dependencies>
+			<dependency>
+				<groupId>com.pig4cloud</groupId>
+				<artifactId>pigx-common-core</artifactId>
+				<version>${pigx.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.pig4cloud</groupId>
+				<artifactId>pigx-common-data</artifactId>
+				<version>${pigx.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.pig4cloud</groupId>
+				<artifactId>pigx-common-gateway</artifactId>
+				<version>${pigx.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.pig4cloud</groupId>
+				<artifactId>pigx-common-gray</artifactId>
+				<version>${pigx.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.pig4cloud</groupId>
+				<artifactId>pigx-common-datasource</artifactId>
+				<version>${pigx.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.pig4cloud</groupId>
+				<artifactId>pigx-common-job</artifactId>
+				<version>${pigx.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.pig4cloud</groupId>
+				<artifactId>pigx-common-log</artifactId>
+				<version>${pigx.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.pig4cloud</groupId>
+				<artifactId>pigx-common-minio</artifactId>
+				<version>${pigx.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.pig4cloud</groupId>
+				<artifactId>pigx-common-security</artifactId>
+				<version>${pigx.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.pig4cloud</groupId>
+				<artifactId>pigx-common-sentinel</artifactId>
+				<version>${pigx.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.pig4cloud</groupId>
+				<artifactId>pigx-common-feign</artifactId>
+				<version>${pigx.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.pig4cloud</groupId>
+				<artifactId>pigx-common-sequence</artifactId>
+				<version>${pigx.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.pig4cloud</groupId>
+				<artifactId>pigx-common-swagger</artifactId>
+				<version>${pigx.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.pig4cloud</groupId>
+				<artifactId>pigx-common-transaction</artifactId>
+				<version>${pigx.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.pig4cloud</groupId>
+				<artifactId>pigx-upms-api</artifactId>
+				<version>${pigx.version}</version>
+			</dependency>
+			<!--mybatis plus extension,包含了mybatis plus core-->
+			<dependency>
+				<groupId>com.baomidou</groupId>
+				<artifactId>mybatis-plus-extension</artifactId>
+				<version>${mybatis-plus.version}</version>
+			</dependency>
+			<!--mybatis-->
+			<dependency>
+				<groupId>com.baomidou</groupId>
+				<artifactId>mybatis-plus-boot-starter</artifactId>
+				<version>${mybatis-plus.version}</version>
+			</dependency>
+			<!-- druid 连接池 -->
+			<dependency>
+				<groupId>com.alibaba</groupId>
+				<artifactId>druid-spring-boot-starter</artifactId>
+				<version>${druid.version}</version>
+			</dependency>
+			<!--mysql 驱动-->
+			<dependency>
+				<groupId>mysql</groupId>
+				<artifactId>mysql-connector-java</artifactId>
+				<version>${mysql.connector.version}</version>
+			</dependency>
+			<!--fastjson-->
+			<dependency>
+				<groupId>com.alibaba</groupId>
+				<artifactId>fastjson</artifactId>
+				<version>${fastjson.version}</version>
+			</dependency>
+			<!--swagger 最新依赖内置版本-->
+			<dependency>
+				<groupId>io.swagger</groupId>
+				<artifactId>swagger-models</artifactId>
+				<version>${swagger.core.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>io.swagger</groupId>
+				<artifactId>swagger-annotations</artifactId>
+				<version>${swagger.core.version}</version>
+			</dependency>
+			<!--微信依赖-->
+			<dependency>
+				<groupId>com.github.binarywang</groupId>
+				<artifactId>weixin-java-mp</artifactId>
+				<version>${mp.weixin.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.github.binarywang</groupId>
+				<artifactId>weixin-java-common</artifactId>
+				<version>${mp.weixin.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.github.javen205</groupId>
+				<artifactId>IJPay</artifactId>
+				<version>${ijpay.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.alipay.sdk</groupId>
+				<artifactId>alipay-sdk-java</artifactId>
+				<version>${aliyun.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>com.baomidou</groupId>
+				<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
+				<version>${dynamic-ds.version}</version>
+			</dependency>
+		</dependencies>
+	</dependencyManagement>
+
+	<build>
+		<plugins>
+			<!--避免和parent bom坐标不一致 -->
+			<plugin>
+				<groupId>com.pig4cloud.plugin</groupId>
+				<artifactId>spring-cloud-maven-plugin</artifactId>
+				<version>1.1.1</version>
+				<executions>
+					<execution>
+						<phase>package</phase>
+						<goals>
+							<goal>info</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+	
+	<pluginRepositories>
+		<pluginRepository>
+			<id>aliyun-plugin</id>
+			<url>https://maven.aliyun.com/repository/public</url>
+			<releases>
+				<enabled>true</enabled>
+			</releases>
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+		</pluginRepository>
+	</pluginRepositories>
+</project>

+ 70 - 0
pigx-common/pigx-common-core/pom.xml

@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~
+  ~      Copyright (c) 2018-2025, lengleng All rights reserved.
+  ~
+  ~  Redistribution and use in source and binary forms, with or without
+  ~  modification, are permitted provided that the following conditions are met:
+  ~
+  ~ Redistributions of source code must retain the above copyright notice,
+  ~  this list of conditions and the following disclaimer.
+  ~  Redistributions in binary form must reproduce the above copyright
+  ~  notice, this list of conditions and the following disclaimer in the
+  ~  documentation and/or other materials provided with the distribution.
+  ~  Neither the name of the pig4cloud.com developer nor the names of its
+  ~  contributors may be used to endorse or promote products derived from
+  ~  this software without specific prior written permission.
+  ~  Author: lengleng (wangiegie@gmail.com)
+  ~
+  -->
+
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+		 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>
+	<parent>
+		<groupId>com.pig4cloud</groupId>
+		<artifactId>pigx-common</artifactId>
+		<version>3.7.0</version>
+	</parent>
+
+	<artifactId>pigx-common-core</artifactId>
+	<packaging>jar</packaging>
+
+	<description>pigx 公共工具类核心包</description>
+
+
+	<dependencies>
+		<!--hutool-->
+		<dependency>
+			<groupId>cn.hutool</groupId>
+			<artifactId>hutool-all</artifactId>
+			<version>${hutool.version}</version>
+		</dependency>
+		<!--server-api-->
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>javax.servlet-api</artifactId>
+		</dependency>
+		<!--hibernate-validator-->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-validation</artifactId>
+		</dependency>
+		<!--json模块-->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-json</artifactId>
+		</dependency>
+		<!--TTL-->
+		<dependency>
+			<groupId>com.alibaba</groupId>
+			<artifactId>transmittable-thread-local</artifactId>
+			<version>${ttl.version}</version>
+		</dependency>
+		<!--swagger 依赖-->
+		<dependency>
+			<groupId>io.swagger</groupId>
+			<artifactId>swagger-annotations</artifactId>
+		</dependency>
+	</dependencies>
+</project>

+ 38 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/config/JacksonConfig.java

@@ -0,0 +1,38 @@
+package com.pig4cloud.pigx.common.core.config;
+
+import cn.hutool.core.date.DatePattern;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.pig4cloud.pigx.common.core.jackson.PigxJavaTimeModule;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
+import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.time.ZoneId;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * JacksonConfig
+ *
+ * @author: lengleng
+ * @author L.cm
+ * @author: lishangbu
+ * @date: 2018/10/22
+ */
+@Configuration
+@ConditionalOnClass(ObjectMapper.class)
+@AutoConfigureBefore(JacksonAutoConfiguration.class)
+public class JacksonConfig {
+	@Bean
+	public Jackson2ObjectMapperBuilderCustomizer customizer() {
+		return builder -> {
+			builder.locale(Locale.CHINA);
+			builder.timeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
+			builder.simpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
+			builder.modules(new PigxJavaTimeModule());
+		};
+	}
+}

+ 41 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/config/MessageSourceConfig.java

@@ -0,0 +1,41 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.core.config;
+
+import org.springframework.context.MessageSource;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.support.ReloadableResourceBundleMessageSource;
+
+/**
+ * @author lengleng
+ * @date 2018/11/14
+ * <p>
+ * 国际化配置
+ */
+@Configuration
+public class MessageSourceConfig {
+
+	@Bean
+	public MessageSource messageSource() {
+		ReloadableResourceBundleMessageSource messageSource
+			= new ReloadableResourceBundleMessageSource();
+		messageSource.setBasename("classpath:i18n/messages");
+		return messageSource;
+	}
+}

+ 35 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/config/RestTemplateConfig.java

@@ -0,0 +1,35 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.core.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author lengleng
+ * @date 2018/8/16
+ * RestTemplate
+ */
+@Configuration
+public class RestTemplateConfig {
+	@Bean
+	public RestTemplate restTemplate() {
+		return new RestTemplate();
+	}
+}

+ 75 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/CacheConstants.java

@@ -0,0 +1,75 @@
+package com.pig4cloud.pigx.common.core.constant;
+
+/**
+ * @author lengleng
+ * @date 2019-04-28
+ * <p>
+ * 缓存的key 常量
+ */
+public interface CacheConstants {
+
+	/**
+	 * 全局缓存,在缓存名称上加上该前缀表示该缓存不区分租户,比如:
+	 * <p/>
+	 * {@code @Cacheable(value = CacheConstants.GLOBALLY+CacheConstants.MENU_DETAILS, key = "#roleId  + '_menu'", unless = "#result == null")}
+	 */
+	String GLOBALLY = "gl:";
+
+	/**
+	 * 验证码前缀
+	 */
+	String DEFAULT_CODE_KEY = "DEFAULT_CODE_KEY:";
+
+
+	/**
+	 * 菜单信息缓存
+	 */
+	String MENU_DETAILS = "menu_details";
+
+	/**
+	 * 用户信息缓存
+	 */
+	String USER_DETAILS = "user_details";
+
+	/**
+	 * 字典信息缓存
+	 */
+	String DICT_DETAILS = "dict_details";
+
+
+	/**
+	 * oauth 客户端信息
+	 */
+	String CLIENT_DETAILS_KEY = "pigx_oauth:client:details";
+
+
+	/**
+	 * spring boot admin 事件key
+	 */
+	String EVENT_KEY = "event_key";
+
+	/**
+	 * 路由存放
+	 */
+	String ROUTE_KEY = "gateway_route_key";
+
+	/**
+	 * redis reload 事件
+	 */
+	String ROUTE_REDIS_RELOAD_TOPIC = "gateway_redis_route_reload_topic";
+
+	/**
+	 * 内存reload 时间
+	 */
+	String ROUTE_JVM_RELOAD_TOPIC = "gateway_jvm_route_reload_topic";
+
+	/**
+	 * 参数缓存
+	 */
+	String PARAMS_DETAILS = "params_details";
+
+	/**
+	 * 租户缓存 (不区分租户)
+	 */
+	String TENANT_DETAILS = GLOBALLY + "tenant_details";
+}

+ 94 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/CommonConstants.java

@@ -0,0 +1,94 @@
+/*
+ *
+ *      Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the pig4cloud.com developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: lengleng (wangiegie@gmail.com)
+ *
+ */
+
+package com.pig4cloud.pigx.common.core.constant;
+
+/**
+ * @author lengleng
+ * @date 2017/10/29
+ */
+public interface CommonConstants {
+	/**
+	 * header 中租户ID
+	 */
+	String TENANT_ID = "TENANT-ID";
+
+	/**
+	 * header 中版本信息
+	 */
+	String VERSION = "VERSION";
+
+	/**
+	 * 租户ID
+	 */
+	Integer TENANT_ID_1 = 1;
+
+	/**
+	 * 删除
+	 */
+	String STATUS_DEL = "1";
+	/**
+	 * 正常
+	 */
+	String STATUS_NORMAL = "0";
+
+	/**
+	 * 锁定
+	 */
+	String STATUS_LOCK = "9";
+
+	/**
+	 * 菜单树根节点
+	 */
+	Integer MENU_TREE_ROOT_ID = -1;
+
+	/**
+	 * 编码
+	 */
+	String UTF8 = "UTF-8";
+
+	/**
+	 * 前端工程名
+	 */
+	String FRONT_END_PROJECT = "pigx-ui";
+
+	/**
+	 * 后端工程名
+	 */
+	String BACK_END_PROJECT = "pigx";
+
+	/**
+	 * 公共参数
+	 */
+	String PIG_PUBLIC_PARAM_KEY = "PIG_PUBLIC_PARAM_KEY";
+
+	/**
+	 * 成功标记
+	 */
+	Integer SUCCESS = 0;
+	/**
+	 * 失败标记
+	 */
+	Integer FAIL = 1;
+
+	/**
+	 * 默认存储bucket
+	 */
+	String BUCKET_NAME = "lengleng";
+}

+ 17 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/PaginationConstants.java

@@ -0,0 +1,17 @@
+package com.pig4cloud.pigx.common.core.constant;
+
+/**
+ * 分页相关的参数
+ * @author lishangbu
+ * @date 2018/11/22
+ */
+public interface PaginationConstants {
+	/**
+	 * 当前页
+	 */
+	String CURRENT="current";
+	/**
+	 * 每页大小
+	 */
+	String SIZE="size";
+}

+ 191 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java

@@ -0,0 +1,191 @@
+/*
+ *
+ *      Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the pig4cloud.com developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: lengleng (wangiegie@gmail.com)
+ *
+ */
+
+package com.pig4cloud.pigx.common.core.constant;
+
+/**
+ * @author lengleng
+ * @date 2017-12-18
+ */
+public interface SecurityConstants {
+	/**
+	 * 刷新
+	 */
+	String REFRESH_TOKEN = "refresh_token";
+	/**
+	 * 验证码有效期
+	 */
+	int CODE_TIME = 60;
+	/**
+	 * 验证码长度
+	 */
+	String CODE_SIZE = "4";
+	/**
+	 * 角色前缀
+	 */
+	String ROLE = "ROLE_";
+	/**
+	 * 前缀
+	 */
+	String PIGX_PREFIX = "pigx_";
+
+	/**
+	 * oauth 相关前缀
+	 */
+	String OAUTH_PREFIX = "oauth:";
+	/**
+	 * 项目的license
+	 */
+	String PIGX_LICENSE = "made by pigx";
+
+	/**
+	 * 内部
+	 */
+	String FROM_IN = "Y";
+
+	/**
+	 * 标志
+	 */
+	String FROM = "from";
+
+	/**
+	 * OAUTH URL
+	 */
+	String OAUTH_TOKEN_URL = "/oauth/token";
+
+	/**
+	 * 手机号登录URL
+	 */
+	String SMS_TOKEN_URL = "/mobile/token/sms";
+
+	/**
+	 * 社交登录URL
+	 */
+	String SOCIAL_TOKEN_URL = "/mobile/token/social";
+	/**
+	 * 自定义登录URL
+	 */
+	String MOBILE_TOKEN_URL = "/mobile/token/*";
+
+	/**
+	 * 微信获取OPENID
+	 */
+	String WX_AUTHORIZATION_CODE_URL = "https://api.weixin.qq.com/sns/oauth2/access_token" +
+			"?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
+
+	/**
+	 * 微信小程序OPENID
+	 */
+	String MINI_APP_AUTHORIZATION_CODE_URL = "https://api.weixin.qq.com/sns/jscode2session" +
+			"?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";
+
+	/**
+	 * 码云获取token
+	 */
+	String GITEE_AUTHORIZATION_CODE_URL = "https://gitee.com/oauth/token?grant_type=" +
+			"authorization_code&code=%S&client_id=%s&redirect_uri=" +
+			"%s&client_secret=%s";
+
+	/**
+	 * 开源中国获取token
+	 */
+	String OSC_AUTHORIZATION_CODE_URL = "https://www.oschina.net/action/openapi/token";
+
+	/**
+	 * 码云获取用户信息
+	 */
+	String GITEE_USER_INFO_URL = "https://gitee.com/api/v5/user?access_token=%s";
+
+	/**
+	 * 开源中国用户信息
+	 */
+	String OSC_USER_INFO_URL = "https://www.oschina.net/action/openapi/user?access_token=%s&dataType=json";
+
+	/**
+	 * {bcrypt} 加密的特征码
+	 */
+	String BCRYPT = "{bcrypt}";
+	/**
+	 * sys_oauth_client_details 表的字段,不包括client_id、client_secret
+	 */
+	String CLIENT_FIELDS = "client_id, CONCAT('{noop}',client_secret) as client_secret, resource_ids, scope, "
+			+ "authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, "
+			+ "refresh_token_validity, additional_information, autoapprove";
+
+	/**
+	 * JdbcClientDetailsService 查询语句
+	 */
+	String BASE_FIND_STATEMENT = "select " + CLIENT_FIELDS
+			+ " from sys_oauth_client_details";
+
+	/**
+	 * 默认的查询语句
+	 */
+	String DEFAULT_FIND_STATEMENT = BASE_FIND_STATEMENT + " order by client_id";
+
+	/**
+	 * 按条件client_id 查询
+	 */
+	String DEFAULT_SELECT_STATEMENT = BASE_FIND_STATEMENT + " where client_id = ?";
+
+	/**
+	 * 资源服务器默认bean名称
+	 */
+	String RESOURCE_SERVER_CONFIGURER = "resourceServerConfigurerAdapter";
+
+	/**
+	 * 客户端模式
+	 */
+	String CLIENT_CREDENTIALS = "client_credentials";
+
+	/**
+	 * 用户ID字段
+	 */
+	String DETAILS_USER_ID = "user_id";
+
+	/**
+	 * 用户名字段
+	 */
+	String DETAILS_USERNAME = "username";
+
+	/**
+	 * 用户部门字段
+	 */
+	String DETAILS_DEPT_ID = "dept_id";
+
+	/**
+	 * 租户ID 字段
+	 */
+	String DETAILS_TENANT_ID = "tenant_id";
+
+	/**
+	 * 协议字段
+	 */
+	String DETAILS_LICENSE = "license";
+
+	/**
+	 * 激活字段 兼容外围系统接入
+	 */
+	String ACTIVE = "active";
+
+	/**
+	 * AES 加密
+	 */
+	String AES = "aes";
+}

+ 42 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/ServiceNameConstants.java

@@ -0,0 +1,42 @@
+/*
+ *
+ *      Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the pig4cloud.com developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: lengleng (wangiegie@gmail.com)
+ *
+ */
+
+package com.pig4cloud.pigx.common.core.constant;
+
+/**
+ * @author lengleng
+ * @date 2018年06月22日16:41:01
+ * 服务名称
+ */
+public interface ServiceNameConstants {
+	/**
+	 * 认证中心
+	 */
+	String AUTH_SERVICE = "pigx-auth";
+
+	/**
+	 * UMPS模块
+	 */
+	String UPMS_SERVICE = "pigx-upms-biz";
+
+	/**
+	 * 分布式事务协调服务
+	 */
+	String TX_MANAGER = "pigx-tx-manager";
+}

+ 33 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/DictTypeEnum.java

@@ -0,0 +1,33 @@
+package com.pig4cloud.pigx.common.core.constant.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author lengleng
+ * @date 2019-05-16
+ * <p>
+ * 字典类型
+ */
+@Getter
+@AllArgsConstructor
+public enum DictTypeEnum {
+	/**
+	 * 字典类型-系统内置(不可修改)
+	 */
+	SYSTEM("1", "系统内置"),
+
+	/**
+	 * 字典类型-业务类型
+	 */
+	BIZ("0", "业务类");
+
+	/**
+	 * 类型
+	 */
+	private String type;
+	/**
+	 * 描述
+	 */
+	private String description;
+}

+ 74 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/LoginTypeEnum.java

@@ -0,0 +1,74 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.core.constant.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author lengleng
+ * @date 2018/8/15
+ * 社交登录类型
+ */
+@Getter
+@AllArgsConstructor
+public enum LoginTypeEnum {
+	/**
+	 * 账号密码登录
+	 */
+	PWD("PWD", "账号密码登录"),
+
+	/**
+	 * 验证码登录
+	 */
+	SMS("SMS", "验证码登录"),
+
+	/**
+	 * QQ登录
+	 */
+	QQ("QQ", "QQ登录"),
+
+	/**
+	 * 微信登录
+	 */
+	WECHAT("WX", "微信登录"),
+
+	/**
+	 * 微信小程序
+	 */
+	MINI_APP("MINI", "微信小程序"),
+
+	/**
+	 * 码云登录
+	 */
+	GITEE("GITEE", "码云登录"),
+
+	/**
+	 * 开源中国登录
+	 */
+	OSC("OSC", "开源中国登录");
+
+	/**
+	 * 类型
+	 */
+	private String type;
+	/**
+	 * 描述
+	 */
+	private String description;
+}

+ 39 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/MenuTypeEnum.java

@@ -0,0 +1,39 @@
+package com.pig4cloud.pigx.common.core.constant.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author lengleng
+ * @date 2020-02-17
+ * <p>
+ * 菜单类型
+ */
+@Getter
+@AllArgsConstructor
+public enum MenuTypeEnum {
+
+	/**
+	 * 左侧菜单
+	 */
+	LEFT_MENU("0", "left"),
+
+	/**
+	 * 顶部菜单
+	 */
+	TOP_MENU("2", "top"),
+
+	/**
+	 * 按钮
+	 */
+	BUTTON("1", "button");
+
+	/**
+	 * 类型
+	 */
+	private String type;
+	/**
+	 * 描述
+	 */
+	private String description;
+}

+ 49 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/ProcessStatusEnum.java

@@ -0,0 +1,49 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.core.constant.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author lengleng
+ * @date 2018/9/30
+ * 流程状态
+ */
+@Getter
+@AllArgsConstructor
+public enum ProcessStatusEnum {
+	/**
+	 * 图片资源
+	 */
+	ACTIVE("active", "图片资源"),
+
+	/**
+	 * xml资源
+	 */
+	SUSPEND("suspend", "xml资源");
+
+	/**
+	 * 类型
+	 */
+	private final String status;
+	/**
+	 * 描述
+	 */
+	private final String description;
+}

+ 49 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/ResourceTypeEnum.java

@@ -0,0 +1,49 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.core.constant.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author lengleng
+ * @date 2018/9/30
+ * 资源类型
+ */
+@Getter
+@AllArgsConstructor
+public enum ResourceTypeEnum {
+	/**
+	 * 图片资源
+	 */
+	IMAGE("image", "图片资源"),
+
+	/**
+	 * xml资源
+	 */
+	XML("xml", "xml资源");
+
+	/**
+	 * 类型
+	 */
+	private final String type;
+	/**
+	 * 描述
+	 */
+	private final String description;
+}

+ 33 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/StyleTypeEnum.java

@@ -0,0 +1,33 @@
+package com.pig4cloud.pigx.common.core.constant.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author lengleng
+ * @date 2020-01-19
+ * <p>
+ * 前端类型类型
+ */
+@Getter
+@AllArgsConstructor
+public enum StyleTypeEnum {
+	/**
+	 * 前端类型-avue 风格
+	 */
+	AVUE("0", "avue 风格"),
+
+	/**
+	 * 前端类型-element 风格
+	 */
+	ELEMENT("1", "element 风格");
+
+	/**
+	 * 类型
+	 */
+	private String style;
+	/**
+	 * 描述
+	 */
+	private String description;
+}

+ 59 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/TaskStatusEnum.java

@@ -0,0 +1,59 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.core.constant.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author lengleng
+ * @date 2018/9/30
+ * 流程状态
+ */
+@Getter
+@AllArgsConstructor
+public enum TaskStatusEnum {
+	/**
+	 * 未提交
+	 */
+	UNSUBMIT("0", "未提交"),
+
+	/**
+	 * 审核中
+	 */
+	CHECK("1", "审核中"),
+
+	/**
+	 * 已完成
+	 */
+	COMPLETED("2", "已完成"),
+
+	/**
+	 * 驳回
+	 */
+	OVERRULE("9", "驳回");
+
+	/**
+	 * 类型
+	 */
+	private final String status;
+	/**
+	 * 描述
+	 */
+	private final String description;
+}

+ 48 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/exception/CheckedException.java

@@ -0,0 +1,48 @@
+/*
+ *
+ *      Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the pig4cloud.com developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: lengleng (wangiegie@gmail.com)
+ *
+ */
+
+package com.pig4cloud.pigx.common.core.exception;
+
+import lombok.NoArgsConstructor;
+
+/**
+ * @author lengleng
+ * @date 😴2018年06月22日16:21:57
+ */
+@NoArgsConstructor
+public class CheckedException extends RuntimeException {
+	private static final long serialVersionUID = 1L;
+
+	public CheckedException(String message) {
+		super(message);
+	}
+
+	public CheckedException(Throwable cause) {
+		super(cause);
+	}
+
+	public CheckedException(String message, Throwable cause) {
+		super(message, cause);
+	}
+
+	public CheckedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+		super(message, cause, enableSuppression, writableStackTrace);
+	}
+
+}

+ 35 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/exception/ValidateCodeException.java

@@ -0,0 +1,35 @@
+/*
+ *
+ *      Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the pig4cloud.com developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: lengleng (wangiegie@gmail.com)
+ *
+ */
+
+package com.pig4cloud.pigx.common.core.exception;
+
+/**
+ * @author lengleng
+ * @date 2018年06月22日16:22:15
+ */
+public class ValidateCodeException extends RuntimeException {
+	private static final long serialVersionUID = -7285211528095468156L;
+
+	public ValidateCodeException() {
+	}
+
+	public ValidateCodeException(String msg) {
+		super(msg);
+	}
+}

+ 35 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/jackson/PigxJavaTimeModule.java

@@ -0,0 +1,35 @@
+package com.pig4cloud.pigx.common.core.jackson;
+
+import cn.hutool.core.date.DatePattern;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.datatype.jsr310.PackageVersion;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * java 8 时间默认序列化
+ *
+ * @author L.cm
+ * @author lishanbu
+ */
+public class PigxJavaTimeModule extends SimpleModule {
+
+	public PigxJavaTimeModule() {
+		super(PackageVersion.VERSION);
+		this.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
+		this.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
+		this.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
+		this.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
+		this.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
+		this.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
+	}
+}

+ 60 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/Sensitive.java

@@ -0,0 +1,60 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.core.sensitive;
+
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 对象脱敏注解
+ *
+ * @author mayee
+ * @version v1.0
+ **/
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+@JacksonAnnotationsInside
+@JsonSerialize(using = SensitiveSerialize.class)
+public @interface Sensitive {
+
+	/**
+	 * 脱敏数据类型, 非Customer时, 将忽略 refixNoMaskLen 和 suffixNoMaskLen 和 maskStr
+	 */
+	SensitiveTypeEnum type() default SensitiveTypeEnum.CUSTOMER;
+
+	/**
+	 * 前置不需要打码的长度
+	 */
+	int prefixNoMaskLen() default 0;
+
+	/**
+	 * 后置不需要打码的长度
+	 */
+	int suffixNoMaskLen() default 0;
+
+	/**
+	 * 用什么打码
+	 */
+	String maskStr() default "*";
+
+}

+ 105 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveSerialize.java

@@ -0,0 +1,105 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.core.sensitive;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.BeanProperty;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.ContextualSerializer;
+import com.pig4cloud.pigx.common.core.util.DesensitizedUtils;
+import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * @author lengleng
+ * @date 2019-08-13
+ * <p>
+ * 脱敏序列化
+ */
+@NoArgsConstructor
+@AllArgsConstructor
+public class SensitiveSerialize extends JsonSerializer<String> implements ContextualSerializer {
+
+	private SensitiveTypeEnum type;
+	private Integer prefixNoMaskLen;
+	private Integer suffixNoMaskLen;
+	private String maskStr;
+
+	@Override
+	public void serialize(final String origin, final JsonGenerator jsonGenerator,
+						  final SerializerProvider serializerProvider) throws IOException {
+		switch (type) {
+			case CHINESE_NAME:
+				jsonGenerator.writeString(DesensitizedUtils.chineseName(origin));
+				break;
+			case ID_CARD:
+				jsonGenerator.writeString(DesensitizedUtils.idCardNum(origin));
+				break;
+			case FIXED_PHONE:
+				jsonGenerator.writeString(DesensitizedUtils.fixedPhone(origin));
+				break;
+			case MOBILE_PHONE:
+				jsonGenerator.writeString(DesensitizedUtils.mobilePhone(origin));
+				break;
+			case ADDRESS:
+				jsonGenerator.writeString(DesensitizedUtils.address(origin));
+				break;
+			case EMAIL:
+				jsonGenerator.writeString(DesensitizedUtils.email(origin));
+				break;
+			case BANK_CARD:
+				jsonGenerator.writeString(DesensitizedUtils.bankCard(origin));
+				break;
+			case PASSWORD:
+				jsonGenerator.writeString(DesensitizedUtils.password(origin));
+				break;
+			case KEY:
+				jsonGenerator.writeString(DesensitizedUtils.key(origin));
+				break;
+			case CUSTOMER:
+				jsonGenerator.writeString(DesensitizedUtils.desValue(origin, prefixNoMaskLen, suffixNoMaskLen, maskStr));
+				break;
+			default:
+				throw new IllegalArgumentException("Unknow sensitive type enum " + type);
+		}
+	}
+
+	@Override
+	public JsonSerializer<?> createContextual(final SerializerProvider serializerProvider,
+											  final BeanProperty beanProperty) throws JsonMappingException {
+		if (beanProperty != null) {
+			if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {
+				Sensitive sensitive = beanProperty.getAnnotation(Sensitive.class);
+				if (sensitive == null) {
+					sensitive = beanProperty.getContextAnnotation(Sensitive.class);
+				}
+				if (sensitive != null) {
+					return new SensitiveSerialize(sensitive.type(), sensitive.prefixNoMaskLen(), sensitive.suffixNoMaskLen(), sensitive.maskStr());
+				}
+			}
+			return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
+		}
+		return serializerProvider.findNullValueSerializer(null);
+	}
+}
+

+ 70 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveTypeEnum.java

@@ -0,0 +1,70 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.core.sensitive;
+
+/**
+ * 敏感信息枚举类
+ *
+ * @author mayee
+ * @version v1.0
+ **/
+public enum SensitiveTypeEnum {
+
+    /**
+     * 自定义
+     */
+    CUSTOMER,
+    /**
+     * 用户名, 刘*华, 徐*
+     */
+    CHINESE_NAME,
+    /**
+     * 身份证号, 110110********1234
+     */
+    ID_CARD,
+    /**
+     * 座机号, ****1234
+     */
+    FIXED_PHONE,
+    /**
+     * 手机号, 176****1234
+     */
+    MOBILE_PHONE,
+    /**
+     * 地址, 北京********
+     */
+    ADDRESS,
+    /**
+     * 电子邮件, s*****o@xx.com
+     */
+    EMAIL,
+    /**
+     * 银行卡, 622202************1234
+     */
+    BANK_CARD,
+    /**
+     * 密码, 永远是 ******, 与长度无关
+     */
+    PASSWORD,
+    /**
+     * 密钥, 永远是 ******, 与长度无关
+     */
+    KEY
+
+
+}

+ 114 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/ClassUtils.java

@@ -0,0 +1,114 @@
+/*
+ *
+ *      Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the pig4cloud.com developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: lengleng (wangiegie@gmail.com)
+ *
+ */
+
+package com.pig4cloud.pigx.common.core.util;
+
+import lombok.experimental.UtilityClass;
+import org.springframework.core.BridgeMethodResolver;
+import org.springframework.core.DefaultParameterNameDiscoverer;
+import org.springframework.core.MethodParameter;
+import org.springframework.core.ParameterNameDiscoverer;
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.core.annotation.SynthesizingMethodParameter;
+import org.springframework.web.method.HandlerMethod;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * 类工具类
+ *
+ * @author L.cm
+ */
+@UtilityClass
+public class ClassUtils extends org.springframework.util.ClassUtils {
+	private final ParameterNameDiscoverer PARAMETERNAMEDISCOVERER = new DefaultParameterNameDiscoverer();
+
+	/**
+	 * 获取方法参数信息
+	 *
+	 * @param constructor    构造器
+	 * @param parameterIndex 参数序号
+	 * @return {MethodParameter}
+	 */
+	public MethodParameter getMethodParameter(Constructor<?> constructor, int parameterIndex) {
+		MethodParameter methodParameter = new SynthesizingMethodParameter(constructor, parameterIndex);
+		methodParameter.initParameterNameDiscovery(PARAMETERNAMEDISCOVERER);
+		return methodParameter;
+	}
+
+	/**
+	 * 获取方法参数信息
+	 *
+	 * @param method         方法
+	 * @param parameterIndex 参数序号
+	 * @return {MethodParameter}
+	 */
+	public MethodParameter getMethodParameter(Method method, int parameterIndex) {
+		MethodParameter methodParameter = new SynthesizingMethodParameter(method, parameterIndex);
+		methodParameter.initParameterNameDiscovery(PARAMETERNAMEDISCOVERER);
+		return methodParameter;
+	}
+
+	/**
+	 * 获取Annotation
+	 *
+	 * @param method         Method
+	 * @param annotationType 注解类
+	 * @param <A>            泛型标记
+	 * @return {Annotation}
+	 */
+	public <A extends Annotation> A getAnnotation(Method method, Class<A> annotationType) {
+		Class<?> targetClass = method.getDeclaringClass();
+		// The method may be on an interface, but we need attributes from the target class.
+		// If the target class is null, the method will be unchanged.
+		Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
+		// If we are dealing with method with generic parameters, find the original method.
+		specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
+		// 先找方法,再找方法上的类
+		A annotation = AnnotatedElementUtils.findMergedAnnotation(specificMethod, annotationType);
+		;
+		if (null != annotation) {
+			return annotation;
+		}
+		// 获取类上面的Annotation,可能包含组合注解,故采用spring的工具类
+		return AnnotatedElementUtils.findMergedAnnotation(specificMethod.getDeclaringClass(), annotationType);
+	}
+
+	/**
+	 * 获取Annotation
+	 *
+	 * @param handlerMethod  HandlerMethod
+	 * @param annotationType 注解类
+	 * @param <A>            泛型标记
+	 * @return {Annotation}
+	 */
+	public <A extends Annotation> A getAnnotation(HandlerMethod handlerMethod, Class<A> annotationType) {
+		// 先找方法,再找方法上的类
+		A annotation = handlerMethod.getMethodAnnotation(annotationType);
+		if (null != annotation) {
+			return annotation;
+		}
+		// 获取类上面的Annotation,可能包含组合注解,故采用spring的工具类
+		Class<?> beanType = handlerMethod.getBeanType();
+		return AnnotatedElementUtils.findMergedAnnotation(beanType, annotationType);
+	}
+
+}

+ 181 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/DesensitizedUtils.java

@@ -0,0 +1,181 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.core.util;
+
+
+import cn.hutool.core.util.StrUtil;
+
+/**
+ * 脱敏工具类
+ *
+ * @author mayee
+ * @version v1.0
+ **/
+public class DesensitizedUtils {
+
+	/**
+	 * 对字符串进行脱敏操作
+	 *
+	 * @param origin          原始字符串
+	 * @param prefixNoMaskLen 左侧需要保留几位明文字段
+	 * @param suffixNoMaskLen 右侧需要保留几位明文字段
+	 * @param maskStr         用于遮罩的字符串, 如'*'
+	 * @return 脱敏后结果
+	 */
+	public static String desValue(String origin, int prefixNoMaskLen, int suffixNoMaskLen, String maskStr) {
+		if (origin == null) {
+			return null;
+		}
+
+		StringBuilder sb = new StringBuilder();
+		for (int i = 0, n = origin.length(); i < n; i++) {
+			if (i < prefixNoMaskLen) {
+				sb.append(origin.charAt(i));
+				continue;
+			}
+			if (i > (n - suffixNoMaskLen - 1)) {
+				sb.append(origin.charAt(i));
+				continue;
+			}
+			sb.append(maskStr);
+		}
+		return sb.toString();
+	}
+
+	/**
+	 * 【中文姓名】只显示最后一个汉字,其他隐藏为星号,比如:**梦
+	 *
+	 * @param fullName 姓名
+	 * @return 结果
+	 */
+	public static String chineseName(String fullName) {
+		if (fullName == null) {
+			return null;
+		}
+		return desValue(fullName, 0, 1, "*");
+	}
+
+	/**
+	 * 【身份证号】显示前六位, 四位,其他隐藏。共计18位或者15位,比如:340304*******1234
+	 *
+	 * @param id 身份证号码
+	 * @return 结果
+	 */
+	public static String idCardNum(String id) {
+		return desValue(id, 6, 4, "*");
+	}
+
+	/**
+	 * 【固定电话】后四位,其他隐藏,比如 ****1234
+	 *
+	 * @param num 固定电话
+	 * @return 结果
+	 */
+	public static String fixedPhone(String num) {
+		return desValue(num, 0, 4, "*");
+	}
+
+	/**
+	 * 【手机号码】前三位,后四位,其他隐藏,比如135****6810
+	 *
+	 * @param num 手机号码
+	 * @return 结果
+	 */
+	public static String mobilePhone(String num) {
+		return desValue(num, 3, 4, "*");
+	}
+
+	/**
+	 * 【地址】只显示到地区,不显示详细地址,比如:北京市海淀区****
+	 *
+	 * @param address 地址
+	 * @return 结果
+	 */
+	public static String address(String address) {
+		return desValue(address, 6, 0, "*");
+	}
+
+	/**
+	 * 【电子邮箱 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示,比如:d**@126.com
+	 *
+	 * @param email 电子邮箱
+	 * @return 结果
+	 */
+	public static String email(String email) {
+		if (email == null) {
+			return null;
+		}
+		int index = StrUtil.indexOf(email, '@');
+		if (index <= 1) {
+			return email;
+		}
+		String preEmail = desValue(email.substring(0, index), 1, 0, "*");
+		return preEmail + email.substring(index);
+
+	}
+
+	/**
+	 * 【银行卡号】前六位,后四位,其他用星号隐藏每位1个星号,比如:622260**********1234
+	 *
+	 * @param cardNum 银行卡号
+	 * @return 结果
+	 */
+	public static String bankCard(String cardNum) {
+		return desValue(cardNum, 6, 4, "*");
+	}
+
+	/**
+	 * 【密码】密码的全部字符都用*代替,比如:******
+	 *
+	 * @param password 密码
+	 * @return 结果
+	 */
+	public static String password(String password) {
+		if (password == null) {
+			return null;
+		}
+		return "******";
+	}
+
+	/**
+	 * 【密钥】密钥除了最后三位,全部都用*代替,比如:***xdS
+	 * 脱敏后长度为6,如果明文长度不足三位,则按实际长度显示,剩余位置补*
+	 *
+	 * @param key 密钥
+	 * @return 结果
+	 */
+	public static String key(String key) {
+		if (key == null) {
+			return null;
+		}
+		int viewLength = 6;
+		StringBuilder tmpKey = new StringBuilder(desValue(key, 0, 3, "*"));
+		if (tmpKey.length() > viewLength) {
+			return tmpKey.substring(tmpKey.length() - viewLength);
+		} else if (tmpKey.length() < viewLength) {
+			int buffLength = viewLength - tmpKey.length();
+			for (int i = 0; i < buffLength; i++) {
+				tmpKey.insert(0, "*");
+			}
+			return tmpKey.toString();
+		} else {
+			return tmpKey.toString();
+		}
+	}
+
+}

+ 96 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/R.java

@@ -0,0 +1,96 @@
+/*
+ *
+ *      Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the pig4cloud.com developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: lengleng (wangiegie@gmail.com)
+ *
+ */
+
+package com.pig4cloud.pigx.common.core.util;
+
+import com.pig4cloud.pigx.common.core.constant.CommonConstants;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.*;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 响应信息主体
+ *
+ * @param <T>
+ * @author lengleng
+ */
+@Builder
+@ToString
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+@ApiModel(value = "响应信息主体")
+public class R<T> implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	@Getter
+	@Setter
+	@ApiModelProperty(value = "返回标记:成功标记=0,失败标记=1")
+	private int code;
+
+	@Getter
+	@Setter
+	@ApiModelProperty(value = "返回信息")
+	private String msg;
+
+
+	@Getter
+	@Setter
+	@ApiModelProperty(value = "数据")
+	private T data;
+
+	public static <T> R<T> ok() {
+		return restResult(null, CommonConstants.SUCCESS, null);
+	}
+
+	public static <T> R<T> ok(T data) {
+		return restResult(data, CommonConstants.SUCCESS, null);
+	}
+
+	public static <T> R<T> ok(T data, String msg) {
+		return restResult(data, CommonConstants.SUCCESS, msg);
+	}
+
+	public static <T> R<T> failed() {
+		return restResult(null, CommonConstants.FAIL, null);
+	}
+
+	public static <T> R<T> failed(String msg) {
+		return restResult(null, CommonConstants.FAIL, msg);
+	}
+
+	public static <T> R<T> failed(T data) {
+		return restResult(data, CommonConstants.FAIL, null);
+	}
+
+	public static <T> R<T> failed(T data, String msg) {
+		return restResult(data, CommonConstants.FAIL, msg);
+	}
+
+	private static <T> R<T> restResult(T data, int code, String msg) {
+		R<T> apiResult = new R<>();
+		apiResult.setCode(code);
+		apiResult.setData(data);
+		apiResult.setMsg(msg);
+		return apiResult;
+	}
+}

+ 102 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/SpringContextHolder.java

@@ -0,0 +1,102 @@
+/*
+ *
+ *      Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the pig4cloud.com developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: lengleng (wangiegie@gmail.com)
+ *
+ */
+
+package com.pig4cloud.pigx.common.core.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author lengleng
+ * @date 2018/6/27
+ * Spring 工具类
+ */
+@Slf4j
+@Service
+@Lazy(false)
+public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
+
+	private static ApplicationContext applicationContext = null;
+
+	/**
+	 * 取得存储在静态变量中的ApplicationContext.
+	 */
+	public static ApplicationContext getApplicationContext() {
+		return applicationContext;
+	}
+
+	/**
+	 * 实现ApplicationContextAware接口, 注入Context到静态变量中.
+	 */
+	@Override
+	public void setApplicationContext(ApplicationContext applicationContext) {
+		SpringContextHolder.applicationContext = applicationContext;
+	}
+
+	/**
+	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T> T getBean(String name) {
+		return (T) applicationContext.getBean(name);
+	}
+
+	/**
+	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
+	 */
+	public static <T> T getBean(Class<T> requiredType) {
+		return applicationContext.getBean(requiredType);
+	}
+
+	/**
+	 * 清除SpringContextHolder中的ApplicationContext为Null.
+	 */
+	public static void clearHolder() {
+		if (log.isDebugEnabled()) {
+			log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
+		}
+		applicationContext = null;
+	}
+
+	/**
+	 * 发布事件
+	 *
+	 * @param event
+	 */
+	public static void publishEvent(ApplicationEvent event) {
+		if (applicationContext == null) {
+			return;
+		}
+		applicationContext.publishEvent(event);
+	}
+
+	/**
+	 * 实现DisposableBean接口, 在Context关闭时清理静态变量.
+	 */
+	@Override
+	public void destroy() {
+		SpringContextHolder.clearHolder();
+	}
+
+}

+ 240 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/WebUtils.java

@@ -0,0 +1,240 @@
+/*
+ *
+ *      Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the pig4cloud.com developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: lengleng (wangiegie@gmail.com)
+ *
+ */
+
+package com.pig4cloud.pigx.common.core.util;
+
+import cn.hutool.core.codec.Base64;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import com.pig4cloud.pigx.common.core.exception.CheckedException;
+import lombok.SneakyThrows;
+import lombok.experimental.UtilityClass;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.util.Assert;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.web.method.HandlerMethod;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+
+
+/**
+ * Miscellaneous utilities for web applications.
+ *
+ * @author L.cm
+ */
+@Slf4j
+@UtilityClass
+public class WebUtils extends org.springframework.web.util.WebUtils {
+	private final String BASIC_ = "Basic ";
+	private final String UNKNOWN = "unknown";
+
+	/**
+	 * 判断是否ajax请求
+	 * spring ajax 返回含有 ResponseBody 或者 RestController注解
+	 *
+	 * @param handlerMethod HandlerMethod
+	 * @return 是否ajax请求
+	 */
+	public boolean isBody(HandlerMethod handlerMethod) {
+		ResponseBody responseBody = ClassUtils.getAnnotation(handlerMethod, ResponseBody.class);
+		return responseBody != null;
+	}
+
+	/**
+	 * 读取cookie
+	 *
+	 * @param name cookie name
+	 * @return cookie value
+	 */
+	public String getCookieVal(String name) {
+		HttpServletRequest request = WebUtils.getRequest();
+		Assert.notNull(request, "request from RequestContextHolder is null");
+		return getCookieVal(request, name);
+	}
+
+	/**
+	 * 读取cookie
+	 *
+	 * @param request HttpServletRequest
+	 * @param name    cookie name
+	 * @return cookie value
+	 */
+	public String getCookieVal(HttpServletRequest request, String name) {
+		Cookie cookie = getCookie(request, name);
+		return cookie != null ? cookie.getValue() : null;
+	}
+
+	/**
+	 * 清除 某个指定的cookie
+	 *
+	 * @param response HttpServletResponse
+	 * @param key      cookie key
+	 */
+	public void removeCookie(HttpServletResponse response, String key) {
+		setCookie(response, key, null, 0);
+	}
+
+	/**
+	 * 设置cookie
+	 *
+	 * @param response        HttpServletResponse
+	 * @param name            cookie name
+	 * @param value           cookie value
+	 * @param maxAgeInSeconds maxage
+	 */
+	public void setCookie(HttpServletResponse response, String name, String value, int maxAgeInSeconds) {
+		Cookie cookie = new Cookie(name, value);
+		cookie.setPath("/");
+		cookie.setMaxAge(maxAgeInSeconds);
+		cookie.setHttpOnly(true);
+		response.addCookie(cookie);
+	}
+
+	/**
+	 * 获取 HttpServletRequest
+	 *
+	 * @return {HttpServletRequest}
+	 */
+	public HttpServletRequest getRequest() {
+		try {
+			RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
+			return ((ServletRequestAttributes) requestAttributes).getRequest();
+		} catch (IllegalStateException e) {
+			return null;
+		}
+	}
+
+	/**
+	 * 获取 HttpServletResponse
+	 *
+	 * @return {HttpServletResponse}
+	 */
+	public HttpServletResponse getResponse() {
+		return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
+	}
+
+	/**
+	 * 返回json
+	 *
+	 * @param response HttpServletResponse
+	 * @param result   结果对象
+	 */
+	public void renderJson(HttpServletResponse response, Object result) {
+		renderJson(response, result, MediaType.APPLICATION_JSON_VALUE);
+	}
+
+	/**
+	 * 返回json
+	 *
+	 * @param response    HttpServletResponse
+	 * @param result      结果对象
+	 * @param contentType contentType
+	 */
+	public void renderJson(HttpServletResponse response, Object result, String contentType) {
+		response.setCharacterEncoding("UTF-8");
+		response.setContentType(contentType);
+		try (PrintWriter out = response.getWriter()) {
+			out.append(JSONUtil.toJsonStr(result));
+		} catch (IOException e) {
+			log.error(e.getMessage(), e);
+		}
+	}
+
+	/**
+	 * 获取ip
+	 *
+	 * @return {String}
+	 */
+	public String getIP() {
+		return getIP(WebUtils.getRequest());
+	}
+
+	/**
+	 * 获取ip
+	 *
+	 * @param request HttpServletRequest
+	 * @return {String}
+	 */
+	public String getIP(HttpServletRequest request) {
+		Assert.notNull(request, "HttpServletRequest is null");
+		String ip = request.getHeader("X-Requested-For");
+		if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
+			ip = request.getHeader("X-Forwarded-For");
+		}
+		if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
+			ip = request.getHeader("Proxy-Client-IP");
+		}
+		if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
+			ip = request.getHeader("WL-Proxy-Client-IP");
+		}
+		if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
+			ip = request.getHeader("HTTP_CLIENT_IP");
+		}
+		if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
+			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
+		}
+		if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
+			ip = request.getRemoteAddr();
+		}
+		return StrUtil.isBlank(ip) ? null : ip.split(",")[0];
+	}
+
+	/**
+	 * 从request 获取CLIENT_ID
+	 *
+	 * @return
+	 */
+	@SneakyThrows
+	public String[] getClientId(ServerHttpRequest request) {
+		String header = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
+
+		if (header == null || !header.startsWith(BASIC_)) {
+			throw new CheckedException("请求头中client信息为空");
+		}
+		byte[] base64Token = header.substring(6).getBytes("UTF-8");
+		byte[] decoded;
+		try {
+			decoded = Base64.decode(base64Token);
+		} catch (IllegalArgumentException e) {
+			throw new CheckedException(
+					"Failed to decode basic authentication token");
+		}
+
+		String token = new String(decoded, StandardCharsets.UTF_8);
+
+		int delim = token.indexOf(":");
+
+		if (delim == -1) {
+			throw new CheckedException("Invalid basic authentication token");
+		}
+		return new String[]{token.substring(0, delim), token.substring(delim + 1)};
+	}
+
+}

+ 5 - 0
pigx-common/pigx-common-core/src/main/resources/META-INF/spring.factories

@@ -0,0 +1,5 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+  com.pig4cloud.pigx.common.core.config.JacksonConfig,\
+  com.pig4cloud.pigx.common.core.config.MessageSourceConfig,\
+  com.pig4cloud.pigx.common.core.config.RestTemplateConfig,\
+  com.pig4cloud.pigx.common.core.util.SpringContextHolder

+ 16 - 0
pigx-common/pigx-common-core/src/main/resources/banner.txt

@@ -0,0 +1,16 @@
+${AnsiColor.BRIGHT_YELLOW}
+
+          :::::::::       :::::::::::       ::::::::       :::    :::
+         :+:    :+:          :+:          :+:    :+:      :+:    :+:
+        +:+    +:+          +:+          +:+              +:+  +:+
+       +#++:++#+           +#+          :#:               +#++:+
+      +#+                 +#+          +#+   +#+#       +#+  +#+
+     #+#                 #+#          #+#    #+#      #+#    #+#
+    ###             ###########       ########       ###    ###
+
+                       www.pig4cloud.com
+
+                  Pig Microservice Architecture
+
+
+

+ 0 - 0
pigx-common/pigx-common-core/src/main/resources/i18n/messages_zh_CN.properties


+ 58 - 0
pigx-common/pigx-common-data/pom.xml

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~
+  ~      Copyright (c) 2018-2025, lengleng All rights reserved.
+  ~
+  ~  Redistribution and use in source and binary forms, with or without
+  ~  modification, are permitted provided that the following conditions are met:
+  ~
+  ~ Redistributions of source code must retain the above copyright notice,
+  ~  this list of conditions and the following disclaimer.
+  ~  Redistributions in binary form must reproduce the above copyright
+  ~  notice, this list of conditions and the following disclaimer in the
+  ~  documentation and/or other materials provided with the distribution.
+  ~  Neither the name of the pig4cloud.com developer nor the names of its
+  ~  contributors may be used to endorse or promote products derived from
+  ~  this software without specific prior written permission.
+  ~  Author: lengleng (wangiegie@gmail.com)
+  ~
+  -->
+
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+		 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>
+	<parent>
+		<groupId>com.pig4cloud</groupId>
+		<artifactId>pigx-common</artifactId>
+		<version>3.7.0</version>
+	</parent>
+
+	<artifactId>pigx-common-data</artifactId>
+	<packaging>jar</packaging>
+
+	<description>pigx 数据操作相关</description>
+
+
+	<dependencies>
+		<!--工具类核心包-->
+		<dependency>
+			<groupId>com.pig4cloud</groupId>
+			<artifactId>pigx-common-core</artifactId>
+		</dependency>
+		<!--mybatis plus extension,包含了mybatis plus core-->
+		<dependency>
+			<groupId>com.baomidou</groupId>
+			<artifactId>mybatis-plus-extension</artifactId>
+		</dependency>
+		<!--安全依赖获取上下文信息-->
+		<dependency>
+			<groupId>com.pig4cloud</groupId>
+			<artifactId>pigx-common-security</artifactId>
+		</dependency>
+		<!--缓存依赖-->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-data-redis</artifactId>
+		</dependency>
+	</dependencies>
+</project>

+ 275 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/DefaultRedisCacheWriter.java

@@ -0,0 +1,275 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.cache;
+
+import org.springframework.dao.PessimisticLockingFailureException;
+import org.springframework.data.redis.cache.RedisCacheWriter;
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
+import org.springframework.data.redis.core.types.Expiration;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.util.Collections;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * {@link RedisCacheWriter} implementation capable of reading/writing binary data from/to Redis in {@literal standalone}
+ * and {@literal cluster} environments. Works upon a given {@link RedisConnectionFactory} to obtain the actual
+ * {@link RedisConnection}. <br />
+ * {@link DefaultRedisCacheWriter} can be used in
+ * {@link RedisCacheWriter#lockingRedisCacheWriter(RedisConnectionFactory) locking} or
+ * {@link RedisCacheWriter#nonLockingRedisCacheWriter(RedisConnectionFactory) non-locking} mode. While
+ * {@literal non-locking} aims for maximum performance it may result in overlapping, non atomic, command execution for
+ * operations spanning multiple Redis interactions like {@code putIfAbsent}. The {@literal locking} counterpart prevents
+ * command overlap by setting an explicit lock key and checking against presence of this key which leads to additional
+ * requests and potential command wait times.
+ *
+ * @author Christoph Strobl
+ * @author Mark Paluch
+ * @since 2.0
+ */
+class DefaultRedisCacheWriter implements RedisCacheWriter {
+
+	private final RedisConnectionFactory connectionFactory;
+	private final Duration sleepTime;
+
+	/**
+	 * @param connectionFactory must not be {@literal null}.
+	 */
+	DefaultRedisCacheWriter(RedisConnectionFactory connectionFactory) {
+		this(connectionFactory, Duration.ZERO);
+	}
+
+	/**
+	 * @param connectionFactory must not be {@literal null}.
+	 * @param sleepTime         sleep time between lock request attempts. Must not be {@literal null}. Use {@link Duration#ZERO}
+	 *                          to disable locking.
+	 */
+	private DefaultRedisCacheWriter(RedisConnectionFactory connectionFactory, Duration sleepTime) {
+
+		Assert.notNull(connectionFactory, "ConnectionFactory must not be null!");
+		Assert.notNull(sleepTime, "SleepTime must not be null!");
+
+		this.connectionFactory = connectionFactory;
+		this.sleepTime = sleepTime;
+	}
+
+	@Override
+	public void put(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
+
+		Assert.notNull(name, "Name must not be null!");
+		Assert.notNull(key, "Key must not be null!");
+		Assert.notNull(value, "Value must not be null!");
+
+		execute(name, connection -> {
+
+			if (shouldExpireWithin(ttl)) {
+				connection.set(key, value, Expiration.from(ttl.toMillis(), TimeUnit.MILLISECONDS), SetOption.upsert());
+			} else {
+				connection.set(key, value);
+			}
+
+			return "OK";
+		});
+	}
+
+
+	@Override
+	public byte[] get(String name, byte[] key) {
+
+		Assert.notNull(name, "Name must not be null!");
+		Assert.notNull(key, "Key must not be null!");
+
+		return execute(name, connection -> connection.get(key));
+	}
+
+
+	@Override
+	public byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
+
+		Assert.notNull(name, "Name must not be null!");
+		Assert.notNull(key, "Key must not be null!");
+		Assert.notNull(value, "Value must not be null!");
+
+		return execute(name, connection -> {
+
+			if (isLockingCacheWriter()) {
+				doLock(name, connection);
+			}
+
+			try {
+				if (connection.setNX(key, value)) {
+
+					if (shouldExpireWithin(ttl)) {
+						connection.pExpire(key, ttl.toMillis());
+					}
+					return null;
+				}
+
+				return connection.get(key);
+			} finally {
+
+				if (isLockingCacheWriter()) {
+					doUnlock(name, connection);
+				}
+			}
+		});
+	}
+
+
+	@Override
+	public void remove(String name, byte[] key) {
+
+		Assert.notNull(name, "Name must not be null!");
+		Assert.notNull(key, "Key must not be null!");
+
+		execute(name, connection -> connection.del(key));
+	}
+
+
+	@Override
+	public void clean(String name, byte[] pattern) {
+
+		Assert.notNull(name, "Name must not be null!");
+		Assert.notNull(pattern, "Pattern must not be null!");
+
+		execute(name, connection -> {
+
+			boolean wasLocked = false;
+
+			try {
+
+				if (isLockingCacheWriter()) {
+					doLock(name, connection);
+					wasLocked = true;
+				}
+
+				byte[][] keys = Optional.ofNullable(connection.keys(pattern)).orElse(Collections.emptySet())
+					.toArray(new byte[0][]);
+
+				if (keys.length > 0) {
+					connection.del(keys);
+				}
+			} finally {
+
+				if (wasLocked && isLockingCacheWriter()) {
+					doUnlock(name, connection);
+				}
+			}
+
+			return "OK";
+		});
+	}
+
+	/**
+	 * Explicitly set a write lock on a cache.
+	 *
+	 * @param name the name of the cache to lock.
+	 */
+	void lock(String name) {
+		execute(name, connection -> doLock(name, connection));
+	}
+
+	/**
+	 * Explicitly remove a write lock from a cache.
+	 *
+	 * @param name the name of the cache to unlock.
+	 */
+	void unlock(String name) {
+		executeLockFree(connection -> doUnlock(name, connection));
+	}
+
+	private Boolean doLock(String name, RedisConnection connection) {
+		return connection.setNX(createCacheLockKey(name), new byte[0]);
+	}
+
+	private Long doUnlock(String name, RedisConnection connection) {
+		return connection.del(createCacheLockKey(name));
+	}
+
+	boolean doCheckLock(String name, RedisConnection connection) {
+		return connection.exists(createCacheLockKey(name));
+	}
+
+	/**
+	 * @return {@literal true} if {@link RedisCacheWriter} uses locks.
+	 */
+	private boolean isLockingCacheWriter() {
+		return !sleepTime.isZero() && !sleepTime.isNegative();
+	}
+
+	private <T> T execute(String name, Function<RedisConnection, T> callback) {
+
+		RedisConnection connection = connectionFactory.getConnection();
+		try {
+
+			checkAndPotentiallyWaitUntilUnlocked(name, connection);
+			return callback.apply(connection);
+		} finally {
+			connection.close();
+		}
+	}
+
+	private void executeLockFree(Consumer<RedisConnection> callback) {
+
+		RedisConnection connection = connectionFactory.getConnection();
+
+		try {
+			callback.accept(connection);
+		} finally {
+			connection.close();
+		}
+	}
+
+	private void checkAndPotentiallyWaitUntilUnlocked(String name, RedisConnection connection) {
+
+		if (!isLockingCacheWriter()) {
+			return;
+		}
+
+		try {
+
+			while (doCheckLock(name, connection)) {
+				Thread.sleep(sleepTime.toMillis());
+			}
+		} catch (InterruptedException ex) {
+
+			// Re-interrupt current thread, to allow other participants to react.
+			Thread.currentThread().interrupt();
+
+			throw new PessimisticLockingFailureException(String.format("Interrupted while waiting to unlock cache %s", name),
+				ex);
+		}
+	}
+
+	private static boolean shouldExpireWithin(@Nullable Duration ttl) {
+		return ttl != null && !ttl.isZero() && !ttl.isNegative();
+	}
+
+	private static byte[] createCacheLockKey(String name) {
+		return (name + "~lock").getBytes(StandardCharsets.UTF_8);
+	}
+}
+

+ 86 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisAutoCacheManager.java

@@ -0,0 +1,86 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.cache;
+
+import cn.hutool.core.util.StrUtil;
+import com.pig4cloud.pigx.common.core.constant.CacheConstants;
+import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.convert.DurationStyle;
+import org.springframework.cache.Cache;
+import org.springframework.data.redis.cache.RedisCache;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.cache.RedisCacheManager;
+import org.springframework.data.redis.cache.RedisCacheWriter;
+import org.springframework.lang.Nullable;
+
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
+import java.util.Map;
+
+/**
+ * redis cache 扩展cache name自动化配置
+ *
+ * @author L.cm
+ * @author lengleng
+ * <p>
+ * cachename = xx#ttl
+ */
+@Slf4j
+public class RedisAutoCacheManager extends RedisCacheManager {
+	private static final String SPLIT_FLAG = "#";
+	private static final int CACHE_LENGTH = 2;
+
+	RedisAutoCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration,
+						  Map<String, RedisCacheConfiguration> initialCacheConfigurations, boolean allowInFlightCacheCreation) {
+		super(cacheWriter, defaultCacheConfiguration, initialCacheConfigurations, allowInFlightCacheCreation);
+	}
+
+	@Override
+	protected RedisCache createRedisCache(String name, @Nullable RedisCacheConfiguration cacheConfig) {
+		if (StrUtil.isBlank(name) || !name.contains(SPLIT_FLAG)) {
+			return super.createRedisCache(name, cacheConfig);
+		}
+
+		String[] cacheArray = name.split(SPLIT_FLAG);
+		if (cacheArray.length < CACHE_LENGTH) {
+			return super.createRedisCache(name, cacheConfig);
+		}
+
+		if (cacheConfig != null) {
+			Duration duration = DurationStyle.detectAndParse(cacheArray[1], ChronoUnit.SECONDS);
+			cacheConfig = cacheConfig.entryTtl(duration);
+		}
+		return super.createRedisCache(name, cacheConfig);
+	}
+
+	/**
+	 * 从上下文中获取租户ID,重写@Cacheable value 值
+	 *
+	 * @param name
+	 * @return
+	 */
+	@Override
+	public Cache getCache(String name) {
+		// see https://gitee.wang/pig/pigx/issues/613
+		if (name.startsWith(CacheConstants.GLOBALLY)) {
+			return super.getCache(name);
+		}
+		return super.getCache(TenantContextHolder.getTenantId() + StrUtil.COLON + name);
+	}
+}

+ 110 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisCacheAutoConfiguration.java

@@ -0,0 +1,110 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.cache;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizers;
+import org.springframework.boot.autoconfigure.cache.CacheProperties;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.cache.CacheManager;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.cache.RedisCacheManager;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializationContext;
+import org.springframework.lang.Nullable;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 扩展redis-cache支持注解cacheName添加超时时间
+ *
+ * @author L.cm
+ */
+@Configuration
+@AutoConfigureAfter({RedisAutoConfiguration.class})
+@ConditionalOnBean({RedisConnectionFactory.class})
+@ConditionalOnMissingBean({CacheManager.class})
+@EnableConfigurationProperties(CacheProperties.class)
+public class RedisCacheAutoConfiguration {
+	private final CacheProperties cacheProperties;
+	private final CacheManagerCustomizers customizerInvoker;
+	@Nullable
+	private final RedisCacheConfiguration redisCacheConfiguration;
+
+	RedisCacheAutoConfiguration(CacheProperties cacheProperties,
+								CacheManagerCustomizers customizerInvoker,
+								ObjectProvider<RedisCacheConfiguration> redisCacheConfiguration) {
+		this.cacheProperties = cacheProperties;
+		this.customizerInvoker = customizerInvoker;
+		this.redisCacheConfiguration = redisCacheConfiguration.getIfAvailable();
+	}
+
+	@Bean
+	public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory, ResourceLoader resourceLoader) {
+		DefaultRedisCacheWriter redisCacheWriter = new DefaultRedisCacheWriter(connectionFactory);
+		RedisCacheConfiguration cacheConfiguration = this.determineConfiguration(resourceLoader.getClassLoader());
+		List<String> cacheNames = this.cacheProperties.getCacheNames();
+		Map<String, RedisCacheConfiguration> initialCaches = new LinkedHashMap<>();
+		if (!cacheNames.isEmpty()) {
+			Map<String, RedisCacheConfiguration> cacheConfigMap = new LinkedHashMap<>(cacheNames.size());
+			cacheNames.forEach(it -> cacheConfigMap.put(it, cacheConfiguration));
+			initialCaches.putAll(cacheConfigMap);
+		}
+		RedisAutoCacheManager cacheManager = new RedisAutoCacheManager(redisCacheWriter, cacheConfiguration,
+			initialCaches, true);
+		cacheManager.setTransactionAware(false);
+		return this.customizerInvoker.customize(cacheManager);
+	}
+
+	private RedisCacheConfiguration determineConfiguration(ClassLoader classLoader) {
+		if (this.redisCacheConfiguration != null) {
+			return this.redisCacheConfiguration;
+		} else {
+			CacheProperties.Redis redisProperties = this.cacheProperties.getRedis();
+			RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
+			config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(classLoader)));
+			if (redisProperties.getTimeToLive() != null) {
+				config = config.entryTtl(redisProperties.getTimeToLive());
+			}
+
+			if (redisProperties.getKeyPrefix() != null) {
+				config = config.prefixKeysWith(redisProperties.getKeyPrefix());
+			}
+
+			if (!redisProperties.isCacheNullValues()) {
+				config = config.disableCachingNullValues();
+			}
+
+			if (!redisProperties.isUseKeyPrefix()) {
+				config = config.disableKeyPrefix();
+			}
+
+			return config;
+		}
+	}
+}

+ 43 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisCacheManagerConfig.java

@@ -0,0 +1,43 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.cache;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer;
+import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizers;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.List;
+
+/**
+ * CacheManagerCustomizers配置
+ *
+ * @author L.cm
+ */
+@Configuration
+@ConditionalOnMissingBean(CacheManagerCustomizers.class)
+public class RedisCacheManagerConfig {
+
+	@Bean
+	public CacheManagerCustomizers cacheManagerCustomizers(
+		ObjectProvider<List<CacheManagerCustomizer<?>>> customizers) {
+		return new CacheManagerCustomizers(customizers.getIfAvailable());
+	}
+}

+ 86 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisTemplateConfig.java

@@ -0,0 +1,86 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.cache;
+
+import io.lettuce.core.ReadFrom;
+import io.lettuce.core.cluster.ClusterClientOptions;
+import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
+import lombok.AllArgsConstructor;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
+import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisClusterConfiguration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import java.time.Duration;
+
+/**
+ * RedisTemplate  配置
+ *
+ * @author L.cm
+ */
+@EnableCaching
+@Configuration
+@AllArgsConstructor
+@AutoConfigureBefore(RedisAutoConfiguration.class)
+public class RedisTemplateConfig {
+
+	@Bean
+	public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
+		RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
+		redisTemplate.setKeySerializer(new StringRedisSerializer());
+		redisTemplate.setHashKeySerializer(new StringRedisSerializer());
+		redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
+		redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
+		redisTemplate.setConnectionFactory(redisConnectionFactory);
+		return redisTemplate;
+	}
+
+
+	@Bean
+	@ConditionalOnProperty(value = "spring.redis.cluster.enable",havingValue = "true")
+	public LettuceConnectionFactory redisConnectionFactory(RedisProperties redisProperties) {
+		RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());
+
+		// https://github.com/lettuce-io/lettuce-core/wiki/Redis-Cluster#user-content-refreshing-the-cluster-topology-view
+		ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
+				.enablePeriodicRefresh()
+				.enableAllAdaptiveRefreshTriggers()
+				.refreshPeriod(Duration.ofSeconds(5))
+				.build();
+
+		ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()
+				.topologyRefreshOptions(clusterTopologyRefreshOptions).build();
+
+		// https://github.com/lettuce-io/lettuce-core/wiki/ReadFrom-Settings
+		LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder()
+				.readFrom(ReadFrom.SLAVE_PREFERRED)
+				.clientOptions(clusterClientOptions).build();
+
+		return new LettuceConnectionFactory(redisClusterConfiguration, lettuceClientConfiguration);
+	}
+}

+ 49 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScope.java

@@ -0,0 +1,49 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.datascope;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * @author lengleng
+ * @date 2018/8/30
+ * 数据权限查询参数
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class DataScope extends HashMap {
+	/**
+	 * 限制范围的字段名称
+	 */
+	private String scopeName = "dept_id";
+
+	/**
+	 * 具体的数据范围
+	 */
+	private List<Integer> deptIds = new ArrayList<>();
+
+	/**
+	 * 是否只查询本部门
+	 */
+	private Boolean isOnly = false;
+}

+ 37 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScopeHandle.java

@@ -0,0 +1,37 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.datascope;
+
+import java.util.List;
+
+/**
+ * @author lengleng
+ * @date 2019-09-07
+ * <p>
+ * data scope 判断处理器,抽象服务扩展
+ */
+public interface DataScopeHandle {
+
+	/**
+	 * 计算用户数据权限
+	 *
+	 * @param deptList
+	 * @return
+	 */
+	Boolean calcScope(List<Integer> deptList);
+}

+ 131 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScopeInterceptor.java

@@ -0,0 +1,131 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.datascope;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
+import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.mapping.SqlCommandType;
+import org.apache.ibatis.plugin.*;
+import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.reflection.SystemMetaObject;
+
+import java.sql.Connection;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+
+/**
+ * @author lengleng
+ * @date 2018/12/26
+ * <p>
+ * mybatis 数据权限拦截器
+ */
+@Slf4j
+@AllArgsConstructor
+@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
+public class DataScopeInterceptor extends AbstractSqlParserHandler implements Interceptor {
+	private final DataScopeHandle dataScopeHandle;
+
+	@Override
+	@SneakyThrows
+	public Object intercept(Invocation invocation) {
+		StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
+		MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
+		this.sqlParser(metaObject);
+		// 先判断是不是SELECT操作
+		MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
+		if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
+			return invocation.proceed();
+		}
+
+		BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
+		String originalSql = boundSql.getSql();
+		Object parameterObject = boundSql.getParameterObject();
+
+		//查找参数中包含DataScope类型的参数
+		DataScope dataScope = findDataScopeObject(parameterObject);
+		if (dataScope == null) {
+			return invocation.proceed();
+		}
+
+		String scopeName = dataScope.getScopeName();
+		List<Integer> deptIds = dataScope.getDeptIds();
+		// 优先获取赋值数据
+		if (CollUtil.isEmpty(deptIds) && dataScopeHandle.calcScope(deptIds)) {
+			return invocation.proceed();
+		}
+		String join = CollectionUtil.join(deptIds, ",");
+		originalSql = "select * from (" + originalSql + ") temp_data_scope where temp_data_scope." + scopeName + " in (" + join + ")";
+		metaObject.setValue("delegate.boundSql.sql", originalSql);
+		return invocation.proceed();
+	}
+
+
+	/**
+	 * 生成拦截对象的代理
+	 *
+	 * @param target 目标对象
+	 * @return 代理对象
+	 */
+	@Override
+	public Object plugin(Object target) {
+		if (target instanceof StatementHandler) {
+			return Plugin.wrap(target, this);
+		}
+		return target;
+	}
+
+	/**
+	 * mybatis配置的属性
+	 *
+	 * @param properties mybatis配置的属性
+	 */
+	@Override
+	public void setProperties(Properties properties) {
+
+	}
+
+	/**
+	 * 查找参数是否包括DataScope对象
+	 *
+	 * @param parameterObj 参数列表
+	 * @return DataScope
+	 */
+	private DataScope findDataScopeObject(Object parameterObj) {
+		if (parameterObj instanceof DataScope) {
+			return (DataScope) parameterObj;
+		} else if (parameterObj instanceof Map) {
+			for (Object val : ((Map<?, ?>) parameterObj).values()) {
+				if (val instanceof DataScope) {
+					return (DataScope) val;
+				}
+			}
+		}
+		return null;
+	}
+
+}

+ 88 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/PigxDefaultDatascopeHandle.java

@@ -0,0 +1,88 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.datascope;
+
+import cn.hutool.core.util.StrUtil;
+import com.pig4cloud.pigx.admin.api.entity.SysDeptRelation;
+import com.pig4cloud.pigx.admin.api.entity.SysRole;
+import com.pig4cloud.pigx.admin.api.feign.RemoteDataScopeService;
+import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
+import com.pig4cloud.pigx.common.data.enums.DataScopeTypeEnum;
+import com.pig4cloud.pigx.common.security.service.PigxUser;
+import com.pig4cloud.pigx.common.security.util.SecurityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.GrantedAuthority;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author lengleng
+ * @date 2019-09-07
+ * <p>
+ * 默认data scope 判断处理器
+ */
+public class PigxDefaultDatascopeHandle implements DataScopeHandle {
+	@Autowired
+	private RemoteDataScopeService dataScopeService;
+
+	/**
+	 * 计算用户数据权限
+	 *
+	 * @param deptList
+	 * @return
+	 */
+	@Override
+	public Boolean calcScope(List<Integer> deptList) {
+		PigxUser user = SecurityUtils.getUser();
+		List<String> roleIdList = user.getAuthorities()
+				.stream().map(GrantedAuthority::getAuthority)
+				.filter(authority -> authority.startsWith(SecurityConstants.ROLE))
+				.map(authority -> authority.split(StrUtil.UNDERLINE)[1])
+				.collect(Collectors.toList());
+
+		SysRole role = dataScopeService.getRoleList(roleIdList).getData().stream()
+				.min(Comparator.comparingInt(SysRole::getDsType)).get();
+
+		Integer dsType = role.getDsType();
+		// 查询全部
+		if (DataScopeTypeEnum.ALL.getType() == dsType) {
+			return true;
+		}
+		// 自定义
+		if (DataScopeTypeEnum.CUSTOM.getType() == dsType) {
+			String dsScope = role.getDsScope();
+			deptList.addAll(Arrays.stream(dsScope.split(StrUtil.COMMA))
+					.map(Integer::parseInt).collect(Collectors.toList()));
+		}
+		// 查询本级及其下级
+		if (DataScopeTypeEnum.OWN_CHILD_LEVEL.getType() == dsType) {
+			List<Integer> deptIdList = dataScopeService.getDescendantList(user.getDeptId())
+					.getData().stream().map(SysDeptRelation::getDescendant)
+					.collect(Collectors.toList());
+			deptList.addAll(deptIdList);
+		}
+		// 只查询本级
+		if (DataScopeTypeEnum.OWN_LEVEL.getType() == dsType) {
+			deptList.add(user.getDeptId());
+		}
+		return false;
+	}
+}

+ 60 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/enums/DataScopeTypeEnum.java

@@ -0,0 +1,60 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author lengleng
+ * @date 2018/12/26
+ * <p>
+ * 数据权限类型
+ */
+@Getter
+@AllArgsConstructor
+public enum DataScopeTypeEnum {
+	/**
+	 * 查询全部数据
+	 */
+	ALL(0, "全部"),
+
+	/**
+	 * 自定义
+	 */
+	CUSTOM(1, "自定义"),
+
+	/**
+	 * 本级及子级
+	 */
+	OWN_CHILD_LEVEL(2, "本级及子级"),
+
+	/**
+	 * 本级
+	 */
+	OWN_LEVEL(3, "本级");
+
+	/**
+	 * 类型
+	 */
+	private final int type;
+	/**
+	 * 描述
+	 */
+	private final String description;
+}

+ 57 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/handler/JsonStringArrayTypeHandler.java

@@ -0,0 +1,57 @@
+package com.pig4cloud.pigx.common.data.handler;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.SneakyThrows;
+import org.apache.ibatis.type.BaseTypeHandler;
+import org.apache.ibatis.type.JdbcType;
+import org.apache.ibatis.type.MappedJdbcTypes;
+import org.apache.ibatis.type.MappedTypes;
+
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * Mybatis数组,符串互转
+ * <p>
+ * MappedJdbcTypes 数据库中的数据类型
+ * MappedTypes java中的的数据类型
+ *
+ * @author xuzihui
+ * @date 2019-11-20
+ */
+@MappedTypes(value = {String[].class})
+@MappedJdbcTypes(value = JdbcType.VARCHAR)
+public class JsonStringArrayTypeHandler extends BaseTypeHandler<String[]> {
+
+	@Override
+	public void setNonNullParameter(PreparedStatement ps, int i, String[] parameter, JdbcType jdbcType)
+			throws SQLException {
+		ps.setString(i, ArrayUtil.join(parameter, StrUtil.COMMA));
+	}
+
+	@Override
+	@SneakyThrows
+	public String[] getNullableResult(ResultSet rs, String columnName) {
+		String reString = rs.getString(columnName);
+		return Convert.toStrArray(reString);
+	}
+
+	@Override
+	@SneakyThrows
+	public String[] getNullableResult(ResultSet rs, int columnIndex) {
+		String reString = rs.getString(columnIndex);
+		return Convert.toStrArray(reString);
+	}
+
+	@Override
+	@SneakyThrows
+	public String[] getNullableResult(CallableStatement cs, int columnIndex) {
+		String reString = cs.getString(columnIndex);
+		return Convert.toStrArray(reString);
+	}
+
+}

+ 101 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/mybatis/MybatisPlusConfiguration.java

@@ -0,0 +1,101 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.mybatis;
+
+import com.baomidou.mybatisplus.core.parser.ISqlParser;
+import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser;
+import com.pig4cloud.pigx.admin.api.feign.RemoteDataScopeService;
+import com.pig4cloud.pigx.common.data.datascope.DataScopeHandle;
+import com.pig4cloud.pigx.common.data.datascope.DataScopeInterceptor;
+import com.pig4cloud.pigx.common.data.datascope.PigxDefaultDatascopeHandle;
+import com.pig4cloud.pigx.common.data.tenant.PigxTenantHandler;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.sql.DataSource;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author lengleng
+ * @date 2020-02-08
+ */
+@Configuration
+@ConditionalOnBean(DataSource.class)
+@AutoConfigureAfter(DataSourceAutoConfiguration.class)
+public class MybatisPlusConfiguration {
+
+	/**
+	 * 创建租户维护处理器对象
+	 *
+	 * @return 处理后的租户维护处理器
+	 */
+	@Bean
+	@ConditionalOnMissingBean
+	public PigxTenantHandler pigxTenantHandler() {
+		return new PigxTenantHandler();
+	}
+
+	/**
+	 * 分页插件
+	 *
+	 * @param tenantHandler 租户处理器
+	 * @return PaginationInterceptor
+	 */
+	@Bean
+	@ConditionalOnMissingBean
+	@ConditionalOnProperty(name = "mybatisPlus.tenantEnable", havingValue = "true", matchIfMissing = true)
+	public PaginationInterceptor paginationInterceptor(PigxTenantHandler tenantHandler) {
+		PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
+		List<ISqlParser> sqlParserList = new ArrayList<>();
+		TenantSqlParser tenantSqlParser = new TenantSqlParser();
+		tenantSqlParser.setTenantHandler(tenantHandler);
+		sqlParserList.add(tenantSqlParser);
+		paginationInterceptor.setSqlParserList(sqlParserList);
+		return paginationInterceptor;
+	}
+
+	/**
+	 * pigx 默认数据权限处理
+	 *
+	 * @return
+	 */
+	@Bean
+	@ConditionalOnMissingBean
+	public DataScopeHandle dataScopeHandle() {
+		return new PigxDefaultDatascopeHandle();
+	}
+
+	/**
+	 * 数据权限插件
+	 *
+	 * @return DataScopeInterceptor
+	 */
+	@Bean
+	@ConditionalOnMissingBean
+	@ConditionalOnBean(DataScopeHandle.class)
+	public DataScopeInterceptor dataScopeInterceptor() {
+		return new DataScopeInterceptor(dataScopeHandle());
+	}
+}

+ 115 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/resolver/SqlFilterArgumentResolver.java

@@ -0,0 +1,115 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.resolver;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.MethodParameter;
+import org.springframework.web.bind.support.WebDataBinderFactory;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
+import org.springframework.web.method.support.ModelAndViewContainer;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+/**
+ * @author lengleng
+ * @date 2019-06-24
+ * <p>
+ * 解决Mybatis Plus Order By SQL注入问题
+ */
+@Slf4j
+public class SqlFilterArgumentResolver implements HandlerMethodArgumentResolver {
+	private final static String[] KEYWORDS = {"master", "truncate", "insert", "select"
+			, "delete", "update", "declare", "alter", "drop", "sleep"};
+
+	/**
+	 * 判断Controller是否包含page 参数
+	 *
+	 * @param parameter 参数
+	 * @return 是否过滤
+	 */
+	@Override
+	public boolean supportsParameter(MethodParameter parameter) {
+		return parameter.getParameterType().equals(Page.class);
+	}
+
+	/**
+	 * @param parameter     入参集合
+	 * @param mavContainer  model 和 view
+	 * @param webRequest    web相关
+	 * @param binderFactory 入参解析
+	 * @return 检查后新的page对象
+	 * <p>
+	 * page 只支持查询 GET .如需解析POST获取请求报文体处理
+	 */
+	@Override
+	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer
+			, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
+
+		HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
+
+		String[] ascs = request.getParameterValues("ascs");
+		String[] descs = request.getParameterValues("descs");
+		String current = request.getParameter("current");
+		String size = request.getParameter("size");
+
+		Page page = new Page();
+		if (StrUtil.isNotBlank(current)) {
+			page.setCurrent(Long.parseLong(current));
+		}
+
+		if (StrUtil.isNotBlank(size)) {
+			page.setSize(Long.parseLong(size));
+		}
+
+		List<OrderItem> orderItemList = new ArrayList<>();
+		Optional.ofNullable(ascs).ifPresent(s -> orderItemList.addAll(Arrays.stream(s)
+				.filter(sqlInjectPredicate())
+				.map(OrderItem::asc).collect(Collectors.toList())));
+		Optional.ofNullable(descs).ifPresent(s -> orderItemList.addAll(Arrays.stream(s)
+				.filter(sqlInjectPredicate())
+				.map(OrderItem::desc).collect(Collectors.toList())));
+		page.addOrder(orderItemList);
+
+		return page;
+	}
+
+	/**
+	 *  判断用户输入里面有没有关键字
+	 * @return Predicate
+	 */
+	private Predicate<String> sqlInjectPredicate() {
+		return sql -> {
+			for (String keyword : KEYWORDS) {
+				if (StrUtil.containsIgnoreCase(sql, keyword)){
+					return false;
+				}
+			}
+			return true;
+		};
+	}
+}

+ 36 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/resolver/WebMvcConfig.java

@@ -0,0 +1,36 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.resolver;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import java.util.List;
+
+/**
+ * @author lengleng
+ * @date 2019-06-24
+ */
+@Configuration
+public class WebMvcConfig implements WebMvcConfigurer {
+	@Override
+	public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
+		argumentResolvers.add(new SqlFilterArgumentResolver());
+	}
+}

+ 35 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/PigxFeignTenantConfiguration.java

@@ -0,0 +1,35 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.tenant;
+
+import feign.RequestInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author lengleng
+ * @date 2018/9/14
+ * feign 租户信息拦截
+ */
+@Configuration
+public class PigxFeignTenantConfiguration {
+	@Bean
+	public RequestInterceptor pigxFeignTenantInterceptor() {
+		return new PigxFeignTenantInterceptor();
+	}
+}

+ 39 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/PigxFeignTenantInterceptor.java

@@ -0,0 +1,39 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.tenant;
+
+import com.pig4cloud.pigx.common.core.constant.CommonConstants;
+import feign.RequestInterceptor;
+import feign.RequestTemplate;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author lengleng
+ * @date 2018/9/14
+ */
+@Slf4j
+public class PigxFeignTenantInterceptor implements RequestInterceptor {
+	@Override
+	public void apply(RequestTemplate requestTemplate) {
+		if (TenantContextHolder.getTenantId() == null) {
+			log.error("TTL 中的 租户ID为空,feign拦截器 >> 增强失败");
+			return;
+		}
+		requestTemplate.header(CommonConstants.TENANT_ID, TenantContextHolder.getTenantId().toString());
+	}
+}

+ 31 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/PigxTenantConfigProperties.java

@@ -0,0 +1,31 @@
+package com.pig4cloud.pigx.common.data.tenant;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 多租户配置
+ *
+ * @author oathsign
+ */
+@Data
+@RefreshScope
+@Configuration
+@ConfigurationProperties(prefix = "pigx.tenant")
+public class PigxTenantConfigProperties {
+
+	/**
+	 * 维护租户列名称
+	 */
+	private String column = "tenant_id";
+
+	/**
+	 * 多租户的数据表集合
+	 */
+	private List<String> tables = new ArrayList<>();
+}

+ 82 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/PigxTenantHandler.java

@@ -0,0 +1,82 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.tenant;
+
+import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
+import lombok.extern.slf4j.Slf4j;
+import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.expression.LongValue;
+import net.sf.jsqlparser.expression.NullValue;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * @author lengleng
+ * @date 2018-12-26
+ * <p>
+ * 租户维护处理器
+ */
+@Slf4j
+public class PigxTenantHandler implements TenantHandler {
+	@Autowired
+	private PigxTenantConfigProperties properties;
+
+	/**
+	 * 获取租户值
+	 * <p>
+	 * TODO 校验租户状态
+	 *
+	 * @return 租户值
+	 */
+	@Override
+	public Expression getTenantId(boolean where) {
+		Integer tenantId = TenantContextHolder.getTenantId();
+		log.debug("当前租户为 >> {}", tenantId);
+
+		if (tenantId == null) {
+			return new NullValue();
+		}
+		return new LongValue(tenantId);
+	}
+
+	/**
+	 * 获取租户字段名
+	 *
+	 * @return 租户字段名
+	 */
+	@Override
+	public String getTenantIdColumn() {
+		return properties.getColumn();
+	}
+
+	/**
+	 * 根据表名判断是否进行过滤
+	 *
+	 * @param tableName 表名
+	 * @return 是否进行过滤
+	 */
+	@Override
+	public boolean doTableFilter(String tableName) {
+		Integer tenantId = TenantContextHolder.getTenantId();
+		// 租户中ID 为空,查询全部,不进行过滤
+		if (tenantId == null) {
+			return Boolean.TRUE;
+		}
+
+		return !properties.getTables().contains(tableName);
+	}
+}

+ 55 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/TenantContextHolder.java

@@ -0,0 +1,55 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.tenant;
+
+import com.alibaba.ttl.TransmittableThreadLocal;
+import lombok.experimental.UtilityClass;
+
+/**
+ * @author lengleng
+ * @date 2018/10/4
+ * 租户工具类
+ */
+@UtilityClass
+public class TenantContextHolder {
+
+	private final ThreadLocal<Integer> THREAD_LOCAL_TENANT = new TransmittableThreadLocal<>();
+
+
+	/**
+	 * TTL 设置租户ID
+	 *
+	 * @param tenantId
+	 */
+	public void setTenantId(Integer tenantId) {
+		THREAD_LOCAL_TENANT.set(tenantId);
+	}
+
+	/**
+	 * 获取TTL中的租户ID
+	 *
+	 * @return
+	 */
+	public Integer getTenantId() {
+		return THREAD_LOCAL_TENANT.get();
+	}
+
+	public void clear() {
+		THREAD_LOCAL_TENANT.remove();
+	}
+}

+ 62 - 0
pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/TenantContextHolderFilter.java

@@ -0,0 +1,62 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.data.tenant;
+
+import cn.hutool.core.util.StrUtil;
+import com.pig4cloud.pigx.common.core.constant.CommonConstants;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.GenericFilterBean;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @author lengleng
+ * @date 2018/9/13
+ */
+@Slf4j
+@Component
+@Order(Ordered.HIGHEST_PRECEDENCE)
+public class TenantContextHolderFilter extends GenericFilterBean {
+
+	@Override
+	@SneakyThrows
+	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) {
+		HttpServletRequest request = (HttpServletRequest) servletRequest;
+		HttpServletResponse response = (HttpServletResponse) servletResponse;
+
+		String tenantId = request.getHeader(CommonConstants.TENANT_ID);
+		log.debug("获取header中的租户ID为:{}", tenantId);
+
+		if (StrUtil.isNotBlank(tenantId)) {
+			TenantContextHolder.setTenantId(Integer.parseInt(tenantId));
+		} else {
+			TenantContextHolder.setTenantId(CommonConstants.TENANT_ID_1);
+		}
+
+		filterChain.doFilter(request, response);
+		TenantContextHolder.clear();
+	}
+}

+ 9 - 0
pigx-common/pigx-common-data/src/main/resources/META-INF/spring.factories

@@ -0,0 +1,9 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+    com.pig4cloud.pigx.common.data.cache.RedisTemplateConfig,\
+    com.pig4cloud.pigx.common.data.cache.RedisCacheManagerConfig,\
+    com.pig4cloud.pigx.common.data.cache.RedisCacheAutoConfiguration,\
+    com.pig4cloud.pigx.common.data.tenant.PigxTenantConfigProperties,\
+    com.pig4cloud.pigx.common.data.tenant.TenantContextHolderFilter,\
+    com.pig4cloud.pigx.common.data.tenant.PigxFeignTenantConfiguration,\
+    com.pig4cloud.pigx.common.data.mybatis.MybatisPlusConfiguration,\
+    com.pig4cloud.pigx.common.data.resolver.WebMvcConfig

+ 86 - 0
pigx-common/pigx-common-datasource/pom.xml

@@ -0,0 +1,86 @@
+<?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>pigx-common</artifactId>
+		<groupId>com.pig4cloud</groupId>
+		<version>3.7.0</version>
+	</parent>
+	<modelVersion>4.0.0</modelVersion>
+
+	<groupId>com.pig4cloud</groupId>
+	<artifactId>pigx-common-datasource</artifactId>
+
+	<packaging>jar</packaging>
+
+	<description>pigx 动态切换数据源</description>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-jdbc</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>javax.servlet-api</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-webmvc</artifactId>
+		</dependency>
+		<!--common-->
+		<dependency>
+			<groupId>com.pig4cloud</groupId>
+			<artifactId>pigx-common-core</artifactId>
+		</dependency>
+		<!--mybatis-->
+		<dependency>
+			<groupId>com.baomidou</groupId>
+			<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.baomidou</groupId>
+			<artifactId>mybatis-plus-boot-starter</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+		</dependency>
+		<!-- druid 连接池 -->
+		<dependency>
+			<groupId>com.alibaba</groupId>
+			<artifactId>druid-spring-boot-starter</artifactId>
+		</dependency>
+		<!--swagger-->
+		<dependency>
+			<groupId>com.pig4cloud</groupId>
+			<artifactId>pigx-common-swagger</artifactId>
+		</dependency>
+		<!--安全模块-->
+		<dependency>
+			<groupId>com.pig4cloud</groupId>
+			<artifactId>pigx-common-security</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.pig4cloud</groupId>
+			<artifactId>pigx-common-log</artifactId>
+		</dependency>
+		<!--代码生成模板引擎-->
+		<dependency>
+			<artifactId>velocity</artifactId>
+			<groupId>org.apache.velocity</groupId>
+			<version>${velocity.version}</version>
+		</dependency>
+		<!--web 模块-->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-web</artifactId>
+		</dependency>
+		<!--undertow容器-->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-undertow</artifactId>
+		</dependency>
+	</dependencies>
+</project>

+ 56 - 0
pigx-common/pigx-common-datasource/src/main/java/com/pig4cloud/pigx/common/datasource/DynamicDataSourceAutoConfiguration.java

@@ -0,0 +1,56 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.datasource;
+
+import com.baomidou.dynamic.datasource.processor.DsProcessor;
+import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
+import com.pig4cloud.pigx.common.datasource.config.DruidDataSourceProperties;
+import com.pig4cloud.pigx.common.datasource.config.JdbcDynamicDataSourceProvider;
+import com.pig4cloud.pigx.common.datasource.config.LastParamDsProcessor;
+import lombok.AllArgsConstructor;
+import org.jasypt.encryption.StringEncryptor;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author lengleng
+ * @date 2020-02-06
+ * <p>
+ * 动态数据源切换配置
+ */
+@Configuration
+@AllArgsConstructor
+@AutoConfigureAfter(DataSourceAutoConfiguration.class)
+@EnableConfigurationProperties(DruidDataSourceProperties.class)
+public class DynamicDataSourceAutoConfiguration {
+	private final StringEncryptor stringEncryptor;
+	private final DruidDataSourceProperties properties;
+
+	@Bean
+	public DynamicDataSourceProvider dynamicDataSourceProvider() {
+		return new JdbcDynamicDataSourceProvider(stringEncryptor, properties);
+	}
+
+	@Bean
+	public DsProcessor dsProcessor() {
+		return new LastParamDsProcessor();
+	}
+}

+ 23 - 0
pigx-common/pigx-common-datasource/src/main/java/com/pig4cloud/pigx/common/datasource/annotation/EnableDynamicDataSource.java

@@ -0,0 +1,23 @@
+package com.pig4cloud.pigx.common.datasource.annotation;
+
+import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
+import com.pig4cloud.pigx.common.datasource.DynamicDataSourceAutoConfiguration;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.context.annotation.Import;
+
+import java.lang.annotation.*;
+
+/**
+ * @author Lucky
+ * @date 2019-05-18
+ * <p>
+ * 开启动态数据源
+ */
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@EnableAutoConfiguration(exclude = {DruidDataSourceAutoConfigure.class})
+@Import(DynamicDataSourceAutoConfiguration.class)
+public @interface EnableDynamicDataSource {
+}

+ 26 - 0
pigx-common/pigx-common-datasource/src/main/java/com/pig4cloud/pigx/common/datasource/config/DruidDataSourceProperties.java

@@ -0,0 +1,26 @@
+package com.pig4cloud.pigx.common.datasource.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author lengleng
+ * @date 2019-05-14
+ * <p>
+ * 参考DruidDataSourceWrapper
+ */
+@Data
+@Component
+@ConfigurationProperties("spring.datasource.druid")
+public class DruidDataSourceProperties {
+	private String username;
+	private String password;
+	private String url;
+	private String driverClassName;
+
+	/**
+	 * 查询数据源的SQL
+	 */
+	private String queryDsSql;
+}

+ 75 - 0
pigx-common/pigx-common-datasource/src/main/java/com/pig4cloud/pigx/common/datasource/config/JdbcDynamicDataSourceProvider.java

@@ -0,0 +1,75 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.datasource.config;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.dynamic.datasource.provider.AbstractJdbcDataSourceProvider;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
+import com.pig4cloud.pigx.common.datasource.support.DataSourceConstants;
+import org.jasypt.encryption.StringEncryptor;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author lengleng
+ * @date 2020/2/6
+ * <p>
+ * 从数据源中获取 配置信息
+ */
+public class JdbcDynamicDataSourceProvider extends AbstractJdbcDataSourceProvider {
+	private final DruidDataSourceProperties properties;
+	private final StringEncryptor stringEncryptor;
+
+	public JdbcDynamicDataSourceProvider(StringEncryptor stringEncryptor, DruidDataSourceProperties properties) {
+		super(properties.getDriverClassName(), properties.getUrl(), properties.getUsername(), properties.getPassword());
+		this.stringEncryptor = stringEncryptor;
+		this.properties = properties;
+	}
+
+	/**
+	 * 执行语句获得数据源参数
+	 *
+	 * @param statement 语句
+	 * @return 数据源参数
+	 * @throws SQLException sql异常
+	 */
+	@Override
+	protected Map<String, DataSourceProperty> executeStmt(Statement statement) throws SQLException {
+		ResultSet rs = statement.executeQuery(StrUtil.isBlank(properties.getQueryDsSql())
+				? DataSourceConstants.QUERY_DS_SQL
+				: properties.getQueryDsSql());
+
+		Map<String, DataSourceProperty> map = new HashMap<>(8);
+		while (rs.next()) {
+			String name = rs.getString(DataSourceConstants.DS_NAME);
+			String username = rs.getString(DataSourceConstants.DS_USER_NAME);
+			String password = rs.getString(DataSourceConstants.DS_USER_PWD);
+			String url = rs.getString(DataSourceConstants.DS_JDBC_URL);
+			DataSourceProperty property = new DataSourceProperty();
+			property.setUsername(username);
+			property.setPassword(stringEncryptor.decrypt(password));
+			property.setUrl(url);
+			map.put(name, property);
+		}
+		return map;
+	}
+}

+ 57 - 0
pigx-common/pigx-common-datasource/src/main/java/com/pig4cloud/pigx/common/datasource/config/LastParamDsProcessor.java

@@ -0,0 +1,57 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.datasource.config;
+
+import com.baomidou.dynamic.datasource.processor.DsProcessor;
+import org.aopalliance.intercept.MethodInvocation;
+
+/**
+ * @author lengleng
+ * @date 2020/2/6
+ * <p>
+ * 参数数据源解析  @DS("#last)
+ */
+public class LastParamDsProcessor extends DsProcessor {
+
+	private static final String LAST_PREFIX = "#last";
+
+
+	/**
+	 * 抽象匹配条件 匹配才会走当前执行器否则走下一级执行器
+	 *
+	 * @param key DS注解里的内容
+	 * @return 是否匹配
+	 */
+	@Override
+	public boolean matches(String key) {
+		return key.startsWith(LAST_PREFIX);
+	}
+
+	/**
+	 * 抽象最终决定数据源
+	 *
+	 * @param invocation 方法执行信息
+	 * @param key        DS注解里的内容
+	 * @return 数据源名称
+	 */
+	@Override
+	public String doDetermineDatasource(MethodInvocation invocation, String key) {
+		Object[] arguments = invocation.getArguments();
+		return String.valueOf(arguments[arguments.length - 1]);
+	}
+}

+ 35 - 0
pigx-common/pigx-common-datasource/src/main/java/com/pig4cloud/pigx/common/datasource/support/DataSourceConstants.java

@@ -0,0 +1,35 @@
+package com.pig4cloud.pigx.common.datasource.support;
+
+/**
+ * @author lengleng
+ * @date 2019-04-01
+ * <p>
+ * 数据源相关常量
+ */
+public interface DataSourceConstants {
+	/**
+	 * 查询数据源的SQL
+	 */
+	String QUERY_DS_SQL = "select * from gen_datasource_conf where del_flag = 0";
+
+	/**
+	 * 数据源名称
+	 */
+	String DS_NAME = "name";
+
+	/**
+	 * jdbcurl
+	 */
+	String DS_JDBC_URL = "url";
+
+	/**
+	 * 用户名
+	 */
+	String DS_USER_NAME = "username";
+
+	/**
+	 * 密码
+	 */
+	String DS_USER_PWD = "password";
+
+}

+ 22 - 0
pigx-common/pigx-common-feign/pom.xml

@@ -0,0 +1,22 @@
+<?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>
+		<groupId>com.pig4cloud</groupId>
+		<artifactId>pigx-common</artifactId>
+		<version>3.7.0</version>
+	</parent>
+
+	<modelVersion>4.0.0</modelVersion>
+	<packaging>jar</packaging>
+	<artifactId>pigx-common-feign</artifactId>
+	<description>feign 通用组件</description>
+	<dependencies>
+		<!--feign 依赖-->
+		<dependency>
+			<groupId>org.springframework.cloud</groupId>
+			<artifactId>spring-cloud-starter-openfeign</artifactId>
+		</dependency>
+	</dependencies>
+</project>

+ 40 - 0
pigx-common/pigx-common-feign/src/main/java/com/pig4cloud/pigx/common/feign/PigxFeignAutoConfiguration.java

@@ -0,0 +1,40 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.feign;
+
+import feign.Feign;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.cloud.openfeign.PigxFeignClientsRegistrar;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+/**
+ * @author lengleng
+ * @date 2020/2/8
+ * <p>
+ * feign 自动化配置
+ */
+@Configuration
+@ConditionalOnClass(Feign.class)
+@Import(PigxFeignClientsRegistrar.class)
+@AutoConfigureAfter(EnableFeignClients.class)
+public class PigxFeignAutoConfiguration {
+
+}

+ 83 - 0
pigx-common/pigx-common-feign/src/main/java/com/pig4cloud/pigx/common/feign/annotation/EnablePigxFeignClients.java

@@ -0,0 +1,83 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.feign.annotation;
+
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.cloud.openfeign.PigxFeignClientsRegistrar;
+import org.springframework.context.annotation.Import;
+
+import java.lang.annotation.*;
+
+/**
+ * @author lengleng
+ * @date 2020-02-08
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@EnableFeignClients
+@Import(PigxFeignClientsRegistrar.class)
+public @interface EnablePigxFeignClients {
+	/**
+	 * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
+	 * declarations e.g.: {@code @ComponentScan("org.my.pkg")} instead of
+	 * {@code @ComponentScan(basePackages="org.my.pkg")}.
+	 *
+	 * @return the array of 'basePackages'.
+	 */
+	String[] value() default {};
+
+	/**
+	 * Base packages to scan for annotated components.
+	 * <p>
+	 * {@link #value()} is an alias for (and mutually exclusive with) this attribute.
+	 * <p>
+	 * Use {@link #basePackageClasses()} for a type-safe alternative to String-based
+	 * package names.
+	 *
+	 * @return the array of 'basePackages'.
+	 */
+	String[] basePackages() default {"com.pig4cloud.pigx"};
+
+	/**
+	 * Type-safe alternative to {@link #basePackages()} for specifying the packages to
+	 * scan for annotated components. The package of each class specified will be scanned.
+	 * <p>
+	 * Consider creating a special no-op marker class or interface in each package that
+	 * serves no purpose other than being referenced by this attribute.
+	 *
+	 * @return the array of 'basePackageClasses'.
+	 */
+	Class<?>[] basePackageClasses() default {};
+
+	/**
+	 * A custom <code>@Configuration</code> for all feign clients. Can contain override
+	 * <code>@Bean</code> definition for the pieces that make up the client, for instance
+	 * {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}.
+	 *
+	 * @see FeignClientsConfiguration for the defaults
+	 */
+	Class<?>[] defaultConfiguration() default {};
+
+	/**
+	 * List of classes annotated with @FeignClient. If not empty, disables classpath scanning.
+	 *
+	 * @return
+	 */
+	Class<?>[] clients() default {};
+}

+ 231 - 0
pigx-common/pigx-common-feign/src/main/java/org/springframework/cloud/openfeign/PigxFeignClientsRegistrar.java

@@ -0,0 +1,231 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package org.springframework.cloud.openfeign;
+
+import com.pig4cloud.pigx.common.feign.PigxFeignAutoConfiguration;
+import lombok.Getter;
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.context.EnvironmentAware;
+import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.core.annotation.AnnotationAttributes;
+import org.springframework.core.env.Environment;
+import org.springframework.core.io.support.SpringFactoriesLoader;
+import org.springframework.core.type.AnnotationMetadata;
+import org.springframework.lang.Nullable;
+import org.springframework.util.StringUtils;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author L.cm
+ * @date 2020/2/8
+ * <p>
+ * feign 自动配置功能 from mica
+ */
+public class PigxFeignClientsRegistrar implements ImportBeanDefinitionRegistrar, BeanClassLoaderAware, EnvironmentAware {
+	@Getter
+	private ClassLoader beanClassLoader;
+	@Getter
+	private Environment environment;
+
+	@Override
+	public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
+		registerFeignClients(registry);
+	}
+
+	@Override
+	public void setBeanClassLoader(ClassLoader classLoader) {
+		this.beanClassLoader = classLoader;
+	}
+
+	private void registerFeignClients(BeanDefinitionRegistry registry) {
+		List<String> feignClients = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
+		// 如果 spring.factories 里为空
+		if (feignClients.isEmpty()) {
+			return;
+		}
+		for (String className : feignClients) {
+			try {
+				Class<?> clazz = beanClassLoader.loadClass(className);
+				AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(clazz, FeignClient.class);
+				if (attributes == null) {
+					continue;
+				}
+				// 如果已经存在该 bean,支持原生的 Feign
+				if (registry.containsBeanDefinition(className)) {
+					continue;
+				}
+				registerClientConfiguration(registry, getClientName(attributes), attributes.get("configuration"));
+
+				validate(attributes);
+				BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
+				definition.addPropertyValue("url", getUrl(attributes));
+				definition.addPropertyValue("path", getPath(attributes));
+				String name = getName(attributes);
+				definition.addPropertyValue("name", name);
+
+				// 兼容最新版本的 spring-cloud-openfeign,尚未发布
+				StringBuilder aliasBuilder = new StringBuilder(18);
+				if (attributes.containsKey("contextId")) {
+					String contextId = getContextId(attributes);
+					aliasBuilder.append(contextId);
+					definition.addPropertyValue("contextId", contextId);
+				} else {
+					aliasBuilder.append(name);
+				}
+
+				definition.addPropertyValue("type", className);
+				definition.addPropertyValue("decode404", attributes.get("decode404"));
+				definition.addPropertyValue("fallback", attributes.get("fallback"));
+				definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
+				definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
+
+				AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
+
+				// alias
+				String alias = aliasBuilder.append("FeignClient").toString();
+
+				// has a default, won't be null
+				boolean primary = (Boolean) attributes.get("primary");
+
+				beanDefinition.setPrimary(primary);
+
+				String qualifier = getQualifier(attributes);
+				if (StringUtils.hasText(qualifier)) {
+					alias = qualifier;
+				}
+
+				BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[]{alias});
+				BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
+
+			} catch (ClassNotFoundException e) {
+				e.printStackTrace();
+			}
+		}
+	}
+
+	/**
+	 * Return the class used by {@link SpringFactoriesLoader} to load configuration
+	 * candidates.
+	 *
+	 * @return the factory class
+	 */
+	private Class<?> getSpringFactoriesLoaderFactoryClass() {
+		return PigxFeignAutoConfiguration.class;
+	}
+
+	private void validate(Map<String, Object> attributes) {
+		AnnotationAttributes annotation = AnnotationAttributes.fromMap(attributes);
+		// This blows up if an aliased property is overspecified
+		FeignClientsRegistrar.validateFallback(annotation.getClass("fallback"));
+		FeignClientsRegistrar.validateFallbackFactory(annotation.getClass("fallbackFactory"));
+	}
+
+	private String getName(Map<String, Object> attributes) {
+		String name = (String) attributes.get("serviceId");
+		if (!StringUtils.hasText(name)) {
+			name = (String) attributes.get("name");
+		}
+		if (!StringUtils.hasText(name)) {
+			name = (String) attributes.get("value");
+		}
+		name = resolve(name);
+		return FeignClientsRegistrar.getName(name);
+	}
+
+	private String getContextId(Map<String, Object> attributes) {
+		String contextId = (String) attributes.get("contextId");
+		if (!StringUtils.hasText(contextId)) {
+			return getName(attributes);
+		}
+
+		contextId = resolve(contextId);
+		return FeignClientsRegistrar.getName(contextId);
+	}
+
+	private String resolve(String value) {
+		if (StringUtils.hasText(value)) {
+			return this.environment.resolvePlaceholders(value);
+		}
+		return value;
+	}
+
+	private String getUrl(Map<String, Object> attributes) {
+		String url = resolve((String) attributes.get("url"));
+		return FeignClientsRegistrar.getUrl(url);
+	}
+
+	private String getPath(Map<String, Object> attributes) {
+		String path = resolve((String) attributes.get("path"));
+		return FeignClientsRegistrar.getPath(path);
+	}
+
+	@Nullable
+	private String getQualifier(@Nullable Map<String, Object> client) {
+		if (client == null) {
+			return null;
+		}
+		String qualifier = (String) client.get("qualifier");
+		if (StringUtils.hasText(qualifier)) {
+			return qualifier;
+		}
+		return null;
+	}
+
+	@Nullable
+	private String getClientName(@Nullable Map<String, Object> client) {
+		if (client == null) {
+			return null;
+		}
+		String value = (String) client.get("contextId");
+		if (!StringUtils.hasText(value)) {
+			value = (String) client.get("value");
+		}
+		if (!StringUtils.hasText(value)) {
+			value = (String) client.get("name");
+		}
+		if (!StringUtils.hasText(value)) {
+			value = (String) client.get("serviceId");
+		}
+		if (StringUtils.hasText(value)) {
+			return value;
+		}
+
+		throw new IllegalStateException("Either 'name' or 'value' must be provided in @" + FeignClient.class.getSimpleName());
+	}
+
+	private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
+		BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
+		builder.addConstructorArgValue(name);
+		builder.addConstructorArgValue(configuration);
+		registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(), builder.getBeanDefinition());
+	}
+
+	@Override
+	public void setEnvironment(Environment environment) {
+		this.environment = environment;
+	}
+
+}

+ 2 - 0
pigx-common/pigx-common-feign/src/main/resources/META-INF/spring.factories

@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+    com.pig4cloud.pigx.common.feign.PigxFeignAutoConfiguration

+ 58 - 0
pigx-common/pigx-common-gateway/pom.xml

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~
+  ~      Copyright (c) 2018-2025, lengleng All rights reserved.
+  ~
+  ~  Redistribution and use in source and binary forms, with or without
+  ~  modification, are permitted provided that the following conditions are met:
+  ~
+  ~ Redistributions of source code must retain the above copyright notice,
+  ~  this list of conditions and the following disclaimer.
+  ~  Redistributions in binary form must reproduce the above copyright
+  ~  notice, this list of conditions and the following disclaimer in the
+  ~  documentation and/or other materials provided with the distribution.
+  ~  Neither the name of the pig4cloud.com developer nor the names of its
+  ~  contributors may be used to endorse or promote products derived from
+  ~  this software without specific prior written permission.
+  ~  Author: lengleng (wangiegie@gmail.com)
+  ~
+  -->
+
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+		 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>
+	<parent>
+		<groupId>com.pig4cloud</groupId>
+		<artifactId>pigx-common</artifactId>
+		<version>3.7.0</version>
+	</parent>
+
+	<artifactId>pigx-common-gateway</artifactId>
+	<packaging>jar</packaging>
+
+	<description>pigx gateway</description>
+
+	<dependencies>
+		<dependency>
+			<groupId>com.pig4cloud</groupId>
+			<artifactId>pigx-common-core</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.cloud</groupId>
+			<artifactId>spring-cloud-gateway-core</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.alibaba.cloud</groupId>
+			<artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
+			<scope>compile</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.cloud</groupId>
+			<artifactId>spring-cloud-starter-loadbalancer</artifactId>
+		</dependency>
+	</dependencies>
+</project>

+ 37 - 0
pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/annotation/EnablePigxDynamicRoute.java

@@ -0,0 +1,37 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.gateway.annotation;
+
+import com.pig4cloud.pigx.common.gateway.configuration.DynamicRouteAutoConfiguration;
+import org.springframework.context.annotation.Import;
+
+import java.lang.annotation.*;
+
+/**
+ * @author lengleng
+ * @date 2018/11/5
+ * <p>
+ * 开启pigx 动态路由
+ */
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@Import(DynamicRouteAutoConfiguration.class)
+public @interface EnablePigxDynamicRoute {
+}

+ 106 - 0
pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/configuration/DynamicRouteAutoConfiguration.java

@@ -0,0 +1,106 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.gateway.configuration;
+
+import com.pig4cloud.pigx.common.core.constant.CacheConstants;
+import com.pig4cloud.pigx.common.gateway.support.RouteCacheHolder;
+import io.lettuce.core.ReadFrom;
+import io.lettuce.core.cluster.ClusterClientOptions;
+import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
+import org.springframework.cloud.gateway.config.GatewayProperties;
+import org.springframework.cloud.gateway.config.PropertiesRouteDefinitionLocator;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisClusterConfiguration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.listener.ChannelTopic;
+import org.springframework.data.redis.listener.RedisMessageListenerContainer;
+
+import java.time.Duration;
+
+/**
+ * @author lengleng
+ * @date 2018/11/5
+ * <p>
+ * 动态路由配置类
+ */
+@Slf4j
+@Configuration
+@ComponentScan("com.pig4cloud.pigx.common.gateway")
+@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
+public class DynamicRouteAutoConfiguration {
+	/**
+	 * 配置文件设置为空
+	 * redis 加载为准
+	 *
+	 * @return
+	 */
+	@Bean
+	public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator() {
+		return new PropertiesRouteDefinitionLocator(new GatewayProperties());
+	}
+
+	/**
+	 * redis 监听配置
+	 *
+	 * @param redisConnectionFactory redis 配置
+	 * @return
+	 */
+	@Bean
+	public RedisMessageListenerContainer redisContainer(RedisConnectionFactory redisConnectionFactory) {
+		RedisMessageListenerContainer container
+				= new RedisMessageListenerContainer();
+		container.setConnectionFactory(redisConnectionFactory);
+		container.addMessageListener((message, bytes) -> {
+			log.warn("接收到重新JVM 重新加载路由事件");
+			RouteCacheHolder.removeRouteList();
+		}, new ChannelTopic(CacheConstants.ROUTE_JVM_RELOAD_TOPIC));
+		return container;
+	}
+
+
+	@Bean
+	@ConditionalOnProperty(value = "spring.redis.cluster.enable",havingValue = "true")
+	public LettuceConnectionFactory redisConnectionFactory(RedisProperties redisProperties) {
+		RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());
+
+		// https://github.com/lettuce-io/lettuce-core/wiki/Redis-Cluster#user-content-refreshing-the-cluster-topology-view
+		ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
+				.enablePeriodicRefresh()
+				.enableAllAdaptiveRefreshTriggers()
+				.refreshPeriod(Duration.ofSeconds(5))
+				.build();
+
+		ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()
+				.topologyRefreshOptions(clusterTopologyRefreshOptions).build();
+
+		// https://github.com/lettuce-io/lettuce-core/wiki/ReadFrom-Settings
+		LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder()
+				.readFrom(ReadFrom.REPLICA_PREFERRED)
+				.clientOptions(clusterClientOptions).build();
+
+		return new LettuceConnectionFactory(redisClusterConfiguration, lettuceClientConfiguration);
+	}
+}

+ 57 - 0
pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/configuration/GrayLoadBalancerClientConfiguration.java

@@ -0,0 +1,57 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.gateway.configuration;
+
+import com.pig4cloud.pigx.common.gateway.rule.GrayLoadBalancer;
+import com.pig4cloud.pigx.common.gateway.rule.VersionGrayLoadBalancer;
+import com.pig4cloud.pigx.common.gateway.filter.GrayReactiveLoadBalancerClientFilter;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.cloud.client.discovery.DiscoveryClient;
+import org.springframework.cloud.gateway.config.GatewayReactiveLoadBalancerClientAutoConfiguration;
+import org.springframework.cloud.gateway.config.LoadBalancerProperties;
+import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Mica ribbon rule auto configuration.
+ *
+ * @author L.cm
+ * @link https://github.com/lets-mica/mica
+ */
+@Configuration
+@EnableConfigurationProperties(LoadBalancerProperties.class)
+@ConditionalOnProperty(value = "gray.rule.enabled", havingValue = "true")
+@AutoConfigureBefore(GatewayReactiveLoadBalancerClientAutoConfiguration.class)
+@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
+public class GrayLoadBalancerClientConfiguration {
+
+	@Bean
+	public ReactiveLoadBalancerClientFilter gatewayLoadBalancerClientFilter(GrayLoadBalancer grayLoadBalancer,
+																			LoadBalancerProperties properties) {
+		return new GrayReactiveLoadBalancerClientFilter(properties, grayLoadBalancer);
+	}
+
+	@Bean
+	public GrayLoadBalancer grayLoadBalancer(DiscoveryClient discoveryClient) {
+		return new VersionGrayLoadBalancer(discoveryClient);
+	}
+}

+ 108 - 0
pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/filter/GrayReactiveLoadBalancerClientFilter.java

@@ -0,0 +1,108 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.gateway.filter;
+
+import com.pig4cloud.pigx.common.gateway.rule.GrayLoadBalancer;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools;
+import org.springframework.cloud.client.loadbalancer.reactive.DefaultResponse;
+import org.springframework.cloud.client.loadbalancer.reactive.Response;
+import org.springframework.cloud.gateway.config.LoadBalancerProperties;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter;
+import org.springframework.cloud.gateway.support.DelegatingServiceInstance;
+import org.springframework.cloud.gateway.support.NotFoundException;
+import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.net.URI;
+
+/**
+ * @author lengleng
+ * @date 2020/1/11
+ */
+@Slf4j
+public class GrayReactiveLoadBalancerClientFilter extends ReactiveLoadBalancerClientFilter {
+	private static final int LOAD_BALANCER_CLIENT_FILTER_ORDER = 10150;
+	private LoadBalancerProperties properties;
+
+	private GrayLoadBalancer grayLoadBalancer;
+
+	public GrayReactiveLoadBalancerClientFilter(LoadBalancerProperties properties, GrayLoadBalancer grayLoadBalancer) {
+		super(null, properties);
+		this.properties = properties;
+		this.grayLoadBalancer = grayLoadBalancer;
+	}
+
+	@Override
+	public int getOrder() {
+		return LOAD_BALANCER_CLIENT_FILTER_ORDER;
+	}
+
+	@Override
+	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+		URI url = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
+		String schemePrefix = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR);
+		if (url == null
+				|| (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
+			return chain.filter(exchange);
+		}
+		// preserve the original url
+		ServerWebExchangeUtils.addOriginalRequestUrl(exchange, url);
+
+		if (log.isTraceEnabled()) {
+			log.trace(ReactiveLoadBalancerClientFilter.class.getSimpleName()
+					+ " url before: " + url);
+		}
+
+		return choose(exchange).doOnNext(response -> {
+
+			if (!response.hasServer()) {
+				throw NotFoundException.create(properties.isUse404(),
+						"Unable to find instance for " + url.getHost());
+			}
+
+			URI uri = exchange.getRequest().getURI();
+
+			// if the `lb:<scheme>` mechanism was used, use `<scheme>` as the default,
+			// if the loadbalancer doesn't provide one.
+			String overrideScheme = null;
+			if (schemePrefix != null) {
+				overrideScheme = url.getScheme();
+			}
+
+			DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance(
+					response.getServer(), overrideScheme);
+
+			URI requestUrl = LoadBalancerUriTools.reconstructURI(serviceInstance, uri);
+
+			if (log.isTraceEnabled()) {
+				log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
+			}
+			exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, requestUrl);
+		}).then(chain.filter(exchange));
+	}
+
+	private Mono<Response<ServiceInstance>> choose(ServerWebExchange exchange) {
+		URI uri = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
+		ServiceInstance serviceInstance = grayLoadBalancer.choose(uri.getHost(),exchange.getRequest());
+		return Mono.just(new DefaultResponse(serviceInstance));
+	}
+}

+ 0 - 0
pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/rule/GrayLoadBalancer.java


部分文件因为文件数量过多而无法显示