<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 前言 攔截器是每個Web框架必備的功能,也是個老生常談的主題了。 本章將分析SpringMVC的攔截器功能是如何設計的,讓讀者了解該功能設計的原理。 # 重要接口及類介紹 1.**HandlerExecutionChain類** 由HandlerMethod和Interceptor集合組成的類,會被HandlerMapping接口的getHandler方法獲取。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-interceptor01.png) 2.**HandlerInterceptor接口** ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-interceptor02.png) SpringMVC攔截器基礎接口。  3.**AbstractHandlerMapping** HandlerMapping的基礎抽象類。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-interceptor03.png) 4.**AsyncHandlerInterceptor** 繼承HandlerInterceptor的接口,額外提供了afterConcurrentHandlingStarted方法,該方法是用來處理異步請求。當Controller中有異步請求方法的時候會觸發該方法。 作者做過測試,異步請求先支持preHandle、然后執行afterConcurrentHandlingStarted。異步線程完成之后執行preHandle、postHandle、afterCompletion。 有興趣的讀者可自行研究。 5.**HandlerInterceptorAdapter** 實現AsyncHandlerInterceptor接口的抽象類,一般我們使用攔截器的話都會繼承這個類。然后復寫相應的方法。 6.**WebRequestInterceptor** 與HandlerInterceptor接口類似,區別是WebRequestInterceptor的preHandle沒有返回值。還有WebRequestInterceptor是針對請求的,接口方法參數中沒有response。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-interceptor04.png) AbstractHandlerMapping內部的interceptors是個Object類型集合。處理的時候判斷為MappedInterceptor[加入到mappedInterceptors集合中];HandlerInterceptor、WebRequestInterceptor(適配成WebRequestHandlerInterceptorAdapter)[加入到adaptedInterceptors中] 7.**MappedInterceptor** 一個包括includePatterns和excludePatterns字符串集合并帶有HandlerInterceptor的類。很明顯,就是對于某些地址做特殊包括和排除的攔截器。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-interceptor05.png) 8.ConversionServiceExposingInterceptor 默認的annotation-driven標簽初始化的時候會初始化ConversionServiceExposingInterceptor這個攔截器,并被當做構造方法的參數來構造MappedInterceptor。之后會被加入到AbstractHandlerMapping的mappedInterceptors集合中。該攔截器會在每個請求之前往request中丟入ConversionService。主要用于spring:eval標簽的使用。 # 源碼分析 首先我們看下攔截器的如何被調用的。 Web請求被DispatcherServlet截獲后,會調用DispatcherServlet的doDispatcher方法。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-interceptor06.png) ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-interceptor07.png) 很明顯地看到,在HandlerAdapter處理之后,以及處理完成之后會調用HandlerExecutionChain的方法。 HandlerExecutionChain的applyPreHandle、applyPostHandle、triggerAfterCompletion方法如下: ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-interceptor08.jpg) ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-interceptor09.png) ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-interceptor10.png) 很明顯,就是調用內部實現HandlerInterceptor該接口集合的各個對應方法。 下面我們看下HandlerExecutionChain的構造過程。 HandlerExecutionChain是從HandlerMapping接口的getHandler方法獲取的。 HandlerMapping的基礎抽象類AbstractHandlerMapping中: ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-interceptor11.png) ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-interceptor12.png) **我們看到,HandlerExecutionChain的攔截器是從AbstractHandlerMapping中的adaptedInterceptors和mappedInterceptors屬性中獲取的。** # 攔截器的配置 清楚了HandlerExecutionChain的攔截器屬性如何構造之后,下面來看下SpringMVC是如何配置攔截器的。 1.*-dispatcher.xml配置文件中添加mvc:interceptors配置 <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <mvc:exclude-mapping path="/login"/>    <mvc:exclude-mapping path="/index"/> <bean class="package.interceptor.XXInterceptor"/> </mvc:interceptor> </mvc:interceptors> 這里配置的每個mvc:interceptor都會被解析成MappedInterceptor。 其中子標簽 <mvc:mapping path="/**"/> 會被解析成MappedInterceptor的includePatterns屬性; <mvc:exclude-mapping path="/**"/> 會被解析成MappedInterceptor的excludePatterns屬性; <bean/> 會被解析成MappedInterceptor的interceptor屬性。 mvc:interceptors這個標簽是被InterceptorsBeanDefinitionParser類解析。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-interceptor13.png) 2.配置RequestMappingHandlerMapping,并配置該bean對應的interceptors集合屬性。這里的interceptors集合是個Object類型的泛型集合。 AbstractHandlerMapping抽象類只暴露了1個攔截器的set方法 -> interceptors。 adaptedInterceptors和mappedInterceptors均沒有暴露set方法,因此我們只能為RequestMappingHandlerMapping配置interceptors屬性。 **其實AbstractHandlerMapping內部的initInterceptors方法中,會遍歷interceptors集合,然后判斷各個項是否是MappedInterceptor、HandlerInterceptor、WebRequestInterceptor。** 其中MappedInterceptor類型的攔截器會被加到mappedInterceptors集合中,HandlerInterceptor類型的會被加到adaptedInterceptors集合中,WebRequestInterceptor類型的會被適配成WebRequestHandlerInterceptorAdapter加到adaptedInterceptors集合中。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-interceptor14.png) ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-interceptor15.png) 如果讀者配置了: <mvc:annotation-driven/> 那么配置如下: <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"> <property name="interceptors"> <bean class="package.interceptor.XXInterceptor"/> </property> <property name="order" value="-1"/> </bean> 否則,可以去掉order這個屬性的設置。 為什么呢? 請參考[Spring中Ordered接口簡介](spring/Spring-Ordered-interface.md) 一般建議使用第一種方法。 # 編寫自定義的攔截器 public class LoginInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 獲得請求路徑的uri String uri = request.getRequestURI(); // 判斷路徑是登出還是登錄驗證,是這兩者之一的話執行Controller中定義的方法 if(uri.endsWith("/login/auth") || uri.endsWith("/login/out")) { return true; } // 進入登錄頁面,判斷session中是否有key,有的話重定向到首頁,否則進入登錄界面 if(uri.endsWith("/login/") || uri.endsWith("/login")) { if(request.getSession() != null && request.getSession().getAttribute("loginUser") != null) { response.sendRedirect(request.getContextPath() + "/index"); } else { return true; } } // 其他情況判斷session中是否有key,有的話繼續用戶的操作 if(request.getSession() != null && request.getSession().getAttribute("loginUser") != null) { return true; } // 最后的情況就是進入登錄頁面 response.sendRedirect(request.getContextPath() + "/login"); return false; } } 登錄Controller: @Controller @RequestMapping(value = "/login") public class LoginController { @RequestMapping(value = {"/", ""}) public String index() { return "login"; } @RequestMapping("/auth") public String auth(@RequestParam String username, HttpServletRequest req) { req.getSession().setAttribute("loginUser", username); return "redirect:/index"; } @RequestMapping("/out") public String out(HttpServletRequest req) { req.getSession().removeAttribute("loginUser"); return "redirect:/login"; } } *-diapatcher.xml配置: <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="org.format.demo.interceptor.LoginInterceptor"/> </mvc:interceptor> </mvc:interceptors> PS:我們看到LoginInterceptor里的preHandle方法對于地址“/login/auth”和"/login/out"不處理。 因此,可以寫點配置,少寫帶java代碼。在攔截器配置中添加2個exclude-mapping,并且去掉LoginInterceptor里的 if(uri.endsWith("/login/auth") || uri.endsWith("/login/out")) { return true; } 配置新增: <mvc:exclude-mapping path="/login/out"/> <mvc:exclude-mapping path="/login/auth"/> # 總結 總結了SpringMVC攔截器的原理以及各種配置,像網上很多人會問為什么攔截器執行preHandle方法返回false之后還是會執行afterCompletion方法,其實我們看下源碼就知道了。 關于異步請求方面的攔截器以及第二種配置方法(interceptors集合屬性可加入繼承自HandlerInterceptorAdapter抽象類的類以及實現WebRequestInterceptor接口的類),讀者可自行研究。 # 參考資料 [http://jinnianshilongnian.iteye.com/blog/1670856](http://jinnianshilongnian.iteye.com/blog/1670856)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看