10.從零搭建WebApi接口開發(fā)框架-記錄請求日志log

在開發(fā)中,需要記錄接口的請求日志及返回日志,便于回溯原因。這里面請求日志為什么要單獨拿出來講,是因為當前是以post body的方式提交接口請求,body是以stream的方式接收,如果在攔截器中獲取該body內(nèi)容后,真實請求中將捕獲不到該參數(shù)了,因此需要引入BodyReaderHttpServletRequestWrapper 來實現(xiàn)接口的請求日志記錄。

pom.xml增加依賴

<dependency>
    <groupId>org.jodd</groupId>
    <artifactId>jodd-core</artifactId>
    <version>3.9</version>
</dependency>

用于獲取當前request中的stream信息

BodyReaderHttpServletRequestWrapper 重新包裝request

public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {

    /**
     * 定義字節(jié)流
     */
    private final byte[] body;

    /**
     * 把請求的http包裝一下
     *
     * @param request request
     * @throws IOException IO異常
     */
    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request)
            throws IOException {
        super(request);
        // body = StreamUtil.readBytes(request.getReader(), JoddDefault.encoding);
        // 因為http協(xié)議默認傳輸?shù)木幋a就是iso-8859-1,如果使用utf-8轉(zhuǎn)碼亂碼的話,可以嘗試使用iso-8859-1
        body = StreamUtil.readBytes(request.getReader(), "UTF-8");
    }

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

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
        return new ServletInputStream() {

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }

            @Override
            public int read() throws IOException {
                return bais.read();
            }
        };
    }
}

HttpServletRequestReplacedFilter 新建過濾器替換request的body

public class HttpServletRequestReplacedFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //Do nothing
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;
        if (request instanceof HttpServletRequest) {
            requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);
        }
        chain.doFilter(requestWrapper, response);
    }

    @Override
    public void destroy() {
        //Do nothing
    }

}

LogInterceptor利用攔截器來記錄日志

public class LogInterceptor implements HandlerInterceptor {
    /**
     * 定義日志
     */
    private static Logger logger = LoggerFactory.getLogger("operationLog");

    /**
     * 記錄操作日志
     *
     * @param request  request
     * @param response response
     * @param handler  handler
     * @return 處理是否成功
     * @throws Exception 異常
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //校驗權(quán)限
        String path = request.getServletPath();
        String contentType = request.getContentType();
        if (contentType != null && contentType.equals("application/json")) {
            // 只有json請求才記錄日志,上傳文件的不記錄
            //參數(shù)
            String parameters = StringUtil.getBodyString(request.getReader());
            User user = TokenUtil.getToken(request);
            logOperation(path, parameters, user);
        }
        return true;
    }

    /**
     * 記錄文本日志
     *
     * @param path       路徑
     * @param parameters 參數(shù)值
     * @param user       user
     */
    public void logOperation(String path, String parameters, User user) {
        String log = "";
        if (user == null) {
            user = new User();
        }
        log = "[OPERALOG-操作日志]" + "-[" + user.getUsername() + "]" + "-[" + getSystemTime() + "]-" + "[INFO]-" + "-" + parameters;
        logger.info(log);
    }

    public static String getSystemTime() {
        String strTime = "";
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        strTime = df.format(new Date());
        return strTime;
    }

    /**
     * @param request      request
     * @param response     response
     * @param handler      handler
     * @param modelAndView modelAndView
     * @throws Exception 異常
     */
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    /**
     * @param request  request
     * @param response response
     * @param handler  handler
     * @param ex       異常
     * @throws Exception 異常
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

這里塊的代碼非常簡單,獲取當前請求的路徑及參數(shù),記錄下來,同時如果header中有authorization的話,再取當前的用戶信息,這一塊可以根據(jù)實際需要來修改。

LogConfig 加入需要記錄日志的url

@Configuration
public class LogConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //校驗是否登錄攔截器
        registry.addInterceptor(new LogInterceptor())
                //消息相關(guān)
                .addPathPatterns("/news/*")
                .addPathPatterns("/checkLogin");
        super.addInterceptors(registry);
    }
}

這一塊和控制權(quán)限一樣,增加一個InterceptorRegistry,并設(shè)置需要攔截的url串

請求的日志結(jié)果如下所示:


日志結(jié)果.png

如果沒有BodyReaderHttpServletRequestWrapper對request的重新包裝,直接獲取body的參數(shù),后續(xù)將會報錯。

源碼下載

本例子詳細源碼

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容