淺入java架構-Filter-篡改RequestBody
沒幹過幾年的朋友,一定會問:爲啥要篡改RequestBody?
這裏筆者不想過多解釋了,列舉個場景:
eg:一個大型項目,分爲N個模塊去開發,分別在東北、華北、華東都有研發中心,其中系統登錄、註冊、認證等基礎功能在東北地區研發,轉賬、匯款、理財等業務功能有我在華北地區研發,聊天、論壇等邊緣輔助功能安排在華東地區研發。
爲了達到模塊低耦合的最佳效果,每個地區分別立項各自的服務器、應用、設計各自的UI頁面,此時用戶發起轉賬交易的時候,只能從cookie中拿到用戶登錄的唯一標識(userId),而轉賬服務會用到userId。
此時有三種方式處理userId傳到服務中:
一、在每一個需要用到userId的控制器中get到userId,再塞到請求對象(RequestBody)中,(代碼重複性太強)
二、定義一個baseControler類,由需要用到userId的控制器繼承,其中實現一,(如果是做代碼重構,工作量太大)
三、定義Filter,從cookie中獲取userId後,在塞到請求對象(RequestBody)
毋庸置疑,選擇第三種,這種系統級別的優化功能,跟業務層面沒有關係,應該保持透明化
步驟一:web.xml中聲明過濾器:NormFilter
<filter>
<filter-name>RequestFilter</filter-name>
<filter-class>com.front.web.filter.RequestFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>RequestFilter</filter-name>
<url-pattern>/web/*</url-pattern>
</filter-mapping>
步驟二:創建過濾器:RequestFilter
/**
* @ClassName RequestFilter
* @Description 篡改requestbody過濾器
* @author lisheng
* @Date 2016年6月14日 下午4:51:56
* @version 1.0.0
*/
public class RequestFilter implements Filter {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@SuppressWarnings("unchecked")
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 獲取request
HttpServletRequest request = (HttpServletRequest) servletRequest;
if (request.getMethod().toUpperCase().equals("GET")) {
filterChain.doFilter(servletRequest, servletResponse);
} else if (request.getMethod().toUpperCase().equals("POST")) {
// 錯誤對象
ClientResponse<Map<String, String>> baseResponseDto = ClientResponse.respFail();
HttpServletRequestWapper requestWapper = new HttpServletRequestWapper(request);
try {
String jsonRequest = getJsonRequest(request, requestWapper);
if (StringUtils.isNotEmpty(jsonRequest)) {
try {
Map requestMap = JsonUtil.json2Map(jsonRequest);
BaseReq baseReq = JsonUtil.json2Object(jsonRequest, BaseReq.class);
String userId = CookieUtils.getCookieValue(request, "userId", "");
requestMap.put("userId", userId);
baseReq.setUserId(userId);
requestWapper.setBody(JsonUtil.toJson(requestMap), baseReq);
filterChain.doFilter(requestWapper, servletResponse);
return;
} catch (Exception e) {
logger.error("doFilter 異常:", e);
}
}
} catch (Exception e) {
logger.error("過濾器異常:", e);
}
servletResponse.setContentType("application/json; charset=utf-8");
servletResponse.setCharacterEncoding("UTF-8");
OutputStream out = servletResponse.getOutputStream();
out.write(JsonUtil.toJson(baseResponseDto).getBytes("UTF-8"));
out.flush();
}
}
@Override
public void destroy() {
}
}
三、創建request轉換類:HttpServletRequestWapper
/**
* @ClassName HttpServletRequestWapper
* @Description 重置requestbody
* @author lisheng
* @Date 2016年6月14日 下午4:50:30
* @version 1.0.0
*/
public class HttpServletRequestWapper extends HttpServletRequestWrapper {
private byte[] body;
private String bodyStr;
private HttpServletRequest request;
public HttpServletRequestWapper(HttpServletRequest request) throws UnsupportedEncodingException {
super(request);
String bodyString = HttpHelper.getBodyString(request);
body = StringUtils.isEmpty(bodyString) ? null : bodyString.getBytes("UTF-8");
this.request = request;
}
public void setBody(String body, BaseReq baseReq) throws UnsupportedEncodingException {
this.request.setAttribute("bodyStr", body);
this.request.setAttribute("baseReq", baseReq);
bodyStr = body;
this.body = body.getBytes("UTF-8");
}
public String getBodyStr() {
return bodyStr;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream(),getCharacterEncoding()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
public boolean isFinished() {
return false;
}
public boolean isReady() {
return false;
}
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return bais.read();
}
};
}
}
以上操作可以將request中的參數塞進Body中。