AnnotationUtils获取GetMapping路径为空的问题及更优方案问询
优化Spring MVC拦截器中获取请求路径的方案
问题背景
在Spring MVC拦截器中,控制器接口存在两种定义方式:
- 使用
@GetMapping/@PostMapping等HTTP动词组合注解 - 使用原生
@RequestMapping注解
直接调用AnnotationUtils.findAnnotation(method, RequestMapping.class)无法获取组合注解的路径值(因为组合注解的路径属性是自身定义的,并非元注解@RequestMapping的属性),原方案通过switch-case逐一检查各组合注解的方式不够简洁,需要优化。
优化方案
方案一:利用Spring原生RequestMappingInfo(推荐)
Spring内部会将所有请求注解(包括组合注解和原生@RequestMapping)统一解析为RequestMappingInfo,包含完整的路径、请求方法、参数等映射信息。通过RequestMappingHandlerMapping可以直接获取该对象,无需手动处理各类注解。
代码示例:
@Component public class MyOwnInterceptor implements HandlerInterceptor { private final RequestMappingHandlerMapping requestMappingHandlerMapping; // 构造注入RequestMappingHandlerMapping public MyOwnInterceptor(RequestMappingHandlerMapping requestMappingHandlerMapping) { this.requestMappingHandlerMapping = requestMappingHandlerMapping; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; // 获取当前方法的RequestMappingInfo RequestMappingInfo mappingInfo = requestMappingHandlerMapping.getMappingForMethod( handlerMethod.getMethod(), handlerMethod.getBeanType() ); if (mappingInfo != null) { // 获取合并后的完整请求路径(包含类上@RequestMapping的前缀) Set<String> pathPatterns = mappingInfo.getPatternsCondition().getPatterns(); String requestPath = pathPatterns.iterator().next(); // 这里添加你的业务逻辑,比如打印路径 System.out.println("请求路径:" + requestPath); } } return true; } }
优势:
- 自动处理类和方法级别的路径合并,无需手动拼接
- 统一解析所有请求注解类型,无需逐个判断
- 能获取到请求方法、参数条件等更多映射信息,扩展性强
方案二:反射统一处理请求注解
如果不想依赖RequestMappingHandlerMapping,可以通过反射批量检查所有请求注解类型,统一提取路径属性。
代码示例:
@Component public class MyOwnInterceptor implements HandlerInterceptor { // 定义所有需要检查的请求注解类型 private static final List<Class<? extends Annotation>> REQUEST_ANNOTATIONS = Arrays.asList( GetMapping.class, PostMapping.class, PutMapping.class, DeleteMapping.class, PatchMapping.class, RequestMapping.class ); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; String requestPath = getRequestPath(handlerMethod.getMethod()); if (requestPath != null) { // 业务逻辑处理 System.out.println("请求路径:" + requestPath); } } return true; } private String getRequestPath(Method method) { for (Class<? extends Annotation> annoClass : REQUEST_ANNOTATIONS) { Annotation annotation = AnnotationUtils.findAnnotation(method, annoClass); if (annotation == null) { continue; } try { // 反射获取注解的value属性 Method valueMethod = annoClass.getMethod("value"); String[] values = (String[]) valueMethod.invoke(annotation); if (values.length > 0 && !values[0].isEmpty()) { return values[0]; } } catch (ReflectiveOperationException e) { // 忽略注解属性获取异常,继续检查下一个注解 continue; } } return null; } }
优势:
- 代码简洁,新增请求注解只需添加到列表中
- 不依赖Spring的映射处理器,轻量化
注意事项
- 方案一的
RequestMappingInfo会自动处理路径中的占位符(如/{id})、路径前缀合并等场景,比方案二更可靠 - 如果控制器类上存在
@RequestMapping前缀,方案二需要额外处理类级别的注解,才能得到完整路径
内容的提问来源于stack exchange,提问作者user3309305
相关产品推荐
相关产品推荐

