什麼是攔截器
攔截器(Interceptor): 用於在某個方法被訪問以前進行攔截,而後在方法執行以前或以後加入某些操做,其實就是AOP的一種實現策略。它經過動態攔截Action調用的對象,容許開發者定義在一個action執行的先後執行的代碼,也能夠在一個action執行前阻止其執行。同時也是提供了一種能夠提取action中可重用的部分的方式。java
攔截器做用
攔截用戶的請求並進行相應的處理,好比:判斷用戶是否登錄,是否在可購買時間內,記錄日誌信息等。web
Spring中兩種實現方式
實現HandlerInterceptor接口
經過實現HandlerInterceptor接口, 通常經過繼承HandlerInterceptorAdapter抽象類實現。spring
DispatcherServlet處理流程:DispatcherServlet處理請求時會構造一個Excecution Chain,即(可能多個)攔截器和真正處理請求的Handler
即Interceptor是鏈式調用的。
preHandle: 在執行Handler以前進行,即Controller方法調用以前執行,主要進行初始化操做。app
postHandle: 在執行Handler以後進行,即Controller 方法調用以後執行,主要對ModelAndView對象進行操做。框架
afterCompletion: 在整個請求結束以後,即渲染對應的視圖以後執行, 主要進行資源清理工做。async
注意事項: 每一個Interceptor的調用會依據它在xml文件中聲明順序依次執行。ide
DispatcherServlet中攔截器相關
實現WebRequestInterceptor接口
------------------------------------------------post
SpringMVC的攔截器Interceptor和過濾器Filter功能很是類似,使用場景也差很少,看起來難以區分。好比二者都能在代碼先後插入執行片斷,均可以用來實現一些公共組件的功能複用(權限檢查、日誌記錄等),其實它們並不同,首先了解一下Interceptor和Filter。this
一.Interceptor
Interceptor是Spring攔截器,要實現一個攔截器功能能夠繼承Spring的HandlerInterceptor接口:lua
package com.hpx.xiyou.wuKong.aop; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component public class sanZangInterceptor implements HandlerInterceptor{ static public final Logger logger = LoggerFactory.getLogger(sanZangInterceptor.class); @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { //System.out.println("interceptortest pre"); logger.info("interceptortest pre"); return true; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { //System.out.println("interceptortest post"); logger.info("interceptortest post"); } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { //System.out.println("interceptortest after"); logger.info("interceptortest after"); } }
HandlerInterceptor接口有三個須要實現的方法:preHandle(),postHandle()和afterCompletion()。
preHandle方法將在請求處理以前調用,SpringMVC中的Interceptor是鏈式調用的,每一個Interceptor的調用都根據它的聲明順序依次執行,且最早執行其preHandle方法,因此能夠在該方法中進行一些前置初始化操做或是預處理。該方法的返回值是布爾類型,若是返回false,表示請求結束,後續的Interceptor和Controller都不會再執行了,若是返回true就執行下一個攔截器的preHandle方法,一直到最後一個攔截器preHandle方法執行完成後調用當前請求的Controller方法。
postHandle方法是在當前請求進行處理以後,也就是Controller方法調用結束以後執行,可是它會在DispatcherServlet進行視圖渲染以前被調用,因此能夠在這個方法中能夠對Controller處理以後的ModelAndView對象進行操做。postHandle方法被調用的方向跟preHandle是相反的,也就是說先聲明的Interceptor的postHandle方法反然後執行。
afterCompletion方法須要當前對應的Interceptor的preHandle方法的返回值爲true時纔會執行。該方法會在整個請求結束以後,也就是在DispatcherServlet渲染了對應的視圖以後執行,這個方法的主要做用是用於資源清理工做。
實現一個interceptor攔截器類後,須要在配置中配置使它生效:實現 WebMvcConfigurerAdapter並重寫 addInterceptors,同時在這個方法裏設置要過濾的URL。
package com.hpx.xiyou.wuKong.Adapter; import com.hpx.xiyou.wuKong.aop.sanZangInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration public class WebConfigurerAdapter extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new sanZangInterceptor()).addPathPatterns("/wukong/**"); } }
以上配置生效後,當訪問/wukong/**類型url時,控制檯輸出以下,其中controller爲controller方法中的打印信息:
interceptortest pre
controller
interceptortest post
interceptortest after
二.Filter
Filter是Spring過濾器,要定義一個Filter類有如下步驟:
首先定義一個Filter類,繼承javax.servlet.Filter類,重寫其init、doFilter、destroy方法。init()方法會在Filter初始化後進行調用,在init()方法裏面咱們能夠經過FilterConfig訪問到初始化參數( getInitParameter()或getInitParameters() )、ServletContext (getServletContext)和當前Filter部署的名稱( getFilterName() )等信息。destroy()方法將在Filter被銷燬以前調用。而doFilter()方法則是真正進行過濾處理的方法,在doFilter()方法內部,咱們能夠過濾請求的request和返回的response,同時咱們還能夠利用FilterChain把當前的request和response傳遞給下一個過濾器或Servlet進行處理。
public
class
FilterTest
implements
Filter {
@Autowired
private
PointService pointService;
@Override
public
void
init(FilterConfig filterConfig)
throws
ServletException {
System.out.println(
"init yes"
);
}
@Override
public
void
doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws
IOException, ServletException {
System.out.println(
"filter test"
);
filterChain.doFilter(servletRequest, servletResponse);
// 傳遞給下一個Filter進行處理
return
;
}
@Override
public
void
destroy() {
System.out.println(
"destroy yes"
);
}
}
|
而後在配置中使該Filter生效:
<filter>
<filter-name>filtertest</filter-name>
<filter-
class
>FilterTest</filter-
class
>
</filter>
<filter-mapping>
<filter-name>filtertest</filter-name>
<url-pattern>/point/*</url-pattern>
</filter-mapping>
|
這樣,當咱們訪問/point/*類型的url,控制檯輸出以下:
init yes
filter test
controller
三.比較
同時配置過濾器和攔截器而後請求,結果以下:
init yes
filter test
interceptortest pre
controller
interceptortest post
interceptortest after
能夠看到filter優先於interceptor被調用。
過濾器和攔截器主要區別以下:
1.兩者適用範圍不一樣。Filter是Servlet規範規定的,只能用於Web程序中,而攔截器既能夠用於Web程序,也能夠用於Application、Swing程序中。
2.規範不一樣。Filter是在Servlet規範定義的,是Servlet容器支持的,而攔截器是在Spring容器內的,是Spring框架支持的。
3.使用的資源不一樣。同其餘代碼塊同樣,攔截器也是一個Spring的組件,歸Spring管理,配置在Spring文件中,所以能使用Spring裏的任何資源、對象(各類bean),而Filter不行。
4.深度不一樣。Filter只在Servlet先後起做用,而攔截器可以深刻到方法先後、異常跑出先後等,攔截器的使用有更大的彈性。