如何利用拦截器获取HTTP请求参数
在开发Web应用时,我们经常需要获取HTTP请求的参数。Spring框架提供了多种方式来获取这些参数,其中一种就是使用拦截器(Interceptor)。本文将详细介绍如何利用拦截器获取HTTP请求参数。
1. 拦截器简介
在Spring框架中,拦截器是实现了HandlerInterceptor
接口的类。拦截器可以在请求被处理之前、之后或者在视图被渲染之前进行拦截,以执行一些自定义的操作。
在我们的项目中,我们定义了一个名为RequestInterceptor
的拦截器,它实现了HandlerInterceptor
接口。在这个拦截器中,我们重写了preHandle
方法,用来在请求被处理之前获取请求参数。
@Slf4j public class RequestInterceptor implements HandlerInterceptor { @Override public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception { // 如果请求是MultipartHttpServletRequest,那么跳过处理 if (request instanceof MultipartHttpServletRequest) { return true; } //获取请求参数 String queryString = request.getQueryString(); log.info("请求参数:{}", queryString); //获取请求body byte[] bodyBytes = StreamUtils.copyToByteArray(request.getInputStream()); String body = new String(bodyBytes, request.getCharacterEncoding()); log.info("请求体:{}", body); // 将请求参数和请求体放入当前线程中 HashMap<String, Object> paramMap = MapUtil.newHashMap(2); paramMap.put("param", queryString); paramMap.put("body", body); RequestParamThreadLocal.set(paramMap); return true; } @Override public void afterCompletion(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler, Exception ex) throws Exception { HandlerInterceptor.super.afterCompletion(request, response, handler, ex); // 移除当前线程中的数据 RequestParamThreadLocal.remove(); } }
我们在WebMvcConfig
类中注册了这个拦截器,使其能够拦截所有的请求。
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RequestInterceptor()).addPathPatterns("/**"); } @Bean @Qualifier(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServlet dispatcherServlet() { return new XinDispatcherServlet(); } }
2. 获取请求参数
在拦截器中,我们可以通过HttpServletRequest
对象来获取请求参数。HttpServletRequest
提供了多种方法来获取请求参数,例如getQueryString()
、getParameterMap()
和getInputStream()
。
但是,HttpServletRequest
的输入流只能被读取一次。一旦读取完毕,就不能再次读取。为了解决这个问题,我们定义了一个名为CustomerHttpServletRequestWrapper
的类,它继承自HttpServletRequestWrapper
,并重写了getInputStream()
和getReader()
方法,使得输入流可以被多次读取。
public class CustomerHttpServletRequestWrapper extends HttpServletRequestWrapper { /** * 缓存下来的HTTP body */ private final byte[] body; public CustomerHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); body = StreamUtils.copyToByteArray(request.getInputStream()); } /** * 重新包装输入流 * * @return {@link ServletInputStream} * @throws IOException ioexception */ @Override public ServletInputStream getInputStream() throws IOException { InputStream bodyStream = new ByteArrayInputStream(body); return new ServletInputStream() { @Override public int read() throws IOException { return bodyStream.read(); } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return true; } @Override public void setReadListener(ReadListener readListener) { } }; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } }
在CustomerDispatcherServlet
类中,我们重写了doDispatch
方法,将原始的HttpServletRequest
包装成CustomerHttpServletRequestWrapper
,然后再传递给super.doDispatch()
方法。
public class CustomerDispatcherServlet extends DispatcherServlet { @Override protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { super.doDispatch(new CustomerHttpServletRequestWrapper(request), response); } }
3. 存储请求参数
为了在后续的处理中方便地获取请求参数,我们将请求参数和请求体存储在了ThreadLocal
中。我们定义了一个名为RequestParamThreadLocal
的类,它提供了set
和get
方法来存储和获取数据。
public class RequestParamThreadLocal { private static final ThreadLocal<Map<String, Object>> REQUEST_PARAM_CONTEXT = new ThreadLocal<>(); public static void set(Map<String, Object> map) { REQUEST_PARAM_CONTEXT.set(map); } public static Map<String, Object> get() { return REQUEST_PARAM_CONTEXT.get(); } public static void remove() { REQUEST_PARAM_CONTEXT.remove(); } }
在RequestInterceptor
的preHandle
方法中,我们将请求参数和请求体存储在了RequestParamThreadLocal
中。
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 获取请求参数和请求体 // ... // 将请求参数和请求体存储在ThreadLocal中 RequestParamThreadLocal.set(paramMap); return true; }
4. 总结
通过使用Spring框架的拦截器,我们可以方便地获取HTTP请求的参数。我们还可以通过自定义HttpServletRequestWrapper
来解决输入流只能被读取一次的问题。最后,我们可以将请求参数和请求体存储在ThreadLocal
中,以便在后续的处理中使用。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix