Browse Source

1.整体提交

wangtuohang@126.com 8 months ago
commit
a00e03c553
100 changed files with 7168 additions and 0 deletions
  1. 15 0
      blade-auth/Dockerfile
  2. 95 0
      blade-auth/pom.xml
  3. 47 0
      blade-auth/src/main/java/org/springblade/auth/AuthApplication.java
  4. 81 0
      blade-auth/src/main/java/org/springblade/auth/config/BladeAuthConfiguration.java
  5. 47 0
      blade-auth/src/main/java/org/springblade/auth/constant/BladeAuthConstant.java
  6. 73 0
      blade-auth/src/main/java/org/springblade/auth/granter/CaptchaTokenGranter.java
  7. 144 0
      blade-auth/src/main/java/org/springblade/auth/granter/RegisterTokenGranter.java
  8. 115 0
      blade-auth/src/main/java/org/springblade/auth/granter/SocialTokenGranter.java
  9. 200 0
      blade-auth/src/main/java/org/springblade/auth/handler/BladeAuthorizationHandler.java
  10. 59 0
      blade-auth/src/main/java/org/springblade/auth/handler/BladePasswordHandler.java
  11. 59 0
      blade-auth/src/main/java/org/springblade/auth/handler/BladeTokenHandler.java
  12. 62 0
      blade-auth/src/main/java/org/springblade/auth/service/BladeClientDetailService.java
  13. 94 0
      blade-auth/src/main/java/org/springblade/auth/service/BladeUserDetailService.java
  14. 83 0
      blade-auth/src/main/java/org/springblade/auth/utils/TokenUtil.java
  15. 15 0
      blade-auth/src/main/resources/application-dev.yml
  16. 15 0
      blade-auth/src/main/resources/application-prod.yml
  17. 15 0
      blade-auth/src/main/resources/application-test.yml
  18. 65 0
      blade-auth/src/main/resources/application.yml
  19. 43 0
      blade-auth/src/test/java/org/springblade/test/CryptoKeyGenerator.java
  20. 24 0
      blade-auth/src/test/java/org/springblade/test/SignKeyGenerator.java
  21. 45 0
      blade-common/pom.xml
  22. 68 0
      blade-common/src/main/java/org/springblade/common/cache/CacheNames.java
  23. 41 0
      blade-common/src/main/java/org/springblade/common/config/BladeCommonConfiguration.java
  24. 90 0
      blade-common/src/main/java/org/springblade/common/constant/CommonConstant.java
  25. 237 0
      blade-common/src/main/java/org/springblade/common/constant/LauncherConstant.java
  26. 75 0
      blade-common/src/main/java/org/springblade/common/constant/TenantConstant.java
  27. 73 0
      blade-common/src/main/java/org/springblade/common/launch/LauncherServiceImpl.java
  28. 35 0
      blade-common/src/main/java/org/springblade/common/utils/CommonUtil.java
  29. 8 0
      blade-common/src/main/resources/banner.txt
  30. 15 0
      blade-gateway/Dockerfile
  31. 103 0
      blade-gateway/pom.xml
  32. 48 0
      blade-gateway/src/main/java/org/springblade/gateway/GateWayApplication.java
  33. 53 0
      blade-gateway/src/main/java/org/springblade/gateway/config/ErrorHandlerConfiguration.java
  34. 90 0
      blade-gateway/src/main/java/org/springblade/gateway/config/RouterFunctionConfiguration.java
  35. 117 0
      blade-gateway/src/main/java/org/springblade/gateway/dynamic/DynamicRouteService.java
  36. 107 0
      blade-gateway/src/main/java/org/springblade/gateway/dynamic/DynamicRouteServiceListener.java
  37. 50 0
      blade-gateway/src/main/java/org/springblade/gateway/dynamic/GatewayFilter.java
  38. 50 0
      blade-gateway/src/main/java/org/springblade/gateway/dynamic/GatewayPredicate.java
  39. 66 0
      blade-gateway/src/main/java/org/springblade/gateway/dynamic/GatewayRoute.java
  40. 139 0
      blade-gateway/src/main/java/org/springblade/gateway/filter/AuthFilter.java
  41. 121 0
      blade-gateway/src/main/java/org/springblade/gateway/filter/GlobalRequestLogFilter.java
  42. 108 0
      blade-gateway/src/main/java/org/springblade/gateway/filter/GlobalResponseLogFilter.java
  43. 63 0
      blade-gateway/src/main/java/org/springblade/gateway/filter/RequestFilter.java
  44. 101 0
      blade-gateway/src/main/java/org/springblade/gateway/handler/ErrorExceptionHandler.java
  45. 68 0
      blade-gateway/src/main/java/org/springblade/gateway/props/AuthProperties.java
  46. 70 0
      blade-gateway/src/main/java/org/springblade/gateway/provider/AuthProvider.java
  47. 46 0
      blade-gateway/src/main/java/org/springblade/gateway/provider/AuthSecure.java
  48. 46 0
      blade-gateway/src/main/java/org/springblade/gateway/provider/BasicSecure.java
  49. 58 0
      blade-gateway/src/main/java/org/springblade/gateway/provider/RequestProvider.java
  50. 93 0
      blade-gateway/src/main/java/org/springblade/gateway/provider/ResponseProvider.java
  51. 46 0
      blade-gateway/src/main/java/org/springblade/gateway/provider/SignSecure.java
  52. 11 0
      blade-gateway/src/main/resources/application-dev.yml
  53. 16 0
      blade-gateway/src/main/resources/application.yml
  54. 12 0
      blade-gateway/src/main/resources/bootstrap.yml
  55. 16 0
      blade-ops-api/blade-flow-api/pom.xml
  56. 70 0
      blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/constant/ProcessConstant.java
  57. 109 0
      blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/feign/IFlowClient.java
  58. 67 0
      blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/feign/IFlowClientFallback.java
  59. 190 0
      blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/pojo/entity/BladeFlow.java
  60. 52 0
      blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/pojo/entity/FlowEntity.java
  61. 54 0
      blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/pojo/enums/FlowModeEnum.java
  62. 75 0
      blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/utils/FlowUtil.java
  63. 80 0
      blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/utils/TaskUtil.java
  64. 27 0
      blade-ops-api/blade-resource-api/pom.xml
  65. 83 0
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/feign/ISmsClient.java
  66. 53 0
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/feign/ISmsClientFallback.java
  67. 82 0
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/pojo/entity/Attach.java
  68. 104 0
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/pojo/entity/Oss.java
  69. 93 0
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/pojo/entity/Sms.java
  70. 71 0
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/pojo/enums/SmsCodeEnum.java
  71. 47 0
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/pojo/vo/AttachVO.java
  72. 32 0
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/pojo/vo/OssVO.java
  73. 57 0
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/pojo/vo/SmsVO.java
  74. 122 0
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/utils/SmsUtil.java
  75. 51 0
      blade-ops-api/pom.xml
  76. 15 0
      blade-ops/blade-admin/Dockerfile
  77. 109 0
      blade-ops/blade-admin/pom.xml
  78. 48 0
      blade-ops/blade-admin/src/main/java/org/springblade/admin/AdminApplication.java
  79. 41 0
      blade-ops/blade-admin/src/main/java/org/springblade/admin/config/AdminConfiguration.java
  80. 61 0
      blade-ops/blade-admin/src/main/java/org/springblade/admin/config/DingTalkConfiguration.java
  81. 96 0
      blade-ops/blade-admin/src/main/java/org/springblade/admin/config/SecurityConfiguration.java
  82. 114 0
      blade-ops/blade-admin/src/main/java/org/springblade/admin/dingtalk/DingTalkNotifier.java
  83. 119 0
      blade-ops/blade-admin/src/main/java/org/springblade/admin/dingtalk/DingTalkService.java
  84. 76 0
      blade-ops/blade-admin/src/main/java/org/springblade/admin/dingtalk/MonitorProperties.java
  85. 84 0
      blade-ops/blade-admin/src/main/java/org/springblade/admin/security/InternalAuthorizationManager.java
  86. 48 0
      blade-ops/blade-admin/src/main/resources/bootstrap.yml
  87. 51 0
      blade-ops/blade-develop/pom.xml
  88. 45 0
      blade-ops/blade-develop/src/main/java/org/springblade/develop/DevelopApplication.java
  89. 204 0
      blade-ops/blade-develop/src/main/java/org/springblade/develop/controller/CodeController.java
  90. 140 0
      blade-ops/blade-develop/src/main/java/org/springblade/develop/controller/DatasourceController.java
  91. 259 0
      blade-ops/blade-develop/src/main/java/org/springblade/develop/controller/ModelController.java
  92. 145 0
      blade-ops/blade-develop/src/main/java/org/springblade/develop/controller/ModelPrototypeController.java
  93. 38 0
      blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/CodeMapper.java
  94. 22 0
      blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/CodeMapper.xml
  95. 38 0
      blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/DatasourceMapper.java
  96. 22 0
      blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/DatasourceMapper.xml
  97. 38 0
      blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/ModelMapper.java
  98. 27 0
      blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/ModelMapper.xml
  99. 38 0
      blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/ModelPrototypeMapper.java
  100. 35 0
      blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/ModelPrototypeMapper.xml

+ 15 - 0
blade-auth/Dockerfile

@@ -0,0 +1,15 @@
+FROM bladex/alpine-java:openjdk17_cn_slim
+
+LABEL maintainer="bladejava@qq.com"
+
+RUN mkdir -p /blade/auth
+
+WORKDIR /blade/auth
+
+EXPOSE 8100
+
+COPY ./target/blade-auth.jar ./app.jar
+
+ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
+
+CMD ["--spring.profiles.active=test"]

+ 95 - 0
blade-auth/pom.xml

@@ -0,0 +1,95 @@
+<?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>BladeX</artifactId>
+        <groupId>org.springblade</groupId>
+        <version>${revision}</version>
+    </parent>
+
+    <artifactId>blade-auth</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <!--Blade-->
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-common</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springblade</groupId>
+                    <artifactId>blade-scope-api</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-db</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-cloud</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-starter-metrics</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-starter-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-starter-swagger</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-starter-social</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-user-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-system-api</artifactId>
+        </dependency>
+        <!--安全模块-->
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-oauth2</artifactId>
+        </dependency>
+        <!-- 验证码 -->
+        <dependency>
+            <groupId>com.github.whvcse</groupId>
+            <artifactId>easy-captcha</artifactId>
+        </dependency>
+        <!-- 链路追踪、服务监控 -->
+        <!--<dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-starter-trace</artifactId>
+        </dependency>-->
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>io.fabric8</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+                <configuration>
+                    <skip>${docker.fabric.skip}</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antrun-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 47 - 0
blade-auth/src/main/java/org/springblade/auth/AuthApplication.java

@@ -0,0 +1,47 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.auth;
+
+
+import org.springblade.core.cloud.client.BladeCloudApplication;
+import org.springblade.core.launch.BladeApplication;
+import org.springblade.core.launch.constant.AppConstant;
+import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
+
+/**
+ * 用户认证服务器
+ *
+ * @author Chill
+ */
+@EnableRedisHttpSession
+@BladeCloudApplication
+public class AuthApplication {
+
+	public static void main(String[] args) {
+		BladeApplication.run(AppConstant.APPLICATION_AUTH_NAME, AuthApplication.class, args);
+	}
+
+}

+ 81 - 0
blade-auth/src/main/java/org/springblade/auth/config/BladeAuthConfiguration.java

@@ -0,0 +1,81 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.auth.config;
+
+import org.springblade.auth.handler.BladeAuthorizationHandler;
+import org.springblade.auth.handler.BladePasswordHandler;
+import org.springblade.auth.handler.BladeTokenHandler;
+import org.springblade.auth.service.BladeClientDetailService;
+import org.springblade.auth.service.BladeUserDetailService;
+import org.springblade.core.jwt.props.JwtProperties;
+import org.springblade.core.oauth2.config.OAuth2AutoConfiguration;
+import org.springblade.core.oauth2.handler.AuthorizationHandler;
+import org.springblade.core.oauth2.handler.PasswordHandler;
+import org.springblade.core.oauth2.handler.TokenHandler;
+import org.springblade.core.oauth2.service.OAuth2ClientService;
+import org.springblade.core.oauth2.service.OAuth2UserService;
+import org.springblade.core.redis.cache.BladeRedis;
+import org.springblade.core.tenant.BladeTenantProperties;
+import org.springblade.system.feign.IUserClient;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+/**
+ * BladeAuthConfiguration
+ *
+ * @author Chill
+ */
+@Configuration(proxyBeanMethods = false)
+@AutoConfigureBefore(OAuth2AutoConfiguration.class)
+public class BladeAuthConfiguration {
+	@Bean
+	public AuthorizationHandler authorizationHandler(BladeRedis bladeRedis, BladeTenantProperties tenantProperties) {
+		return new BladeAuthorizationHandler(bladeRedis, tenantProperties);
+	}
+
+	@Bean
+	public PasswordHandler passwordHandler() {
+		return new BladePasswordHandler();
+	}
+
+	@Bean
+	public TokenHandler tokenHandler(JwtProperties jwtProperties) {
+		return new BladeTokenHandler(jwtProperties);
+	}
+
+	@Bean
+	public OAuth2ClientService oAuth2ClientService(JdbcTemplate jdbcTemplate) {
+		return new BladeClientDetailService(jdbcTemplate);
+	}
+
+	@Bean
+	public OAuth2UserService oAuth2UserService(IUserClient userClient) {
+		return new BladeUserDetailService(userClient);
+	}
+
+}

+ 47 - 0
blade-auth/src/main/java/org/springblade/auth/constant/BladeAuthConstant.java

@@ -0,0 +1,47 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.auth.constant;
+
+/**
+ * AuthorizationConstant
+ *
+ * @author Chill
+ */
+public interface BladeAuthConstant {
+
+	/**
+	 * 是否开启注册参数key
+	 */
+	String REGISTER_USER_VALUE = "account.registerUser";
+	/**
+	 * 账号锁定错误次数参数key
+	 */
+	String FAIL_COUNT_VALUE = "account.failCount";
+	/**
+	 * 账号锁定默认错误次数
+	 */
+	Integer FAIL_COUNT = 5;
+}

+ 73 - 0
blade-auth/src/main/java/org/springblade/auth/granter/CaptchaTokenGranter.java

@@ -0,0 +1,73 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.auth.granter;
+
+import org.springblade.core.oauth2.constant.OAuth2TokenConstant;
+import org.springblade.core.oauth2.exception.UserInvalidException;
+import org.springblade.core.oauth2.granter.PasswordTokenGranter;
+import org.springblade.core.oauth2.handler.PasswordHandler;
+import org.springblade.core.oauth2.provider.OAuth2Request;
+import org.springblade.core.oauth2.service.OAuth2ClientService;
+import org.springblade.core.oauth2.service.OAuth2User;
+import org.springblade.core.oauth2.service.OAuth2UserService;
+import org.springblade.core.redis.cache.BladeRedis;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springframework.stereotype.Component;
+
+/**
+ * CaptchaTokenGranter
+ *
+ * @author BladeX
+ */
+@Component
+public class CaptchaTokenGranter extends PasswordTokenGranter {
+
+	private final BladeRedis bladeRedis;
+
+	public CaptchaTokenGranter(OAuth2ClientService clientService, OAuth2UserService userService, PasswordHandler passwordHandler, BladeRedis bladeRedis) {
+		super(clientService, userService, passwordHandler);
+		this.bladeRedis = bladeRedis;
+	}
+
+	@Override
+	public String type() {
+		return CAPTCHA;
+	}
+
+	@Override
+	public OAuth2User user(OAuth2Request request) {
+		// 获取验证码信息
+		String key = request.getCaptchaKey();
+		String code = request.getCaptchaCode();
+		// 获取验证码
+		String redisCode = bladeRedis.get(OAuth2TokenConstant.CAPTCHA_CACHE_KEY + key);
+		// 判断验证码
+		if (code == null || !StringUtil.equalsIgnoreCase(redisCode, code)) {
+			throw new UserInvalidException(OAuth2TokenConstant.CAPTCHA_NOT_CORRECT);
+		}
+		return super.user(request);
+	}
+}

+ 144 - 0
blade-auth/src/main/java/org/springblade/auth/granter/RegisterTokenGranter.java

@@ -0,0 +1,144 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.auth.granter;
+
+import org.jetbrains.annotations.NotNull;
+import org.springblade.core.oauth2.exception.ExceptionCode;
+import org.springblade.core.oauth2.exception.UserInvalidException;
+import org.springblade.core.oauth2.granter.AbstractTokenGranter;
+import org.springblade.core.oauth2.handler.PasswordHandler;
+import org.springblade.core.oauth2.provider.OAuth2Request;
+import org.springblade.core.oauth2.service.OAuth2Client;
+import org.springblade.core.oauth2.service.OAuth2ClientService;
+import org.springblade.core.oauth2.service.OAuth2User;
+import org.springblade.core.oauth2.service.OAuth2UserService;
+import org.springblade.core.oauth2.service.impl.OAuth2UserDetail;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.NumberUtil;
+import org.springblade.system.cache.ParamCache;
+import org.springblade.system.pojo.entity.User;
+import org.springblade.system.pojo.enums.UserType;
+import org.springblade.system.feign.IUserClient;
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.function.Predicate;
+
+import static org.springblade.auth.constant.BladeAuthConstant.REGISTER_USER_VALUE;
+
+/**
+ * RegisterTokenGranter
+ *
+ * @author BladeX
+ */
+@Component
+public class RegisterTokenGranter extends AbstractTokenGranter {
+
+	private final IUserClient userClient;
+
+	public RegisterTokenGranter(OAuth2ClientService clientService, OAuth2UserService userService, PasswordHandler passwordHandler, IUserClient userClient) {
+		super(clientService, userService, passwordHandler);
+		this.userClient = userClient;
+	}
+
+	@Override
+	public String type() {
+		return REGISTER;
+	}
+
+	@Override
+	public OAuth2User user(OAuth2Request request) {
+		// 校验注册功能是否开启
+		Boolean registerOpen = Func.toBoolean(ParamCache.getValue(REGISTER_USER_VALUE), false);
+		if (!registerOpen) {
+			throw new UserInvalidException("注册功能暂未开启,请联系管理员");
+		}
+
+		// 用户注册信息
+		User user = new User();
+		user.setUserType(UserType.WEB.getCategory());
+		user.setTenantId(request.getTenantId());
+		user.setAccount(request.getUsername());
+		user.setPassword(request.getPassword());
+		user.setName(request.getName());
+		user.setRealName(request.getName());
+		user.setPhone(request.getPhone());
+		user.setEmail(request.getEmail());
+
+		// 校验用户格式
+		validateUser(user);
+
+		R<String> result = userClient.registerUser(user);
+
+		// 执行用户注册
+		if (result.isSuccess()) {
+			// 构建oauth2所需用户信息
+			user.setId(NumberUtil.toLong(result.getData()));
+			return convertOAuth2UserDetail(user, client(request));
+		}
+		throw new UserInvalidException(ExceptionCode.INVALID_USER.getMessage());
+	}
+
+	private void validateUser(User user) {
+		Predicate<String> isNameValid = name -> name.matches("^([\\u4e00-\\u9fa5]{2,20}|[a-zA-Z]{2,10})$");
+		Predicate<String> isUsernameValid = username -> username.matches("^(?=.*[a-zA-Z])[a-zA-Z0-9_\\-@]{3,20}$");
+		Predicate<String> isPasswordValid = password -> password.matches("^(?=.*[0-9])(?=.*[a-zA-Z])[\\w@-]{6,45}$");
+		Predicate<String> isPhoneValid = phone -> phone.matches("^1[3-9]\\d{9}$");
+		Predicate<String> isEmailValid = email -> email.matches("^[A-Za-z0-9+_.-]+@(.+)$");
+		if (!isNameValid.test(user.getName())) {
+			throw new UserInvalidException("用户姓名长度必须在2-10之间,且仅能设置纯中文或纯英文");
+		}
+		if (!isUsernameValid.test(user.getAccount())) {
+			throw new UserInvalidException("用户账号长度必须在3-20之间,且需要包含英文,可额外携带数字、下划线、横杠、@");
+		}
+		if (!isPhoneValid.test(user.getPhone())) {
+			throw new UserInvalidException("手机号格式不正确");
+		}
+		if (!isEmailValid.test(user.getEmail())) {
+			throw new UserInvalidException("邮箱格式不正确");
+		}
+		if (!isPasswordValid.test(user.getPassword())) {
+			throw new UserInvalidException("密码长度格式不符合要求");
+		}
+	}
+
+	@NotNull
+	private OAuth2UserDetail convertOAuth2UserDetail(User user, OAuth2Client client) {
+		OAuth2UserDetail userDetail = new OAuth2UserDetail();
+		userDetail.setUserId(String.valueOf(user.getId()));
+		userDetail.setTenantId(user.getTenantId());
+		userDetail.setName(user.getName());
+		userDetail.setRealName(user.getName());
+		userDetail.setAccount(user.getAccount());
+		userDetail.setPassword(user.getPassword());
+		userDetail.setPhone(user.getPhone());
+		userDetail.setEmail(user.getEmail());
+		userDetail.setAuthorities(Collections.singletonList(REGISTER));
+		userDetail.setClient(client);
+		return userDetail;
+	}
+}

+ 115 - 0
blade-auth/src/main/java/org/springblade/auth/granter/SocialTokenGranter.java

@@ -0,0 +1,115 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.auth.granter;
+
+import me.zhyd.oauth.model.AuthCallback;
+import me.zhyd.oauth.model.AuthResponse;
+import me.zhyd.oauth.model.AuthUser;
+import me.zhyd.oauth.request.AuthRequest;
+import org.springblade.auth.utils.TokenUtil;
+import org.springblade.core.oauth2.exception.OAuth2ErrorCode;
+import org.springblade.core.oauth2.granter.AbstractTokenGranter;
+import org.springblade.core.oauth2.handler.PasswordHandler;
+import org.springblade.core.oauth2.provider.OAuth2Request;
+import org.springblade.core.oauth2.service.OAuth2ClientService;
+import org.springblade.core.oauth2.service.OAuth2User;
+import org.springblade.core.oauth2.service.OAuth2UserService;
+import org.springblade.core.oauth2.utils.OAuth2ExceptionUtil;
+import org.springblade.core.social.props.SocialProperties;
+import org.springblade.core.social.utils.SocialUtil;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.BeanUtil;
+import org.springblade.system.pojo.entity.UserInfo;
+import org.springblade.system.pojo.entity.UserOauth;
+import org.springblade.system.feign.IUserClient;
+import org.springframework.stereotype.Component;
+
+import java.util.Objects;
+
+/**
+ * SocialTokenGranter
+ *
+ * @author Chill
+ */
+@Component
+public class SocialTokenGranter extends AbstractTokenGranter {
+
+
+	private static final Integer AUTH_SUCCESS_CODE = 2000;
+
+	private final IUserClient userClient;
+	private final SocialProperties socialProperties;
+
+
+	public SocialTokenGranter(OAuth2ClientService clientService, OAuth2UserService oAuth2UserService, PasswordHandler passwordHandler, IUserClient userClient, SocialProperties socialProperties) {
+		super(clientService, oAuth2UserService, passwordHandler);
+		this.userClient = userClient;
+		this.socialProperties = socialProperties;
+	}
+
+	@Override
+	public String type() {
+		return SOCIAL;
+	}
+
+	@Override
+	public OAuth2User user(OAuth2Request request) {
+		String tenantId = request.getTenantId();
+		// 开放平台来源
+		String sourceParameter = request.getSource();
+		// 匹配是否有别名定义
+		String source = socialProperties.getAlias().getOrDefault(sourceParameter, sourceParameter);
+		// 开放平台授权码
+		String code = request.getCode();
+		// 开放平台状态吗
+		String state = request.getState();
+
+		// 获取开放平台授权数据
+		AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
+		AuthCallback authCallback = new AuthCallback();
+		authCallback.setCode(code);
+		authCallback.setState(state);
+		AuthResponse<?> authResponse = authRequest.login(authCallback);
+		AuthUser authUser = null;
+		if (authResponse.getCode() == AUTH_SUCCESS_CODE) {
+			authUser = (AuthUser) authResponse.getData();
+		} else {
+			OAuth2ExceptionUtil.throwFromCode(OAuth2ErrorCode.INVALID_USER);
+		}
+
+		// 组装数据
+		UserOauth userOauth = Objects.requireNonNull(BeanUtil.copyProperties(authUser, UserOauth.class));
+		userOauth.setSource(authUser.getSource());
+		userOauth.setTenantId(tenantId);
+		userOauth.setUuid(authUser.getUuid());
+		R<UserInfo> result = userClient.userAuthInfo(userOauth);
+		if (!result.isSuccess()) {
+			OAuth2ExceptionUtil.throwFromCode(OAuth2ErrorCode.USER_NOT_FOUND);
+		}
+		return TokenUtil.convertUser(result.getData(), request);
+	}
+
+}

+ 200 - 0
blade-auth/src/main/java/org/springblade/auth/handler/BladeAuthorizationHandler.java

@@ -0,0 +1,200 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.auth.handler;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.common.cache.CacheNames;
+import org.springblade.common.constant.TenantConstant;
+import org.springblade.core.oauth2.exception.ExceptionCode;
+import org.springblade.core.oauth2.handler.AbstractAuthorizationHandler;
+import org.springblade.core.oauth2.provider.OAuth2Request;
+import org.springblade.core.oauth2.provider.OAuth2Validation;
+import org.springblade.core.oauth2.service.OAuth2User;
+import org.springblade.core.redis.cache.BladeRedis;
+import org.springblade.core.tenant.BladeTenantProperties;
+import org.springblade.core.tool.jackson.JsonUtil;
+import org.springblade.core.tool.utils.DateUtil;
+import org.springblade.core.tool.utils.DesUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.system.cache.ParamCache;
+import org.springblade.system.cache.SysCache;
+import org.springblade.system.pojo.entity.Tenant;
+
+import java.time.Duration;
+import java.util.Date;
+
+import static org.springblade.auth.constant.BladeAuthConstant.FAIL_COUNT;
+import static org.springblade.auth.constant.BladeAuthConstant.FAIL_COUNT_VALUE;
+
+/**
+ * AbstractAuthorizationHandler
+ *
+ * @author BladeX
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class BladeAuthorizationHandler extends AbstractAuthorizationHandler {
+
+	private final BladeRedis bladeRedis;
+	private final BladeTenantProperties tenantProperties;
+
+	/**
+	 * 认证校验
+	 *
+	 * @param user    用户信息
+	 * @param request 请求信息
+	 * @return boolean
+	 */
+	@Override
+	public OAuth2Validation authValidation(OAuth2User user, OAuth2Request request) {
+		// 密码模式、刷新token模式、验证码模式需要校验租户状态
+		if (request.isPassword() || request.isRefreshToken() || request.isCaptchaCode()) {
+			// 租户校验
+			OAuth2Validation tenantValidation = validateTenant(user.getTenantId());
+			if (!tenantValidation.isSuccess()) {
+				return tenantValidation;
+			}
+			// 判断登录是否锁定
+			OAuth2Validation failCountValidation = validateFailCount(user.getTenantId(), user.getAccount());
+			if (!failCountValidation.isSuccess()) {
+				return failCountValidation;
+			}
+		}
+		return super.authValidation(user, request);
+	}
+
+	/**
+	 * 认证成功回调
+	 *
+	 * @param user 用户信息
+	 */
+	@Override
+	public void authSuccessful(OAuth2User user, OAuth2Request request) {
+		// 清空错误锁定次数
+		delFailCount(user.getTenantId(), user.getAccount());
+
+		log.info("用户:{},认证成功", user.getAccount());
+	}
+
+	/**
+	 * 认证失败回调
+	 *
+	 * @param user       用户信息
+	 * @param validation 失败信息
+	 */
+	@Override
+	public void authFailure(OAuth2User user, OAuth2Request request, OAuth2Validation validation) {
+		// 增加错误锁定次数
+		addFailCount(user.getTenantId(), user.getAccount());
+
+		log.error("用户:{},认证失败,失败原因:{}", user.getAccount(), validation.getMessage());
+	}
+
+	/**
+	 * 租户授权校验
+	 *
+	 * @param tenantId 租户id
+	 * @return OAuth2Validation
+	 */
+	private OAuth2Validation validateTenant(String tenantId) {
+		// 租户校验
+		Tenant tenant = SysCache.getTenant(tenantId);
+		if (tenant == null) {
+			return buildValidationFailure(ExceptionCode.USER_TENANT_NOT_FOUND);
+		}
+		// 租户授权时间校验
+		Date expireTime = tenant.getExpireTime();
+		if (tenantProperties.getLicense()) {
+			String licenseKey = tenant.getLicenseKey();
+			String decrypt = DesUtil.decryptFormHex(licenseKey, TenantConstant.DES_KEY);
+			expireTime = JsonUtil.parse(decrypt, Tenant.class).getExpireTime();
+		}
+		if (expireTime != null && expireTime.before(DateUtil.now())) {
+			return buildValidationFailure(ExceptionCode.UNAUTHORIZED_USER_TENANT);
+		}
+		return new OAuth2Validation();
+	}
+
+	/**
+	 * 判断登录是否锁定
+	 *
+	 * @param tenantId 租户id
+	 * @param account  账号
+	 * @return OAuth2Validation
+	 */
+	private OAuth2Validation validateFailCount(String tenantId, String account) {
+		int cnt = getFailCount(tenantId, account);
+		int failCount = Func.toInt(ParamCache.getValue(FAIL_COUNT_VALUE), FAIL_COUNT);
+		if (cnt >= failCount) {
+			return buildValidationFailure(ExceptionCode.USER_TOO_MANY_FAILS);
+		}
+		return new OAuth2Validation();
+	}
+
+	/**
+	 * 获取账号错误次数
+	 *
+	 * @param tenantId 租户id
+	 * @param username 账号
+	 * @return int
+	 */
+	private int getFailCount(String tenantId, String username) {
+		return Func.toInt(bladeRedis.get(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, username)), 0);
+	}
+
+	/**
+	 * 设置账号错误次数
+	 *
+	 * @param tenantId 租户id
+	 * @param username 账号
+	 */
+	private void addFailCount(String tenantId, String username) {
+		int count = getFailCount(tenantId, username);
+		bladeRedis.setEx(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, username), count + 1, Duration.ofMinutes(30));
+	}
+
+	/**
+	 * 设置账号错误次数
+	 *
+	 * @param tenantId 租户id
+	 * @param username 账号
+	 * @param count    次数
+	 */
+	private void setFailCount(String tenantId, String username, int count) {
+		bladeRedis.setEx(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, username), count + 1, Duration.ofMinutes(30));
+	}
+
+	/**
+	 * 清空账号错误次数
+	 *
+	 * @param tenantId 租户id
+	 * @param username 账号
+	 */
+	private void delFailCount(String tenantId, String username) {
+		bladeRedis.del(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, username));
+	}
+}

+ 59 - 0
blade-auth/src/main/java/org/springblade/auth/handler/BladePasswordHandler.java

@@ -0,0 +1,59 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.auth.handler;
+
+import org.springblade.core.oauth2.handler.OAuth2PasswordHandler;
+
+/**
+ * BladePasswordHandler
+ *
+ * @author BladeX
+ */
+public class BladePasswordHandler extends OAuth2PasswordHandler {
+
+	/**
+	 * 判断密码是否匹配
+	 *
+	 * @param rawPassword     请求时提交的原密码
+	 * @param encodedPassword 数据库加密后的密码
+	 * @return boolean
+	 */
+	@Override
+	public boolean matches(String rawPassword, String encodedPassword) {
+		return super.matches(rawPassword, encodedPassword);
+	}
+
+	/**
+	 * 加密密码规则
+	 *
+	 * @param rawPassword 密码
+	 * @return 加密后的密码
+	 */
+	@Override
+	public String encode(String rawPassword) {
+		return super.encode(rawPassword);
+	}
+}

+ 59 - 0
blade-auth/src/main/java/org/springblade/auth/handler/BladeTokenHandler.java

@@ -0,0 +1,59 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.auth.handler;
+
+import org.springblade.core.jwt.props.JwtProperties;
+import org.springblade.core.launch.constant.TokenConstant;
+import org.springblade.core.oauth2.handler.OAuth2TokenHandler;
+import org.springblade.core.oauth2.provider.OAuth2Request;
+import org.springblade.core.oauth2.provider.OAuth2Token;
+import org.springblade.core.oauth2.service.OAuth2User;
+import org.springblade.core.tool.support.Kv;
+
+/**
+ * BladeTokenHandler
+ *
+ * @author BladeX
+ */
+public class BladeTokenHandler extends OAuth2TokenHandler {
+
+	public BladeTokenHandler(JwtProperties properties) {
+		super(properties);
+	}
+
+	@Override
+	public OAuth2Token enhance(OAuth2User user, OAuth2Token token, OAuth2Request request) {
+		// 父类令牌状态配置
+		OAuth2Token enhanceToken = super.enhance(user, token, request);
+
+		// 令牌统一处理,增加或删减字段
+		Kv args = enhanceToken.getArgs();
+		args.set(TokenConstant.USER_NAME, user.getAccount());
+
+		// 返回令牌
+		return enhanceToken;
+	}
+}

+ 62 - 0
blade-auth/src/main/java/org/springblade/auth/service/BladeClientDetailService.java

@@ -0,0 +1,62 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.auth.service;
+
+import org.springblade.core.oauth2.provider.OAuth2Request;
+import org.springblade.core.oauth2.service.OAuth2Client;
+import org.springblade.core.oauth2.service.impl.OAuth2ClientDetailService;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+/**
+ * BladeClientDetailService
+ *
+ * @author Chill
+ */
+public class BladeClientDetailService extends OAuth2ClientDetailService {
+	public BladeClientDetailService(JdbcTemplate jdbcTemplate) {
+		super(jdbcTemplate);
+	}
+
+	@Override
+	public OAuth2Client loadByClientId(String clientId) {
+		return super.loadByClientId(clientId);
+	}
+
+	@Override
+	public OAuth2Client loadByClientId(String clientId, OAuth2Request request) {
+		return super.loadByClientId(clientId, request);
+	}
+
+	@Override
+	public boolean validateClient(OAuth2Client client, String clientId, String clientSecret) {
+		return super.validateClient(client, clientId, clientSecret);
+	}
+
+	@Override
+	public boolean validateGranter(OAuth2Client client, String grantType) {
+		return super.validateGranter(client, grantType);
+	}
+}

+ 94 - 0
blade-auth/src/main/java/org/springblade/auth/service/BladeUserDetailService.java

@@ -0,0 +1,94 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.auth.service;
+
+import lombok.RequiredArgsConstructor;
+import org.springblade.auth.utils.TokenUtil;
+import org.springblade.core.oauth2.exception.OAuth2ErrorCode;
+import org.springblade.core.oauth2.provider.OAuth2Request;
+import org.springblade.core.oauth2.service.OAuth2User;
+import org.springblade.core.oauth2.service.OAuth2UserService;
+import org.springblade.core.oauth2.utils.OAuth2ExceptionUtil;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.system.pojo.entity.UserInfo;
+import org.springblade.system.pojo.enums.UserType;
+import org.springblade.system.feign.IUserClient;
+
+import java.util.Optional;
+
+/**
+ * BladeUserDetailService
+ *
+ * @author Chill
+ */
+@RequiredArgsConstructor
+public class BladeUserDetailService implements OAuth2UserService {
+	private final IUserClient userClient;
+
+	@Override
+	public OAuth2User loadByUserId(String userId, OAuth2Request request) {
+		// 获取用户参数
+		String userType = Optional.ofNullable(request.getUserType())
+			.filter(s -> !StringUtil.isBlank(s))
+			.orElse(UserType.WEB.getName());
+
+		// 获取用户信息
+		R<UserInfo> result = userClient.userInfo(Func.toLong(userId), userType);
+		if (!result.isSuccess()) {
+			OAuth2ExceptionUtil.throwFromCode(OAuth2ErrorCode.USER_NOT_FOUND);
+		}
+		// 构建oauth2用户信息
+		return TokenUtil.convertUser(result.getData(), request);
+	}
+
+	@Override
+	public OAuth2User loadByUsername(String username, OAuth2Request request) {
+		// 获取用户参数
+		String userType = Optional.ofNullable(request.getUserType())
+			.filter(s -> !StringUtil.isBlank(s))
+			.orElse(UserType.WEB.getName());
+		String tenantId = request.getTenantId();
+
+		// 获取用户信息
+		R<UserInfo> result = userClient.userInfo(tenantId, username, userType);
+		if (!result.isSuccess()) {
+			return null;
+		}
+		// 构建oauth2用户信息
+		return TokenUtil.convertUser(result.getData(), request);
+	}
+
+	@Override
+	public boolean validateUser(OAuth2User user) {
+		return Optional.ofNullable(user)
+			.filter(u -> u.getUserId() != null && !u.getUserId().isEmpty()) // 检查userId不为空
+			.filter(u -> u.getAuthorities() != null && !u.getAuthorities().isEmpty()) // 检查authorities不为空
+			.isPresent(); // 如果上述条件都满足,则返回true,否则返回false
+	}
+
+}

+ 83 - 0
blade-auth/src/main/java/org/springblade/auth/utils/TokenUtil.java

@@ -0,0 +1,83 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.auth.utils;
+
+import org.springblade.core.oauth2.provider.OAuth2Request;
+import org.springblade.core.oauth2.service.OAuth2User;
+import org.springblade.core.oauth2.service.impl.OAuth2UserDetail;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.system.pojo.entity.User;
+import org.springblade.system.pojo.entity.UserInfo;
+
+/**
+ * 认证工具类
+ *
+ * @author Chill
+ */
+public class TokenUtil {
+
+	/**
+	 * 系统用户转换为OAuth2标准用户
+	 *
+	 * @param userInfo 用户信息
+	 * @param request  请求信息
+	 * @return OAuth2User
+	 */
+	public static OAuth2User convertUser(UserInfo userInfo, OAuth2Request request) {
+		// 为空则返回null
+		if (userInfo == null) {
+			return null;
+		}
+		User user = userInfo.getUser();
+		String userDept = request.getUserDept();
+		String userRole = request.getUserRole();
+		// 多部门情况下指定单部门
+		if (Func.isNotEmpty(userDept) && user.getDeptId().contains(userDept)) {
+			user.setDeptId(userDept);
+		}
+		// 多角色情况下指定单角色
+		if (Func.isNotEmpty(userRole) && user.getRoleId().contains(userRole)) {
+			user.setRoleId(userRole);
+		}
+		// 构建oauth2所需用户信息
+		OAuth2UserDetail userDetail = new OAuth2UserDetail();
+		userDetail.setUserId(String.valueOf(user.getId()));
+		userDetail.setTenantId(user.getTenantId());
+		userDetail.setName(user.getName());
+		userDetail.setRealName(user.getRealName());
+		userDetail.setAccount(user.getAccount());
+		userDetail.setPassword(user.getPassword());
+		userDetail.setDeptId(user.getDeptId());
+		userDetail.setPostId(user.getPostId());
+		userDetail.setRoleId(user.getRoleId());
+		userDetail.setRoleName(Func.join(userInfo.getRoles()));
+		userDetail.setAvatar(user.getAvatar());
+		userDetail.setAuthorities(userInfo.getRoles());
+		userDetail.setDetail(userInfo.getDetail());
+		return userDetail;
+	}
+
+}

+ 15 - 0
blade-auth/src/main/resources/application-dev.yml

@@ -0,0 +1,15 @@
+#服务器端口
+server:
+  port: 8100
+
+#数据源配置
+spring:
+  datasource:
+    url: ${blade.datasource.dev.url}
+    username: ${blade.datasource.dev.username}
+    password: ${blade.datasource.dev.password}
+
+#第三方登陆
+social:
+  enabled: true
+  domain: http://127.0.0.1:1888

+ 15 - 0
blade-auth/src/main/resources/application-prod.yml

@@ -0,0 +1,15 @@
+#服务器端口
+server:
+  port: 8100
+
+#数据源配置
+spring:
+  datasource:
+    url: ${blade.datasource.prod.url}
+    username: ${blade.datasource.prod.username}
+    password: ${blade.datasource.prod.password}
+
+#第三方登陆
+social:
+  enabled: true
+  domain: http://127.0.0.1:1888

+ 15 - 0
blade-auth/src/main/resources/application-test.yml

@@ -0,0 +1,15 @@
+#服务器端口
+server:
+  port: 8100
+
+#数据源配置
+spring:
+  datasource:
+    url: ${blade.datasource.test.url}
+    username: ${blade.datasource.test.username}
+    password: ${blade.datasource.test.password}
+
+#第三方登陆
+social:
+  enabled: true
+  domain: http://127.0.0.1:1888

+ 65 - 0
blade-auth/src/main/resources/application.yml

@@ -0,0 +1,65 @@
+# 在使用Spring默认数据源Hikari的情况下配置以下配置项
+spring:
+  datasource:
+    hikari:
+      # 自动提交从池中返回的连接
+      auto-commit: true
+      # 连接池中维护的最小空闲连接数
+      minimum-idle: 10
+      # 连接池中允许的最大连接数。缺省值:10;推荐的公式:((core_count * 2) + effective_spindle_count)
+      maximum-pool-size: 60
+      # 空闲连接超时时间,默认值600000(10分钟),大于等于max-lifetime且max-lifetime>0,会被重置为0;不等于0且小于10秒,会被重置为10秒。
+      # 只有空闲连接数大于最大连接数且空闲时间超过该值,才会被释放
+      idle-timeout: 30000
+      # 连接最大存活时间.不等于0且小于30秒,会被重置为默认值30分钟.设置应该比mysql设置的超时时间短
+      max-lifetime: 1800000
+      # 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 缺省:30秒
+      connection-timeout: 30000
+      # 连接测试查询
+      connection-test-query: select 1
+      #connection-test-query: select 1 from dual
+  freemarker:
+    # 模板后缀名
+    suffix: .ftl
+    # 文档类型
+    content-type: text/html
+    # 页面编码
+    charset: UTF-8
+    # 页面缓存
+    cache: false
+    # 模板路径
+    template-loader-path: classpath:/templates/
+  web:
+    # 资源路径
+    resources:
+      static-locations: classpath:/static/
+
+#swagger文档
+swagger:
+  base-packages:
+    - org.springblade
+    - org.springframework.security.oauth2.provider.endpoint
+
+#第三方登陆
+social:
+  oauth:
+    GITHUB:
+      client-id: 233************
+      client-secret: 233************************************
+      redirect-uri: ${social.domain}/oauth/redirect/github
+    GITEE:
+      client-id: 233************
+      client-secret: 233************************************
+      redirect-uri: ${social.domain}/oauth/redirect/gitee
+    WECHAT_OPEN:
+      client-id: 233************
+      client-secret: 233************************************
+      redirect-uri: ${social.domain}/oauth/redirect/wechat
+    QQ:
+      client-id: 233************
+      client-secret: 233************************************
+      redirect-uri: ${social.domain}/oauth/redirect/qq
+    DINGTALK:
+      client-id: 233************
+      client-secret: 233************************************
+      redirect-uri: ${social.domain}/oauth/redirect/dingtalk

+ 43 - 0
blade-auth/src/test/java/org/springblade/test/CryptoKeyGenerator.java

@@ -0,0 +1,43 @@
+package org.springblade.test;
+
+import org.springblade.core.tool.utils.AesUtil;
+import org.springblade.core.tool.utils.DesUtil;
+import org.springblade.core.tool.utils.StringPool;
+
+/**
+ * Key生成器
+ *
+ * @author Chill
+ */
+public class CryptoKeyGenerator {
+
+	public static void main(String[] args) {
+		System.out.println("=======================================================");
+		System.out.println("====== blade.token.crypto-key 的值从中挑选一个便可 =======");
+		System.out.println("=======================================================");
+		for (int i = 0; i < 10; i++) {
+			String cryptoKey = AesUtil.genAesKey();
+			System.out.println("BladeX CryptoKey:[" + cryptoKey + "] ");
+		}
+		System.out.println("=======================================================");
+		System.out.println(StringPool.EMPTY);
+		System.out.println("=======================================================");
+		System.out.println("===== blade.api.crypto.aes-key 的值从中挑选一个便可 ======");
+		System.out.println("=======================================================");
+		for (int i = 0; i < 10; i++) {
+			String AesKey = AesUtil.genAesKey();
+			System.out.println("BladeX AesKey:[" + AesKey + "] ");
+		}
+		System.out.println("=======================================================");
+		System.out.println(StringPool.EMPTY);
+		System.out.println("=======================================================");
+		System.out.println("===== blade.api.crypto.des-key 的值从中挑选一个便可 ======");
+		System.out.println("=======================================================");
+		for (int i = 0; i < 10; i++) {
+			String DesKey = DesUtil.genDesKey();
+			System.out.println("BladeX DesKey:[" + DesKey + "] ");
+		}
+		System.out.println("=======================================================");
+	}
+
+}

+ 24 - 0
blade-auth/src/test/java/org/springblade/test/SignKeyGenerator.java

@@ -0,0 +1,24 @@
+package org.springblade.test;
+
+import org.springblade.core.tool.utils.RandomType;
+import org.springblade.core.tool.utils.StringUtil;
+
+/**
+ * signKey生成器
+ *
+ * @author Chill
+ */
+public class SignKeyGenerator {
+
+	public static void main(String[] args) {
+		System.out.println("=======================================================");
+		System.out.println("====== blade.token.sign-key 的值从中挑选一个便可 =========");
+		System.out.println("=======================================================");
+		for (int i = 0; i < 10; i++) {
+			String signKey = StringUtil.random(32, RandomType.ALL);
+			System.out.println("BladeX SignKey:[" + signKey + "] ");
+		}
+		System.out.println("=======================================================");
+	}
+
+}

+ 45 - 0
blade-common/pom.xml

@@ -0,0 +1,45 @@
+<?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>BladeX</artifactId>
+        <groupId>org.springblade</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>blade-common</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-launch</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-starter-loadbalancer</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-auto</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                    <finalName>${project.name}</finalName>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 68 - 0
blade-common/src/main/java/org/springblade/common/cache/CacheNames.java

@@ -0,0 +1,68 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.common.cache;
+
+/**
+ * 缓存名
+ *
+ * @author Chill
+ */
+public interface CacheNames {
+
+	/**
+	 * 返回拼接后的key
+	 *
+	 * @param cacheKey      缓存key
+	 * @param cacheKeyValue 缓存key值
+	 * @return tenantKey
+	 */
+	static String cacheKey(String cacheKey, String cacheKeyValue) {
+		return cacheKey.concat(cacheKeyValue);
+	}
+
+	/**
+	 * 返回租户格式的key
+	 *
+	 * @param tenantId      租户编号
+	 * @param cacheKey      缓存key
+	 * @param cacheKeyValue 缓存key值
+	 * @return tenantKey
+	 */
+	static String tenantKey(String tenantId, String cacheKey, String cacheKeyValue) {
+		return tenantId.concat(":").concat(cacheKey).concat(cacheKeyValue);
+	}
+
+	/**
+	 * 验证码key
+	 */
+	String CAPTCHA_KEY = "blade:auth::blade:captcha:";
+
+	/**
+	 * 登录失败key
+	 */
+	String USER_FAIL_KEY = "blade:user::blade:fail:";
+
+}

+ 41 - 0
blade-common/src/main/java/org/springblade/common/config/BladeCommonConfiguration.java

@@ -0,0 +1,41 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.common.config;
+
+
+import lombok.AllArgsConstructor;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 公共封装包配置类
+ *
+ * @author Chill
+ */
+@Configuration(proxyBeanMethods = false)
+@AllArgsConstructor
+public class BladeCommonConfiguration {
+
+}

+ 90 - 0
blade-common/src/main/java/org/springblade/common/constant/CommonConstant.java

@@ -0,0 +1,90 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.common.constant;
+
+/**
+ * 通用常量
+ *
+ * @author Chill
+ */
+public interface CommonConstant {
+
+	String APPLICATION_APP_NAME = "app-management";
+	String APPLICATION_JDRH_NAME = "jdrh";
+	String APPLICATION_DEMO_NAME = "demo";
+	String APPLICATION_MPUSH_NAME = "mpush";
+	/**
+	 * sword 系统名
+	 */
+	String SWORD_NAME = "sword";
+
+	/**
+	 * saber 系统名
+	 */
+	String SABER_NAME = "saber";
+
+	/**
+	 * 顶级父节点id
+	 */
+	Long TOP_PARENT_ID = 0L;
+
+	/**
+	 * 顶级父节点名称
+	 */
+	String TOP_PARENT_NAME = "顶级";
+
+	/**
+	 * 未封存状态值
+	 */
+	Integer NOT_SEALED_ID = 0;
+
+	/**
+	 * 默认密码
+	 */
+	String DEFAULT_PASSWORD = "123456";
+
+	/**
+	 * 默认密码参数值
+	 */
+	String DEFAULT_PARAM_PASSWORD = "account.initPassword";
+
+	/**
+	 * 默认排序字段
+	 */
+	String SORT_FIELD = "sort";
+
+	/**
+	 * 数据权限类型
+	 */
+	Integer DATA_SCOPE_CATEGORY = 1;
+
+	/**
+	 * 接口权限类型
+	 */
+	Integer API_SCOPE_CATEGORY = 2;
+
+
+}

+ 237 - 0
blade-common/src/main/java/org/springblade/common/constant/LauncherConstant.java

@@ -0,0 +1,237 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.common.constant;
+
+import org.springblade.core.launch.constant.AppConstant;
+
+/**
+ * 启动常量
+ *
+ * @author Chill
+ */
+public interface LauncherConstant {
+
+	/**
+	 * nacos 用户名
+	 */
+	String NACOS_USERNAME = "nacos";
+
+	/**
+	 * nacos 密码
+	 */
+	String NACOS_PASSWORD = "xwkj2022@";
+
+	/**
+	 * nacos dev 地址
+	 */
+	String NACOS_DEV_ADDR = "127.0.0.1:8848";
+
+	/**
+	 * nacos prod 地址
+	 */
+	String NACOS_PROD_ADDR = "172.30.0.48:8848";
+
+	/**
+	 * nacos test 地址
+	 */
+	String NACOS_TEST_ADDR = "172.30.0.48:8848";
+
+	/**
+	 * sentinel dev 地址
+	 */
+	String SENTINEL_DEV_ADDR = "127.0.0.1:8858";
+
+	/**
+	 * sentinel prod 地址
+	 */
+	String SENTINEL_PROD_ADDR = "172.30.0.58:8858";
+
+	/**
+	 * sentinel test 地址
+	 */
+	String SENTINEL_TEST_ADDR = "172.30.0.58:8858";
+
+	/**
+	 * seata dev 地址
+	 */
+	String SEATA_DEV_ADDR = "127.0.0.1:8091";
+
+	/**
+	 * seata prod 地址
+	 */
+	String SEATA_PROD_ADDR = "172.30.0.68:8091";
+
+	/**
+	 * seata test 地址
+	 */
+	String SEATA_TEST_ADDR = "172.30.0.68:8091";
+
+	/**
+	 * zipkin dev 地址
+	 */
+	String ZIPKIN_DEV_ADDR = "http://127.0.0.1:9411";
+
+	/**
+	 * zipkin prod 地址
+	 */
+	String ZIPKIN_PROD_ADDR = "http://172.30.0.71:9411";
+
+	/**
+	 * zipkin test 地址
+	 */
+	String ZIPKIN_TEST_ADDR = "http://172.30.0.71:9411";
+
+	/**
+	 * elk dev 地址
+	 */
+	String ELK_DEV_ADDR = "127.0.0.1:9000";
+
+	/**
+	 * elk prod 地址
+	 */
+	String ELK_PROD_ADDR = "172.30.0.72:9000";
+
+	/**
+	 * elk test 地址
+	 */
+	String ELK_TEST_ADDR = "172.30.0.72:9000";
+
+	/**
+	 * seata file模式
+	 */
+	String FILE_MODE = "file";
+
+	/**
+	 * seata nacos模式
+	 */
+	String NACOS_MODE = "nacos";
+
+	/**
+	 * seata default模式
+	 */
+	String DEFAULT_MODE = "default";
+
+	/**
+	 * seata group后缀
+	 */
+	String GROUP_NAME = "-group";
+
+	/**
+	 * seata 服务组格式
+	 *
+	 * @param appName 服务名
+	 * @return group
+	 */
+	static String seataServiceGroup(String appName) {
+		return appName.concat(GROUP_NAME);
+	}
+
+	/**
+	 * 动态获取nacos地址
+	 *
+	 * @param profile 环境变量
+	 * @return addr
+	 */
+	static String nacosAddr(String profile) {
+		switch (profile) {
+			case (AppConstant.PROD_CODE):
+				return NACOS_PROD_ADDR;
+			case (AppConstant.TEST_CODE):
+				return NACOS_TEST_ADDR;
+			default:
+				return NACOS_DEV_ADDR;
+		}
+	}
+
+	/**
+	 * 动态获取sentinel地址
+	 *
+	 * @param profile 环境变量
+	 * @return addr
+	 */
+	static String sentinelAddr(String profile) {
+		switch (profile) {
+			case (AppConstant.PROD_CODE):
+				return SENTINEL_PROD_ADDR;
+			case (AppConstant.TEST_CODE):
+				return SENTINEL_TEST_ADDR;
+			default:
+				return SENTINEL_DEV_ADDR;
+		}
+	}
+
+	/**
+	 * 动态获取seata地址
+	 *
+	 * @param profile 环境变量
+	 * @return addr
+	 */
+	static String seataAddr(String profile) {
+		switch (profile) {
+			case (AppConstant.PROD_CODE):
+				return SEATA_PROD_ADDR;
+			case (AppConstant.TEST_CODE):
+				return SEATA_TEST_ADDR;
+			default:
+				return SEATA_DEV_ADDR;
+		}
+	}
+
+	/**
+	 * 动态获取zipkin地址
+	 *
+	 * @param profile 环境变量
+	 * @return addr
+	 */
+	static String zipkinAddr(String profile) {
+		switch (profile) {
+			case (AppConstant.PROD_CODE):
+				return ZIPKIN_PROD_ADDR;
+			case (AppConstant.TEST_CODE):
+				return ZIPKIN_TEST_ADDR;
+			default:
+				return ZIPKIN_DEV_ADDR;
+		}
+	}
+
+	/**
+	 * 动态获取elk地址
+	 *
+	 * @param profile 环境变量
+	 * @return addr
+	 */
+	static String elkAddr(String profile) {
+		switch (profile) {
+			case (AppConstant.PROD_CODE):
+				return ELK_PROD_ADDR;
+			case (AppConstant.TEST_CODE):
+				return ELK_TEST_ADDR;
+			default:
+				return ELK_DEV_ADDR;
+		}
+	}
+
+}

+ 75 - 0
blade-common/src/main/java/org/springblade/common/constant/TenantConstant.java

@@ -0,0 +1,75 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.common.constant;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 租户常量
+ *
+ * @author Chill
+ */
+public interface TenantConstant {
+
+	/**
+	 * 租户默认密码KEY
+	 */
+	String PASSWORD_KEY = "tenant.default.password";
+
+	/**
+	 * 租户默认账号额度KEY
+	 */
+	String ACCOUNT_NUMBER_KEY = "tenant.default.accountNumber";
+
+	/**
+	 * 租户默认菜单集合KEY
+	 */
+	String ACCOUNT_MENU_CODE_KEY = "tenant.default.menuCode";
+
+	/**
+	 * 租户默认密码
+	 */
+	String DEFAULT_PASSWORD = "123456";
+
+	/**
+	 * 租户授权码默认16位密钥
+	 */
+	String DES_KEY = "0000000000000000";
+
+	/**
+	 * 租户默认账号额度
+	 */
+	Integer DEFAULT_ACCOUNT_NUMBER = -1;
+
+	/**
+	 * 租户默认菜单集合
+	 */
+	List<String> MENU_CODES = Arrays.asList(
+		"desk", "flow", "work", "monitor", "resource", "role", "user", "dept", "dictbiz", "topmenu"
+	);
+
+}

+ 73 - 0
blade-common/src/main/java/org/springblade/common/launch/LauncherServiceImpl.java

@@ -0,0 +1,73 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.common.launch;
+
+import org.springblade.common.constant.LauncherConstant;
+import org.springblade.core.auto.service.AutoService;
+import org.springblade.core.launch.service.LauncherService;
+import org.springblade.core.launch.utils.PropsUtil;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+
+import java.util.Properties;
+
+/**
+ * 启动参数拓展
+ *
+ * @author smallchil
+ */
+@AutoService(LauncherService.class)
+public class LauncherServiceImpl implements LauncherService {
+
+	@Override
+	public void launcher(SpringApplicationBuilder builder, String appName, String profile, boolean isLocalDev) {
+		Properties props = System.getProperties();
+		// 通用注册
+//		PropsUtil.setProperty(props, "spring.cloud.nacos.config.extension-configs[0].data-id", NacosConstant.dataId("example", profile));
+		PropsUtil.setProperty(props, "spring.cloud.nacos.username", LauncherConstant.NACOS_USERNAME);
+		PropsUtil.setProperty(props, "spring.cloud.nacos.password", LauncherConstant.NACOS_PASSWORD);
+		PropsUtil.setProperty(props, "spring.cloud.nacos.discovery.server-addr", LauncherConstant.nacosAddr(profile));
+		PropsUtil.setProperty(props, "spring.cloud.nacos.config.server-addr", LauncherConstant.nacosAddr(profile));
+		PropsUtil.setProperty(props, "spring.cloud.sentinel.transport.dashboard", LauncherConstant.sentinelAddr(profile));
+		PropsUtil.setProperty(props, "spring.zipkin.base-url", LauncherConstant.zipkinAddr(profile));
+		PropsUtil.setProperty(props, "spring.datasource.dynamic.enabled", "true");
+
+		// 开启elk日志
+		// PropsUtil.setProperty(props, "blade.log.elk.destination", LauncherConstant.elkAddr(profile));
+
+		// seata注册地址
+		// PropsUtil.setProperty(props, "seata.service.grouplist.default", LauncherConstant.seataAddr(profile));
+		// seata注册group格式
+		// PropsUtil.setProperty(props, "seata.tx-service-group", LauncherConstant.seataServiceGroup(appName));
+		// seata配置服务group
+		// PropsUtil.setProperty(props, "seata.service.vgroup-mapping.".concat(LauncherConstant.seataServiceGroup(appName)), LauncherConstant.DEFAULT_MODE);
+		// seata注册模式配置
+		// PropsUtil.setProperty(props, "seata.registry.type", LauncherConstant.NACOS_MODE);
+		// PropsUtil.setProperty(props, "seata.registry.nacos.server-addr", LauncherConstant.nacosAddr(profile));
+		// PropsUtil.setProperty(props, "seata.config.type", LauncherConstant.NACOS_MODE);
+		// PropsUtil.setProperty(props, "seata.config.nacos.server-addr", LauncherConstant.nacosAddr(profile));
+	}
+
+}

+ 35 - 0
blade-common/src/main/java/org/springblade/common/utils/CommonUtil.java

@@ -0,0 +1,35 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.common.utils;
+
+/**
+ * 通用工具类
+ *
+ * @author Chill
+ */
+public class CommonUtil {
+
+}

+ 8 - 0
blade-common/src/main/resources/banner.txt

@@ -0,0 +1,8 @@
+${AnsiColor.BLUE}                   ______  _             _       ___   ___
+${AnsiColor.BLUE}                   | ___ \| |           | |      \  \ /  /
+${AnsiColor.BLUE}                   | |_/ /| |  __ _   __| |  ___  \  V  /
+${AnsiColor.BLUE}                   | ___ \| | / _` | / _` | / _ \   > <
+${AnsiColor.BLUE}                   | |_/ /| || (_| || (_| ||  __/ /  .  \
+${AnsiColor.BLUE}                   \____/ |_| \__,_| \__,_| \___|/__/ \__\
+
+${AnsiColor.BLUE}:: BladeX ${blade.service.version} :: ${spring.application.name}:${AnsiColor.RED}${blade.env}${AnsiColor.BLUE} :: Running SpringBoot ${spring-boot.version} :: ${AnsiColor.BRIGHT_BLACK}

+ 15 - 0
blade-gateway/Dockerfile

@@ -0,0 +1,15 @@
+FROM bladex/alpine-java:openjdk17_cn_slim
+
+LABEL maintainer="bladejava@qq.com"
+
+RUN mkdir -p /blade/gateway
+
+WORKDIR /blade/gateway
+
+EXPOSE 80
+
+COPY ./target/blade-gateway.jar ./app.jar
+
+ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
+
+CMD ["--spring.profiles.active=test"]

+ 103 - 0
blade-gateway/pom.xml

@@ -0,0 +1,103 @@
+<?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>BladeX</artifactId>
+        <groupId>org.springblade</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>blade-gateway</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <!--Blade-->
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-launch</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-web</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-undertow</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-common</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springblade</groupId>
+                    <artifactId>blade-core-launch</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-starter-metrics</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-starter-jwt</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+        <!--Spring-->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-gateway</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bootstrap</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>de.codecentric</groupId>
+            <artifactId>spring-boot-admin-starter-client</artifactId>
+        </dependency>
+        <!-- 开启knife4j -->
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-gateway-spring-boot-starter</artifactId>
+        </dependency>
+        <!-- 开启swagger-ui -->
+        <!--<dependency>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
+        </dependency>-->
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>io.fabric8</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+                <configuration>
+                    <skip>${docker.fabric.skip}</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antrun-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 48 - 0
blade-gateway/src/main/java/org/springblade/gateway/GateWayApplication.java

@@ -0,0 +1,48 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.gateway;
+
+import org.springblade.core.launch.BladeApplication;
+import org.springblade.core.launch.constant.AppConstant;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+/**
+ * 项目启动
+ *
+ * @author Chill
+ */
+@EnableScheduling
+@EnableDiscoveryClient
+@SpringBootApplication
+public class GateWayApplication {
+
+	public static void main(String[] args) {
+		BladeApplication.run(AppConstant.APPLICATION_GATEWAY_NAME, GateWayApplication.class, args);
+	}
+
+}

+ 53 - 0
blade-gateway/src/main/java/org/springblade/gateway/config/ErrorHandlerConfiguration.java

@@ -0,0 +1,53 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.gateway.config;
+
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springblade.gateway.handler.ErrorExceptionHandler;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 异常处理配置类
+ *
+ * @author Chill
+ */
+@Configuration(proxyBeanMethods = false)
+@AutoConfigureBefore(ErrorWebFluxAutoConfiguration.class)
+@EnableConfigurationProperties({ServerProperties.class})
+public class ErrorHandlerConfiguration {
+
+	@Bean
+	public ErrorExceptionHandler globalExceptionHandler(ObjectMapper objectMapper) {
+		return new ErrorExceptionHandler(objectMapper);
+	}
+
+}

+ 90 - 0
blade-gateway/src/main/java/org/springblade/gateway/config/RouterFunctionConfiguration.java

@@ -0,0 +1,90 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.gateway.config;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.gateway.props.AuthProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.web.cors.reactive.CorsUtils;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.WebFilter;
+import org.springframework.web.server.WebFilterChain;
+import reactor.core.publisher.Mono;
+
+/**
+ * 路由配置信息
+ *
+ * @author Chill
+ */
+@Slf4j
+@Configuration(proxyBeanMethods = false)
+@AllArgsConstructor
+@EnableConfigurationProperties({AuthProperties.class})
+public class RouterFunctionConfiguration {
+
+	/**
+	 * 这里为支持的请求头,如果有自定义的header字段请自己添加
+	 */
+	private static final String ALLOWED_HEADERS = "X-Requested-With, Tenant-Id, Blade-Auth, Content-Type, Authorization, credential, X-XSRF-TOKEN, token, username, client, knfie4j-gateway-request, knife4j-gateway-code, request-origion";
+	private static final String ALLOWED_METHODS = "GET,POST,PUT,DELETE,OPTIONS,HEAD";
+	private static final String ALLOWED_ORIGIN = "*";
+	private static final String ALLOWED_EXPOSE = "*";
+	private static final String MAX_AGE = "18000L";
+
+	/**
+	 * 跨域配置
+	 */
+	@Bean
+	public WebFilter corsFilter() {
+		return (ServerWebExchange ctx, WebFilterChain chain) -> {
+			ServerHttpRequest request = ctx.getRequest();
+			if (CorsUtils.isCorsRequest(request)) {
+				ServerHttpResponse response = ctx.getResponse();
+				HttpHeaders headers = response.getHeaders();
+				headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
+				headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
+				headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
+				headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE);
+				headers.add("Access-Control-Max-Age", MAX_AGE);
+				headers.add("Access-Control-Allow-Credentials", "true");
+				if (request.getMethod() == HttpMethod.OPTIONS) {
+					response.setStatusCode(HttpStatus.OK);
+					return Mono.empty();
+				}
+			}
+			return chain.filter(ctx);
+		};
+	}
+
+}

+ 117 - 0
blade-gateway/src/main/java/org/springblade/gateway/dynamic/DynamicRouteService.java

@@ -0,0 +1,117 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.gateway.dynamic;
+
+import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
+import org.springframework.cloud.gateway.route.RouteDefinition;
+import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.ApplicationEventPublisherAware;
+import org.springframework.stereotype.Service;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+
+/**
+ * 动态路由业务类
+ *
+ * @author Chill
+ */
+@Service
+public class DynamicRouteService implements ApplicationEventPublisherAware {
+
+	private final RouteDefinitionWriter routeDefinitionWriter;
+
+	private ApplicationEventPublisher publisher;
+
+	public DynamicRouteService(RouteDefinitionWriter routeDefinitionWriter) {
+		this.routeDefinitionWriter = routeDefinitionWriter;
+	}
+
+	@Override
+	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
+		this.publisher = applicationEventPublisher;
+	}
+
+	/**
+	 * 增加路由
+	 */
+	public String save(RouteDefinition definition) {
+		try {
+			routeDefinitionWriter.save(Mono.just(definition)).subscribe();
+			this.publisher.publishEvent(new RefreshRoutesEvent(this));
+			return "save success";
+		} catch (Exception e) {
+			e.printStackTrace();
+			return "save failure";
+		}
+	}
+
+	/**
+	 * 更新路由
+	 */
+	public String update(RouteDefinition definition) {
+		try {
+			this.routeDefinitionWriter.delete(Mono.just(definition.getId()));
+			this.routeDefinitionWriter.save(Mono.just(definition)).subscribe();
+			this.publisher.publishEvent(new RefreshRoutesEvent(this));
+			return "update success";
+		} catch (Exception e) {
+			e.printStackTrace();
+			return "update failure";
+		}
+	}
+
+	/**
+	 * 更新路由
+	 */
+	public String updateList(List<RouteDefinition> routeDefinitions) {
+		try {
+			if (!routeDefinitions.isEmpty()) {
+				routeDefinitions.forEach(this::update);
+			}
+			return "update done";
+		} catch (Exception e) {
+			e.printStackTrace();
+			return "update failure";
+		}
+	}
+
+	/**
+	 * 删除路由
+	 */
+	public String delete(String id) {
+		try {
+			this.routeDefinitionWriter.delete(Mono.just(id));
+			return "delete success";
+		} catch (Exception e) {
+			e.printStackTrace();
+			return "delete failure";
+		}
+	}
+
+
+}

+ 107 - 0
blade-gateway/src/main/java/org/springblade/gateway/dynamic/DynamicRouteServiceListener.java

@@ -0,0 +1,107 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.gateway.dynamic;
+
+import com.alibaba.cloud.nacos.NacosConfigProperties;
+import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.nacos.api.NacosFactory;
+import com.alibaba.nacos.api.PropertyKeyConst;
+import com.alibaba.nacos.api.config.ConfigService;
+import com.alibaba.nacos.api.config.listener.Listener;
+import com.alibaba.nacos.api.exception.NacosException;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.core.launch.constant.NacosConstant;
+import org.springblade.core.launch.props.BladeProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.cloud.gateway.route.RouteDefinition;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.Executor;
+
+/**
+ * 动态路由监听器
+ *
+ * @author Chill
+ */
+@Order
+@Slf4j
+@Component
+@RefreshScope
+public class DynamicRouteServiceListener {
+
+	private final DynamicRouteService dynamicRouteService;
+	private final NacosDiscoveryProperties nacosDiscoveryProperties;
+	private final NacosConfigProperties nacosConfigProperties;
+	private final BladeProperties bladeProperties;
+
+	public DynamicRouteServiceListener(DynamicRouteService dynamicRouteService, NacosDiscoveryProperties nacosDiscoveryProperties, NacosConfigProperties nacosConfigProperties, BladeProperties bladeProperties) {
+		this.dynamicRouteService = dynamicRouteService;
+		this.nacosDiscoveryProperties = nacosDiscoveryProperties;
+		this.nacosConfigProperties = nacosConfigProperties;
+		this.bladeProperties = bladeProperties;
+		dynamicRouteServiceListener();
+	}
+
+	/**
+	 * 监听Nacos下发的动态路由配置
+	 */
+	private void dynamicRouteServiceListener() {
+		try {
+			String dataId = NacosConstant.dataId(bladeProperties.getName(), bladeProperties.getEnv(), NacosConstant.NACOS_CONFIG_JSON_FORMAT);
+			String group = nacosConfigProperties.getGroup();
+			Properties properties = new Properties();
+			properties.setProperty(PropertyKeyConst.SERVER_ADDR, nacosDiscoveryProperties.getServerAddr());
+			properties.setProperty(PropertyKeyConst.NAMESPACE, nacosDiscoveryProperties.getNamespace());
+			properties.setProperty(PropertyKeyConst.USERNAME, nacosDiscoveryProperties.getUsername());
+			properties.setProperty(PropertyKeyConst.PASSWORD, nacosDiscoveryProperties.getPassword());
+			ConfigService configService = NacosFactory.createConfigService(properties);
+			configService.addListener(dataId, group, new Listener() {
+				@Override
+				public void receiveConfigInfo(String configInfo) {
+					List<RouteDefinition> routeDefinitions = JSON.parseArray(configInfo, RouteDefinition.class);
+					dynamicRouteService.updateList(routeDefinitions);
+				}
+
+				@Override
+				public Executor getExecutor() {
+					return null;
+				}
+			});
+			String configInfo = configService.getConfig(dataId, group, 5000);
+			if (configInfo != null) {
+				List<RouteDefinition> routeDefinitions = JSON.parseArray(configInfo, RouteDefinition.class);
+				dynamicRouteService.updateList(routeDefinitions);
+			}
+		} catch (NacosException ignored) {
+			ignored.printStackTrace();
+		}
+	}
+
+}

+ 50 - 0
blade-gateway/src/main/java/org/springblade/gateway/dynamic/GatewayFilter.java

@@ -0,0 +1,50 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.gateway.dynamic;
+
+import lombok.Data;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * 过滤器定义模型
+ *
+ * @author Chill
+ */
+@Data
+public class GatewayFilter {
+
+	/**
+	 * 过滤器对应的Name
+	 */
+	private String name;
+
+	/**
+	 * 对应的路由规则
+	 */
+	private Map<String, String> args = new LinkedHashMap<>();
+}

+ 50 - 0
blade-gateway/src/main/java/org/springblade/gateway/dynamic/GatewayPredicate.java

@@ -0,0 +1,50 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.gateway.dynamic;
+
+import lombok.Data;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * 路由断言定义模型
+ *
+ * @author Chill
+ */
+@Data
+public class GatewayPredicate {
+
+	/**
+	 * 断言对应的Name
+	 */
+	private String name;
+
+	/**
+	 * 配置的断言规则
+	 */
+	private Map<String, String> args = new LinkedHashMap<>();
+}

+ 66 - 0
blade-gateway/src/main/java/org/springblade/gateway/dynamic/GatewayRoute.java

@@ -0,0 +1,66 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.gateway.dynamic;
+
+
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Gateway的路由定义模型
+ *
+ * @author Chill
+ */
+@Data
+public class GatewayRoute {
+
+	/**
+	 * 路由的id
+	 */
+	private String id;
+
+	/**
+	 * 路由断言集合配置
+	 */
+	private List<GatewayPredicate> predicates = new ArrayList<>();
+
+	/**
+	 * 路由过滤器集合配置
+	 */
+	private List<GatewayFilter> filters = new ArrayList<>();
+
+	/**
+	 * 路由规则转发的目标uri
+	 */
+	private String uri;
+
+	/**
+	 * 路由执行的顺序
+	 */
+	private int order = 0;
+}

+ 139 - 0
blade-gateway/src/main/java/org/springblade/gateway/filter/AuthFilter.java

@@ -0,0 +1,139 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.gateway.filter;
+
+import com.alibaba.nacos.common.utils.StringUtils;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.jsonwebtoken.Claims;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.core.jwt.JwtCrypto;
+import org.springblade.core.jwt.JwtUtil;
+import org.springblade.core.jwt.props.JwtProperties;
+import org.springblade.core.launch.constant.TokenConstant;
+import org.springblade.core.launch.props.BladeProperties;
+import org.springblade.gateway.props.AuthProperties;
+import org.springblade.gateway.provider.AuthProvider;
+import org.springblade.gateway.provider.RequestProvider;
+import org.springblade.gateway.provider.ResponseProvider;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.core.Ordered;
+import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.util.AntPathMatcher;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.nio.charset.StandardCharsets;
+
+import static org.springblade.core.jwt.JwtCrypto.BLADE_TOKEN_CRYPTO_KEY;
+
+/**
+ * 鉴权认证
+ *
+ * @author Chill
+ */
+@Slf4j
+@Component
+@AllArgsConstructor
+public class AuthFilter implements GlobalFilter, Ordered {
+	private final AuthProperties authProperties;
+	private final ObjectMapper objectMapper;
+	private final JwtProperties jwtProperties;
+	private final BladeProperties bladeProperties;
+	private final AntPathMatcher antPathMatcher = new AntPathMatcher();
+
+	@Override
+	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+		//校验 Token 放行
+		String originalRequestUrl = RequestProvider.getOriginalRequestUrl(exchange);
+		String path = exchange.getRequest().getURI().getPath();
+		if (isSkip(path) || isSkip(originalRequestUrl)) {
+			return chain.filter(exchange);
+		}
+		//校验 Token 合法性
+		ServerHttpResponse resp = exchange.getResponse();
+		String headerToken = exchange.getRequest().getHeaders().getFirst(AuthProvider.AUTH_KEY);
+		String paramToken = exchange.getRequest().getQueryParams().getFirst(AuthProvider.AUTH_KEY);
+		if (StringUtils.isBlank(headerToken) && StringUtils.isBlank(paramToken)) {
+			return unAuth(resp, "缺失令牌,鉴权失败");
+		}
+		String auth = StringUtils.isBlank(headerToken) ? paramToken : headerToken;
+		String token = JwtUtil.getToken(auth);
+		//校验 加密Token 合法性
+		if (JwtUtil.isCrypto(auth)) {
+			token = JwtCrypto.decryptToString(token, bladeProperties.getEnvironment().getProperty(BLADE_TOKEN_CRYPTO_KEY));
+		}
+		Claims claims = JwtUtil.parseJWT(token);
+		if (token == null || claims == null) {
+			return unAuth(resp, "请求未授权");
+		}
+		//判断 Token 状态
+		if (jwtProperties.getState()) {
+			String tenantId = String.valueOf(claims.get(TokenConstant.TENANT_ID));
+			String clientId = String.valueOf(claims.get(TokenConstant.CLIENT_ID));
+			String userId = String.valueOf(claims.get(TokenConstant.USER_ID));
+			String accessToken = JwtUtil.getAccessToken(tenantId, clientId, userId, token);
+			if (!token.equalsIgnoreCase(accessToken)) {
+				return unAuth(resp, "令牌已失效");
+			}
+		}
+		return chain.filter(exchange);
+	}
+
+	private boolean isSkip(String path) {
+		return AuthProvider.getDefaultSkipUrl().stream().anyMatch(pattern -> antPathMatcher.match(pattern, path))
+			|| authProperties.getSkipUrl().stream().anyMatch(pattern -> antPathMatcher.match(pattern, path))
+ 			|| authProperties.getAuth().stream().anyMatch(auth -> antPathMatcher.match(auth.getPattern(), path))
+ 			|| authProperties.getBasic().stream().anyMatch(basic -> antPathMatcher.match(basic.getPattern(), path))
+			|| authProperties.getSign().stream().anyMatch(sign -> antPathMatcher.match(sign.getPattern(), path));
+	}
+
+	private Mono<Void> unAuth(ServerHttpResponse resp, String msg) {
+		resp.setStatusCode(HttpStatus.UNAUTHORIZED);
+		resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
+		String result = "";
+		try {
+			result = objectMapper.writeValueAsString(ResponseProvider.unAuth(msg));
+		} catch (JsonProcessingException e) {
+			log.error(e.getMessage(), e);
+		}
+		DataBuffer buffer = resp.bufferFactory().wrap(result.getBytes(StandardCharsets.UTF_8));
+		return resp.writeWith(Flux.just(buffer));
+	}
+
+
+	@Override
+	public int getOrder() {
+		return -100;
+	}
+
+}

+ 121 - 0
blade-gateway/src/main/java/org/springblade/gateway/filter/GlobalRequestLogFilter.java

@@ -0,0 +1,121 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: DreamLu (596392912@qq.com)
+ */
+package org.springblade.gateway.filter;
+
+import com.alibaba.nacos.common.utils.StringUtils;
+import io.jsonwebtoken.Claims;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.core.jwt.JwtUtil;
+import org.springblade.gateway.provider.AuthProvider;
+import org.springblade.gateway.provider.RequestProvider;
+import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * webflux 日志请求记录,方便开发调试。请求日志过滤器排序尽量低。
+ *
+ * <p>
+ * 注意:暂时不支持结构体打印,想实现,请看下面的链接。
+ * https://stackoverflow.com/questions/45240005/how-to-log-request-and-response-bodies-in-spring-webflux
+ * https://github.com/Silvmike/webflux-demo/blob/master/tests/src/test/java/ru/hardcoders/demo/webflux/web_handler/filters/logging
+ * </p>
+ *
+ * @author dream.lu
+ */
+@Slf4j
+@Configuration(proxyBeanMethods = false)
+@RequiredArgsConstructor
+@ConditionalOnProperty(value = "blade.log.request.enabled", havingValue = "true", matchIfMissing = true)
+public class GlobalRequestLogFilter implements GlobalFilter, Ordered {
+	private final WebEndpointProperties endpointProperties;
+
+	@Override
+	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+		ServerHttpRequest request = exchange.getRequest();
+		// 打印请求路径
+		String path = request.getPath().pathWithinApplication().value();
+
+		// 忽略 endpoint 请求
+		String endpointBasePath = endpointProperties.getBasePath();
+		if (StringUtils.isNotBlank(endpointBasePath) && path.startsWith(endpointBasePath)) {
+			return chain.filter(exchange);
+		}
+
+		String requestUrl = RequestProvider.getOriginalRequestUrl(exchange);
+
+		// 构建成一条长 日志,避免并发下日志错乱
+		StringBuilder beforeReqLog = new StringBuilder(300);
+		// 日志参数
+		List<Object> beforeReqArgs = new ArrayList<>();
+		beforeReqLog.append("\n\n================ Gateway Request Start  ================\n");
+		// 打印路由
+		beforeReqLog.append("===> {}: {}\n");
+		// 参数
+		String requestMethod = request.getMethod().name();
+		beforeReqArgs.add(requestMethod);
+		beforeReqArgs.add(requestUrl);
+
+		// 打印请求头
+		HttpHeaders headers = request.getHeaders();
+		headers.forEach((headerName, headerValue) -> {
+			beforeReqLog.append("===Headers===  {}: {}\n");
+			beforeReqArgs.add(headerName);
+			if (AuthProvider.AUTH_KEY.toLowerCase().equals(headerName)) {
+				String value = headerValue.get(0);
+				String token = JwtUtil.getToken(value);
+				Claims claims = JwtUtil.parseJWT(token);
+				beforeReqArgs.add((claims == null) ? "" : claims.toString());
+				beforeReqLog.append("===Headers===  {}: {}\n");
+				beforeReqArgs.add(headerName.concat("-original"));
+				beforeReqArgs.add(headerValue.toArray());
+			} else {
+				beforeReqArgs.add(headerValue.toArray());
+			}
+		});
+
+		beforeReqLog.append("================  Gateway Request End  =================\n");
+		// 打印执行时间
+		log.info(beforeReqLog.toString(), beforeReqArgs.toArray());
+		return chain.filter(exchange);
+	}
+
+	@Override
+	public int getOrder() {
+		return Ordered.LOWEST_PRECEDENCE;
+	}
+}

+ 108 - 0
blade-gateway/src/main/java/org/springblade/gateway/filter/GlobalResponseLogFilter.java

@@ -0,0 +1,108 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: DreamLu (596392912@qq.com)
+ */
+package org.springblade.gateway.filter;
+
+import com.alibaba.nacos.common.utils.StringUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.util.UriComponentsBuilder;
+import reactor.core.publisher.Mono;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * webflux 相应日志,方便开发调试,注意排序要优先。
+ *
+ * @author dream.lu
+ */
+@Slf4j
+@Configuration(proxyBeanMethods = false)
+@RequiredArgsConstructor
+@ConditionalOnProperty(value = "blade.log.request.enabled", havingValue = "true", matchIfMissing = true)
+public class GlobalResponseLogFilter implements GlobalFilter, Ordered {
+	private final WebEndpointProperties endpointProperties;
+
+	@Override
+	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+		ServerHttpRequest request = exchange.getRequest();
+		// 打印请求路径
+		String path = request.getPath().pathWithinApplication().value();
+		// 忽略 endpoint 请求
+		String endpointBasePath = endpointProperties.getBasePath();
+		if (StringUtils.isNotBlank(endpointBasePath) && path.startsWith(endpointBasePath)) {
+			return chain.filter(exchange);
+		}
+		return chain.filter(exchange).then(
+			Mono.fromRunnable(() -> {
+				MultiValueMap<String, String> queryParams = request.getQueryParams();
+				String requestUrl = UriComponentsBuilder.fromPath(path).queryParams(queryParams).build().toUriString();
+
+				// 构建成一条长 日志,避免并发下日志错乱
+				StringBuilder responseLog = new StringBuilder(300);
+				// 日志参数
+				List<Object> responseArgs = new ArrayList<>();
+				responseLog.append("\n\n================ Gateway Response Start  ================\n");
+				ServerHttpResponse response = exchange.getResponse();
+				// 打印路由 200 get: /api/xxx/xxx
+				responseLog.append("<=== {} {}: {}\n");
+				// 参数
+				String requestMethod = request.getMethod().name();
+				responseArgs.add(response.getStatusCode().value());
+				responseArgs.add(requestMethod);
+				responseArgs.add(requestUrl);
+
+				// 打印请求头
+				HttpHeaders headers = response.getHeaders();
+				headers.forEach((headerName, headerValue) -> {
+					responseLog.append("===Headers===  {}: {}\n");
+					responseArgs.add(headerName);
+					responseArgs.add(headerValue.toArray());
+				});
+
+				responseLog.append("================  Gateway Response End  =================\n");
+				// 打印执行时间
+				log.info(responseLog.toString(), responseArgs.toArray());
+			})
+		);
+	}
+
+	@Override
+	public int getOrder() {
+		return Ordered.HIGHEST_PRECEDENCE;
+	}
+}

+ 63 - 0
blade-gateway/src/main/java/org/springblade/gateway/filter/RequestFilter.java

@@ -0,0 +1,63 @@
+package org.springblade.gateway.filter;
+
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.core.Ordered;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
+import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl;
+
+/**
+ * <p>
+ * 全局拦截器,作用所有的微服务
+ * <p>
+ * 1. 对请求头中参数进行处理 from 参数进行清洗
+ * 2. 重写StripPrefix = 1,支持全局
+ *
+ * @author lengleng
+ */
+@Component
+public class RequestFilter implements GlobalFilter, Ordered {
+
+	/**
+	 * Process the Web request and (optionally) delegate to the next
+	 * {@code WebFilter} through the given {@link GatewayFilterChain}.
+	 *
+	 * @param exchange the current server exchange
+	 * @param chain    provides a way to delegate to the next filter
+	 * @return {@code Mono<Void>} to indicate when request processing is complete
+	 */
+	@Override
+	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+		// 1. 清洗请求头中from 参数
+		ServerHttpRequest request = exchange.getRequest().mutate()
+			.headers(httpHeaders -> httpHeaders.remove("X"))
+			.build();
+
+		// 2. 重写StripPrefix
+		addOriginalRequestUrl(exchange, request.getURI());
+		String rawPath = request.getURI().getRawPath();
+		String newPath = "/" + Arrays.stream(StringUtils.tokenizeToStringArray(rawPath, "/"))
+			.skip(1L).collect(Collectors.joining("/"));
+		ServerHttpRequest newRequest = request.mutate()
+			.path(newPath)
+			.build();
+		exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, newRequest.getURI());
+
+		return chain.filter(exchange.mutate().request(newRequest.mutate().build()).build());
+	}
+
+	@Override
+	public int getOrder() {
+		return -1000;
+	}
+
+}

+ 101 - 0
blade-gateway/src/main/java/org/springblade/gateway/handler/ErrorExceptionHandler.java

@@ -0,0 +1,101 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.gateway.handler;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.RequiredArgsConstructor;
+import org.springblade.gateway.provider.ResponseProvider;
+import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
+import org.springframework.core.annotation.Order;
+import org.springframework.core.io.buffer.DataBufferFactory;
+import org.springframework.http.MediaType;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.web.server.ResponseStatusException;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.util.Map;
+
+/**
+ * 异常处理
+ *
+ * @author Chill
+ */
+@Order(-1)
+@RequiredArgsConstructor
+public class ErrorExceptionHandler implements ErrorWebExceptionHandler {
+
+	private final ObjectMapper objectMapper;
+
+	@Override
+	public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
+		ServerHttpRequest request = exchange.getRequest();
+		ServerHttpResponse response = exchange.getResponse();
+
+		if (response.isCommitted()) {
+			return Mono.error(ex);
+		}
+
+		response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
+		if (ex instanceof ResponseStatusException) {
+			response.setStatusCode(((ResponseStatusException) ex).getStatusCode());
+		}
+
+		return response.writeWith(Mono.fromSupplier(() -> {
+			DataBufferFactory bufferFactory = response.bufferFactory();
+			try {
+				int status = 500;
+				if (response.getStatusCode() != null) {
+					status = response.getStatusCode().value();
+				}
+				Map<String, Object> result = ResponseProvider.response(status, this.buildMessage(request, ex));
+				return bufferFactory.wrap(objectMapper.writeValueAsBytes(result));
+			} catch (JsonProcessingException e) {
+				return bufferFactory.wrap(new byte[0]);
+			}
+		}));
+	}
+
+
+	/**
+	 * 构建异常信息
+	 */
+	private String buildMessage(ServerHttpRequest request, Throwable ex) {
+		StringBuilder message = new StringBuilder("Failed to handle request [");
+		message.append(request.getMethod().name());
+		message.append(" ");
+		message.append(request.getURI());
+		message.append("]");
+		if (ex != null) {
+			message.append(": ");
+			message.append(ex.getMessage());
+		}
+		return message.toString();
+	}
+
+}

+ 68 - 0
blade-gateway/src/main/java/org/springblade/gateway/props/AuthProperties.java

@@ -0,0 +1,68 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.gateway.props;
+
+import lombok.Data;
+import org.springblade.gateway.provider.AuthSecure;
+import org.springblade.gateway.provider.BasicSecure;
+import org.springblade.gateway.provider.SignSecure;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 权限过滤
+ *
+ * @author Chill
+ */
+@Data
+@RefreshScope
+@ConfigurationProperties("blade.secure")
+public class AuthProperties {
+
+	/**
+	 * 放行API集合
+	 */
+	private final List<String> skipUrl = new ArrayList<>();
+
+	/**
+	 * 自定义授权配置
+	 */
+	private final List<AuthSecure> auth = new ArrayList<>();
+
+	/**
+	 * 基础认证配置
+	 */
+	private final List<BasicSecure> basic = new ArrayList<>();
+
+	/**
+	 * 签名认证配置
+	 */
+	private final List<SignSecure> sign = new ArrayList<>();
+
+}

+ 70 - 0
blade-gateway/src/main/java/org/springblade/gateway/provider/AuthProvider.java

@@ -0,0 +1,70 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.gateway.provider;
+
+import org.springblade.core.launch.constant.TokenConstant;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 鉴权配置
+ *
+ * @author Chill
+ */
+public class AuthProvider {
+
+	public static final String AUTH_KEY = TokenConstant.AUTH_HEADER;
+	private static final List<String> DEFAULT_SKIP_URL = new ArrayList<>();
+
+	static {
+		DEFAULT_SKIP_URL.add("/example");
+		DEFAULT_SKIP_URL.add("/oauth/token/**");
+		DEFAULT_SKIP_URL.add("/oauth/captcha/**");
+		DEFAULT_SKIP_URL.add("/oauth/clear-cache/**");
+		DEFAULT_SKIP_URL.add("/oauth/user-info");
+		DEFAULT_SKIP_URL.add("/oauth/render/**");
+		DEFAULT_SKIP_URL.add("/oauth/callback/**");
+		DEFAULT_SKIP_URL.add("/oauth/revoke/**");
+		DEFAULT_SKIP_URL.add("/oauth/refresh/**");
+		DEFAULT_SKIP_URL.add("/token/**");
+		DEFAULT_SKIP_URL.add("/actuator/**");
+		DEFAULT_SKIP_URL.add("/v3/api-docs/**");
+		DEFAULT_SKIP_URL.add("/tenant/info");
+		DEFAULT_SKIP_URL.add("/process/resource-view");
+		DEFAULT_SKIP_URL.add("/process/diagram-view");
+		DEFAULT_SKIP_URL.add("/manager/check-upload");
+		DEFAULT_SKIP_URL.add("/assets/**");
+	}
+
+	/**
+	 * 默认无需鉴权的API
+	 */
+	public static List<String> getDefaultSkipUrl() {
+		return DEFAULT_SKIP_URL;
+	}
+
+}

+ 46 - 0
blade-gateway/src/main/java/org/springblade/gateway/provider/AuthSecure.java

@@ -0,0 +1,46 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.gateway.provider;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 自定义授权规则
+ *
+ * @author Chill
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class AuthSecure {
+	/**
+	 * 请求路径
+	 */
+	private String pattern;
+
+}

+ 46 - 0
blade-gateway/src/main/java/org/springblade/gateway/provider/BasicSecure.java

@@ -0,0 +1,46 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.gateway.provider;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 基础授权规则
+ *
+ * @author Chill
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class BasicSecure {
+	/**
+	 * 请求路径
+	 */
+	private String pattern;
+
+}

+ 58 - 0
blade-gateway/src/main/java/org/springblade/gateway/provider/RequestProvider.java

@@ -0,0 +1,58 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.gateway.provider;
+
+import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import java.net.URI;
+import java.util.LinkedHashSet;
+
+/**
+ * RequestProvider
+ *
+ * @author Chill
+ */
+public class RequestProvider {
+
+	/**
+	 * 获取原始url
+	 *
+	 * @param exchange
+	 * @return
+	 */
+	public static String getOriginalRequestUrl(ServerWebExchange exchange) {
+		ServerHttpRequest request = exchange.getRequest();
+		LinkedHashSet<URI> uris = exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
+		URI requestUri = uris.stream().findFirst().orElse(request.getURI());
+		MultiValueMap<String, String> queryParams = request.getQueryParams();
+		return UriComponentsBuilder.fromPath(requestUri.getRawPath()).queryParams(queryParams).build().toUriString();
+	}
+
+}

+ 93 - 0
blade-gateway/src/main/java/org/springblade/gateway/provider/ResponseProvider.java

@@ -0,0 +1,93 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.gateway.provider;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 请求响应返回
+ *
+ * @author Chill
+ */
+public class ResponseProvider {
+
+	/**
+	 * 成功
+	 *
+	 * @param message 信息
+	 * @return
+	 */
+	public static Map<String, Object> success(String message) {
+		return response(200, message);
+	}
+
+	/**
+	 * 失败
+	 *
+	 * @param message 信息
+	 * @return
+	 */
+	public static Map<String, Object> fail(String message) {
+		return response(400, message);
+	}
+
+	/**
+	 * 未授权
+	 *
+	 * @param message 信息
+	 * @return
+	 */
+	public static Map<String, Object> unAuth(String message) {
+		return response(401, message);
+	}
+
+	/**
+	 * 服务器异常
+	 *
+	 * @param message 信息
+	 * @return
+	 */
+	public static Map<String, Object> error(String message) {
+		return response(500, message);
+	}
+
+	/**
+	 * 构建返回的JSON数据格式
+	 *
+	 * @param status  状态码
+	 * @param message 信息
+	 * @return
+	 */
+	public static Map<String, Object> response(int status, String message) {
+		Map<String, Object> map = new HashMap<>(16);
+		map.put("code", status);
+		map.put("msg", message);
+		map.put("data", null);
+		return map;
+	}
+
+}

+ 46 - 0
blade-gateway/src/main/java/org/springblade/gateway/provider/SignSecure.java

@@ -0,0 +1,46 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.gateway.provider;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 签名授权规则
+ *
+ * @author Chill
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class SignSecure {
+	/**
+	 * 请求路径
+	 */
+	private String pattern;
+
+}

+ 11 - 0
blade-gateway/src/main/resources/application-dev.yml

@@ -0,0 +1,11 @@
+blade:
+  #多团队协作服务配置
+  loadbalancer:
+    #开启配置
+    enabled: true
+    #灰度版本
+    #version: 3.0.0
+    #负载均衡优先调用的ip段
+    prior-ip-pattern:
+      - 192.168.0.*
+      - 127.0.0.1

+ 16 - 0
blade-gateway/src/main/resources/application.yml

@@ -0,0 +1,16 @@
+knife4j:
+  gateway:
+    enabled: true
+    tags-sorter: order
+    operations-sorter: order
+    # 指定服务发现的模式聚合微服务文档,并且是默认`default`分组
+    strategy: discover
+    discover:
+      enabled: true
+      # 指定版本号(Swagger2|OpenAPI3)
+      version : openapi3
+      # 需要排除的微服务(eg:网关服务)
+      excluded-services:
+        - blade-admin
+        - blade-gateway
+        - blade-log

+ 12 - 0
blade-gateway/src/main/resources/bootstrap.yml

@@ -0,0 +1,12 @@
+server:
+  port: 80
+
+spring:
+  cloud:
+    gateway:
+      discovery:
+        locator:
+          enabled: true
+    loadbalancer:
+      retry:
+        enabled: true

+ 16 - 0
blade-ops-api/blade-flow-api/pom.xml

@@ -0,0 +1,16 @@
+<?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>blade-ops-api</artifactId>
+        <groupId>org.springblade</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>blade-flow-api</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>jar</packaging>
+
+</project>

+ 70 - 0
blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/constant/ProcessConstant.java

@@ -0,0 +1,70 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.flow.core.constant;
+
+/**
+ * 流程常量.
+ *
+ * @author Chill
+ */
+public interface ProcessConstant {
+
+	/**
+	 * 请假流程标识
+	 */
+	String LEAVE_KEY = "Leave";
+
+	/**
+	 * 报销流程标识
+	 */
+	String EXPENSE_KEY = "Expense";
+
+	/**
+	 * 同意标识
+	 */
+	String PASS_KEY = "pass";
+
+	/**
+	 * 同意代号
+	 */
+	String PASS_ALIAS = "ok";
+
+	/**
+	 * 同意默认批复
+	 */
+	String PASS_COMMENT = "同意";
+
+	/**
+	 * 驳回默认批复
+	 */
+	String NOT_PASS_COMMENT = "驳回";
+
+	/**
+	 * 创建人变量名
+	 */
+	String TASK_VARIABLE_CREATE_USER = "createUser";
+
+}

+ 109 - 0
blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/feign/IFlowClient.java

@@ -0,0 +1,109 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.flow.core.feign;
+
+import org.springblade.core.launch.constant.AppConstant;
+import org.springblade.core.tool.api.R;
+import org.springblade.flow.core.pojo.entity.BladeFlow;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.Map;
+
+/**
+ * 工作流远程调用接口.
+ *
+ * @author Chill
+ */
+@FeignClient(
+	value = AppConstant.APPLICATION_FLOW_NAME,
+	fallback = IFlowClientFallback.class
+)
+public interface IFlowClient {
+
+	String API_PREFIX = "/feign/client/flow";
+	String START_PROCESS_INSTANCE_BY_ID = API_PREFIX + "/start-process-instance-by-id";
+	String START_PROCESS_INSTANCE_BY_KEY = API_PREFIX + "/start-process-instance-by-key";
+	String COMPLETE_TASK = API_PREFIX + "/complete-task";
+	String TASK_VARIABLE = API_PREFIX + "/task-variable";
+	String TASK_VARIABLES = API_PREFIX + "/task-variables";
+
+	/**
+	 * 开启流程
+	 *
+	 * @param processDefinitionId 流程id
+	 * @param businessKey         业务key
+	 * @param variables           参数
+	 * @return BladeFlow
+	 */
+	@PostMapping(START_PROCESS_INSTANCE_BY_ID)
+	R<BladeFlow> startProcessInstanceById(@RequestParam("processDefinitionId") String processDefinitionId, @RequestParam("businessKey") String businessKey, @RequestBody Map<String, Object> variables);
+
+	/**
+	 * 开启流程
+	 *
+	 * @param processDefinitionKey 流程标识
+	 * @param businessKey          业务key
+	 * @param variables            参数
+	 * @return BladeFlow
+	 */
+	@PostMapping(START_PROCESS_INSTANCE_BY_KEY)
+	R<BladeFlow> startProcessInstanceByKey(@RequestParam("processDefinitionKey") String processDefinitionKey, @RequestParam("businessKey") String businessKey, @RequestBody Map<String, Object> variables);
+
+	/**
+	 * 完成任务
+	 *
+	 * @param taskId            任务id
+	 * @param processInstanceId 流程实例id
+	 * @param comment           评论
+	 * @param variables         参数
+	 * @return R
+	 */
+	@PostMapping(COMPLETE_TASK)
+	R completeTask(@RequestParam("taskId") String taskId, @RequestParam("processInstanceId") String processInstanceId, @RequestParam("comment") String comment, @RequestBody Map<String, Object> variables);
+
+	/**
+	 * 获取流程变量
+	 *
+	 * @param taskId       任务id
+	 * @param variableName 变量名
+	 * @return R
+	 */
+	@GetMapping(TASK_VARIABLE)
+	R<Object> taskVariable(@RequestParam("taskId") String taskId, @RequestParam("variableName") String variableName);
+
+	/**
+	 * 获取流程变量集合
+	 *
+	 * @param taskId 任务id
+	 * @return R
+	 */
+	@GetMapping(TASK_VARIABLES)
+	R<Map<String, Object>> taskVariables(@RequestParam("taskId") String taskId);
+}

+ 67 - 0
blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/feign/IFlowClientFallback.java

@@ -0,0 +1,67 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.flow.core.feign;
+
+import org.springblade.core.tool.api.R;
+import org.springblade.flow.core.pojo.entity.BladeFlow;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * 流程远程调用失败处理类
+ *
+ * @author Chill
+ */
+@Component
+public class IFlowClientFallback implements IFlowClient {
+
+	@Override
+	public R<BladeFlow> startProcessInstanceById(String processDefinitionId, String businessKey, Map<String, Object> variables) {
+		return R.fail("远程调用失败");
+	}
+
+	@Override
+	public R<BladeFlow> startProcessInstanceByKey(String processDefinitionKey, String businessKey, Map<String, Object> variables) {
+		return R.fail("远程调用失败");
+	}
+
+	@Override
+	public R completeTask(String taskId, String processInstanceId, String comment, Map<String, Object> variables) {
+		return R.fail("远程调用失败");
+	}
+
+	@Override
+	public R<Object> taskVariable(String taskId, String variableName) {
+		return R.fail("远程调用失败");
+	}
+
+	@Override
+	public R<Map<String, Object>> taskVariables(String taskId) {
+		return R.fail("远程调用失败");
+	}
+
+}

+ 190 - 0
blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/pojo/entity/BladeFlow.java

@@ -0,0 +1,190 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.flow.core.pojo.entity;
+
+import lombok.Data;
+import org.springblade.flow.core.constant.ProcessConstant;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * 工作流通用实体类
+ *
+ * @author Chill
+ */
+@Data
+public class BladeFlow implements Serializable {
+	@Serial
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 任务编号
+	 */
+	private String taskId;
+	/**
+	 * 任务名称
+	 */
+	private String taskName;
+	/**
+	 * 任务定义Key
+	 */
+	private String taskDefinitionKey;
+	/**
+	 * 任务执行人编号
+	 */
+	private String assignee;
+	/**
+	 * 任务执行人名称
+	 */
+	private String assigneeName;
+	/**
+	 * 流程分类
+	 */
+	private String category;
+	/**
+	 * 流程分类名
+	 */
+	private String categoryName;
+	/**
+	 * 创建时间
+	 */
+	private Date createTime;
+	/**
+	 * 结束时间
+	 */
+	private Date endTime;
+	/**
+	 * 签收时间
+	 */
+	private Date claimTime;
+	/**
+	 * 历史任务结束时间
+	 */
+	private Date historyTaskEndTime;
+	/**
+	 * 执行ID
+	 */
+	private String executionId;
+	/**
+	 * 流程实例ID
+	 */
+	private String processInstanceId;
+	/**
+	 * 流程ID
+	 */
+	private String processDefinitionId;
+	/**
+	 * 流程标识
+	 */
+	private String processDefinitionKey;
+	/**
+	 * 流程名
+	 */
+	private String processDefinitionName;
+	/**
+	 * 流程版本
+	 */
+	private int processDefinitionVersion;
+	/**
+	 * 流程说明
+	 */
+	private String processDefinitionDesc;
+	/**
+	 * 流程简图名
+	 */
+	private String processDefinitionDiagramResName;
+	/**
+	 * 流程重命名
+	 */
+	private String processDefinitionResName;
+	/**
+	 * 历史任务流程实例ID 查看流程图会用到
+	 */
+	private String historyProcessInstanceId;
+	/**
+	 * 流程实例是否结束
+	 */
+	private String processIsFinished;
+	/**
+	 * 历史活动ID
+	 */
+	private String historyActivityId;
+	/**
+	 * 历史活动流程
+	 */
+	private String historyActivityName;
+	/**
+	 * 历史活动耗时
+	 */
+	private String historyActivityDurationTime;
+	/**
+	 * 业务绑定Table
+	 */
+	private String businessTable;
+	/**
+	 * 业务绑定ID
+	 */
+	private String businessId;
+	/**
+	 * 任务状态
+	 */
+	private String status;
+	/**
+	 * 任务意见
+	 */
+	private String comment;
+	/**
+	 * 是否通过
+	 */
+	private boolean isPass;
+	/**
+	 * 是否通过代号
+	 */
+	private String flag;
+	/**
+	 * 开始查询日期
+	 */
+	private Date beginDate;
+	/**
+	 * 结束查询日期
+	 */
+	private Date endDate;
+	/**
+	 * 流程参数
+	 */
+	private Map<String, Object> variables;
+
+	/**
+	 * 获取是否通过
+	 */
+	public boolean isPass() {
+		return ProcessConstant.PASS_ALIAS.equals(flag) || ProcessConstant.PASS_COMMENT.equals(comment);
+	}
+
+}

+ 52 - 0
blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/pojo/entity/FlowEntity.java

@@ -0,0 +1,52 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.flow.core.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.core.mp.base.BaseEntity;
+
+/**
+ * FlowEntity
+ *
+ * @author Chill
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FlowEntity extends BaseEntity {
+
+	@TableField(exist = false)
+	private BladeFlow flow;
+
+	public BladeFlow getFlow() {
+		if (flow == null) {
+			flow = new BladeFlow();
+		}
+		return flow;
+	}
+
+}

+ 54 - 0
blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/pojo/enums/FlowModeEnum.java

@@ -0,0 +1,54 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.flow.core.pojo.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 流程类型枚举
+ *
+ * @author Chill
+ */
+@Getter
+@AllArgsConstructor
+public enum FlowModeEnum {
+
+	/**
+	 * 通用流程
+	 */
+	COMMON("common", 1),
+
+	/**
+	 * 定制流程
+	 */
+	CUSTOM("custom", 2),
+	;
+
+	final String name;
+	final int mode;
+
+}

+ 75 - 0
blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/utils/FlowUtil.java

@@ -0,0 +1,75 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.flow.core.utils;
+
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.flow.core.constant.ProcessConstant;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 工作流工具类
+ *
+ * @author Chill
+ */
+public class FlowUtil {
+
+	/**
+	 * 定义流程key对应的表名
+	 */
+	private final static Map<String, String> BUSINESS_TABLE = new HashMap<>();
+
+	static {
+		BUSINESS_TABLE.put(ProcessConstant.LEAVE_KEY, "blade_process_leave");
+	}
+
+	/**
+	 * 通过流程key获取业务表名
+	 *
+	 * @param key 流程key
+	 */
+	public static String getBusinessTable(String key) {
+		String businessTable = BUSINESS_TABLE.get(key);
+		if (Func.isEmpty(businessTable)) {
+			throw new RuntimeException("流程启动失败,未找到相关业务表");
+		}
+		return businessTable;
+	}
+
+	/**
+	 * 获取业务标识
+	 *
+	 * @param businessTable 业务表
+	 * @param businessId    业务表主键
+	 * @return businessKey
+	 */
+	public static String getBusinessKey(String businessTable, String businessId) {
+		return StringUtil.format("{}:{}", businessTable, businessId);
+	}
+
+}

+ 80 - 0
blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/utils/TaskUtil.java

@@ -0,0 +1,80 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.flow.core.utils;
+
+import org.springblade.core.secure.utils.AuthUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.StringUtil;
+
+import static org.springblade.core.launch.constant.FlowConstant.TASK_USR_PREFIX;
+
+/**
+ * 工作流任务工具类
+ *
+ * @author Chill
+ */
+public class TaskUtil {
+
+	/**
+	 * 获取任务用户格式
+	 *
+	 * @return taskUser
+	 */
+	public static String getTaskUser() {
+		return StringUtil.format("{}{}", TASK_USR_PREFIX, AuthUtil.getUserId());
+	}
+
+	/**
+	 * 获取任务用户格式
+	 *
+	 * @param userId 用户id
+	 * @return taskUser
+	 */
+	public static String getTaskUser(String userId) {
+		return StringUtil.format("{}{}", TASK_USR_PREFIX, userId);
+	}
+
+
+	/**
+	 * 获取用户主键
+	 *
+	 * @param taskUser 任务用户
+	 * @return userId
+	 */
+	public static Long getUserId(String taskUser) {
+		return Func.toLong(StringUtil.removePrefix(taskUser, TASK_USR_PREFIX));
+	}
+
+	/**
+	 * 获取用户组格式
+	 *
+	 * @return candidateGroup
+	 */
+	public static String getCandidateGroup() {
+		return AuthUtil.getUserRole();
+	}
+
+}

+ 27 - 0
blade-ops-api/blade-resource-api/pom.xml

@@ -0,0 +1,27 @@
+<?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>blade-ops-api</artifactId>
+        <groupId>org.springblade</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>blade-resource-api</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-starter-sms</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-starter-tenant</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 83 - 0
blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/feign/ISmsClient.java

@@ -0,0 +1,83 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.resource.feign;
+
+import org.springblade.core.launch.constant.AppConstant;
+import org.springblade.core.sms.model.SmsResponse;
+import org.springblade.core.tool.api.R;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+/**
+ * ISmsClient
+ *
+ * @author Chill
+ */
+@FeignClient(
+	value = AppConstant.APPLICATION_RESOURCE_NAME,
+	fallback = ISmsClientFallback.class
+)
+public interface ISmsClient {
+	String API_PREFIX = "/feign/client/sms";
+	String SEND_MESSAGE = API_PREFIX + "/send-message";
+	String SEND_VALIDATE = API_PREFIX + "/send-validate";
+	String VALIDATE_MESSAGE = API_PREFIX + "/validate-message";
+
+	/**
+	 * 通用短信发送
+	 *
+	 * @param code   资源编号
+	 * @param params 模板参数
+	 * @param phones 手机号集合
+	 * @return R
+	 */
+	@PostMapping(SEND_MESSAGE)
+	R<SmsResponse> sendMessage(@RequestParam("code") String code, @RequestParam("params") String params, @RequestParam("phones") String phones);
+
+	/**
+	 * 短信验证码发送
+	 *
+	 * @param code  资源编号
+	 * @param phone 手机号
+	 * @return R
+	 */
+	@PostMapping(SEND_VALIDATE)
+	R sendValidate(@RequestParam("code") String code, @RequestParam("phone") String phone);
+
+	/**
+	 * 校验短信
+	 *
+	 * @param code  资源编号
+	 * @param id    校验id
+	 * @param value 校验值
+	 * @param phone 手机号
+	 * @return R
+	 */
+	@PostMapping(VALIDATE_MESSAGE)
+	R validateMessage(@RequestParam("code") String code, @RequestParam("id") String id, @RequestParam("value") String value, @RequestParam("phone") String phone);
+
+}

+ 53 - 0
blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/feign/ISmsClientFallback.java

@@ -0,0 +1,53 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.resource.feign;
+
+import org.springblade.core.tool.api.R;
+import org.springframework.stereotype.Component;
+
+/**
+ * 流程远程调用失败处理类
+ *
+ * @author Chill
+ */
+@Component
+public class ISmsClientFallback implements ISmsClient {
+	@Override
+	public R sendMessage(String code, String params, String phones) {
+		return R.fail("远程调用失败");
+	}
+
+	@Override
+	public R sendValidate(String code, String phone) {
+		return R.fail("远程调用失败");
+	}
+
+	@Override
+	public R validateMessage(String code, String id, String value, String phone) {
+		return R.fail("远程调用失败");
+	}
+
+}

+ 82 - 0
blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/pojo/entity/Attach.java

@@ -0,0 +1,82 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.resource.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.core.tenant.mp.TenantEntity;
+
+import java.io.Serial;
+
+/**
+ * 附件表实体类
+ *
+ * @author Chill
+ */
+@Data
+@TableName("blade_attach")
+@EqualsAndHashCode(callSuper = true)
+@Schema(description = "附件表")
+public class Attach extends TenantEntity {
+
+	@Serial
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 附件地址
+	 */
+	@Schema(description = "附件地址")
+	private String link;
+	/**
+	 * 附件域名
+	 */
+	@Schema(description = "附件域名")
+	private String domainUrl;
+	/**
+	 * 附件名称
+	 */
+	@Schema(description = "附件名称")
+	private String name;
+	/**
+	 * 附件原名
+	 */
+	@Schema(description = "附件原名")
+	private String originalName;
+	/**
+	 * 附件拓展名
+	 */
+	@Schema(description = "附件拓展名")
+	private String extension;
+	/**
+	 * 附件大小
+	 */
+	@Schema(description = "附件大小")
+	private Long attachSize;
+
+
+}

+ 104 - 0
blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/pojo/entity/Oss.java

@@ -0,0 +1,104 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.resource.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.core.tenant.mp.TenantEntity;
+
+import java.io.Serial;
+
+/**
+ * 实体类
+ *
+ * @author BladeX
+ */
+@Data
+@TableName("blade_oss")
+@EqualsAndHashCode(callSuper = true)
+@Schema(description = "Oss对象")
+public class Oss extends TenantEntity {
+
+	@Serial
+	private static final long serialVersionUID = 1L;
+	/**
+	 * 所属分类
+	 */
+	@Schema(description = "所属分类")
+	private Integer category;
+
+	/**
+	 * 资源编号
+	 */
+	@Schema(description = "资源编号")
+	private String ossCode;
+
+	/**
+	 * 资源地址
+	 */
+	@Schema(description = "资源地址")
+	private String endpoint;
+
+	/**
+	 * 外网资源地址
+	 */
+	@Schema(description = "外网资源地址")
+	private String transformEndpoint;
+	/**
+	 * accessKey
+	 */
+	@Schema(description = "accessKey")
+	private String accessKey;
+	/**
+	 * secretKey
+	 */
+	@Schema(description = "secretKey")
+	private String secretKey;
+	/**
+	 * 空间名
+	 */
+	@Schema(description = "空间名")
+	private String bucketName;
+	/**
+	 * 应用ID TencentCOS需要
+	 */
+	@Schema(description = "应用ID")
+	private String appId;
+	/**
+	 * 地域简称 TencentCOS需要
+	 */
+	@Schema(description = "地域简称")
+	private String region;
+	/**
+	 * 备注
+	 */
+	@Schema(description = "备注")
+	private String remark;
+
+
+}

+ 93 - 0
blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/pojo/entity/Sms.java

@@ -0,0 +1,93 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.resource.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.core.tenant.mp.TenantEntity;
+
+import java.io.Serial;
+
+/**
+ * 短信配置表实体类
+ *
+ * @author BladeX
+ */
+@Data
+@TableName("blade_sms")
+@EqualsAndHashCode(callSuper = true)
+@Schema(description = "短信配置表")
+public class Sms extends TenantEntity {
+
+	@Serial
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 资源编号
+	 */
+	@Schema(description = "资源编号")
+	private String smsCode;
+
+	/**
+	 * 模板ID
+	 */
+	@Schema(description = "模板ID")
+	private String templateId;
+	/**
+	 * 分类
+	 */
+	@Schema(description = "分类")
+	private Integer category;
+	/**
+	 * accessKey
+	 */
+	@Schema(description = "accessKey")
+	private String accessKey;
+	/**
+	 * secretKey
+	 */
+	@Schema(description = "secretKey")
+	private String secretKey;
+	/**
+	 * regionId
+	 */
+	@Schema(description = "regionId")
+	private String regionId;
+	/**
+	 * 短信签名
+	 */
+	@Schema(description = "短信签名")
+	private String signName;
+	/**
+	 * 备注
+	 */
+	@Schema(description = "备注")
+	private String remark;
+
+
+}

+ 71 - 0
blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/pojo/enums/SmsCodeEnum.java

@@ -0,0 +1,71 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.resource.pojo.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.springblade.core.tool.utils.StringPool;
+
+/**
+ * Sms资源编码枚举类
+ *
+ * @author Chill
+ * @apiNote 该枚举类对应短信配置模块的资源编码,可根据业务需求自行拓展
+ */
+@Getter
+@AllArgsConstructor
+public enum SmsCodeEnum {
+
+	/**
+	 * 默认编号
+	 */
+	DEFAULT(StringPool.EMPTY, 1),
+
+	/**
+	 * 验证码编号
+	 */
+	VALIDATE("validate", 2),
+
+	/**
+	 * 通知公告编号
+	 */
+	NOTICE("notice", 3),
+
+	/**
+	 * 下单通知编号
+	 */
+	ORDER("order", 4),
+
+	/**
+	 * 会议通知编号
+	 */
+	MEETING("meeting", 5),
+	;
+
+	final String name;
+	final int category;
+
+}

+ 47 - 0
blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/pojo/vo/AttachVO.java

@@ -0,0 +1,47 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.resource.pojo.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.resource.pojo.entity.Attach;
+
+import java.io.Serial;
+
+/**
+ * 附件表视图实体类
+ *
+ * @author Chill
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Schema(description = "附件表")
+public class AttachVO extends Attach {
+	@Serial
+	private static final long serialVersionUID = 1L;
+
+}

+ 32 - 0
blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/pojo/vo/OssVO.java

@@ -0,0 +1,32 @@
+package org.springblade.resource.pojo.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.resource.pojo.entity.Oss;
+
+import java.io.Serial;
+
+/**
+ * OssVO
+ *
+ * @author Chill
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Schema(description = "对象存储表")
+public class OssVO extends Oss {
+	@Serial
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 分类名
+	 */
+	private String categoryName;
+
+	/**
+	 * 是否启用
+	 */
+	private String statusName;
+
+}

+ 57 - 0
blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/pojo/vo/SmsVO.java

@@ -0,0 +1,57 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.resource.pojo.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.resource.pojo.entity.Sms;
+
+import java.io.Serial;
+
+/**
+ * 短信配置表视图实体类
+ *
+ * @author BladeX
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Schema(description = "短信配置表")
+public class SmsVO extends Sms {
+	@Serial
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 分类名
+	 */
+	private String categoryName;
+
+	/**
+	 * 是否启用
+	 */
+	private String statusName;
+
+}

+ 122 - 0
blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/utils/SmsUtil.java

@@ -0,0 +1,122 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.resource.utils;
+
+import org.springblade.core.sms.model.SmsCode;
+import org.springblade.core.sms.model.SmsResponse;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.jackson.JsonUtil;
+import org.springblade.core.tool.utils.RandomType;
+import org.springblade.core.tool.utils.SpringUtil;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.resource.feign.ISmsClient;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 短信服务工具类
+ *
+ * @author Chill
+ */
+public class SmsUtil {
+
+	public static final String PARAM_KEY = "code";
+	public static final String SEND_SUCCESS = "短信发送成功";
+	public static final String SEND_FAIL = "短信发送失败";
+	public static final String VALIDATE_SUCCESS = "短信校验成功";
+	public static final String VALIDATE_FAIL = "短信校验失败";
+
+	private static ISmsClient smsClient;
+
+	/**
+	 * 获取短信服务构建类
+	 *
+	 * @return SmsBuilder
+	 */
+	public static ISmsClient getSmsClient() {
+		if (smsClient == null) {
+			smsClient = SpringUtil.getBean(ISmsClient.class);
+		}
+		return smsClient;
+	}
+
+	/**
+	 * 获取短信验证码参数
+	 *
+	 * @return 验证码参数
+	 */
+	public static Map<String, String> getValidateParams() {
+		Map<String, String> params = new HashMap<>(1);
+		params.put(PARAM_KEY, StringUtil.random(6, RandomType.INT));
+		return params;
+	}
+
+	/**
+	 * 发送短信
+	 *
+	 * @param code   资源编号
+	 * @param params 模板参数
+	 * @param phones 手机号集合
+	 * @return 发送结果
+	 */
+	public static SmsResponse sendMessage(String code, Map<String, String> params, String phones) {
+		R<SmsResponse> result = getSmsClient().sendMessage(code, JsonUtil.toJson(params), phones);
+		return result.getData();
+	}
+
+	/**
+	 * 发送验证码
+	 *
+	 * @param code  资源编号
+	 * @param phone 手机号
+	 * @return 发送结果
+	 */
+	public static SmsCode sendValidate(String code, String phone) {
+		SmsCode smsCode = new SmsCode();
+		R result = getSmsClient().sendValidate(code, phone);
+		if (result.isSuccess()) {
+			smsCode = JsonUtil.parse(JsonUtil.toJson(result.getData()), SmsCode.class);
+		} else {
+			smsCode.setSuccess(Boolean.FALSE);
+		}
+		return smsCode;
+	}
+
+	/**
+	 * 校验短信
+	 *
+	 * @param code  资源编号
+	 * @param id    校验id
+	 * @param value 校验值
+	 * @return 发送结果
+	 */
+	public static boolean validateMessage(String code, String id, String value, String phone) {
+		R result = getSmsClient().validateMessage(code, id, value, phone);
+		return result.isSuccess();
+	}
+
+}

+ 51 - 0
blade-ops-api/pom.xml

@@ -0,0 +1,51 @@
+<?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>BladeX</artifactId>
+        <groupId>org.springblade</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>blade-ops-api</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>pom</packaging>
+    <description>BladeX 微服务API集合</description>
+
+    <modules>
+        <module>blade-flow-api</module>
+        <module>blade-resource-api</module>
+    </modules>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-starter-mybatis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-openfeign</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-auto</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                    <finalName>${project.name}</finalName>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 15 - 0
blade-ops/blade-admin/Dockerfile

@@ -0,0 +1,15 @@
+FROM bladex/alpine-java:openjdk17_cn_slim
+
+LABEL maintainer="bladejava@qq.com"
+
+RUN mkdir -p /blade/admin
+
+WORKDIR /blade/admin
+
+EXPOSE 7002
+
+COPY ./target/blade-admin.jar ./app.jar
+
+ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
+
+CMD ["--spring.profiles.active=test"]

+ 109 - 0
blade-ops/blade-admin/pom.xml

@@ -0,0 +1,109 @@
+<?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>blade-ops</artifactId>
+        <groupId>org.springblade</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>blade-admin</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <!--Blade-->
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-common</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springblade</groupId>
+                    <artifactId>blade-core-launch</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-launch</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-web</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-undertow</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-starter-prometheus</artifactId>
+        </dependency>
+        <!-- Nacos -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.alibaba.nacos</groupId>
+                    <artifactId>nacos-client</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.alibaba.nacos</groupId>
+                    <artifactId>nacos-client</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.nacos</groupId>
+            <artifactId>nacos-client</artifactId>
+        </dependency>
+        <!--Admin-Server-->
+        <dependency>
+            <groupId>de.codecentric</groupId>
+            <artifactId>spring-boot-admin-starter-server</artifactId>
+        </dependency>
+        <!--Security-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+        <!--<dependency>
+            <groupId>org.springframework.security.oauth.boot</groupId>
+            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
+        </dependency>-->
+        <!--Taobao-Sdk-->
+        <dependency>
+            <groupId>com.taobao</groupId>
+            <artifactId>taobao-sdk</artifactId>
+            <version>20201116</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>io.fabric8</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+                <configuration>
+                    <skip>${docker.fabric.skip}</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antrun-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 48 - 0
blade-ops/blade-admin/src/main/java/org/springblade/admin/AdminApplication.java

@@ -0,0 +1,48 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.admin;
+
+import de.codecentric.boot.admin.server.config.EnableAdminServer;
+import org.springblade.core.launch.BladeApplication;
+import org.springblade.core.launch.constant.AppConstant;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+
+/**
+ * admin启动器
+ *
+ * @author Chill
+ */
+@EnableAdminServer
+@EnableDiscoveryClient
+@SpringBootApplication
+public class AdminApplication {
+
+	public static void main(String[] args) {
+		BladeApplication.run(AppConstant.APPLICATION_ADMIN_NAME, AdminApplication.class, args);
+	}
+
+}

+ 41 - 0
blade-ops/blade-admin/src/main/java/org/springblade/admin/config/AdminConfiguration.java

@@ -0,0 +1,41 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.admin.config;
+
+import org.springblade.admin.dingtalk.MonitorProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 启动器
+ *
+ * @author Chill
+ */
+@Configuration(proxyBeanMethods = false)
+@EnableConfigurationProperties(MonitorProperties.class)
+public class AdminConfiguration {
+
+}

+ 61 - 0
blade-ops/blade-admin/src/main/java/org/springblade/admin/config/DingTalkConfiguration.java

@@ -0,0 +1,61 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: DreamLu (596392912@qq.com)
+ */
+package org.springblade.admin.config;
+
+import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
+import org.springblade.admin.dingtalk.DingTalkNotifier;
+import org.springblade.admin.dingtalk.DingTalkService;
+import org.springblade.admin.dingtalk.MonitorProperties;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.web.reactive.function.client.WebClient;
+
+/**
+ * 钉钉自动配置
+ *
+ * @author L.cm
+ */
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnProperty(value = "monitor.ding-talk.enabled", havingValue = "true")
+public class DingTalkConfiguration {
+
+	@Bean
+	public DingTalkService dingTalkService(MonitorProperties properties,
+										   WebClient.Builder builder) {
+		return new DingTalkService(properties, builder.build());
+	}
+
+	@Bean
+	public DingTalkNotifier dingTalkNotifier(MonitorProperties properties,
+											 DingTalkService dingTalkService,
+											 InstanceRepository repository,
+											 Environment environment) {
+		return new DingTalkNotifier(dingTalkService, properties, environment, repository);
+	}
+
+}

+ 96 - 0
blade-ops/blade-admin/src/main/java/org/springblade/admin/config/SecurityConfiguration.java

@@ -0,0 +1,96 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: DreamLu (596392912@qq.com)
+ */
+package org.springblade.admin.config;
+
+import de.codecentric.boot.admin.server.config.AdminServerProperties;
+import org.springblade.admin.security.InternalAuthorizationManager;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
+import org.springframework.security.config.web.server.ServerHttpSecurity;
+import org.springframework.security.web.server.SecurityWebFilterChain;
+import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler;
+
+import java.net.URI;
+
+/**
+ * 监控安全配置
+ *
+ * @author L.cm
+ */
+@EnableWebFluxSecurity
+@Configuration(proxyBeanMethods = false)
+@EnableConfigurationProperties(AdminServerProperties.class)
+public class SecurityConfiguration {
+	private final String contextPath;
+
+	public SecurityConfiguration(AdminServerProperties adminServerProperties) {
+		this.contextPath = adminServerProperties.getContextPath();
+	}
+
+	@Bean
+	public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
+		// @formatter:off
+		RedirectServerAuthenticationSuccessHandler successHandler = new RedirectServerAuthenticationSuccessHandler();
+		successHandler.setLocation(URI.create(contextPath + "/"));
+		return http
+			// 明确调用headers()方法进行配置
+			.headers(headers -> headers
+				// 禁用frameOptions
+				.frameOptions(ServerHttpSecurity.HeaderSpec.FrameOptionsSpec::disable)
+			)
+			// 配置授权规则
+			.authorizeExchange(exchanges -> exchanges
+				.pathMatchers(
+					contextPath + "/assets/**",
+					contextPath + "/login",
+					contextPath + "/v1/agent/**",
+					contextPath + "/v1/catalog/**",
+					contextPath + "/v1/health/**"
+				).permitAll()
+				.pathMatchers(contextPath + "/actuator", contextPath + "/actuator/**")
+				.access(new InternalAuthorizationManager())
+				.anyExchange().authenticated()
+			)
+			// 配置表单登录
+			.formLogin(formLogin -> formLogin
+				.loginPage(contextPath + "/login")
+				.authenticationSuccessHandler(successHandler)
+			)
+			// 配置登出
+			.logout(logout -> logout
+				.logoutUrl(contextPath + "/logout")
+			)
+			// 禁用HTTP Basic认证
+			.httpBasic(ServerHttpSecurity.HttpBasicSpec::disable)
+			// 禁用CSRF
+			.csrf(ServerHttpSecurity.CsrfSpec::disable)
+			.build();
+		// @formatter:on
+	}
+
+}

+ 114 - 0
blade-ops/blade-admin/src/main/java/org/springblade/admin/dingtalk/DingTalkNotifier.java

@@ -0,0 +1,114 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: DreamLu (596392912@qq.com)
+ */
+package org.springblade.admin.dingtalk;
+
+import de.codecentric.boot.admin.server.domain.entities.Instance;
+import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
+import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
+import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent;
+import de.codecentric.boot.admin.server.domain.values.Registration;
+import de.codecentric.boot.admin.server.domain.values.StatusInfo;
+import de.codecentric.boot.admin.server.notify.AbstractEventNotifier;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.env.Environment;
+import org.springframework.lang.NonNull;
+import reactor.core.publisher.Mono;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * 服务上下线告警
+ *
+ * <p>
+ * 注意:AbstractStatusChangeNotifier 这个事件有毛病
+ * </p>
+ *
+ * @author L.cm
+ */
+@Slf4j
+public class DingTalkNotifier extends AbstractEventNotifier {
+	private final DingTalkService dingTalkService;
+	private final MonitorProperties properties;
+	private final Environment environment;
+	public static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+	public DingTalkNotifier(DingTalkService dingTalkService, MonitorProperties properties,
+							Environment environment, InstanceRepository repository) {
+		super(repository);
+		this.dingTalkService = dingTalkService;
+		this.properties = properties;
+		this.environment = environment;
+	}
+
+	@NonNull
+	@Override
+	protected Mono<Void> doNotify(@NonNull InstanceEvent event, @NonNull Instance instance) {
+		if (event instanceof InstanceStatusChangedEvent) {
+			// 构造请求结构
+			return createAndPushMsg(event, instance);
+		}
+		return Mono.empty();
+	}
+
+	private Mono<Void> createAndPushMsg(InstanceEvent event, Instance instance) {
+		Registration registration = instance.getRegistration();
+		// 服务名
+		String appName = registration.getName();
+		// 服务地址
+		String serviceUrl = registration.getServiceUrl();
+		StatusInfo status = instance.getStatusInfo();
+		// 时间
+		LocalDateTime localDateTime = LocalDateTime.ofInstant(event.getTimestamp(), ZoneId.systemDefault());
+		MonitorProperties.DingTalk dingTalk = properties.getDingTalk();
+		String title = dingTalk.getService().getTitle();
+
+		String message = "## **" + title + "**\n" +
+			"#### **【服务】** " + appName + "\n" +
+			"#### **【环境】** " + environment.getActiveProfiles()[0] + "\n" +
+			"#### **【地址】** " + serviceUrl + "\n" +
+			"#### **【状态】** " + statusCn(status) + "\n" +
+			"#### **【时间】** " + DATETIME_FORMATTER.format(localDateTime) + "\n" +
+			"#### **【详情】** " + dingTalk.getLink() + "\n";
+
+		return dingTalkService.pushMsg(title, message);
+	}
+
+	private String statusCn(StatusInfo status) {
+		if (status.isUp()) {
+			return "应用上线(IS UP)";
+		} else if (status.isDown()) {
+			return "应用宕机(IS DOWN)";
+		} else if (status.isOffline()) {
+			return "应用掉线(IS OFFLINE)";
+		} else if (status.isUnknown()) {
+			return "未知状态(UNKNOWN)";
+		} else {
+			return "异常状态";
+		}
+	}
+}

+ 119 - 0
blade-ops/blade-admin/src/main/java/org/springblade/admin/dingtalk/DingTalkService.java

@@ -0,0 +1,119 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: DreamLu (596392912@qq.com)
+ */
+package org.springblade.admin.dingtalk;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.MediaType;
+import org.springframework.util.Base64Utils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.reactive.function.BodyInserters;
+import org.springframework.web.reactive.function.client.WebClient;
+import org.springframework.web.util.UriUtils;
+import reactor.core.publisher.Mono;
+
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 钉钉 服务
+ *
+ * @author L.cm
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class DingTalkService {
+	private static final String DING_TALK_ROBOT_URL = "https://oapi.dingtalk.com/robot/send?access_token=";
+	private final MonitorProperties properties;
+	private final WebClient webClient;
+
+	/**
+	 * 发送消息
+	 *
+	 * @param title title
+	 * @param text  消息
+	 */
+	public Mono<Void> pushMsg(String title, String text) {
+		log.info("钉钉消息:[创建消息体]title:{}, text:{}", title, text);
+
+		HashMap<String, String> params = new HashMap<>(2);
+		params.put("title", title);
+		params.put("text", text);
+
+		Map<String, Object> body = new HashMap<>(2);
+		body.put("msgtype", "markdown");
+		body.put("markdown", params);
+		log.info("创建消息体 json:{}", body);
+
+		MonitorProperties.DingTalk dingTalk = properties.getDingTalk();
+		String accessToken = dingTalk.getAccessToken();
+		if (!StringUtils.hasText(accessToken)) {
+			log.error("DingTalk alert config accessToken ${monitor.ding-talk.access-token} is blank.");
+			return Mono.empty();
+		}
+
+		String urlString = DING_TALK_ROBOT_URL + dingTalk.getAccessToken();
+		// 有私钥要签名
+		String secret = dingTalk.getSecret();
+		if (StringUtils.hasText(secret)) {
+			long timestamp = System.currentTimeMillis();
+			urlString += String.format("&timestamp=%s&sign=%s", timestamp, getSign(secret, timestamp));
+		}
+		return webClient.post()
+			.uri(URI.create(urlString))
+			.contentType(MediaType.APPLICATION_JSON)
+			.body(BodyInserters.fromValue(body))
+			.retrieve()
+			.bodyToMono(String.class)
+			.doOnSuccess((result) -> log.info("钉钉消息:[消息返回]result:{}", result))
+			.then();
+	}
+
+	private static String getSign(String secret, long timestamp) {
+		String stringToSign = timestamp + "\n" + secret;
+		byte[] hmacSha256Bytes = digestHmac(stringToSign, secret);
+		return UriUtils.encode(Base64Utils.encodeToString(hmacSha256Bytes), StandardCharsets.UTF_8);
+	}
+
+	public static byte[] digestHmac(String data, String key) {
+		SecretKey secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
+		try {
+			Mac mac = Mac.getInstance(secretKey.getAlgorithm());
+			mac.init(secretKey);
+			return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
+		} catch (NoSuchAlgorithmException | InvalidKeyException e) {
+			throw new RuntimeException(e.getMessage());
+		}
+	}
+
+}

+ 76 - 0
blade-ops/blade-admin/src/main/java/org/springblade/admin/dingtalk/MonitorProperties.java

@@ -0,0 +1,76 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: DreamLu (596392912@qq.com)
+ */
+package org.springblade.admin.dingtalk;
+
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+
+/**
+ * 监控配置
+ *
+ * @author L.cm
+ */
+@Getter
+@Setter
+@RefreshScope
+@ConfigurationProperties("monitor")
+public class MonitorProperties {
+	private DingTalk dingTalk = new DingTalk();
+
+	@Getter
+	@Setter
+	public static class DingTalk {
+		/**
+		 * 启用钉钉告警,默认为 true
+		 */
+		private boolean enabled = false;
+		/**
+		 * 钉钉机器人 token
+		 */
+		private String accessToken;
+		/**
+		 * 签名:如果有 secret 则进行签名,兼容老接口
+		 */
+		private String secret;
+		/**
+		 * 地址配置
+		 */
+		private String link;
+		private Service service = new Service();
+	}
+
+	@Getter
+	@Setter
+	public static class Service {
+		/**
+		 * 服务 状态 title
+		 */
+		private String title = "服务状态通知";
+	}
+}

+ 84 - 0
blade-ops/blade-admin/src/main/java/org/springblade/admin/security/InternalAuthorizationManager.java

@@ -0,0 +1,84 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: DreamLu (596392912@qq.com)
+ */
+package org.springblade.admin.security;
+
+import org.springblade.core.launch.utils.INetUtil;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.security.authorization.AuthorizationDecision;
+import org.springframework.security.authorization.ReactiveAuthorizationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.server.authorization.AuthorizationContext;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.net.InetSocketAddress;
+import java.util.Optional;
+
+/**
+ * 内网认证管理,内网放行,外网认证
+ *
+ * @author L.cm
+ */
+public class InternalAuthorizationManager implements ReactiveAuthorizationManager<AuthorizationContext> {
+	private static final String HEADER_X_FORWARDED_FOR = "X-Forwarded-For";
+
+	@Override
+	public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, AuthorizationContext context) {
+		return Mono.just(getAuthorizationDecision(context));
+	}
+
+	private static AuthorizationDecision getAuthorizationDecision(AuthorizationContext context) {
+		return new AuthorizationDecision(isInternalNet(context));
+	}
+
+	/**
+	 * 判断是否内网 ip 请求
+	 *
+	 * @param context AuthorizationContext
+	 * @return 是否内网 ip
+	 */
+	private static boolean isInternalNet(AuthorizationContext context) {
+		ServerHttpRequest request = Optional.ofNullable(context)
+			.map(AuthorizationContext::getExchange)
+			.map(ServerWebExchange::getRequest)
+			.orElse(null);
+		if (request == null) {
+			return false;
+		}
+		HttpHeaders headers = request.getHeaders();
+		// 如果没有 X-Forwarded-For 代表为 admin 拉取
+		if (!headers.containsKey(HEADER_X_FORWARDED_FOR)) {
+			return true;
+		}
+		return Optional.of(request)
+			.map(ServerHttpRequest::getRemoteAddress)
+			.map(InetSocketAddress::getAddress)
+			.map(INetUtil::isInternalIp)
+			.orElse(false);
+	}
+
+}

+ 48 - 0
blade-ops/blade-admin/src/main/resources/bootstrap.yml

@@ -0,0 +1,48 @@
+server:
+  port: 7002
+  undertow:
+    threads:
+      # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
+      io: 16
+      # 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
+      worker: 400
+    # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
+    buffer-size: 1024
+    # 是否分配的直接内存
+    direct-buffers: true
+
+spring:
+  boot:
+    admin:
+      # 忽略服务名
+      discovery:
+        ignored-services:
+          - consul
+          - serverAddr
+      # 自定义UI界面
+      ui:
+        title: BladeX Monitor
+        external-views:
+          - label: 架构官网
+            url: https://bladex.cn/
+            order: 1
+            iframe: true
+      # 用于内网安全,判断 admin proxy
+      instance-proxy:
+        ignored-headers: "X-Forwarded-For"
+  # 自定义登录用户名密码
+  security:
+    user:
+      name: blade
+      password: blade
+
+# 监控的相关配置
+monitor:
+  ding-talk:
+    enabled: false
+    # 用于自定义域名,默认会自动填充为 http://ip:port
+    link: http://localhost:${server.port}
+    # 钉钉配置的令牌
+    access-token: xxx
+    # 如果采用密钥形式,需要添加,否则需要去掉该参数
+    secret:

+ 51 - 0
blade-ops/blade-develop/pom.xml

@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+<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>org.springblade</groupId>
+        <artifactId>blade-ops</artifactId>
+        <version>${revision}</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>blade-develop</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <!--Blade-->
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-boot</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-starter-develop</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-starter-swagger</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-dict-api</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antrun-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 45 - 0
blade-ops/blade-develop/src/main/java/org/springblade/develop/DevelopApplication.java

@@ -0,0 +1,45 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.develop;
+
+import org.springblade.core.cloud.client.BladeCloudApplication;
+import org.springblade.core.launch.BladeApplication;
+import org.springblade.core.launch.constant.AppConstant;
+
+/**
+ * Develop启动器
+ *
+ * @author Chill
+ */
+@BladeCloudApplication
+public class DevelopApplication {
+
+	public static void main(String[] args) {
+		BladeApplication.run(AppConstant.APPLICATION_DEVELOP_NAME, DevelopApplication.class, args);
+	}
+
+}
+

+ 204 - 0
blade-ops/blade-develop/src/main/java/org/springblade/develop/controller/CodeController.java

@@ -0,0 +1,204 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.develop.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.validation.Valid;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.secure.annotation.PreAuth;
+import org.springblade.core.tenant.annotation.NonDS;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.constant.RoleConstant;
+import org.springblade.core.tool.jackson.JsonUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.develop.constant.DevelopConstant;
+import org.springblade.develop.pojo.entity.Code;
+import org.springblade.develop.pojo.entity.Datasource;
+import org.springblade.develop.pojo.entity.Model;
+import org.springblade.develop.pojo.entity.ModelPrototype;
+import org.springblade.develop.service.ICodeService;
+import org.springblade.develop.service.IDatasourceService;
+import org.springblade.develop.service.IModelPrototypeService;
+import org.springblade.develop.service.IModelService;
+import org.springblade.develop.support.BladeCodeGenerator;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 控制器
+ *
+ * @author Chill
+ */
+@NonDS
+@RestController
+@AllArgsConstructor
+@RequestMapping("/code")
+@Tag(name = "代码生成", description = "代码生成")
+@PreAuth(RoleConstant.HAS_ROLE_ADMINISTRATOR)
+public class CodeController extends BladeController {
+
+	private final ICodeService codeService;
+	private final IDatasourceService datasourceService;
+	private final IModelService modelService;
+	private final IModelPrototypeService modelPrototypeService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperationSupport(order = 1)
+	@Operation(summary = "详情", description = "传入code")
+	public R<Code> detail(Code code) {
+		Code detail = codeService.getOne(Condition.getQueryWrapper(code));
+		return R.data(detail);
+	}
+
+	/**
+	 * 分页
+	 */
+	@GetMapping("/list")
+	@Parameters({
+		@Parameter(name = "codeName", description = "模块名", in = ParameterIn.QUERY, schema = @Schema(type = "string")),
+		@Parameter(name = "tableName", description = "表名", in = ParameterIn.QUERY, schema = @Schema(type = "string")),
+		@Parameter(name = "modelName", description = "实体名", in = ParameterIn.QUERY, schema = @Schema(type = "string"))
+	})
+	@ApiOperationSupport(order = 2)
+	@Operation(summary = "分页", description = "传入code")
+	public R<IPage<Code>> list(@Parameter(hidden = true) @RequestParam Map<String, Object> code, Query query) {
+		IPage<Code> pages = codeService.page(Condition.getPage(query), Condition.getQueryWrapper(code, Code.class));
+		return R.data(pages);
+	}
+
+	/**
+	 * 新增或修改
+	 */
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 3)
+	@Operation(summary = "新增或修改", description = "传入code")
+	public R submit(@Valid @RequestBody Code code) {
+		return R.status(codeService.submit(code));
+	}
+
+
+	/**
+	 * 删除
+	 */
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 4)
+	@Operation(summary = "删除", description = "传入ids")
+	public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(codeService.removeByIds(Func.toLongList(ids)));
+	}
+
+	/**
+	 * 复制
+	 */
+	@PostMapping("/copy")
+	@ApiOperationSupport(order = 5)
+	@Operation(summary = "复制", description = "传入id")
+	public R copy(@Parameter(description = "主键", required = true) @RequestParam Long id) {
+		Code code = codeService.getById(id);
+		code.setId(null);
+		code.setCodeName(code.getCodeName() + "-copy");
+		return R.status(codeService.save(code));
+	}
+
+	/**
+	 * 代码生成
+	 */
+	@PostMapping("/gen-code")
+	@ApiOperationSupport(order = 6)
+	@Operation(summary = "代码生成", description = "传入ids")
+	public R genCode(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
+		Collection<Code> codes = codeService.listByIds(Func.toLongList(ids));
+		codes.forEach(code -> {
+			BladeCodeGenerator generator = new BladeCodeGenerator();
+			// 设置基础模型
+			Model model = modelService.getById(code.getModelId());
+			generator.setModelCode(model.getModelCode());
+			generator.setModelClass(model.getModelClass());
+			// 设置模型集合
+			List<ModelPrototype> prototypes = modelPrototypeService.prototypeList(model.getId());
+			generator.setModel(JsonUtil.readMap(JsonUtil.toJson(model)));
+			generator.setPrototypes(JsonUtil.readListMap(JsonUtil.toJson(prototypes)));
+			if (StringUtil.isNotBlank(code.getSubModelId()) && StringUtil.equals(code.getTemplateType(), DevelopConstant.TEMPLATE_SUB)) {
+				Model subModel = modelService.getById(Func.toLong(code.getSubModelId()));
+				List<ModelPrototype> subPrototypes = modelPrototypeService.prototypeList(subModel.getId());
+				generator.setSubModel(JsonUtil.readMap(JsonUtil.toJson(subModel)));
+				generator.setSubPrototypes(JsonUtil.readListMap(JsonUtil.toJson(subPrototypes)));
+			}
+			// 设置数据源
+			Datasource datasource = datasourceService.getById(model.getDatasourceId());
+			generator.setDriverName(datasource.getDriverClass());
+			generator.setUrl(datasource.getUrl());
+			generator.setUsername(datasource.getUsername());
+			generator.setPassword(datasource.getPassword());
+			// 设置基础配置
+			generator.setCodeStyle(code.getCodeStyle());
+			generator.setCodeName(code.getCodeName());
+			generator.setServiceName(code.getServiceName());
+			generator.setPackageName(code.getPackageName());
+			generator.setPackageDir(code.getApiPath());
+			generator.setPackageWebDir(code.getWebPath());
+			generator.setTablePrefix(Func.toStrArray(code.getTablePrefix()));
+			generator.setIncludeTables(Func.toStrArray(code.getTableName()));
+			// 设置模版信息
+			generator.setTemplateType(code.getTemplateType());
+			generator.setAuthor(code.getAuthor());
+			generator.setSubModelId(code.getSubModelId());
+			generator.setSubFkId(code.getSubFkId());
+			generator.setTreeId(code.getTreeId());
+			generator.setTreePid(code.getTreePid());
+			generator.setTreeName(code.getTreeName());
+			// 设置是否继承基础业务字段
+			generator.setHasSuperEntity(code.getBaseMode() == 2);
+			// 设置是否开启包装器模式
+			generator.setHasWrapper(code.getWrapMode() == 2);
+			// 设置是否开启远程调用模式
+			generator.setHasFeign(code.getFeignMode() == 2);
+			// 设置控制器服务名前缀
+			generator.setHasServiceName(Boolean.TRUE);
+			// 启动代码生成
+			generator.run();
+		});
+		return R.success("代码生成成功");
+	}
+
+}

+ 140 - 0
blade-ops/blade-develop/src/main/java/org/springblade/develop/controller/DatasourceController.java

@@ -0,0 +1,140 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.develop.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tenant.annotation.NonDS;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.develop.pojo.entity.Datasource;
+import org.springblade.develop.service.IDatasourceService;
+import org.springframework.web.bind.annotation.*;
+
+import jakarta.validation.Valid;
+import java.util.List;
+
+/**
+ * 数据源配置表 控制器
+ *
+ * @author Chill
+ */
+@NonDS
+@RestController
+@AllArgsConstructor
+@RequestMapping("/datasource")
+@Tag(name = "数据源配置表", description = "数据源配置表接口")
+public class DatasourceController extends BladeController {
+
+	private final IDatasourceService datasourceService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperationSupport(order = 1)
+	@Operation(summary = "详情", description = "传入datasource")
+	public R<Datasource> detail(Datasource datasource) {
+		Datasource detail = datasourceService.getOne(Condition.getQueryWrapper(datasource));
+		return R.data(detail);
+	}
+
+	/**
+	 * 分页 数据源配置表
+	 */
+	@GetMapping("/list")
+	@ApiOperationSupport(order = 2)
+	@Operation(summary = "分页", description = "传入datasource")
+	public R<IPage<Datasource>> list(Datasource datasource, Query query) {
+		IPage<Datasource> pages = datasourceService.page(Condition.getPage(query), Condition.getQueryWrapper(datasource));
+		return R.data(pages);
+	}
+
+	/**
+	 * 新增 数据源配置表
+	 */
+	@PostMapping("/save")
+	@ApiOperationSupport(order = 4)
+	@Operation(summary = "新增", description = "传入datasource")
+	public R save(@Valid @RequestBody Datasource datasource) {
+		return R.status(datasourceService.save(datasource));
+	}
+
+	/**
+	 * 修改 数据源配置表
+	 */
+	@PostMapping("/update")
+	@ApiOperationSupport(order = 5)
+	@Operation(summary = "修改", description = "传入datasource")
+	public R update(@Valid @RequestBody Datasource datasource) {
+		return R.status(datasourceService.updateById(datasource));
+	}
+
+	/**
+	 * 新增或修改 数据源配置表
+	 */
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 6)
+	@Operation(summary = "新增或修改", description = "传入datasource")
+	public R submit(@Valid @RequestBody Datasource datasource) {
+		if (StringUtil.isNotBlank(datasource.getUrl())) {
+			datasource.setUrl(datasource.getUrl().replace("&amp;", "&"));
+		}
+		return R.status(datasourceService.saveOrUpdate(datasource));
+	}
+
+
+	/**
+	 * 删除 数据源配置表
+	 */
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 7)
+	@Operation(summary = "逻辑删除", description = "传入ids")
+	public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(datasourceService.deleteLogic(Func.toLongList(ids)));
+	}
+
+	/**
+	 * 数据源列表
+	 */
+	@GetMapping("/select")
+	@ApiOperationSupport(order = 8)
+	@Operation(summary = "下拉数据源", description = "查询列表")
+	public R<List<Datasource>> select() {
+		List<Datasource> list = datasourceService.list();
+		return R.data(list);
+	}
+
+
+}

+ 259 - 0
blade-ops/blade-develop/src/main/java/org/springblade/develop/controller/ModelController.java

@@ -0,0 +1,259 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.develop.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
+import com.baomidou.mybatisplus.generator.config.StrategyConfig;
+import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.StringPool;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.develop.pojo.entity.Datasource;
+import org.springblade.develop.pojo.entity.Model;
+import org.springblade.develop.pojo.entity.ModelPrototype;
+import org.springblade.develop.service.IDatasourceService;
+import org.springblade.develop.service.IModelPrototypeService;
+import org.springblade.develop.service.IModelService;
+import org.springframework.web.bind.annotation.*;
+
+import jakarta.validation.Valid;
+import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 数据模型表 控制器
+ *
+ * @author Chill
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/model")
+@Tag(name = "数据模型表", description = "数据模型表接口")
+public class ModelController extends BladeController {
+
+	private final IModelService modelService;
+	private final IModelPrototypeService modelPrototypeService;
+	private final IDatasourceService datasourceService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperationSupport(order = 1)
+	@Operation(summary = "详情", description = "传入model")
+	public R<Model> detail(Model model) {
+		Model detail = modelService.getOne(Condition.getQueryWrapper(model));
+		return R.data(detail);
+	}
+
+	/**
+	 * 分页 数据模型表
+	 */
+	@GetMapping("/list")
+	@ApiOperationSupport(order = 2)
+	@Operation(summary = "分页", description = "传入model")
+	public R<IPage<Model>> list(Model model, Query query) {
+		IPage<Model> pages = modelService.page(Condition.getPage(query), Condition.getQueryWrapper(model));
+		return R.data(pages);
+	}
+
+	/**
+	 * 新增 数据模型表
+	 */
+	@PostMapping("/save")
+	@ApiOperationSupport(order = 3)
+	@Operation(summary = "新增", description = "传入model")
+	public R save(@Valid @RequestBody Model model) {
+		return R.status(modelService.save(model));
+	}
+
+	/**
+	 * 修改 数据模型表
+	 */
+	@PostMapping("/update")
+	@ApiOperationSupport(order = 4)
+	@Operation(summary = "修改", description = "传入model")
+	public R update(@Valid @RequestBody Model model) {
+		return R.status(modelService.updateById(model));
+	}
+
+	/**
+	 * 新增或修改 数据模型表
+	 */
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 5)
+	@Operation(summary = "新增或修改", description = "传入model")
+	public R submit(@Valid @RequestBody Model model) {
+		boolean temp = modelService.saveOrUpdate(model);
+		if (temp) {
+			return R.data(model);
+		} else {
+			return R.status(Boolean.FALSE);
+		}
+	}
+
+	/**
+	 * 删除 数据模型表
+	 */
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 6)
+	@Operation(summary = "逻辑删除", description = "传入ids")
+	public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(modelService.delete(Func.toLongList(ids)));
+	}
+
+	/**
+	 * 模型列表
+	 */
+	@GetMapping("/select")
+	@ApiOperationSupport(order = 7)
+	@Operation(summary = "模型列表", description = "模型列表")
+	public R<List<Model>> select() {
+		List<Model> list = modelService.list();
+		list.forEach(model -> model.setModelName(model.getModelTable() + StringPool.COLON + StringPool.SPACE + model.getModelName()));
+		return R.data(list);
+	}
+
+	/**
+	 * 获取物理表列表
+	 */
+	@GetMapping("/table-list")
+	@ApiOperationSupport(order = 8)
+	@Operation(summary = "物理表列表", description = "传入datasourceId")
+	public R<List<TableInfo>> tableList(Long datasourceId) {
+		Datasource datasource = datasourceService.getById(datasourceId);
+		ConfigBuilder config = getConfigBuilder(datasource);
+		List<TableInfo> tableInfoList = config.getTableInfoList().stream()
+			.filter(tableInfo -> !StringUtil.startsWithIgnoreCase(tableInfo.getName(), "ACT_"))
+			.map(tableInfo -> tableInfo.setComment(tableInfo.getName() + StringPool.COLON + tableInfo.getComment()))
+			.collect(Collectors.toList());
+		return R.data(tableInfoList);
+	}
+
+	/**
+	 * 获取物理表信息
+	 */
+	@GetMapping("/table-info")
+	@ApiOperationSupport(order = 9)
+	@Operation(summary = "物理表信息", description = "传入model信息")
+	public R<TableInfo> tableInfo(Long modelId, String tableName, Long datasourceId) {
+		if (StringUtil.isBlank(tableName)) {
+			Model model = modelService.getById(modelId);
+			tableName = model.getModelTable();
+		}
+		TableInfo tableInfo = getTableInfo(tableName, datasourceId);
+		return R.data(tableInfo);
+	}
+
+	/**
+	 * 获取字段信息
+	 */
+	@GetMapping("/model-prototype")
+	@ApiOperationSupport(order = 10)
+	@Operation(summary = "物理表字段信息", description = "传入modelId与datasourceId")
+	public R modelPrototype(Long modelId, Long datasourceId) {
+		List<ModelPrototype> modelPrototypeList = modelPrototypeService.list(Wrappers.<ModelPrototype>query().lambda().eq(ModelPrototype::getModelId, modelId));
+		if (modelPrototypeList.size() > 0) {
+			return R.data(modelPrototypeList);
+		}
+		Model model = modelService.getById(modelId);
+		String tableName = model.getModelTable();
+		TableInfo tableInfo = getTableInfo(tableName, datasourceId);
+		if (tableInfo != null) {
+			return R.data(tableInfo.getFields());
+		} else {
+			return R.fail("未获得相关表信息");
+		}
+	}
+
+	/**
+	 * 获取表信息
+	 *
+	 * @param tableName    表名
+	 * @param datasourceId 数据源主键
+	 */
+	private TableInfo getTableInfo(String tableName, Long datasourceId) {
+		Datasource datasource = datasourceService.getById(datasourceId);
+		ConfigBuilder config = getConfigBuilder(datasource, tableName);
+		List<TableInfo> tableInfoList = config.getTableInfoList();
+		TableInfo tableInfo = null;
+		Iterator<TableInfo> iterator = tableInfoList.stream().filter(table -> table.getName().equals(tableName)).collect(Collectors.toList()).iterator();
+		if (iterator.hasNext()) {
+			tableInfo = iterator.next();
+			if (tableName.contains(StringPool.UNDERSCORE)) {
+				tableInfo.setEntityName(tableInfo.getEntityName().replace(StringUtil.firstCharToUpper(tableName.split(StringPool.UNDERSCORE)[0]), StringPool.EMPTY));
+			} else {
+				tableInfo.setEntityName(StringUtil.firstCharToUpper(tableName));
+			}
+		}
+		return tableInfo;
+	}
+
+	/**
+	 * 获取表配置信息
+	 *
+	 * @param datasource 数据源信息
+	 */
+	private ConfigBuilder getConfigBuilder(Datasource datasource) {
+		return getConfigBuilder(datasource, null);
+	}
+
+	/**
+	 * 获取表配置信息
+	 *
+	 * @param datasource 数据源信息
+	 * @param tableName  表名
+	 */
+	private ConfigBuilder getConfigBuilder(Datasource datasource, String tableName) {
+		StrategyConfig.Builder builder = new StrategyConfig.Builder();
+		if (StringUtil.isNotBlank(tableName)) {
+			builder.addInclude(tableName);
+		}
+		StrategyConfig strategyConfig = builder.entityBuilder()
+			.naming(NamingStrategy.underline_to_camel)
+			.columnNaming(NamingStrategy.underline_to_camel).build();
+		DataSourceConfig datasourceConfig = new DataSourceConfig.Builder(
+			datasource.getUrl(), datasource.getUsername(), datasource.getPassword()
+		).build();
+		return new ConfigBuilder(null, datasourceConfig, strategyConfig, null, null, null);
+	}
+
+
+}

+ 145 - 0
blade-ops/blade-develop/src/main/java/org/springblade/develop/controller/ModelPrototypeController.java

@@ -0,0 +1,145 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.develop.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.StringPool;
+import org.springblade.develop.pojo.entity.ModelPrototype;
+import org.springblade.develop.service.IModelPrototypeService;
+import org.springframework.web.bind.annotation.*;
+
+import jakarta.validation.Valid;
+import java.util.List;
+
+/**
+ * 数据原型表 控制器
+ *
+ * @author Chill
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/model-prototype")
+@Tag(name = "数据原型表", description = "数据原型表接口")
+public class ModelPrototypeController extends BladeController {
+
+	private final IModelPrototypeService modelPrototypeService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperationSupport(order = 1)
+	@Operation(summary = "详情", description = "传入modelPrototype")
+	public R<ModelPrototype> detail(ModelPrototype modelPrototype) {
+		ModelPrototype detail = modelPrototypeService.getOne(Condition.getQueryWrapper(modelPrototype));
+		return R.data(detail);
+	}
+
+	/**
+	 * 分页 数据原型表
+	 */
+	@GetMapping("/list")
+	@ApiOperationSupport(order = 2)
+	@Operation(summary = "分页", description = "传入modelPrototype")
+	public R<IPage<ModelPrototype>> list(ModelPrototype modelPrototype, Query query) {
+		IPage<ModelPrototype> pages = modelPrototypeService.page(Condition.getPage(query), Condition.getQueryWrapper(modelPrototype));
+		return R.data(pages);
+	}
+
+	/**
+	 * 新增 数据原型表
+	 */
+	@PostMapping("/save")
+	@ApiOperationSupport(order = 4)
+	@Operation(summary = "新增", description = "传入modelPrototype")
+	public R save(@Valid @RequestBody ModelPrototype modelPrototype) {
+		return R.status(modelPrototypeService.save(modelPrototype));
+	}
+
+	/**
+	 * 修改 数据原型表
+	 */
+	@PostMapping("/update")
+	@ApiOperationSupport(order = 5)
+	@Operation(summary = "修改", description = "传入modelPrototype")
+	public R update(@Valid @RequestBody ModelPrototype modelPrototype) {
+		return R.status(modelPrototypeService.updateById(modelPrototype));
+	}
+
+	/**
+	 * 新增或修改 数据原型表
+	 */
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 6)
+	@Operation(summary = "新增或修改", description = "传入modelPrototype")
+	public R submit(@Valid @RequestBody ModelPrototype modelPrototype) {
+		return R.status(modelPrototypeService.saveOrUpdate(modelPrototype));
+	}
+
+	/**
+	 * 批量新增或修改 数据原型表
+	 */
+	@PostMapping("/submit-list")
+	@ApiOperationSupport(order = 7)
+	@Operation(summary = "批量新增或修改", description = "传入modelPrototype集合")
+	public R submitList(@Valid @RequestBody List<ModelPrototype> modelPrototypes) {
+		return R.status(modelPrototypeService.submitList(modelPrototypes));
+	}
+
+	/**
+	 * 删除 数据原型表
+	 */
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 8)
+	@Operation(summary = "逻辑删除", description = "传入ids")
+	public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(modelPrototypeService.deleteLogic(Func.toLongList(ids)));
+	}
+
+	/**
+	 * 数据原型列表
+	 */
+	@GetMapping("/select")
+	@ApiOperationSupport(order = 9)
+	@Operation(summary = "数据原型列表", description = "数据原型列表")
+	public R<List<ModelPrototype>> select(@Parameter(description = "数据模型Id", required = true) @RequestParam Long modelId) {
+		List<ModelPrototype> list = modelPrototypeService.list(Wrappers.<ModelPrototype>query().lambda().eq(ModelPrototype::getModelId, modelId));
+		list.forEach(prototype -> prototype.setJdbcComment(prototype.getJdbcName() + StringPool.COLON + StringPool.SPACE + prototype.getJdbcComment()));
+		return R.data(list);
+	}
+
+}

+ 38 - 0
blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/CodeMapper.java

@@ -0,0 +1,38 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.develop.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springblade.develop.pojo.entity.Code;
+
+/**
+ * Mapper 接口
+ *
+ * @author Chill
+ */
+public interface CodeMapper extends BaseMapper<Code> {
+
+}

+ 22 - 0
blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/CodeMapper.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.develop.mapper.CodeMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="codeResultMap" type="org.springblade.develop.pojo.entity.Code">
+        <id column="id" property="id"/>
+        <result column="datasource_id" property="datasourceId"/>
+        <result column="service_name" property="serviceName"/>
+        <result column="code_name" property="codeName"/>
+        <result column="table_name" property="tableName"/>
+        <result column="pk_name" property="pkName"/>
+        <result column="base_mode" property="baseMode"/>
+        <result column="wrap_mode" property="wrapMode"/>
+        <result column="table_prefix" property="tablePrefix"/>
+        <result column="package_name" property="packageName"/>
+        <result column="api_path" property="apiPath"/>
+        <result column="web_path" property="webPath"/>
+        <result column="is_deleted" property="isDeleted"/>
+    </resultMap>
+
+</mapper>

+ 38 - 0
blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/DatasourceMapper.java

@@ -0,0 +1,38 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.develop.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springblade.develop.pojo.entity.Datasource;
+
+/**
+ * 数据源配置表 Mapper 接口
+ *
+ * @author Chill
+ */
+public interface DatasourceMapper extends BaseMapper<Datasource> {
+
+}

+ 22 - 0
blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/DatasourceMapper.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.develop.mapper.DatasourceMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="datasourceResultMap" type="org.springblade.develop.pojo.entity.Datasource">
+        <result column="id" property="id"/>
+        <result column="create_user" property="createUser"/>
+        <result column="create_dept" property="createDept"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_user" property="updateUser"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="status" property="status"/>
+        <result column="is_deleted" property="isDeleted"/>
+        <result column="driver_class" property="driverClass"/>
+        <result column="url" property="url"/>
+        <result column="username" property="username"/>
+        <result column="password" property="password"/>
+        <result column="remark" property="remark"/>
+    </resultMap>
+
+</mapper>

+ 38 - 0
blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/ModelMapper.java

@@ -0,0 +1,38 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.develop.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springblade.develop.pojo.entity.Model;
+
+/**
+ * 数据模型表 Mapper 接口
+ *
+ * @author Chill
+ */
+public interface ModelMapper extends BaseMapper<Model> {
+
+}

+ 27 - 0
blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/ModelMapper.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.develop.mapper.ModelMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="modelResultMap" type="org.springblade.develop.pojo.entity.Model">
+        <id column="id" property="id"/>
+        <result column="create_user" property="createUser"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_user" property="updateUser"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="status" property="status"/>
+        <result column="is_deleted" property="isDeleted"/>
+        <result column="datasource_id" property="datasourceId"/>
+        <result column="model_name" property="modelName"/>
+        <result column="model_code" property="modelCode"/>
+        <result column="model_table" property="modelTable"/>
+        <result column="model_class" property="modelClass"/>
+        <result column="model_remark" property="modelRemark"/>
+    </resultMap>
+
+
+    <select id="selectModelPage" resultMap="modelResultMap">
+        select * from blade_model where is_deleted = 0
+    </select>
+
+</mapper>

+ 38 - 0
blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/ModelPrototypeMapper.java

@@ -0,0 +1,38 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.develop.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springblade.develop.pojo.entity.ModelPrototype;
+
+/**
+ * 数据原型表 Mapper 接口
+ *
+ * @author Chill
+ */
+public interface ModelPrototypeMapper extends BaseMapper<ModelPrototype> {
+
+}

+ 35 - 0
blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/ModelPrototypeMapper.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.develop.mapper.ModelPrototypeMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="modelPrototypeResultMap" type="org.springblade.develop.pojo.entity.ModelPrototype">
+        <id column="id" property="id"/>
+        <result column="create_user" property="createUser"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_user" property="updateUser"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="status" property="status"/>
+        <result column="is_deleted" property="isDeleted"/>
+        <result column="jdbc_name" property="jdbcName"/>
+        <result column="jdbc_type" property="jdbcType"/>
+        <result column="jdbc_comment" property="jdbcComment"/>
+        <result column="property_type" property="propertyType"/>
+        <result column="property_entity" property="propertyEntity"/>
+        <result column="property_name" property="propertyName"/>
+        <result column="is_form" property="isForm"/>
+        <result column="is_row" property="isRow"/>
+        <result column="component_type" property="componentType"/>
+        <result column="dict_code" property="dictCode"/>
+        <result column="is_required" property="isRequired"/>
+        <result column="is_list" property="isList"/>
+        <result column="is_query" property="isQuery"/>
+        <result column="query_type" property="queryType"/>
+    </resultMap>
+
+
+    <select id="selectModelPrototypePage" resultMap="modelPrototypeResultMap">
+        select * from blade_model_prototype where is_deleted = 0
+    </select>
+
+</mapper>

Some files were not shown because too many files changed in this diff