在spring中袜腥,filter都默認(rèn)繼承OncePerRequestFilter漆腌,但為什么要這樣呢畔派?
OncePerRequestFilter顧名思義槐沼,他能夠確保在一次請(qǐng)求只通過(guò)一次filter曙蒸,而不需要重復(fù)執(zhí)行。
- AccessLogFilter 核心代碼
public class AccessLogFilter extends OncePerRequestFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(AccessLogFilter .class);
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
Long startTime = System.currentTimeMillis();
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
filterChain.doFilter(requestWrapper, responseWrapper);
String requestPayload = new String(requestWrapper.getContentAsByteArray(),
request.getCharacterEncoding());
String responsePayload = IOUtils.toString(responseWrapper.getContentInputStream(), responseWrapper.getCharacterEncoding());
responseWrapper.copyBodyToResponse();
}
}
其核心思想是實(shí)現(xiàn)了OncePerRequestFilter這個(gè)虛基類(lèi)岗钩,而這個(gè)虛基類(lèi)是實(shí)現(xiàn)了Filter接口纽窟,并且要基于SpringMVC框架的,因此這個(gè)方法只能適用于SpringMVC工程
核心方法是doFilterInternal
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
Long startTime = System.currentTimeMillis();
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
filterChain.doFilter(requestWrapper, responseWrapper);
String requestPayload = getPayLoad(requestWrapper.getContentAsByteArray(),
request.getCharacterEncoding());
String responsePayload = getPayLoad(responseWrapper.getContentAsByteArray(),
response.getCharacterEncoding());
responseWrapper.copyBodyToResponse();
StringBuilder logResult = generateResultLogger(logMap);
if (LOGGER.isInfoEnabled()){
LOGGER.info(logResult.toString());
}
}
首先通過(guò)
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
這兩個(gè)方式對(duì)請(qǐng)求和返回進(jìn)行包裝(讓body可以被緩存)兼吓,這樣來(lái)解決inputstream不能多次讀取的問(wèn)題
調(diào)用
filterChain.doFilter(requestWrapper, responseWrapper);
來(lái)執(zhí)行其他的filter之后
可以通過(guò)
String requestPayload = new String(requestWrapper.getContentAsByteArray(),
request.getCharacterEncoding());
String responsePayload = IOUtils.toString(responseWrapper.getContentInputStream(), responseWrapper.getCharacterEncoding());
這種方式取出request和response的內(nèi)容臂港,最后一定不要忘記
responseWrapper.copyBodyToResponse();
重新寫(xiě)入response
最后打印出整個(gè)log