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 - - - - -