2018年8月26日 星期日

Spring Filter - RESTFUL Log

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

但這樣就太囉嗦

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

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

所以filter要針對request動點手腳

@WebFilter(
    filterName="testFilter",
    urlPatterns={"/testRest"}
)
public class SpringRequestBodyFilter extends OncePerRequestFilter{
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        BodyReaderHttpServletRequestWrapper requestWrapper = new BodyReaderHttpServletRequestWrapper(request);
        System.out.println("body: " + requestWrapper.getBody());

        filterChain.doFilter(requestWrapper, response);
    }
}

public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper{
    private final String body;

    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        try(BufferedReader bufferedReader = request.getReader()){
            body = request.getReader().lines().collect(Collectors.joining());
        }
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        return new DelegatingServletInputStream(new ByteArrayInputStream(body.getBytes()));
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }

    public String getBody() {
        return this.body;
    }
}
第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

沒有留言:

張貼留言