Spring Boot启动时如何获取所有请求方法、路径、头及请求体?
Spring Boot启动后预扫描端点并生成信息文件的实现方案
需求肯定能实现
Spring Boot提供了上下文生命周期钩子,可以在应用完全启动、任何端点被访问前触发端点扫描逻辑,还能通过框架提供的API获取所有端点的元数据(请求方法、路径、头信息),请求体的信息可以通过方法参数注解识别。
现有代码的问题
你的代码没法正常工作,主要有这几个问题:
- 判断请求体的逻辑不准确:只靠方法参数数量>0来判断是否接收请求体,很多端点有参数但不是请求体(比如
@RequestParam),应该直接检查参数上的@RequestBody注解 - 注解获取不全面:只获取
@RequestMapping注解,但实际开发中常用@PostMapping、@PutMapping这类派生注解,这些注解本身包含@RequestMapping,但用getMethodAnnotation会直接拿不到,得用findAnnotation - 没有自动触发逻辑:当前类只是
@Component,但scanEndpointsWithRequestBody方法没人调用,得绑定到应用启动完成的事件上 - 缺少文件生成逻辑:代码只是打印路径,没实现写入文件的功能
修正后的完整实现
下面是可以直接用的代码,包含启动自动触发、准确识别端点信息、生成文件的逻辑:
import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.mvc.method.RequestMappingInfo; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Parameter; import java.util.Map; import java.util.Set; @Component public class EndpointScanner implements ApplicationListener<ContextRefreshedEvent> { private final RequestMappingHandlerMapping handlerMapping; public EndpointScanner(RequestMappingHandlerMapping handlerMapping) { this.handlerMapping = handlerMapping; } @Override public void onApplicationEvent(ContextRefreshedEvent event) { // 避免上下文刷新多次触发(比如父子上下文) if (event.getApplicationContext().getParent() == null) { scanAndGenerateEndpointFile(); } } private void scanAndGenerateEndpointFile() { Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods(); StringBuilder content = new StringBuilder(); content.append("所有端点信息:\n"); content.append("========================================\n"); for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) { RequestMappingInfo info = entry.getKey(); HandlerMethod handlerMethod = entry.getValue(); // 获取请求方法(GET/POST/PUT等) Set<String> httpMethods = info.getMethodsCondition().getMethods(); if (httpMethods.isEmpty()) { httpMethods.add("ANY"); } // 请求路径 Set<String> paths = info.getPathsCondition().getPatterns(); // 请求头条件 Set<String> headers = info.getHeadersCondition().getExpressions(); // 判断是否接收请求体 boolean acceptsRequestBody = false; for (Parameter parameter : handlerMethod.getMethod().getParameters()) { if (parameter.isAnnotationPresent(RequestBody.class)) { acceptsRequestBody = true; break; } } // 拼接信息 content.append("请求方法: ").append(String.join(", ", httpMethods)).append("\n"); content.append("请求路径: ").append(String.join(", ", paths)).append("\n"); content.append("请求头条件: ").append(headers.isEmpty() ? "无" : String.join(", ", headers)).append("\n"); content.append("是否接收请求体: ").append(acceptsRequestBody ? "是" : "否").append("\n"); content.append("处理方法: ").append(handlerMethod.getMethod().getDeclaringClass().getName()) .append(".").append(handlerMethod.getMethod().getName()).append("\n"); content.append("========================================\n"); } // 写入文件 try (FileWriter writer = new FileWriter("endpoints_info.txt")) { writer.write(content.toString()); System.out.println("端点信息文件已生成: endpoints_info.txt"); } catch (IOException e) { System.err.println("生成端点文件失败: " + e.getMessage()); e.printStackTrace(); } } }
关键说明
- 启动触发时机:实现
ApplicationListener<ContextRefreshedEvent>,在Spring上下文完全刷新后执行扫描,加了getParent() == null判断,避免嵌入式容器的父子上下文重复触发 - 准确识别请求体:遍历方法参数,检查是否有
@RequestBody注解,这是判断端点是否接收请求体的标准方式 - 全面获取元数据:从
RequestMappingInfo中直接拿请求方法、路径、头条件,不管用的是@RequestMapping还是派生注解都能覆盖 - 文件生成:用
FileWriter写入文本文件,你可以根据需求改成JSON、XML等格式,或者调整输出内容
内容的提问来源于stack exchange,提问作者Shreyas Murali
相关产品推荐
相关产品推荐

