SpringBoot配置拦截器,获取get和post请求的内容
做这个需求时还遇到过一个小问题,因为拦截后想要获取post请求的参数需要用getInputStream()或getReader()来获取内容,但因为在整个请求中io流只能获取一次,我在这里就获取的话,后面会报相应的错误,故要重写类和方法,将获取到的流保存下来
配置拦截器,重写preHandle(),postHandle(),afterCompletion()方法处理入参,这三个方法的作用
preHandle():在请求处理之前进行调用(Controller方法调用之前),返回结果为true时,请求将会继续执行后面的操作,为false时,被请求时,请求终止,且后面的 postHandle 和 afterCompletion 方法都不会执行
postHandle():请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
afterCompletion():请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
package com.htsc.thfx.interceptor.interceptor;
import org.springframework.util.StreamUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
public class BootInterceptor implements HandlerInterceptor {
/**
* 在请求处理之前进行调用(Controller方法调用之前)
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("执行了BootInterceptor的preHandle方法");
// 根据请求类型获取 入参
String method = httpServletRequest.getMethod();
if ("GET".equalsIgnoreCase(method)) {
Map<String, String[]> parameterMap = httpServletRequest.getParameterMap();
} else {
//获取请求body
byte[] bodyBytes = StreamUtils.copyToByteArray(httpServletRequest.getInputStream());
String body = new String(bodyBytes, httpServletRequest.getCharacterEncoding());
}
//如果设置为true时,请求将会继续执行后面的操作
//如果设置为false时,被请求时,请求终止,且后面的 postHandle 和 afterCompletion 方法都不会执行
return true;
}
/**
* 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
*/
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("执行了BootInterceptor的postHandle方法");
}
/**
* 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
*/
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("执行了BootInterceptor的afterCompletion方法");
}
}
package com.htsc.thfx.interceptor.config;
import com.htsc.thfx.interceptor.interceptor.BootInterceptor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.*;
import java.util.List;
@Configuration
public class BootConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer pathMatchConfigurer) {
}
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer contentNegotiationConfigurer) {
}
@Override
public void configureAsyncSupport(AsyncSupportConfigurer asyncSupportConfigurer) {
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer defaultServletHandlerConfigurer) {
}
@Override
public void addFormatters(FormatterRegistry formatterRegistry) {
}
@Override
public void addInterceptors(InterceptorRegistry interceptorRegistry) {
InterceptorRegistration registration = interceptorRegistry.addInterceptor(new BootInterceptor());
// 过滤所有接口
registration.addPathPatterns("/**");
// 排除不过滤的接口
registration.excludePathPatterns(
"/simulationPort/**"
);
}
@Bean
@Qualifier(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
return new XinDispatcherServlet();
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry resourceHandlerRegistry) {
}
@Override
public void addCorsMappings(CorsRegistry corsRegistry) {
}
@Override
public void addViewControllers(ViewControllerRegistry viewControllerRegistry) {
}
@Override
public void configureViewResolvers(ViewResolverRegistry viewResolverRegistry) {
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> list) {
}
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> list) {
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> list) {
}
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> list) {
}
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> list) {
}
@Override
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> list) {
}
@Override
public Validator getValidator() {
return null;
}
@Override
public MessageCodesResolver getMessageCodesResolver() {
return null;
}
}
自定义 DispatcherServlet 来分派 XinHttpServletRequestWrapper
package com.htsc.thfx.interceptor.config;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 自定义 DispatcherServlet 来分派 XinHttpServletRequestWrapper
*/
public class XinDispatcherServlet extends DispatcherServlet {
/**
* 包装成自定义的request
*
* @param request
* @param response
* @throws Exception
*/
@Override
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
super.doDispatch(new XinHttpServletRequestWrapper(request), response);
}
}
自定义HttpServletRequestWrapper 来包装输入流
package com.htsc.thfx.interceptor.config;
import org.springframework.util.StreamUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
/**
* 自定义 HttpServletRequestWrapper 来包装输入流
* 背景:因为ServletInputStream被读取后无法第二次再读取了,所以要把读取过的内容存下来,然后需要的时候对外提供可被重复读取的ByteArrayInputStream
* 为了重写 ServletInputStream 的 getInputStream()方法,要自定义一个 HttpServletRequestWrapper
*/
public class XinHttpServletRequestWrapper extends HttpServletRequestWrapper {
/**
* 缓存下来的HTTP body
*/
private byte[] body;
public XinHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
body = StreamUtils.copyToByteArray(request.getInputStream());
}
/**
* 重新包装 getInputStream
*
* @return
* @throws IOException
*/
@Override
public ServletInputStream getInputStream() throws IOException {
InputStream bodyStream = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bodyStream.read();
}
/**
* 下面的方法一般情况下不会被使用,如果引入了一些需要使用ServletInputStream的外部组件,后面可以关注一下。
* @return
*/
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
/**
* 重新包装 getReader
*
* @return
* @throws IOException
*/
@Override
public BufferedReader getReader() throws IOException {
InputStream bodyStream = new ByteArrayInputStream(body);
return new BufferedReader(new InputStreamReader(getInputStream()));
}
}