- 使用场景:通过request能获取到一次body中的值,有时候我们需要多次获取body中的值的需求,因此需要对流再次封装再次传递
- 例如:在controller中我们通过@RequestBody注解来获取前端传过来的json数据,这里已经使用了一次request来获取body中的值。等我们有需求,在完成这一个controller时,通过aop来记录一下操作记录,则可能会需要再次获取到body中的值
- 获取request的参数方法
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
a.重写自定义HttpServletRequestWrapper
public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {
public String _body;
public MultiReadHttpServletRequest(HttpServletRequest request) throws IOException {
super(request);
StringBuffer sBuffer = new StringBuffer();
BufferedReader bufferedReader = request.getReader();
String line;
while ((line = bufferedReader.readLine()) != null) {
sBuffer.append(line);
}
_body = sBuffer.toString();
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(_body.getBytes());
return new ServletInputStream() {
@Override
public int read() {
return byteArrayInputStream.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
};
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
b. 自定义过滤器Filter
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
if(request instanceof HttpServletRequest) {
requestWrapper = new MultiReadHttpServletRequest((HttpServletRequest) request);
}
//获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中。
// 在chain.doFiler方法中传递新的request对象
if(requestWrapper == null) {
chain.doFilter(request, response);
} else {
chain.doFilter(requestWrapper, response);
}
}
@Override
public void destroy() {
}
}
c.在配置文件进行配置
@Configuration
public class MyWebConfig implements WebMvcConfigurer {
@Bean
public FilterRegistrationBean filterRegist() {
FilterRegistrationBean frBean = new FilterRegistrationBean();
frBean.setFilter(new MyFilter());
frBean.addUrlPatterns("/*");
System.out.println("filter");
return frBean;
}
}
提醒一下:如果你进行文件导入时使用了MultiPartFile 这个组件来上传文件,还是会报 getInputSteam()has already exists的异常。所以你只需要将上传文件的那个请求进行过滤就可以了
- 过滤器修改如下:
public class MyFilter implements Filter {
private final Set<String> ALLOWED_PATHS = Collections.unmodifiableSet(new HashSet<>(
Arrays.asList("/writeExcelToDir")));
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
if(request instanceof HttpServletRequest) {
HttpServletRequest servletRequest = (HttpServletRequest) request;
String requestURI = servletRequest.getRequestURI();
if (ALLOWED_PATHS.contains(requestURI)){
chain.doFilter(servletRequest,response);
}else {
requestWrapper = new MultiReadHttpServletRequest(servletRequest);
//获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中。
// 在chain.doFiler方法中传递新的request对象
chain.doFilter(requestWrapper, response);
}
}
}