如何利用装饰器模式使重复读取请求体Request Body
1、在获取请求体的时候, HttpServletRequest提供了getInputStream方法用来获取,但这是一次性的,流关闭以后就不能再获取,此时我们可以继承HttpServletRequestWrapper来增强HttpServletRequest
2、继承
@Slf4j
public class RequestBodyWrapper extends HttpServletRequestWrapper {
/**
* 保存body
*/
private byte[] requestBody = null;
public RequestBodyWrapper(HttpServletRequest request) {
super(request);
try {
requestBody = StreamUtils.copyToByteArray(request.getInputStream());
} catch (IOException e) {
log.error("", e);
}
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream is = new ByteArrayInputStream(requestBody);
return new ServletInputStream() {
@Override
public int read() {
return is.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
public byte[] getRequestBody() {
return requestBody;
}
}
3、使用前置过滤器封装HttpServletRequest
@WebFilter(filterName = "requestBodyFilter",urlPatterns = {"/*"})
@Order(Integer.MIN_VALUE)
@Slf4j
public class RequestBodyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//requestWrapper中保存着供二次使用的请求数据
ServletRequest requestWrapper = null;
if (request instanceof HttpServletRequest) {
requestWrapper = new RequestBodyWrapper((HttpServletRequest) request);
}
if(requestWrapper == null) {
chain.doFilter(request, response);
} else {
chain.doFilter(requestWrapper, response);
}
}
@Override
public void destroy() {
}
}
4、封装一个公共方法,随时在业务逻辑中获取body
public static String getBody(HttpServletRequest request) {
if(request instanceof RequestBodyWrapper) {
RequestBodyWrapper wrapper = (RequestBodyWrapper)request;
return new String(wrapper.getRequestBody());
} else {
return "";
}
}
注:在Controller层,@RequestBody的使用完全不受影响,可正常使用