文章目录
前言HandlerInterceptorAdapter/HandlerInterceptor拦截器,并重复读取HttpServletRequest的getInputStream()方法1. 基于Spring HandlerInterceptorAdapter/HandlerInterceptor的拦截器2. 设置HandlerInterceptor的执行顺序3. HttpServletRequest和HttpServletResponse的一些常见操作4. 如何实现 HttpServletRequest 中 InputStream 的方法重复读取5. 实现HandlerInterceptor整体示例
前言
如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。 而且听说点赞的人每天的运气都不会太差,实在白嫖的话,那欢迎常来啊!!!
HandlerInterceptorAdapter/HandlerInterceptor拦截器,并重复读取HttpServletRequest的getInputStream()方法
1. 基于Spring HandlerInterceptorAdapter/HandlerInterceptor的拦截器
HandlerInterceptorAdapter是Spring Framework中提供的一个拦截器适配器,用于拦截请求的处理过程。它是HandlerInterceptor接口的一个实现,并提供了默认的空方法,使得开发者可以选择性地覆盖需要的方法。
拦截器允许你在请求处理的不同阶段执行自定义的逻辑,比如在请求被处理前、处理中、处理后等阶段。HandlerInterceptorAdapter简化了拦截器的使用,开发者只需要继承它并重写需要的方法,而不需要实现HandlerInterceptor接口的所有方法。
以下是HandlerInterceptorAdapter中的一些方法和它们的作用: 1. preHandle:在请求处理之前被调用。可以用于执行一些前置处理逻辑,比如权限检查、日志记录等。如果该方法返回true,则继续执行后续的拦截器和处理器;如果返回false,则中断执行,请求不会继续传递给后续的拦截器和处理器。 2. postHandle:在请求处理之后、视图渲染之前被调用。可以用于执行一些后置处理逻辑,比如修改ModelAndView。 3. afterCompletion:在整个请求完成后被调用。可以用于执行一些资源清理工作,比如释放资源、记录执行时间等。它的调用时机是在视图渲染完成之后,所以对响应的修改不会影响到最终的响应。
使用HandlerInterceptorAdapter的好处在于,你可以只关注你感兴趣的拦截点,而不需要实现所有的方法。如果你只关心请求前的处理逻辑,你只需要重写preHandle方法即可。 注意:在Spring 5.x及更高版本,推荐使用HandlerInterceptor接口,而不是继承HandlerInterceptorAdapter。HandlerInterceptorAdapter在Spring 5.x中已被标记为过时。如果你的项目使用的是较新版本的Spring,请直接实现HandlerInterceptor接口。
2. 设置HandlerInterceptor的执行顺序
在Spring MVC中,多个HandlerInterceptor的执行顺序是可以通过配置进行控制的。可以通过实现WebMvcConfigurer接口或使用@Configuration注解的方式,在Spring MVC配置中定义拦截器并指定它们的顺序。
以下是一种常见的配置方式,用于指定拦截器的执行顺序:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 创建并添加拦截器实例
HandlerInterceptorInterceptor1 interceptor1 = new HandlerInterceptor1();
HandlerInterceptorInterceptor2 interceptor2 = new HandlerInterceptor2();
// 通过registry指定拦截器的顺序
registry.addInterceptor(interceptor1).order(1);
registry.addInterceptor(interceptor2).order(2);
}
}
3. HttpServletRequest和HttpServletResponse的一些常见操作
HttpServletRequest (请求操作)
获取请求信息:
getMethod(): 获取HTTP方法(GET、POST、PUT等)。getRequestURI(): 返回请求的完整 URI,包括上下文路径、servlet 路径和任何路径参数。getServletPath():返回请求的 URL 中 servlet 的部分。getParameter(name): 获取请求参数的值。getHeader(name): 获取指定名称的HTTP头信息。getParameterMap():对象中获取请求参数的方法。
请求内容操作:
getInputStream(): 获取请求的输入流,用于读取请求体内容。getReader(): 获取请求的Reader对象,用于读取字符流。
请求属性操作:
setAttribute(name, value): 设置请求级别的属性。getAttribute(name): 获取请求级别的属性值。removeAttribute(name): 移除请求级别的属性。
HttpServletResponse (响应操作)
设置响应信息:
setStatus(status): 设置响应的状态码(如200、404等)。setContentType(type): 设置响应内容的MIME类型。setHeader(name, value): 设置响应头信息。
响应内容操作:
getOutputStream(): 获取响应的输出流,用于写入响应体内容。getWriter(): 获取响应的Writer对象,用于写入字符流。
重定向和发送错误:
sendRedirect(location): 发送重定向响应到指定的URL。sendError(status, message): 发送错误响应,可附带自定义消息。
缓存控制:
setHeader(“Cache-Control”, “no-cache”): 禁用缓存。setDateHeader(name, date): 设置日期类型的响应头
4. 如何实现 HttpServletRequest 中 InputStream 的方法重复读取
在Spring MVC中,默认情况下,HttpServletRequest的getInputStream()方法只能被调用一次,因为它返回的是一个输入流,一旦读取,就无法再次读取。然而,有时候我们需要多次读取请求体内容。 实现思路: 设置一个拦截器,每次调用之前将HttpServletRequest 中的InputStream备份。
示例:
@Bean
@Order(1)
public ManyHandlerInterceptorFilter manyHandlerInterceptorFilter(){
return new ManyHandlerInterceptorFilter();
}
过滤器:
public class ManyHandlerInterceptorFilter implements Filter{
@Override
public void init(FilterConfig arg0) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
if (!ServletFileUpload.isMultipartContent(httpRequest)) {
httpRequest = new ReusableInputStreamRequestWrapper(httpRequest);
}
//将request 传到下一个Filter
filterChain.doFilter(httpRequest, response);
}
}
重写getInputStream方法:
@Slf4j
public class ReusableInputStreamRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
private String bodyString;
private static final String CHARSET_UTF8 = "UTF-8";
public ReusableInputStreamRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
// 读取请求体内容并缓存
bodyString = StreamUtils.copyToString(request.getInputStream(), Charset.forName(CHARSET_UTF8));
body = bodyString.getBytes(CHARSET_UTF8);
}
public String getBodyString() {
return this.bodyString;
}
public byte [] getBody(){
return this.body;
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream innerBAIS = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return innerBAIS.read();
}
};
}
}
5. 实现HandlerInterceptor整体示例
@Slf4j
@Component
public class TestBIterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest requestWrapper, HttpServletResponse response, Object handler) throws IOException {
log.info("request请求方法method:[{}],请求地址path[{}] , uri[{}]", requestWrapper.getMethod(),requestWrapper.getServletPath(),requestWrapper.getRequestURI());
log.info("请求参数- map:{}", JsonUtils.toJson((requestWrapper.getParameterMap())));
log.info("请求参数- body:{}", IOUtils.toString(requestWrapper.getInputStream()));
return Boolean.TRUE;
}
}
精彩内容
发表评论