SpringMVC的處理器攔截器相似於Servlet開發中的過濾器Filter,用於對處理器進行預處理和後處理。開發者能夠本身定義一些攔截器來實現特定的功能。css
1.【攔截器鏈】(Interceptor Chain): 將攔截器按必定的順序鏈接成一條鏈。在訪問被攔截的方法或者字段時,攔截器鏈中的攔截器就會按照以前定義的順序被調用。html
2.過濾器與攔截器的區別java
攔截器是AOP思想的具體應用。web
過濾器 | 攔截器 |
---|---|
servlet規範中的一部分,任何java web工程均可以使用 | 攔截器是SpringMVC框架本身的,只有使用了SpringMVC框架的工程才能使用 |
在url-pattern中配置了/*以後,能夠對全部要訪問的資源進行攔截 | 攔截器只會攔截訪問的控制器方法, 若是訪問的是jsp/html/css/image/js是不會進行攔截的 |
想要自定義攔截器,必須實現 HandlerInterceptor 接口。redis
/** 自定義攔截器 */ public class HanderInterceptorOne implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle攔截器攔截了"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { System.out.println("postHandle方法執行了"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { System.out.println("afterCompletion方法執行了"); } }
配置springMVC.xmlspring
<!-- 配置攔截器 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean id="handlerInterceptorOne" class="com.itheima.myInterceptor.HanderInterceptorOne"/> </mvc:interceptor> </mvc:interceptors>
1. 訪問的index.jspsession
<%-- 測試攔截器 --%> <a href="${pageContext.request.contextPath}/interceptor/function">攔截器測試</a>
2. 控制器代碼mvc
/** 測試攔截器的控制器 */ @Controller @RequestMapping("/interceptor") public class InterceptorController { @RequestMapping("/function") public String testFunction() { System.out.println("控制器中的方法執行了"); return "success"; } }
3. 運行結果app
preHandle攔截器攔截了 控制器中的方法執行了 postHandle方法執行了 afterCompletion方法執行了
1. 攔截器的放行框架
放行的含義是指,若是有下一個攔截器就執行下一個,若是該攔截器處於攔截器鏈的最後一個,則執行控制器中的方法。
2. 攔截器中方法的說明
攔截器HandlerInterceptor接口中的三個方法詳解。
2.1 boolean preHandle
方法
2.1.1 方法源碼
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; }
2.1.2 如何調用:按照攔截器定義順序調用
2.1.3 什麼時候調用:只要配置了都會被調用
2.1.4 邏輯功能:若是開發者決定該攔截器對請求攔截處理後還要調用其餘的攔截器,或者是業務處理器去進行處理,則返回true。若是開發者決定不須要再調用其餘的組件去處理請求,則返回false。
2.2 void postHandle
方法
2.2.1 方法源碼
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {}
2.2.2 如何調用:按照攔截器定義逆序調用
2.2.3 什麼時候調用:攔截器鏈內全部攔截器返回成功時調用
2.2.4 邏輯功能:在業務處理器處理完請求後,可是DispatcherServlet向客戶端返回響應前被調用,在該方法中對用戶請求request進行處理。
2.3 void afterCompletion
方法
2.3.1 方法源碼
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {}
2.3.2 如何調用:按攔截器定義逆序調用
2.3.3 什麼時候調用:只有對應的preHandle返回true纔會被調用
2.3.4 邏輯功能:在DispatcherServlet徹底處理完請求後被調用,能夠在該方法中進行一些資源清理的操做。
3. 攔截器的做用路徑
做用路徑能夠經過在配置文件中配置。能夠配置多個
<!-- 配置攔截器的做用範圍 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> -- 用於指定攔截的url,能夠配置多個 <mvc:exclude-mapping path="/xxx"/> -- 用於指定排除的url,能夠配置多個 <bean id="handlerInterceptorOne" class="com.itheima.myInterceptor.HanderInterceptorOne"/> </mvc:interceptor> </mvc:interceptors>
4. 多個攔截器的執行順序
多個攔截器是按照配置的順序決定的,下面以前後配置
HandlerInterceptorDemo1/HandlerInterceptorDemo2
爲例:
1. 攔截器1代碼
public class HandlerInterceptorDemo1 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { System.out.println("攔截器1:preHandle攔截器攔截了"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { System.out.println("攔截器1:postHandle方法在DispatcherServlet響應前執行了"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { System.out.println("攔截器1:afterCompletion方法在DispatcherServlet響應後執行了"); } }
2. 攔截器2代碼
將攔截器中的輸出語句中的攔截器1換成攔截器2,類名換成HandlerInterceptorDemo2
3. 配置文件
<!-- 正常執行的攔截器配置,按照配置的順序執行 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean id="handlerInterceptorDemo1" class="com.itheima.myInterceptor.HandlerInterceptorDemo1"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**"/> <bean id="handlerInterceptorDemo2" class="com.itheima.myInterceptor.HandlerInterceptorDemo2"/> </mvc:interceptor> </mvc:interceptors>
4. 測試代碼
訪問的index.jsp代碼和控制器代碼同上【*】測試運行結果...
5. 執行結果
攔截器1:preHandle攔截器攔截了 攔截器2:preHandle攔截器攔截了 控制器中的方法執行了 攔截器2:postHandle方法在DispatcherServlet響應前執行了 攔截器1:postHandle方法在DispatcherServlet響應前執行了 攔截器2:afterCompletion方法在DispatcherServlet響應後執行了 攔截器1:afterCompletion方法在DispatcherServlet響應後執行了
1. 攔截器1代碼
同上一個案例的攔截器1的代碼
2. 攔截器2代碼
public class HandlerInterceptorDemo2 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { System.out.println("攔截器2:preHandle攔截器攔截了"); return false; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { System.out.println("攔截器2:postHandle方法在DispatcherServlet響應前執行了"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { System.out.println("攔截器2:afterCompletion方法在DispatcherServlet響應後執行了"); } }
3. 配置文件
同上一個案例的配置文件
4. 測試代碼
訪問的index.jsp代碼和控制器代碼同上【*】測試運行結果...
5. 執行結果
攔截器1:preHandle攔截器攔截了 攔截器2:preHandle攔截器攔截了 攔截器1:afterCompletion方法在DispatcherServlet響應後執行了
6、攔截器的簡單案例
驗證用戶是否登陸(認證用戶)
1. 實現思路
1.1 有一個登錄頁面,須要寫一個controller訪問頁面。
1.2 登錄頁面有一提交表單的動做。須要在controller中處理。
1.2.1 判斷用戶名密碼是否正確。
1.2.2 若是正確,向session(redis)中寫入用戶信息。
1.2.3 返回登錄成功。
1.3 攔截用戶請求,判斷用戶是否登錄。
1.3.1 若是用戶已經登錄。放行 1.3.2 若是用戶未登錄,跳轉到登錄頁面
2. 控制器代碼
@Controller @RequestMapping("/user") public class UserController { /** 跳轉到登錄頁面 */ @RequestMapping("/jumplogin") public String jumpLogin(Model model) throws Exception { return "login"; } /** 登錄提交 */ @RequestMapping("/login") public String login(HttpSession session, String userid, String pwd) throws Exception { // 向session記錄用戶身份信息 session.setAttribute("user", userid); return "success"; } /** 退出登錄 */ @RequestMapping("logout") public String logout(HttpSession session) throws Exception { // session 過時 session.invalidate(); return "login"; } }
3. 攔截器代碼
public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException { // 若是是登錄頁面則放行 System.out.println("uri: " + request.getRequestURI()); if (request.getRequestURI().contains("login")) { return true; } HttpSession session = request.getSession(); // 若是用戶已登錄也放行 if(session.getAttribute("user") != null) { return true; } // 用戶沒有登錄跳轉到登錄頁面 request.getRequestDispatcher("/WEB-INF/pages/login.jsp").forward(request, response); return false; } }
4. springMVC.xml配置
<!-- 登錄案例的攔截器 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean id="loginInterceptor" class="com.itheima.myInterceptor.LoginInterceptor"/> </mvc:interceptor> </mvc:interceptors>
5. 登錄頁面login.jsp
<form action="${pageContext.request.contextPath}/user/login"> 用戶名:<input type="text" name="userid"> <br> 密碼: <input type="password" name="pwd"> <br> <input type="submit" value="提交"> </form>