有時(shí)候我們需要到攔截器中做下參數(shù)的預(yù)處理,如危險(xiǎn)字符過(guò)濾、權(quán)限判斷、打印請(qǐng)求參數(shù)日志 等操作。
以前使用url中以?和& 拼接或使用form-data等傳參形式都沒(méi)有問(wèn)題。 而現(xiàn)在參數(shù)都以contentType="application/json;charset=utf-8" 的形式放到了request Body中,如果我們提前去拿一次,那么等程序運(yùn)行到controller中時(shí)參數(shù)已經(jīng)是為空再也獲取不到了。所以我們得想辦法解決這個(gè)問(wèn)題。
如下先自定義一個(gè)Request類:RequestWrapper 繼承HttpServletRequestWrapper 。
- 定義類屬性HttpServletRequest,this.request保存request的引用。
- 定義類屬性byte[] requestBody, 在重寫的getInputStream方法中使用IOUtils.copy將輸入流轉(zhuǎn)輸出流再轉(zhuǎn) byte[],然后進(jìn)行賦值。
- 最后構(gòu)造一個(gè)ByteArrayInputStream 返回。這樣就不會(huì)影響原來(lái)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請(qǐng)求對(duì)象
private HttpServletRequest request;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
this.request = request;
getInputStream();
}
/**
* @return
* @throws IOException
*/
@Override
public ServletInputStream getInputStream() throws IOException {
/**
* 每次調(diào)用此方法時(shí)將數(shù)據(jù)流中的數(shù)據(jù)讀取出來(lái),然后再回填到InputStream之中
* 解決通過(guò)@RequestBody和@RequestParam(POST方式)讀取一次后控制器拿不到參數(shù)問(wèn)題
*/
if (null == this.requestBody) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ServletInputStream inputStream = request.getInputStream();
IOUtils.copy(inputStream, baos);
this.requestBody = baos.toByteArray();
baos.close();
inputStream.close();
}
/**
* 關(guān)鍵一步,自己構(gòu)造 ServletInputStream。沒(méi)有這一部分后面再?gòu)膔equest拿出來(lái)的參數(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對(duì)象傳入 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);