網(wǎng)站開發(fā)研究背景域名搜索
攔截器,通俗來來將,就是我們將訪問某個路徑的請求給攔截下來,然后可以對這個請求做一些操作
基本使用
創(chuàng)建攔截器類
讓類實現(xiàn)HandlerInterceptor接口,重寫接口中的三個方法。
@Component
//定義攔截器類,實現(xiàn)HandlerInterceptor接口
//注意當前類必須受Spring容器控制
public class ProjectInterceptor implements HandlerInterceptor {@Override//原始方法調用前執(zhí)行的內容public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle...");// true 放行,false 攔截return true;}@Override//原始方法調用后執(zhí)行的內容public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle...");}@Override//原始方法調用完成后執(zhí)行的內容public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion...");}
}
配置攔截器類
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {@Autowiredprivate ProjectInterceptor projectInterceptor;// 這個方法是用來配置靜態(tài)資源的,比如html,js,css等等@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");}// 這個方法用來注冊攔截器,我們自己寫好的攔截器需要通過這里添加注冊才能生效@Overrideprotected void addInterceptors(InterceptorRegistry registry) {//配置攔截器registry.addInterceptor(projectInterceptor).addPathPatterns("/books" );//配置不攔截路徑 .excludePathPatterns("/login");}
}
這里ProjectInterceptor攔截器也可以不注入,直接new一個該類
我們可以看到攔截器HandlerInterceptor的使用方法:
- 首先編寫攔截器HandlerInterceptor,來寫出攔截后要執(zhí)行的邏輯
- 然后編寫攔截器配置類,來 **注冊攔截器 **,使之生效,并且可以配置需要 攔截的路徑
三種攔截方式
- 前置處理方法 - preHandle - 進入controller方法之前
- 后置處理方法 - postHandle - 方法內部處理完成,頁面渲染之前
- 完成處理方法 - afterCompletion - 方法內部處理完成,頁面渲染之前
這三個方法中,最常用的是 **preHandle **, 在這個方法中可以通過返回值來決定是否要進行放行,我們可以把業(yè)務邏輯放在該方法中,如果滿足業(yè)務則返回true放行,不滿足則返回false攔截。
接下來我們來具體看一下這三種攔截方式對應的函數(shù)
攔截器參數(shù)
前置處理方法
原始方法之前運行preHandle
public boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception {System.out.println("preHandle");return true;
}
- request: 請求對象。使用request對象可以獲取請求數(shù)據(jù)中的內容,如獲取請求頭的
Content-Type
- response: 響應對象
- handler: 被調用的處理器對象,本質上是一個方法對象,對反射中的Method對象進行了再包裝。使用handler參數(shù),可以獲取方法的相關信息(和反射中的class類一樣)
后置處理方法
原始方法運行后運行,如果原始方法被攔截,則不執(zhí)行
public void postHandle(HttpServletRequest request,HttpServletResponse response,Object handler,ModelAndView modelAndView) throws Exception {System.out.println("postHandle");
}
前三個參數(shù)和上面的是一致的。
modelAndView:如果處理器執(zhí)行完成具有返回結果,可以讀取到對應數(shù)據(jù)與頁面信息,并進行調整
因為咱們現(xiàn)在都是返回json數(shù)據(jù),所以該參數(shù)的使用率不高。
完成處理方法
攔截器最后執(zhí)行的方法,無論原始方法是否執(zhí)行
public void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex) throws Exception {System.out.println("afterCompletion");
}
前三個參數(shù)與上面的是一致的。
ex:如果處理器執(zhí)行過程中出現(xiàn)異常對象,可以針對異常情況進行單獨處理
因為我們現(xiàn)在已經(jīng)有全局異常處理器類,所以該參數(shù)的使用率也不高。
多個攔截器
寫法
配置類和之前一樣,只不過多注冊了攔截器
@Configuration
@ComponentScan({"com.itheima.controller"})
@EnableWebMvc
//實現(xiàn)WebMvcConfigurer接口可以簡化開發(fā),但具有一定的侵入性
public class SpringMvcConfig implements WebMvcConfigurer {@Autowiredprivate ProjectInterceptor projectInterceptor;@Autowiredprivate ProjectInterceptor2 projectInterceptor2;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//配置多攔截器registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");registry.addInterceptor(projectInterceptor2).addPathPatterns("/books","/books/*");}
}
執(zhí)行順序
攔截器執(zhí)行的順序是和配置順序有關。就和前面所提到的運維人員進入機房的案例,先進后出。
- 當配置多個攔截器時,形成攔截器鏈
- 攔截器鏈的運行順序參照攔截器添加順序為準
- 當攔截器中出現(xiàn)對原始處理器的攔截,后面的攔截器均終止運行
- 當攔截器運行中斷,僅運行配置在前面的攔截器的afterCompletion操作
preHandle:與配置順序相同,必定運行
postHandle:與配置順序相反,可能不運行
afterCompletion:與配置順序相反,可能不運行。
這個順序不太好記,最終只需要把握住一個原則即可:以最終的運行結果為準
攔截器與過濾器
兩者的區(qū)別
- 過濾器基于函數(shù)回調、攔截器基于反射;
- 過濾器幾乎對所有請求起作用,攔截器只對目標執(zhí)行方法起作用;
- 過濾器對請求進行預處理、再交給Servlet處理并且生成響應,最后Filter再對服務器響應進行后處理;攔截器可以在方法執(zhí)行前調用(preHandle),方法執(zhí)行后調用(postHandle),視圖頁面渲染后調用(afterCompletion)
如果大家有什么思考和問題,可以在評論區(qū)討論,也可以私信我,很樂意為大家效勞。
好啦,今天的每日一題到這里就結束了,如果大家覺得有用,可以可以給我一個小小的贊呢,我們下期再見!