拦截器介绍
1)SpringMVC拦截器: 实现对每一个请求处理前后进行相关的业务处理,类似Servlet中的Filter
2)SpringMVC中的Interceptor拦截请求是通过HandlerInterceptor来实现的
3)所有HandlerMapping实现都支持处理程序拦截器,功能可以实现检查会话,记录日志等,拦截器必须实现HandlerInterceptor接口
4)该接口有三个方法
- preHandle(..)在实际的处理程序执行之前
- postHandle(..)在执行处理程序之后
- afterCompletion(..)完成(..)完整的请求完成后
5)preHandle(..)方法返回一个布尔值.我们可以使用此方法中断或继续执行链的处理.当此方法返回 true时,处理程序执行链将继续.当他返回false时,DispatcherServlet假设拦截器本身已经处理了请求(例如,呈现了一个适当的视图),并且不再继续执行链中的其他拦截器和实际的处理程序.
Filter与Interceptor的区别
1) 如果都匹配的话,Filter使先执行,然后再执行Intercetor
2) Filter使Servlets规范的三大主键之一,而Interceptor是SpringMVC的组件
一: 拦截POST请求
springmvc 拦截器获取不到Post请求参数
Spring MVC 拦截器默认情况下无法直接获取POST请求的参数,因为HttpServletRequest的getParameter方法在拦截器中不会被自动调用。这是因为,在拦截器中,request对象被封装在一个ServletRequestWrapper
中,而ServletRequestWrapper
对POST请求的参数访问做了特殊处理,导致拦截器无法直接获取到参数。
解决方法:使用HttpServletRequest
的getReader()
或getInputStream()
方法读取请求体,然后解析里面的参数。
package org.example.testspringbootrabbitmqconsumer.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.util.ContentCachingRequestWrapper;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class UserHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取body入参
String body = "";
if (request instanceof RequestWrapper) {
body = ((RequestWrapper) request).getBodyString();
}
// 获取路径参数
String urlParams = JSONUtil.toJsonStr(request.getParameterMap());
// 获取@PathVariable路径参数
Map pathVariables = (Map)request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
return true;
}}
二:问题处理
问题:流只能被读取一次,在拦截器中读取后,Controller获取不到流了,因此请求的参数拿不到了
解决: 写一个过滤器
package org.example.testspringbootrabbitmqconsumer.test1;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;
public class RequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
String sessionStream = getBodyString(request);
body = sessionStream.getBytes(Charset.forName("UTF-8"));
}
public String getBodyString(){
return new String(body,Charset.forName("UTF-8"));
}
/**
* 获取请求Body
*
* @param request
* @return
*/
public String getBodyString(final ServletRequest request) {
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try {
inputStream = cloneInputStream(request.getInputStream());
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line);
}
}
catch (IOException e) {
e.printStackTrace();
}
finally {
if (inputStream != null) {
try {
inputStream.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
/**
* Description: 复制输入流</br>
*
* @param inputStream
* @return</br>
*/
public InputStream cloneInputStream(ServletInputStream inputStream) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
try {
while ((len = inputStream.read(buffer)) > -1) {
byteArrayOutputStream.write(buffer, 0, len);
}
byteArrayOutputStream.flush();
}
catch (IOException e) {
e.printStackTrace();
}
InputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
return byteArrayInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
}
package org.example.testspringbootrabbitmqconsumer.test1;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
@WebFilter(urlPatterns = "/*",filterName = "channelFilter")
public class ChannelFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException, IOException {
// 防止流读取一次后就没有了, 所以需要将流继续写出去
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
ServletRequest requestWrapper = new RequestWrapper(httpServletRequest);
filterChain.doFilter(requestWrapper, servletResponse);
}
@Override
public void destroy() {
}
}