概述
HttpServletRequestWrapper提供了许多处理HttpServletRequest的方法,通常情况下,程序调用HttpServletRequest之后,该request无法被再次调用。
场景
在有些场景下,需要多次调用request中的参数值,例如身份验证。将多个校验参数放入请求体中,自定义验证码过滤器CaptchaFilter和密码过滤器PwdFilter放入FilterChain中。当request被CaptchaFilter获取并得到验证码校验通过后,调用filterChain.doFilter(request, response)放行,当请求进入PwdFilter时,该过滤器期望获取到请求体中的用户名和密码,但是此时request通过getReader()读取后,结果为空,后续处理中可能产生NullPointerException。
本文通过继承HttpServletRequestWrapper,重写部分方法,自定义包装类实现request复用。
在使用本文方法之前,要确保request在此之前没有被任何方法使用(即调用过getInputStream()方法)。
实现
首先,继承HttpServletRequestWrapper,读取一次request并缓存。
public class CustomizeServletRequestWrapper extends HttpServletRequestWrapper {
private final ServletInputStream inputStream;
/**
* Constructs a request object wrapping the given request.
*
* @param request The request to wrap
* @throws IllegalArgumentException if the request is null
*/
public CustomizeServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
// 读取request并缓存
byte[] body = IOUtils.toByteArray(request.getInputStream());
this.inputStream = new RequestCachingInputStream(body);
}
//代理ServletInputStream
private static class RequestCachingInputStream extends ServletInputStream {
private final ByteArrayInputStream is;
public RequestCachingInputStream(byte[] bytes) {
this.is = new ByteArrayInputStream(bytes);
}
@Override
public int read() throws IOException {
return this.is.read();
}
@Override
public boolean isFinished() {
return this.is.available() == 0;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener readlistener) {
}
}
}
缓存request数据后,重写HttpServletRequestWrapper的getInputStream()和getReader()方法:
private BufferedReader reader;
@Override
public ServletInputStream getInputStream() throws IOException {
if (this.inputStream != null) {
return this.inputStream;
}
return super.getInputStream();
}
@Override
public BufferedReader getReader() throws IOException {
if (this.reader == null) {
this.reader = new BufferedReader(new InputStreamReader(getInputStream(), getCharacterEncoding()));
}
return this.reader;
}
在类中添加获取请求体参数的方法:
private String requestBodyLine;
/**
* 将请求体参数存入Map中
* @return
* @throws IOException
*/
public Map<String, Object> getRequestBodyToMap() throws IOException {
String jsonInfo = this.getRequestBodyToStr();
return JsonUtils.parseMap(jsonInfo);
}
public String getRequestBodyToStr() throws IOException {
if (this.requestBodyLine == null) {
BufferedReader reader = this.getReader();
StringBuilder builder = new StringBuilder();
String line = reader.readLine();
while (line != null) {
builder.append(line);
line = reader.readLine();
}
requestBodyLine = builder.toString();
reader.close();
}
return requestBodyLine;
}
完整的装饰类:
import com.jingzheng.common.utils.json.JsonUtils;
import org.apache.commons.io.IOUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Map;
public class CustomizeServletRequestWrapper extends HttpServletRequestWrapper {
private final ServletInputStream inputStream;
private BufferedReader reader;
private String requestBodyLine;
/**
* Constructs a request object wrapping the given request.
*
* @param request The request to wrap
* @throws IllegalArgumentException if the request is null
*/
public CustomizeServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
//读一次 然后缓存 实现同一request多次读取
byte[] body = IOUtils.toByteArray(request.getInputStream());
this.inputStream = new RequestCachingInputStream(body);
}
@Override
public ServletInputStream getInputStream() throws IOException {
if (this.inputStream != null) {
return this.inputStream;
}
return super.getInputStream();
}
@Override
public BufferedReader getReader() throws IOException {
if (this.reader == null) {
this.reader = new BufferedReader(new InputStreamReader(getInputStream(), getCharacterEncoding()));
}
return this.reader;
}
/**
* 将请求体参数存入Map中
* @return
* @throws IOException
*/
public Map<String, Object> getRequestBodyToMap() throws IOException {
String jsonInfo = this.getRequestBodyToStr();
return JsonUtils.parseMap(jsonInfo);
}
public String getRequestBodyToStr() throws IOException {
if (this.requestBodyLine == null) {
BufferedReader reader = this.getReader();
StringBuilder builder = new StringBuilder();
String line = reader.readLine();
while (line != null) {
builder.append(line);
line = reader.readLine();
}
requestBodyLine = builder.toString();
reader.close();
}
return requestBodyLine;
}
//代理ServletInputStream 内容为当前缓存的bytes
private static class RequestCachingInputStream extends ServletInputStream {
private final ByteArrayInputStream is;
public RequestCachingInputStream(byte[] bytes) {
this.is = new ByteArrayInputStream(bytes);
}
@Override
public int read() throws IOException {
return this.is.read();
}
@Override
public boolean isFinished() {
return this.is.available() == 0;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener readlistener) {
}
}
}
实例调用
public void requestWrapperDemo(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
// 复用request
RepeatableServletRequestWrapper requestWrapper;
requestWrapper = new RepeatableServletRequestWrapper(request);
// 获取请求参数
Map<String, Object> requestBodyToMap = requestWrapper.getRequestBodyToMap();
// 不直接将request传入过滤器链中,而是将requestWrapper传入
filterChain.doFilter(requestWrapper, response);
}
原创不易,转载、引用请标明出处。
如有帮助,欢迎点赞!!!