今天实现一个通过拦截器HandlerIntercer获取到请求数据对参数进行校验的需求。
获取的body中的数据方式有两种:
StringBuffer data = new StringBuffer();
String line = null;
BufferedReader reader = request.getReader();
try {
while (null != (line = reader.readLine())){
data.append(line);
}
}catch (IOException e) {
e.printStackTrace();
}
或者
String result = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
都会使用到HttpServletRequest中的getReader()来读取字符流,结果到达controller中时报错:
java.lang.IllegalStateException: getReader() has already been called for this request
查询一些博客,说到原因是getReader()和getInputStream(),只能使用一次,在controller层加了@RequestBody的注解会再调用一次就会报错。
解决的方式:
- 自定义request
package com.ruoyi.biz.utils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;
/**
* @ClassName HandlerCheckCodeInterceptor
* @Description 自定义HttpServletRequestWrapper
* @Author zj
* @Date 10:10 2022/6/10
* @Version 1.0
**/
public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
private byte[] body;
public CustomHttpServletRequestWrapper(HttpServletRequest request) throws IOException
{
super(request);
BufferedReader reader = request.getReader();
try (StringWriter writer = new StringWriter()) {
int read;
char[] buf = new char[1024 * 8];
while ((read = reader.read(buf)) != -1) {
writer.write(buf, 0, read);
}
this.body = writer.getBuffer().toString().getBytes();
}
}
public String getBody(){
return new String(body, StandardCharsets.UTF_8);
}
@Override
public ServletInputStream getInputStream() throws IOException
{
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
return new ServletInputStream()
{
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
public int read() throws IOException
{
return byteArrayInputStream.read();
}
};
}
@Override
public BufferedReader getReader() throws IOException
{
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
- 定义一个过滤器加入我们自定义的HttpServletRequestWrapper
package com.ruoyi.biz.filter;
import com.ruoyi.biz.utils.CustomHttpServletRequestWrapper;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @ClassName GetRequestBodyFilter
* @Description TODO
* @Author zj
* @Date 14:42 2022/6/10
* @Version 1.0
**/
@Component
@WebFilter(urlPatterns = "/*", filterName = "GetRequestBodyFilter")
public class GetRequestBodyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
if(servletRequest instanceof HttpServletRequest) {
requestWrapper = new CustomHttpServletRequestWrapper((HttpServletRequest) servletRequest);
}
if(requestWrapper == null) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
filterChain.doFilter(requestWrapper, servletResponse);
}
}
}
- 拦截器中如何获取到body数据
package com.ruoyi.biz.interceptor;
import com.alibaba.fastjson.JSON;
import com.ruoyi.biz.annotation.ParameterVerificationAnnotation;
import com.ruoyi.biz.standard.HandlerParameterVerificationService;
import com.ruoyi.biz.utils.SpringContextUtils;
import com.ruoyi.common.core.constant.HttpStatus;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
/**
* @ClassName HandlerCheckCodeInterceptor
* @Description TODO
* @Author zj
* @Date 10:10 2022/6/10
* @Version 1.0
**/
@Component
public class HandlerParameterVerificationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
CustomHttpServletRequestWrapper wrapper = (CustomHttpServletRequestWrapper) request;
String body = wrapper.getBody();
System.out.println("body数据--------->"+body);
return true;
}
}
解决的思路是getReader()读取到一次数据放到缓存中,重写getReader(),后面再调用就从缓存中拿到数据。
参考博客:
https://blog.csdn.net/qq_25379811/article/details/119000904