文章目录

前言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;

}

}

精彩内容

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。