今天先插入一個小主題,個人覺得很實用,這支程式是在Spring MVC- A Beginner Guide中學到的,
Interceptor概念等同於filter,就是在Spring MVC處理Request與Response前與後作一些處理,在Spring MVC中提供HandlerInterceptor介面供開發者實作,必須Override preHandle方法(Spring MVC呼叫對應的Controller之前執行的方法)、postHandle(Controller處理完成一個Request後執行的發法)以及afterCompletion(一個Request/Response cycle後執行的方法)。
以今天的例子,我們的目的在於得到Controller處理一個Request所需的時間,Spring提供一個好用的計時物件StopWatch,要紀錄整個cycle,我們需要一個獨立的Thread來執行StopWatch,Java裡有一個ThreadLocal物件可以達到這個目的,整體來看,就是在呼叫Controller之前呼叫StopWatch的Start方法開始計時,整個Cycle完之後呼叫StopWatch的Stop方法,並呼叫getTotalTimeMillis方法即可得到整個cycle所需時間。
新增一個MonitorController實作HandlerInterceptor,其code如下:
public class MonitorInterceptor implements HandlerInterceptor {
ThreadLocal<StopWatch> threadTimer=new ThreadLocal<>();
//建立一個ThreadLocal物件,型別StopWatch可提供計時功能
Logger logger=Logger.getLogger(this.getClass());
private String getURLPath(HttpServletRequest request){
String currentPath=request.getRequestURI();
String queryString=request.getQueryString();
queryString=queryString==null ? "" : "?"+queryString;
return currentPath+queryString; //Request的完成Path
}
private String getCurrentTime(){
DateFormat formatter=new SimpleDateFormat("MM/dd/yyyy 'at' hh:mm:ss");
Calendar calendar=Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
return formatter.format(calendar.getTime());
}
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// TODO Auto-generated method stub
StopWatch stopWatch=new StopWatch(handler.toString());
//New 一個StopWatch物件
stopWatch.start(handler.toString());//開始計時
threadTimer.set(stopWatch); //放入ThreadLocal由獨立的Thread計時
//紀錄存取的網址
logger.info("Accessing URL Path:"+ getURLPath(request));
//紀錄呼叫Controller前的時間
logger.info("Request processing started on:"+getCurrentTime());
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
//紀錄Controller處理一個Request結束後的時間
logger.info("Request processing ended on"+getCurrentTime());
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
StopWatch stopWatch=threadTimer.get(); //從ThreadLocal取得StopWatch物件
stopWatch.stop(); //呼叫stop(),停止計數
//呼叫StopWatch物件getTotalTimemillis方法,可得知處理一個Request,Controller花了多少時間
logger.info("Total time taken for processing"+stopWatch.getTotalTimeMillis()+" ms");
threadTimer.set(null); //清空ThreadLocal物件 ,以免與下次Request再設定同樣的StopWatch衝突
logger.info("========================================");
}
}
除了新增Class,同時需要在dispatchservletcontext.xml,宣告Interceptor並指定剛剛新增的class,其code如下:
<mvc:interceptors>
<bean class="tw.blogger.springtech.springmvc.controller.interceptor.MonitorInterceptor" />
</mvc:interceptors>
另外要在Console輸出,在log4j.xml中加入MonitorInterceptor,code如下
<?xml version="1.0" encoding="UTF-8"?>
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<!-- Appenders -->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{HH:mm:ss} [%t] %c{1} - %m%n" />
</layout>
</appender>
......
<logger name="tw.blogger.springtech.springmvc.controller.interceptor">
<level value="info" />
</logger>
.......
<root>
<priority value="warn" />
<appender-ref ref="console" />
</root>
</log4j:configuration>
啟動Server,首頁如下
Console顯示花了1ms
19:49:56 [http-nio-8080-exec-5] MonitorInterceptor - Request processing started on:10/23/2014 at 07:49:56
19:49:56 [http-nio-8080-exec-5] HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
19:49:56 [http-nio-8080-exec-5] MonitorInterceptor - Request processing ended on10/23/2014 at 07:49:56
19:49:56 [http-nio-8080-exec-5] DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'dispatcher': assuming HandlerAdapter completed request handling
19:49:56 [http-nio-8080-exec-5] MonitorInterceptor - Total time taken for processing1 ms
要求輸出Excel畫面如下,
Console log顯示花了1226ms
19:52:42 [http-nio-8080-exec-7] MonitorInterceptor - Request processing ended on10/23/2014 at 07:52:42
19:52:42 [http-nio-8080-exec-7] ContentNegotiatingViewResolver - Requested media types are [application/vnd.ms-excel] based on Accept header types and producible media types [*/*])
19:52:42 [http-nio-8080-exec-7] ContentNegotiatingViewResolver - Returning [tw.blogger.springtech.springmvc.view.ExcelView: name 'excelView'] based on requested media type 'application/vnd.ms-excel'
19:52:42 [http-nio-8080-exec-7] DispatcherServlet - Rendering view [tw.blogger.springtech.springmvc.view.ExcelView: name 'excelView'] in DispatcherServlet with name 'dispatcher'
Hibernate: select dcn0_.prikey as prikey1_1_, dcn0_.category as category2_1_, dcn0_.completedDate as complete3_1_, dcn0_.issuedDate as issuedDa4_1_, dcn0_.no as no5_1_, dcn0_.rev as rev6_1_, dcn0_.trackNumber as trackNum7_1_ from DCN dcn0_
19:52:43 [http-nio-8080-exec-7] MonitorInterceptor - Total time taken for processing1226 ms
19:52:43 [http-nio-8080-exec-7] MonitorInterceptor - ========================================
19:52:43 [http-nio-8080-exec-7] DispatcherServlet - Successfully completed request
19:52:43 [http-nio-8080-exec-7] ExceptionTranslationFilter - Chain processed normally
19:52:43 [http-nio-8080-exec-7] SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
明天繼續