Spring Boot中如何基于注解修改@RequestMapping的URL端点?
解决Spring Boot通过自定义注解修改RequestMapping端点的问题
问题原因
你之前的代码没生效,核心原因是Spring Boot默认已经注册了RequestMappingHandlerMapping,你用@Component注册的自定义实现不会替换掉默认实例,请求依然会走默认的HandlerMapping,所以你的路径修改逻辑不会被触发。
解决步骤
1. 确保自定义@Version注解的定义正确
支持类和方法级别标注,灵活控制版本路径:
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Version { int value(); }
2. 调整自定义RequestMappingHandlerMapping实现
去掉@Component注解,专注实现路径修改逻辑,优先读取方法上的@Version,再读取类上的:
public class VersionedRequestMappingHandlerMapping extends RequestMappingHandlerMapping { @Override protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { RequestMappingInfo methodMapping = super.getMappingForMethod(method, handlerType); if (methodMapping == null) { return null; } // 优先获取方法上的版本注解,没有则取类上的 Version versionAnnotation = AnnotationUtils.findAnnotation(method, Version.class); if (versionAnnotation == null) { versionAnnotation = AnnotationUtils.findAnnotation(handlerType, Version.class); } if (versionAnnotation != null) { String versionPath = "/v" + versionAnnotation.value(); RequestMappingInfo versionMapping = RequestMappingInfo.paths(versionPath).build(); return versionMapping.combine(methodMapping); } return methodMapping; } }
3. 通过配置类替换默认的HandlerMapping
实现WebMvcRegistrations接口,注册自定义的HandlerMapping,确保它替换Spring默认的实例:
@Configuration public class WebVersionConfig implements WebMvcRegistrations { @Override public RequestMappingHandlerMapping getRequestMappingHandlerMapping() { VersionedRequestMappingHandlerMapping handlerMapping = new VersionedRequestMappingHandlerMapping(); // 设置与默认HandlerMapping相同的优先级和基础配置,保证原有功能不受影响 handlerMapping.setOrder(0); handlerMapping.setInterceptors(getInterceptors()); handlerMapping.setContentNegotiationManager(getContentNegotiationManager()); handlerMapping.setCorsConfigurations(getCorsConfigurations()); return handlerMapping; } // 注入默认的拦截器、内容协商管理器、跨域配置,保持原有行为 @Autowired(required = false) private List<HandlerInterceptor> interceptors = Collections.emptyList(); @Autowired private ContentNegotiationManager contentNegotiationManager; @Autowired(required = false) private Map<String, CorsConfiguration> corsConfigurations = Collections.emptyMap(); private List<HandlerInterceptor> getInterceptors() { return this.interceptors; } private ContentNegotiationManager getContentNegotiationManager() { return this.contentNegotiationManager; } private Map<String, CorsConfiguration> getCorsConfigurations() { return this.corsConfigurations; } }
4. 测试验证
编写测试控制器:
@RestController @Version(1) public class TestController { @GetMapping("/test") public ResponseEntity<String> testV1() { return ResponseEntity.ok("Hello from v1/test"); } @Version(2) @GetMapping("/test") public ResponseEntity<String> testV2() { return ResponseEntity.ok("Hello from v2/test"); } }
启动项目后,访问/v1/test会返回v1的内容,访问/v2/test会返回v2的内容,符合预期。
内容的提问来源于stack exchange,提问作者AbdulazizYas
相关产品推荐
相关产品推荐

