Commit a9fdc6b42d4a2df297a39e4d9485f286d5591321

Authored by YunaiV
1 parent 56821608

fix:【framework 框架】确保在 Bean 创建前映射应用请求前缀

yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java
1 package cn.iocoder.yudao.framework.web.config; 1 package cn.iocoder.yudao.framework.web.config;
2 2
  3 +import cn.hutool.core.util.StrUtil;
3 import cn.iocoder.yudao.framework.common.biz.infra.logger.ApiErrorLogCommonApi; 4 import cn.iocoder.yudao.framework.common.biz.infra.logger.ApiErrorLogCommonApi;
4 import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; 5 import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
5 import cn.iocoder.yudao.framework.web.core.filter.CacheRequestBodyFilter; 6 import cn.iocoder.yudao.framework.web.core.filter.CacheRequestBodyFilter;
@@ -7,6 +8,7 @@ import cn.iocoder.yudao.framework.web.core.filter.DemoFilter; @@ -7,6 +8,7 @@ import cn.iocoder.yudao.framework.web.core.filter.DemoFilter;
7 import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; 8 import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
8 import cn.iocoder.yudao.framework.web.core.handler.GlobalResponseBodyHandler; 9 import cn.iocoder.yudao.framework.web.core.handler.GlobalResponseBodyHandler;
9 import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; 10 import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
  11 +import com.google.common.collect.Maps;
10 import jakarta.annotation.Resource; 12 import jakarta.annotation.Resource;
11 import jakarta.servlet.Filter; 13 import jakarta.servlet.Filter;
12 import org.springframework.beans.factory.annotation.Value; 14 import org.springframework.beans.factory.annotation.Value;
@@ -14,6 +16,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration; @@ -14,6 +16,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
14 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 16 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
15 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 17 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
16 import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration; 18 import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration;
  19 +import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
17 import org.springframework.boot.context.properties.EnableConfigurationProperties; 20 import org.springframework.boot.context.properties.EnableConfigurationProperties;
18 import org.springframework.boot.web.client.RestTemplateBuilder; 21 import org.springframework.boot.web.client.RestTemplateBuilder;
19 import org.springframework.boot.web.servlet.FilterRegistrationBean; 22 import org.springframework.boot.web.servlet.FilterRegistrationBean;
@@ -26,35 +29,57 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; @@ -26,35 +29,57 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
26 import org.springframework.web.filter.CorsFilter; 29 import org.springframework.web.filter.CorsFilter;
27 import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; 30 import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
28 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 31 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  32 +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
  33 +
  34 +import java.util.Map;
  35 +import java.util.function.Predicate;
29 36
30 @AutoConfiguration 37 @AutoConfiguration
31 @EnableConfigurationProperties(WebProperties.class) 38 @EnableConfigurationProperties(WebProperties.class)
32 -public class YudaoWebAutoConfiguration implements WebMvcConfigurer { 39 +public class YudaoWebAutoConfiguration {
33 40
34 - @Resource  
35 - private WebProperties webProperties;  
36 /** 41 /**
37 * 应用名 42 * 应用名
38 */ 43 */
39 @Value("${spring.application.name}") 44 @Value("${spring.application.name}")
40 private String applicationName; 45 private String applicationName;
41 46
42 - @Override  
43 - public void configurePathMatch(PathMatchConfigurer configurer) {  
44 - configurePathMatch(configurer, webProperties.getAdminApi());  
45 - configurePathMatch(configurer, webProperties.getAppApi());  
46 - } 47 + @Bean
  48 + public WebMvcRegistrations webMvcRegistrations(WebProperties webProperties) {
  49 + return new WebMvcRegistrations() {
47 50
48 - /**  
49 - * 设置 API 前缀,仅仅匹配 controller 包下的  
50 - *  
51 - * @param configurer 配置  
52 - * @param api API 配置  
53 - */  
54 - private void configurePathMatch(PathMatchConfigurer configurer, WebProperties.Api api) {  
55 - AntPathMatcher antPathMatcher = new AntPathMatcher(".");  
56 - configurer.addPathPrefix(api.getPrefix(), clazz -> clazz.isAnnotationPresent(RestController.class)  
57 - && antPathMatcher.match(api.getController(), clazz.getPackage().getName())); // 仅仅匹配 controller 包 51 + @Override
  52 + public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
  53 + var mapping = new RequestMappingHandlerMapping();
  54 + // 实例化时就带上前缀
  55 + mapping.setPathPrefixes(buildPathPrefixes(webProperties));
  56 + return mapping;
  57 + }
  58 +
  59 + /**
  60 + * 构建 prefix → 匹配条件的映射
  61 + */
  62 + private Map<String, Predicate<Class<?>>> buildPathPrefixes(WebProperties webProperties) {
  63 + AntPathMatcher antPathMatcher = new AntPathMatcher(".");
  64 + Map<String, Predicate<Class<?>>> pathPrefixes = Maps.newLinkedHashMapWithExpectedSize(2);
  65 + putPathPrefix(pathPrefixes, webProperties.getAdminApi(), antPathMatcher);
  66 + putPathPrefix(pathPrefixes, webProperties.getAppApi(), antPathMatcher);
  67 + return pathPrefixes;
  68 + }
  69 +
  70 + /**
  71 + * 设置 API 前缀,仅仅匹配 controller 包下的
  72 + */
  73 + private void putPathPrefix(Map<String, Predicate<Class<?>>> pathPrefixes, WebProperties.Api api, AntPathMatcher matcher) {
  74 + if (api == null || StrUtil.isEmpty(api.getPrefix())) {
  75 + return;
  76 + }
  77 + pathPrefixes.put(api.getPrefix(), // api 前缀
  78 + clazz -> clazz.isAnnotationPresent(RestController.class)
  79 + && matcher.match(api.getController(), clazz.getPackage().getName()));
  80 + }
  81 +
  82 + };
58 } 83 }
59 84
60 @Bean 85 @Bean