非Spring Boot的Spring MVC API遇404,如何列出所有已注册端点?
非Spring Boot环境下Spring MVC列出已注册端点的方法
当遇到404错误时,确认所有已注册的请求端点是排查问题的关键,以下是几种无需依赖Spring Boot Actuator的实现方式:
1. 通过ApplicationContext获取HandlerMapping
直接从Spring容器中获取核心的请求映射处理器,遍历所有注册的端点:
@Autowired private ApplicationContext context; @GetMapping("/list-endpoints") public ResponseEntity<Map<String, String>> listAllEndpoints() { Map<String, String> endpointMap = new HashMap<>(); // 获取容器中所有HandlerMapping实例 Map<String, HandlerMapping> handlerMappings = context.getBeansOfType(HandlerMapping.class); for (HandlerMapping mapping : handlerMappings.values()) { if (mapping instanceof RequestMappingHandlerMapping) { RequestMappingHandlerMapping requestMapping = (RequestMappingHandlerMapping) mapping; // 获取所有注册的请求处理方法 Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMapping.getHandlerMethods(); for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) { RequestMappingInfo info = entry.getKey(); HandlerMethod method = entry.getValue(); // 提取请求路径并关联处理方法信息 Set<String> patterns = info.getPatternsCondition().getPatterns(); for (String pattern : patterns) { endpointMap.put(pattern, String.format("%s.%s()", method.getBeanType().getSimpleName(), method.getMethod().getName())); } } } } return ResponseEntity.ok(endpointMap); }
这段代码可以写在一个控制器中,访问对应的路径就能返回所有已注册的端点列表。
2. 监听容器初始化事件打印端点
通过实现ApplicationListener,在Spring容器初始化完成后自动打印所有端点:
@Component public class EndpointPrinterListener implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { ApplicationContext context = event.getApplicationContext(); Map<String, HandlerMapping> handlerMappings = context.getBeansOfType(HandlerMapping.class); System.out.println("=== Spring MVC已注册端点列表 ==="); for (HandlerMapping mapping : handlerMappings.values()) { if (mapping instanceof RequestMappingHandlerMapping) { RequestMappingHandlerMapping requestMapping = (RequestMappingHandlerMapping) mapping; Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMapping.getHandlerMethods(); for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) { RequestMappingInfo info = entry.getKey(); HandlerMethod method = entry.getValue(); // 输出请求路径、请求方法和对应的处理类方法 info.getPatternsCondition().getPatterns().forEach(pattern -> { StringBuilder sb = new StringBuilder(); sb.append(pattern).append(" ["); info.getMethodsCondition().getMethods().forEach(m -> sb.append(m.name()).append(",")); if (sb.charAt(sb.length()-1) == ',') sb.deleteCharAt(sb.length()-1); sb.append("] -> ").append(method.getBeanType().getName()).append(".").append(method.getMethod().getName()).append("()"); System.out.println(sb); }); } } } } }
启动应用后,控制台会直接输出所有已注册的端点信息,适合在启动阶段排查映射问题。
3. 启用日志调试输出端点
无需编写代码,通过配置日志框架,将RequestMappingHandlerMapping的日志级别设为DEBUG,就能在启动时看到所有注册的请求映射:
以Log4j2为例,在配置文件中添加:
<Logger name="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" level="DEBUG"/>
启动后,日志中会输出类似如下的内容:
Mapped "{[/api/users],methods=[GET]}" onto public com.example.dto.User com.example.controller.UserController.getUserById(java.lang.Long)
清晰展示每个端点的路径、请求方法和对应的处理方法。
注意事项
- 确保控制器类已被Spring扫描到,比如配置了
<context:component-scan base-package="com.example.controller"/>或使用@ComponentScan注解。 - 如果使用了自定义的
HandlerMapping实现,需要在遍历判断时纳入,避免遗漏特殊映射。
内容的提问来源于stack exchange,提问作者Mr Smith
相关产品推荐
相关产品推荐

