由于项目需要使用拦截器对请求参数进行操作,可是请求流只能操作一次,导致后面方法不能再获取流了。
新建SpringBoot项目
1. 新建拦截器WebConfig.java
/**
* @date: 2023/2/6 11:21
* @author: zhouzhaodong
* @description:
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
/**
* 添加Web项目的拦截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 对所有访问路径,都通过MyInterceptor类型的拦截器进行拦截
// 放行登录页,登陆操作,静态资源
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/", "/login", "/index.html", "/user/login", "/css/**", "/images/**", "/js/**", "/fonts/**");
}
}
2. 获取请求参数并处理逻辑
/**
* @date: 2023/2/6 12:46
* @author: zhouzhaodong
* @description: 获取请求参数并处理
*/
public class RequestWrapper extends HttpServletRequestWrapper {
private final Logger logger = LoggerFactory.getLogger(RequestWrapper.class);
private final byte[] body;
public RequestWrapper(HttpServletRequest request) {
super(request);
String sessionStream = getBodyString(request);
body = sessionStream.getBytes(StandardCharsets.UTF_8);
}
public String getBodyString() {
return new String(body, StandardCharsets.UTF_8);
}
/**
* @date: 2023/2/6 12:46
* @author: zhouzhaodong
* @description: 获取请求Body
*/
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, StandardCharsets.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();
}
}
}
logger.info("获取body请求参数:" + sb);
return sb.toString();
}
/**
* @date: 2023/2/6 12:46
* @author: zhouzhaodong
* @description: 复制输入流
*/
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();
}
return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
}
3. 实现HandlerInterceptor接口
/**
* @date: 2023/2/6 11:19
* @author: zhouzhaodong
* @description: 实现HandlerInterceptor接口
*/
public class MyInterceptor implements HandlerInterceptor {
private final Logger logger = LoggerFactory.getLogger(MyInterceptor.class);
/**
* @date: 2023/2/6 11:19
* @author: zhouzhaodong
* @description: 访问控制器方法前执行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
logger.info("================进入拦截器======================");
logger.info(new Date() + "--preHandle:" + request.getRequestURL());
logger.info("***************************【RequestBeginning】***************************");
logger.info("----------------StartProcessingRequest----------------");
try {
long currentTime = System.currentTimeMillis();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = new Date(currentTime);
logger.info("CurrentTime: {}", formatter.format(date));
logger.info("ResponseTime: {}", (System.currentTimeMillis() - currentTime) + "ms");
String requestUrl = request.getRequestURI();
logger.info("RequestURL: {} ", requestUrl);
logger.info("GetMethod: {}", handler);
String method = request.getMethod();
logger.info("Method: {}", method);
//获取请求参数
RequestWrapper requestWrapper = new RequestWrapper(request);
//这里getBodyString()方法无参数
logger.info("RequestBody: {}", requestWrapper.getBodyString());
} catch (Exception e) {
logger.error("MVC业务处理-拦截器异常:", e);
}
logger.info("-------------------------End-------------------------");
return true;
}
/**
* @date: 2023/2/6 12:46
* @author: zhouzhaodong
* @description: 访问控制器方法后执行
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
logger.info(new Date() + "--postHandle:" + request.getRequestURL());
}
/**
* @date: 2023/2/6 12:46
* @author: zhouzhaodong
* @description: postHandle方法执行完成后执行,一般用于释放资源
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
logger.info(new Date() + "--afterCompletion:" + request.getRequestURL());
}
}
4. application.yml
spring:
main:
# 当出现相同名字的类进行注册时,准许覆盖注册
allow-bean-definition-overriding: true
5. 启动类添加@ServletComponentScan注解
6. 新建TestController.java
/**
* @date: 2023/2/6 12:24
* @author: zhouzhaodong
* @description: 测试
*/
@RestController
public class TestController {
@PostMapping("/one/abc")
public String abc(@RequestBody User user){
return user.getName();
}
}
7. 不进行处理先测试看结果
请求结果:
控制台输出:
可以看出,流被读取了一次然后后台就获取不到了。
8. 通过过滤器获取参数然后传到后面程序中
/**
* @date: 2023/2/6 12:47
* @author: zhouzhaodong
* @description:
*/
@Component
@WebFilter(urlPatterns = "/*", filterName = "channelFilter")
public class ChannelFilter implements Filter {
private final Logger logger = LoggerFactory.getLogger(ChannelFilter.class);
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
logger.info("================进入过滤器======================");
// 防止流读取一次后就没有了, 所以需要将流继续写出去
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
RequestWrapper requestWrapper = new RequestWrapper(httpServletRequest);
filterChain.doFilter(requestWrapper, servletResponse);
}
@Override
public void destroy() {
}
}
9. 流处理后再进行测试
请求结果:
控制台输出:
解决啦!!!
源代码路径
https://github.com/zhouzhaodong/springboot/tree/master/springboot-interceptor