2018年8月26日 星期日

Spring Filter - RESTFUL Log

最直接的方式就在每個method內直接加入restful log

但這樣就太囉嗦

所以改用filter來處理這件事情

但由於request body只能被讀取一次的特性

所以filter要針對request動點手腳

  1. @WebFilter(
  2. filterName="testFilter",
  3. urlPatterns={"/testRest"}
  4. )
  5. public class SpringRequestBodyFilter extends OncePerRequestFilter{
  6. @Override
  7. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
  8. throws ServletException, IOException {
  9.  
  10. BodyReaderHttpServletRequestWrapper requestWrapper = new BodyReaderHttpServletRequestWrapper(request);
  11. System.out.println("body: " + requestWrapper.getBody());
  12.  
  13. filterChain.doFilter(requestWrapper, response);
  14. }
  15. }
  16.  
  17. public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper{
  18. private final String body;
  19.  
  20. public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
  21. super(request);
  22. try(BufferedReader bufferedReader = request.getReader()){
  23. body = request.getReader().lines().collect(Collectors.joining());
  24. }
  25. }
  26.  
  27. @Override
  28. public ServletInputStream getInputStream() throws IOException {
  29. return new DelegatingServletInputStream(new ByteArrayInputStream(body.getBytes()));
  30. }
  31.  
  32. @Override
  33. public BufferedReader getReader() throws IOException {
  34. return new BufferedReader(new InputStreamReader(this.getInputStream()));
  35. }
  36.  
  37. public String getBody() {
  38. return this.body;
  39. }
  40. }
第10行將HttpServletRequest包裝成BodyReaderHttpServletRequestWrapper傳給filter

BodyReaderHttpServletRequestWrapper的功能就是先讀取request body並存到body欄位中
由於前面提到過request body只能讀取一次的特性
所以要重新建立inputStream和reader
若有用到inputStream或reader時才不會出現Stream closed的錯誤

第29行這邊我用org.springframework.mock.web.DelegatingServletInputStream
這個是用spring test的(要自己實作ServletInputStream也可以,但已有寫好的沒有不拿來用的理由)

完整程式可參考https://github.com/softmenlouis/springBoot-filter.git

沒有留言:

張貼留言