有時候我們需要到攔截器中做下參數(shù)的預處理钧萍,如危險字符過濾粘茄、權限判斷碗啄、打印請求參數(shù)日志 等操作。
以前使用url中以振峻?和& 拼接或使用form-data等傳參形式都沒有問題公般。 而現(xiàn)在參數(shù)都以contentType="application/json;charset=utf-8" 的形式放到了request Body中弛秋,如果我們提前去拿一次,那么等程序運行到controller中時參數(shù)已經(jīng)是為空再也獲取不到了俐载。所以我們得想辦法解決這個問題蟹略。
如下先自定義一個Request類:RequestWrapper 繼承HttpServletRequestWrapper 。
- 定義類屬性HttpServletRequest遏佣,this.request保存request的引用挖炬。
- 定義類屬性byte[] requestBody, 在重寫的getInputStream方法中使用IOUtils.copy將輸入流轉輸出流再轉 byte[]状婶,然后進行賦值意敛。
- 最后構造一個ByteArrayInputStream 返回馅巷。這樣就不會影響原來request的InputStream。
package org.szwj.ca.identityauthsrv.controller;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.io.IOUtils;
public class RequestWrapper extends HttpServletRequestWrapper {
private final Logger logger = LoggerFactory.getLogger(RequestWrapper.class);
//參數(shù)字節(jié)數(shù)組
private byte[] requestBody;
//Http請求對象
private HttpServletRequest request;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
this.request = request;
getInputStream();
}
/**
* @return
* @throws IOException
*/
@Override
public ServletInputStream getInputStream() throws IOException {
/**
* 每次調用此方法時將數(shù)據(jù)流中的數(shù)據(jù)讀取出來草姻,然后再回填到InputStream之中
* 解決通過@RequestBody和@RequestParam(POST方式)讀取一次后控制器拿不到參數(shù)問題
*/
if (null == this.requestBody) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ServletInputStream inputStream = request.getInputStream();
IOUtils.copy(inputStream, baos);
this.requestBody = baos.toByteArray();
baos.close();
inputStream.close();
}
/**
* 關鍵一步钓猬,自己構造 ServletInputStream。沒有這一部分后面再從request拿出來的參數(shù)還是空的
*/
final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
@Override
public int read() {
int read = bais.read();
try {
bais.close();
} catch (IOException e) {
logger.error("bais.close() 異常", e);
}
return read;
}
};
}
public byte[] getRequestBody() {
return requestBody;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
}
編寫Filter撩独,將自定義的RequestWrapper對象傳入 chain.doFilter敞曹。
@Component
@WebFilter(filterName = "proxyFilter", urlPatterns = {"/*"})
class ProxyFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(ProxyFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
try {
ServletRequest requestWrapper = null;
if (request instanceof HttpServletRequest) {
requestWrapper = new RequestWrapper((HttpServletRequest) request);
}
if (requestWrapper == null) {
chain.doFilter(request, response);
} else {
chain.doFilter(requestWrapper, response);
}
} catch (IOException e) {
logger.error("ProxyFilter.doFilter 異常", e);
} catch (ServletException e) {
logger.error("ProxyFilter.doFilter 異常", e);
}
}
@Override
public void destroy() {
}
}
在攔截器中使用如下
@Override
protected void service(HttpServletRequest servletRequest,
HttpServletResponse servletResponse) throws ServletException, IOException {
String msg = "";
RequestWrapper requestWrapper = null;
String relBizNo = "";
if (servletRequest instanceof RequestWrapper) {
requestWrapper = (RequestWrapper) servletRequest;
byte[] requestBody = requestWrapper.getRequestBody();
String body = new String(requestBody);