diff --git a/pom.xml b/pom.xml
index f1de8c80..b4a9829a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,7 +16,8 @@
yudao-module-system
yudao-module-infra
-
+ yudao-spring-boot-starter-env
+
${project.artifactId}
diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml
index 12b2da69..d4a21d3c 100644
--- a/yudao-dependencies/pom.xml
+++ b/yudao-dependencies/pom.xml
@@ -157,6 +157,12 @@
${spring.boot.version}
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-env
+ ${revision}
+
+
cn.iocoder.cloud
diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java
index 2e4d9ab9..947d3e81 100644
--- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java
@@ -13,6 +13,8 @@ public interface WebFilterOrderEnum {
int TRACE_FILTER = CORS_FILTER + 1;
+ int ENV_TAG_FILTER = TRACE_FILTER + 1;
+
int REQUEST_BODY_CACHE_FILTER = Integer.MIN_VALUE + 500;
// OrderedRequestContextFilter 默认为 -105,用于国际化上下文等等
diff --git a/yudao-framework/yudao-spring-boot-starter-env/pom.xml b/yudao-framework/yudao-spring-boot-starter-env/pom.xml
new file mode 100644
index 00000000..c502a726
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-env/pom.xml
@@ -0,0 +1,51 @@
+
+
+
+ cn.iocoder.cloud
+ yudao-framework
+ ${revision}
+
+ 4.0.0
+ yudao-spring-boot-starter-env
+ jar
+
+ ${project.artifactId}
+
+ 开发环境拓展,实现类似阿里的特性环境的能力
+ 1. https://segmentfault.com/a/1190000018022987
+
+ https://github.com/YunaiV/ruoyi-vue-pro
+
+
+ 8
+ 8
+
+
+
+
+ cn.iocoder.cloud
+ yudao-common
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+
+ org.springframework
+ spring-web
+
+
+
+ jakarta.servlet
+ jakarta.servlet-api
+
+
+
+
+
diff --git a/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/EnvProperties.java b/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/EnvProperties.java
new file mode 100644
index 00000000..1be3a519
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/EnvProperties.java
@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.framework.env.config;
+
+import lombok.Data;
+
+/**
+ * 环境
+ *
+ * @author 芋道源码
+ */
+@Data
+public class EnvProperties {
+
+ /**
+ * 环境标签
+ */
+ private String tag;
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/YudaoEnvWebAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/YudaoEnvWebAutoConfiguration.java
new file mode 100644
index 00000000..ad21b80b
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/YudaoEnvWebAutoConfiguration.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.framework.env.config;
+
+import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
+import cn.iocoder.yudao.framework.env.core.web.EnvWebFilter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
+public class YudaoEnvWebAutoConfiguration {
+
+ /**
+ * 创建 {@link EnvWebFilter} Bean
+ */
+ @Bean
+ public FilterRegistrationBean envWebFilterFilter() {
+ EnvWebFilter filter = new EnvWebFilter();
+ FilterRegistrationBean bean = new FilterRegistrationBean<>(filter);
+ bean.setOrder(WebFilterOrderEnum.ENV_TAG_FILTER);
+ return bean;
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/context/EnvContextHolder.java b/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/context/EnvContextHolder.java
new file mode 100644
index 00000000..a246a781
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/context/EnvContextHolder.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.framework.env.core.context;
+
+import cn.hutool.core.collection.CollUtil;
+import com.alibaba.ttl.TransmittableThreadLocal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 开发环境上下文
+ *
+ * @author 芋道源码
+ */
+public class EnvContextHolder {
+
+ /**
+ * 标签的上下文
+ *
+ * 使用 {@link List} 的原因,可能存在多层设置或者清理
+ */
+ private static final ThreadLocal> tagContext = TransmittableThreadLocal.withInitial(ArrayList::new);
+
+ public static void setTag(String tag) {
+ tagContext.get().add(tag);
+ }
+
+ public static String getTag() {
+ return CollUtil.getLast(tagContext.get());
+ }
+
+ public static void removeTag() {
+ List tags = tagContext.get();
+ if (CollUtil.isEmpty(tags)) {
+ return;
+ }
+ tags.remove(tags.size() - 1);
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/package-info.java b/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/package-info.java
new file mode 100644
index 00000000..9ef9a1d6
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/package-info.java
@@ -0,0 +1 @@
+package cn.iocoder.yudao.framework.env.core;
diff --git a/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/util/EnvUtils.java b/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/util/EnvUtils.java
new file mode 100644
index 00000000..e7fb36c9
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/util/EnvUtils.java
@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.framework.env.core.util;
+
+import cn.hutool.core.net.NetUtil;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Objects;
+
+/**
+ * 环境 Utils
+ *
+ * @author 芋道源码
+ */
+public class EnvUtils {
+
+ private static final String HEADER_DUBBO_TAG = "tag";
+
+ private static final String HOST_NAME_VALUE = "${HOSTNAME}";
+
+ public static String getTag(HttpServletRequest request) {
+ String tag = request.getHeader(HEADER_DUBBO_TAG);
+ // 如果请求的是 "${HOSTNAME}",则解析成对应的本地主机名
+ // 目的:特殊逻辑,解决 IDEA Rest Client 不支持环境变量的读取,所以就服务器来做
+ return Objects.equals(tag, HOST_NAME_VALUE) ? NetUtil.getLocalHostName() : tag;
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/web/EnvWebFilter.java b/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/web/EnvWebFilter.java
new file mode 100644
index 00000000..0c933a26
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/web/EnvWebFilter.java
@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.framework.env.core.web;
+
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.env.core.context.EnvContextHolder;
+import cn.iocoder.yudao.framework.env.core.util.EnvUtils;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 环境的 {@link javax.servlet.Filter} 实现类
+ * 当有 tag 请求头时,设置到 {@link EnvContextHolder} 的标签上下文
+ *
+ * @author 芋道源码
+ */
+public class EnvWebFilter extends OncePerRequestFilter {
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
+ throws ServletException, IOException {
+ // 如果没有 tag,则走默认的流程
+ String tag = EnvUtils.getTag(request);
+ if (StrUtil.isEmpty(tag)) {
+ chain.doFilter(request, response);
+ return;
+ }
+
+ // 如果有 tag,则设置到上下文
+ EnvContextHolder.setTag(tag);
+ try {
+ chain.doFilter(request, response);
+ } finally {
+ EnvContextHolder.removeTag();
+ }
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/package-info.java b/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/package-info.java
new file mode 100644
index 00000000..20d1d3ac
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * 开发环境拓展,实现类似阿里的特性环境的能力
+ * 1. https://segmentfault.com/a/1190000018022987
+ *
+ * @author 芋道源码
+ */
+package cn.iocoder.yudao.framework.env;
diff --git a/yudao-framework/yudao-spring-boot-starter-env/src/main/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-env/src/main/resources/META-INF/spring.factories
new file mode 100644
index 00000000..c5751ebd
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-env/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+ cn.iocoder.yudao.framework.env.config.YudaoEnvWebAutoConfiguration
diff --git a/yudao-framework/yudao-spring-boot-starter-rpc/pom.xml b/yudao-framework/yudao-spring-boot-starter-rpc/pom.xml
index 5fba4bdf..5216178f 100644
--- a/yudao-framework/yudao-spring-boot-starter-rpc/pom.xml
+++ b/yudao-framework/yudao-spring-boot-starter-rpc/pom.xml
@@ -38,7 +38,7 @@
org.apache.dubbo
dubbo-common
-
+
diff --git a/yudao-module-system/yudao-module-system-biz/pom.xml b/yudao-module-system/yudao-module-system-biz/pom.xml
index a370bf1a..6b6db3c7 100644
--- a/yudao-module-system/yudao-module-system-biz/pom.xml
+++ b/yudao-module-system/yudao-module-system-biz/pom.xml
@@ -24,6 +24,11 @@
spring-cloud-starter-bootstrap
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-env
+
+
cn.iocoder.cloud
@@ -105,11 +110,11 @@
spring-cloud-starter-alibaba-nacos-config
-
-
-
-
-
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-job
+
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.http b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.http
index a155da83..2c38d003 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.http
+++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.http
@@ -2,6 +2,7 @@
POST {{systemBaseUrl}}/system/auth/login
Content-Type: application/json
tenant-id: {{adminTenentId}}
+tag: 123
{
"username": "admin",
diff --git a/归档/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/config/DubboWebAutoConfiguration.java b/归档/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/config/DubboWebAutoConfiguration.java
deleted file mode 100644
index e9339d76..00000000
--- a/归档/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/config/DubboWebAutoConfiguration.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package cn.iocoder.mall.dubbo.config;
-
-import cn.iocoder.mall.dubbo.core.web.DubboRouterTagWebInterceptor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
-@Configuration
-@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
-public class DubboWebAutoConfiguration implements WebMvcConfigurer {
-
- private Logger logger = LoggerFactory.getLogger(DubboWebAutoConfiguration.class);
-
- // ========== 拦截器相关 ==========
-
- @Override
- public void addInterceptors(InterceptorRegistry registry) {
- try {
- // 设置为 -1000 的原因,保证在比较前面就处理该逻辑。例如说,认证拦截器;
- registry.addInterceptor(new DubboRouterTagWebInterceptor()).order(-1000);
- logger.info("[addInterceptors][加载 DubboRouterTagWebInterceptor 拦截器完成]");
- } catch (NoSuchBeanDefinitionException e) {
- logger.warn("[addInterceptors][无法获取 DubboRouterTagWebInterceptor 拦截器,无法使用基于 dubbo-tag 请求头进行 Dubbo 标签路由]");
- }
- }
-
-}
diff --git a/归档/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/router/DubboRouterTagContextHolder.java b/归档/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/router/DubboRouterTagContextHolder.java
deleted file mode 100644
index 2a658b6b..00000000
--- a/归档/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/router/DubboRouterTagContextHolder.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package cn.iocoder.mall.dubbo.core.router;
-
-import cn.iocoder.mall.dubbo.core.filter.DubboProviderRouterTagFilter;
-
-/**
- * Dubbo 路由 Tag 的上下文
- *
- * @see DubboProviderRouterTagFilter
- * @see cn.iocoder.mall.dubbo.core.web.DubboRouterTagWebInterceptor
- */
-public class DubboRouterTagContextHolder {
-
- private static ThreadLocal tagContext = new ThreadLocal<>();
-
- public static void setTag(String tag) {
- tagContext.set(tag);
- }
-
- public static String getTag() {
- return tagContext.get();
- }
-
- public static void clear() {
- tagContext.remove();
- }
-
-}
diff --git a/归档/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/web/DubboRouterTagWebInterceptor.java b/归档/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/web/DubboRouterTagWebInterceptor.java
deleted file mode 100644
index 17bf0bbc..00000000
--- a/归档/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/web/DubboRouterTagWebInterceptor.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package cn.iocoder.mall.dubbo.core.web;
-
-import cn.iocoder.common.framework.util.OSUtils;
-import cn.iocoder.common.framework.util.StringUtils;
-import cn.iocoder.mall.dubbo.core.cluster.interceptor.DubboConsumerRouterTagClusterInterceptor;
-import cn.iocoder.mall.dubbo.core.filter.DubboProviderRouterTagFilter;
-import cn.iocoder.mall.dubbo.core.router.DubboRouterTagContextHolder;
-import org.springframework.web.servlet.HandlerInterceptor;
-import org.springframework.web.servlet.ModelAndView;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * Dubbo 路由标签的 Web 拦截器,将请求 Header 中的 {@link #HEADER_DUBBO_TAG} 设置到 {@link DubboRouterTagContextHolder} 中。
- *
- * @see DubboProviderRouterTagFilter
- * @see DubboConsumerRouterTagClusterInterceptor
- */
-public class DubboRouterTagWebInterceptor implements HandlerInterceptor {
-
- private static final String HEADER_DUBBO_TAG = "dubbo-tag";
-
- private static final String HOST_NAME_VALUE = "${HOSTNAME}";
-
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
- String tag = request.getHeader(HEADER_DUBBO_TAG);
- if (StringUtils.hasText(tag)) {
- // 特殊逻辑,解决 IDEA Rest Client 不支持环境变量的读取,所以就服务器来做
- if (HOST_NAME_VALUE.equals(tag)) {
- tag = OSUtils.getHostName();
- }
- // 设置到 DubboRouterTagContextHolder 上下文
- DubboRouterTagContextHolder.setTag(tag);
- }
- return true;
- }
-
- @Override
- public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
- DubboRouterTagContextHolder.clear();
- }
-
-}
diff --git a/归档/common/mall-spring-boot-starter-dubbo/src/main/resources/META-INF/spring.factories b/归档/common/mall-spring-boot-starter-dubbo/src/main/resources/META-INF/spring.factories
index 4e6ca3aa..25dddc37 100644
--- a/归档/common/mall-spring-boot-starter-dubbo/src/main/resources/META-INF/spring.factories
+++ b/归档/common/mall-spring-boot-starter-dubbo/src/main/resources/META-INF/spring.factories
@@ -1,5 +1,2 @@
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- cn.iocoder.mall.dubbo.config.DubboWebAutoConfiguration
-
org.springframework.boot.env.EnvironmentPostProcessor=\
cn.iocoder.mall.dubbo.config.DubboEnvironmentPostProcessor
diff --git a/归档/common/pom.xml b/归档/common/pom.xml
deleted file mode 100644
index 3596975d..00000000
--- a/归档/common/pom.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
- onemall
- cn.iocoder.mall
- 1.0-SNAPSHOT
-
- 4.0.0
-
- common
- pom
-
- common-framework
- mall-spring-boot
- mall-spring-boot-starter-swagger
- mall-spring-boot-starter-web
- mall-security-annotations
- mall-spring-boot-starter-security-admin
- mall-spring-boot-starter-security-user
- mall-spring-boot-starter-sentry
- mall-spring-boot-starter-mybatis
- mall-spring-boot-starter-dubbo
- mall-spring-boot-starter-system-error-code
- mall-spring-boot-starter-rocketmq
- mall-spring-boot-starter-xxl-job
- mall-spring-boot-starter-redis
-
-
-
-
-
- cn.iocoder.mall
- mall-dependencies
- 1.0-SNAPSHOT
- pom
- import
-
-
-
-
-