Springboot中多个Rest控制器能否使用相同request mapping?如何按RequestHeader匹配?
在Spring Boot中配置多个同RequestMapping的REST控制器并按RequestHeader路由
当然可以实现。Spring Boot支持多个控制器使用相同的@RequestMapping路径,核心是通过请求头(RequestHeader)的匹配规则来让Spring正确路由到对应的控制器,下面是两种常用的实现方案:
方式一:直接利用@RequestMapping的headers属性(简单场景)
这是最直接的实现方式,在@RequestMapping(或@GetMapping/@PostMapping等派生注解)中通过headers参数指定匹配条件,Spring会自动根据请求头判断调用哪个控制器方法。
示例代码:
// 匹配请求头包含X-Version=v1的请求 @RestController @RequestMapping("/api/user") public class UserV1Controller { @GetMapping(headers = "X-Version=v1") public String getUserInfo() { return "用户信息来自V1版本接口"; } } // 匹配请求头包含X-Version=v2的请求 @RestController @RequestMapping("/api/user") public class UserV2Controller { @GetMapping(headers = "X-Version=v2") public String getUserInfo() { return "用户信息来自V2版本接口"; } } // 作为默认匹配(当请求头不匹配上述两个控制器时触发) @RestController @RequestMapping("/api/user") public class UserDefaultController { @GetMapping public String getUserInfo() { return "用户信息来自默认版本接口"; } }
说明:headers参数支持多种写法,比如headers = "X-Version!=v1"(排除指定值)、headers = "X-Version"(只要存在该请求头即可),可以根据需求灵活调整。
方式二:自定义请求匹配逻辑(复杂场景)
如果需要更灵活的匹配规则(比如正则匹配请求头值、多请求头组合判断),可以通过自定义RequestMappingHandlerMapping和RequestCondition来实现。
步骤1:创建自定义注解标记版本
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface ApiVersion { // 指定用来匹配的请求头名称,默认X-Version String header() default "X-Version"; // 指定请求头需要匹配的值 String value(); }
步骤2:实现自定义请求匹配条件
public class HeaderVersionCondition implements RequestCondition<HeaderVersionCondition> { private final String versionHeader; private final String versionValue; public HeaderVersionCondition(String versionHeader, String versionValue) { this.versionHeader = versionHeader; this.versionValue = versionValue; } @Override public HeaderVersionCondition combine(HeaderVersionCondition other) { // 方法上的注解优先级高于类上的 return new HeaderVersionCondition(other.versionHeader, other.versionValue); } @Override public HeaderVersionCondition getMatchingCondition(HttpServletRequest request) { String requestVersion = request.getHeader(versionHeader); // 匹配成功则返回当前条件,否则返回null表示不匹配 return versionValue.equals(requestVersion) ? this : null; } @Override public int compareTo(HeaderVersionCondition other, HttpServletRequest request) { // 精确匹配的优先级更高 return versionValue.equals(request.getHeader(versionHeader)) ? 1 : -1; } }
步骤3:自定义RequestMappingHandlerMapping
@Component public class VersionRequestMappingHandlerMapping extends RequestMappingHandlerMapping { @Override protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) { // 解析类上的@ApiVersion注解 ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType, ApiVersion.class); return apiVersion != null ? new HeaderVersionCondition(apiVersion.header(), apiVersion.value()) : null; } @Override protected RequestCondition<?> getCustomMethodCondition(Method method) { // 解析方法上的@ApiVersion注解 ApiVersion apiVersion = AnnotationUtils.findAnnotation(method, ApiVersion.class); return apiVersion != null ? new HeaderVersionCondition(apiVersion.header(), apiVersion.value()) : null; } }
步骤4:在控制器上使用自定义注解
@RestController @RequestMapping("/api/user") @ApiVersion(value = "v1") public class UserV1Controller { @GetMapping public String getUserInfo() { return "用户信息来自V1版本接口"; } } @RestController @RequestMapping("/api/user") @ApiVersion(value = "v2") public class UserV2Controller { @GetMapping public String getUserInfo() { return "用户信息来自V2版本接口"; } }
注意事项
- 确保多个控制器的匹配条件互斥,否则Spring会抛出
AmbiguousHandlerException(请求匹配歧义)。 - 方法级别的注解匹配优先级高于类级别的注解。
- 可以结合
produces、consumes等属性进一步细化匹配规则。
内容的提问来源于stack exchange,提问作者esquare
相关产品推荐
相关产品推荐

