浅入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中。