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配置:

<bean id="timeBasedAccessInterceptor" class="com.spring.handler.TimeBasedAccessInterceptor">  
    <property name="openingTime" value="9" />  
    <property name="closingTime" value="12" />  
    <property name="mappingURL" value=".*/user\.do\?action=reg.*" />  
</bean>  
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">  
    <property name="interceptors">  
        <list>  
            <ref bean="timeBasedAccessInterceptor"/>  
        </list>  
    </property>  
</bean>  

這里我們定義了一個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>    
        <!-- 匹配的是url路徑, 如果不配置或/**,將攔截所有的Controller -->  
        <mvc:mapping path="/" />  
        <mvc:mapping path="/user/**" />  
        <mvc:mapping path="/test/**" />  
        <bean class="com.alibaba.interceptor.CommonInterceptor"></bean>    
    </mvc:interceptor>  
    <!-- 當設置多個攔截器時,先按順序調用preHandle方法,然后逆序調用每個攔截器的postHandle和afterCompletion方法 -->  
</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 (以上內容部分轉自此篇文章)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM