1. 程式人生 > >通過攔截器Interceptor實現Spring MVC中Controller介面訪問資訊的記錄

通過攔截器Interceptor實現Spring MVC中Controller介面訪問資訊的記錄

java web工程專案使用了Spring+Spring MVC+Hibernate的結構,在Controller中的方法都是用於處理前端的訪問資訊,Controller通過呼叫Service進行業務處理後給前端返回ModelAndView物件或者只返回Json格式資料。如果能夠獲得Http請求在後端程式中處理的相關資訊,對於開發和除錯時十分方便的。工程中使用了Spring MVC的Interceptor對所有Http請求及其響應進行攔截,從而獲取到本次訪問介面資訊以及程式處理時長等資訊,特意在此記錄一下實現方式。

package com.api.web.interceptor;

import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.yijia.api.util.SimpleDateFormatCache;

/**
 * 記錄資訊:</br> 訪問時間</br>Controller路徑</br>對應方法名</br>請求引數資訊</br>請求相對路徑</br>請求處理時長
 *
 * @author Administrator
 *
 */
public class TimeCostInterceptor implements HandlerInterceptor {

    // before the actual handler will be executed
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        long startTime = System.currentTimeMillis();
        request.setAttribute("startTime", startTime);
        if (handler instanceof HandlerMethod) {
            StringBuilder sb = new StringBuilder(1000);

            sb.append("-----------------------").append(SimpleDateFormatCache.getYmdhms().format(new Date()))
                    .append("-------------------------------------\n");
            HandlerMethod h = (HandlerMethod) handler;
            sb.append("Controller: ").append(h.getBean().getClass().getName()).append("\n");
            sb.append("Method    : ").append(h.getMethod().getName()).append("\n");
            sb.append("Params    : ").append(getParamString(request.getParameterMap())).append("\n");
            sb.append("URI       : ").append(request.getRequestURI()).append("\n");
            System.out.println(sb.toString());
        }
        return true;
    }

    // after the handler is executed
    public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        long startTime = (Long) request.getAttribute("startTime");
        long endTime = System.currentTimeMillis();
        long executeTime = endTime - startTime;
        if(handler instanceof HandlerMethod){
            StringBuilder sb = new StringBuilder(1000);
            sb.append("CostTime  : ").append(executeTime).append("ms").append("\n");
            sb.append("-------------------------------------------------------------------------------");
            System.out.println(sb.toString());
        }
    }

    private String getParamString(Map<String, String[]> map) {
        StringBuilder sb = new StringBuilder();
        for(Entry<String,String[]> e:map.entrySet()){
            sb.append(e.getKey()).append("=");
            String[] value = e.getValue();
            if(value != null && value.length == 1){
                sb.append(value[0]).append("\t");
            }else{
                sb.append(Arrays.toString(value)).append("\t");
            }
        }
        return sb.toString();
    }

    public void afterCompletion(HttpServletRequest arg0,
            HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {

    }
}

由於Interceptor是Spring MVC的功能元件,所以需要把此攔截器配置在springmvc的xml配置檔案中(或者使用其他配置方式比如javaConfig):

複製程式碼
 <mvc:interceptors>
        <!-- 使用bean定義一個Interceptor,直接定義在mvc:interceptors根下面的Interceptor將攔截所有的請求 -->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>            
            <!-- 需排除攔截的地址 -->  
            <mvc:exclude-mapping path="/" />
            <mvc:exclude-mapping path="/test" />
            <!-- 定義在mvc:interceptor下面的表示是對特定的請求才進行攔截的 -->
            <bean class
="com.api.web.interceptor.TimeCostInterceptor"/> </mvc:interceptor> </mvc:interceptors>
複製程式碼

定義並配置好好攔截器後,在程式Controller中的介面被訪問的時候,相關訪問資訊就會輸出到控制檯上,也可以使用日誌將訪問資訊記錄到日誌中。

記錄效果如下所示:

總結:

攔截器通對使用者請求進行攔截可以對使用者的請求(HttpServletRequest)進行預處理,也可以對返回給使用者的響應(HttpServletResponse)進行訪問後處理,還可以在請求完成後針對請求的異常資訊進行處理。能夠在request物件和response物件中進行操作的問題都可以通過攔截器進行統一處理,常用的場景包括使用者登入控制、許可權檢查,跨域請求訪問許可權控制等。