1. 程式人生 > >Spring MVC中的攔截器/過濾器HandlerInterceptorAdapter的使用

Spring MVC中的攔截器/過濾器HandlerInterceptorAdapter的使用

一般情況下,對來自瀏覽器的請求的攔截,是利用Filter實現的

而在Spring中,基於Filter這種方式可以實現Bean預處理、後處理。 比如注入FilterRegistrationBean,然後在這個Bean上傳遞自己繼承Filter實現的自定義Filter進入即可。

而Spring MVC也有攔截器,不僅可實現Filter的所有功能,還可以更精確的控制攔截精度。

Spring MVC提供的org.springframework.web.servlet.handler.HandlerInterceptorAdapter這個介面卡,繼承此類,可以非常方便的實現自己的攔截器。

它有三個方法:

複製程式碼
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception {
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {
}
複製程式碼
preHandle在業務處理器處理請求之前被呼叫。預處理,可以進行編碼、安全控制等處理;

postHandle在業務處理器處理請求執行完成後,生成檢視之前執行。後處理(呼叫了Service並返回ModelAndView,但未進行頁面渲染),有機會修改ModelAndView;

afterCompletion在DispatcherServlet完全處理完請求後被呼叫,可用於清理資源等。返回處理(已經渲染了頁面),可以根據ex是否為null判斷是否發生了異常,進行日誌記錄;

如果基於XML配置使用Spring MVC,可以利用SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping進行Url對映(相當於struts的path對映)和攔截請求(注入interceptors)。

如果基於註解使用Spring MVC,可以使用DefaultAnnotationHandlerMapping注入interceptors。

注意無論基於XML還是基於註解,HandlerMapping Bean都是需要在XML中配置的。

示例一:

在這個例子中,我們假設UserController中的註冊操作只在9:00-12:00開放,那麼就可以使用攔截器實現這個功能。

複製程式碼
public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {
private int openingTime;
private int closingTime;
private String mappingURL;//利用正則對映到需要攔截的路徑
public void setOpeningTime(int openingTime) {
this.openingTime = openingTime;
}
public void setClosingTime(int closingTime) {
this.closingTime = closingTime;
}
public void setMappingURL(String mappingURL) {
this.mappingURL = mappingURL;
}
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
String url=request.getRequestURL().toString();
if(mappingURL==null || url.matches(mappingURL)){
Calendar c=Calendar.getInstance();
c.setTime(new Date());
int now=c.get(Calendar.HOUR_OF_DAY);
if(now<openingTime || now>closingTime){
request.setAttribute(“msg”, “註冊開放時間:9:00-12:00”);
request.getRequestDispatcher("/msg.jsp").forward(request, response);
return false;
}
return true;
}
return true;
}
}
複製程式碼
XML配置:

複製程式碼












複製程式碼
這裡我們定義了一個mappingURL屬性,實現利用正則表示式對url進行匹配,從而更細粒度的進行攔截。當然如果不定義mappingURL,則預設攔截所有對Controller的請求。

UserController:

複製程式碼
@Controller
@RequestMapping("/user.do")
public class UserController{
@Autowired
private UserService userService;
@RequestMapping(params=“action=reg”)
public ModelAndView reg(Users user) throws Exception {
userService.addUser(user);
return new ModelAndView(“profile”,“user”,user);
}
// other option …
}
複製程式碼
也可以配置多個攔截器,每個攔截器進行不同的分工。

示例二:

主要是XML配置不一樣

複製程式碼

mvc:interceptors
mvc:interceptor

<mvc:mapping path="/" />
<mvc:mapping path="/user/" />
<mvc:mapping path="/test/
" />

</mvc:interceptor>

</mvc:interceptors>
複製程式碼
複製程式碼
package com.alibaba.interceptor;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.alibaba.util.RequestUtil;

public class CommonInterceptor extends HandlerInterceptorAdapter{
private final Logger log = LoggerFactory.getLogger(CommonInterceptor.class);
public static final String LAST_PAGE = “com.alibaba.lastPage”;
/*
* 利用正則對映到需要攔截的路徑

private String mappingURL; 
 
public void setMappingURL(String mappingURL) {     
           this.mappingURL = mappingURL;     
}    

/
/
*
* 在業務處理器處理請求之前被呼叫
* 如果返回false
* 從當前的攔截器往回執行所有攔截器的afterCompletion(),再退出攔截器鏈
* 如果返回true
* 執行下一個攔截器,直到所有的攔截器都執行完畢
* 再執行被攔截的Controller
* 然後進入攔截器鏈,
* 從最後一個攔截器往回執行所有的postHandle()
* 接著再從最後一個攔截器往回執行所有的afterCompletion()
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
if (“GET”.equalsIgnoreCase(request.getMethod())) {
RequestUtil.saveRequest();
}
log.info(“執行順序: 1、preHandle==”);
String requestUri = request.getRequestURI();
String contextPath = request.getContextPath();
String url = requestUri.substring(contextPath.length());

    log.info("requestUri:"+requestUri);    
    log.info("contextPath:"+contextPath);    
    log.info("url:"+url);    
      
    String username =  (String)request.getSession().getAttribute("user");   
    if(username == null){  
        log.info("Interceptor:跳轉到login頁面!");  
        request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);  
        return false;  
    }else  
        return true;     
}    

/** 
 * 在業務處理器處理請求執行完成後,生成檢視之前執行的動作    
 * 可在modelAndView中加入資料,比如當前時間 
 */  
@Override    
public void postHandle(HttpServletRequest request,    
        HttpServletResponse response, Object handler,    
        ModelAndView modelAndView) throws Exception {     
    log.info("==============執行順序: 2、postHandle================");    
    if(modelAndView != null){  //加入當前時間    
        modelAndView.addObject("var", "測試postHandle");    
    }    
}    

/**  
 * 在DispatcherServlet完全處理完請求後被呼叫,可用於清理資源等   
 *   
 * 當有攔截器丟擲異常時,會從當前攔截器往回執行所有的攔截器的afterCompletion()  
 */    
@Override    
public void afterCompletion(HttpServletRequest request,    
        HttpServletResponse response, Object handler, Exception ex)    
        throws Exception {    
    log.info("==============執行順序: 3、afterCompletion================");    
}    

}
複製程式碼

參考:

http://blog.csdn.net/liuwenbo0920/article/details/7283757(以上內容部分轉自此篇文章)

http://www.cnblogs.com/xingele0917/p/4318008.html

http://blog.csdn.net/ye_sheng/article/details/48395663 (以上內容部分轉自此篇文章)