Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 国产97色在线|免费,成人网18免费下,欧洲亚洲精品

          整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          為什么別人的網(wǎng)頁有登錄攔截而你沒有,這就教你學(xué)會它

          為什么別人的網(wǎng)頁有登錄攔截而你沒有,這就教你學(xué)會它

          個 登 錄 有 必 要 做 成 那 樣 嗎 ? \textcolor{green}{一個登錄有必要做成那樣嗎?}一個登錄有必要做成那樣嗎?我 的 回 答 : 非 常 有 必 要 \textcolor{red}{我的回答:非常有必要}我的回答:非常有必要
          試 想 一 下 , 如 果 一 個 網(wǎng) 站 可 以 隨 便 進(jìn) 去 點 贊 等 操 作 , 那 還 要 登 錄 干 什 么 ? \textcolor{green}{試想一下,如果一個網(wǎng)站可以隨便進(jìn)去點贊等操作,那還要登錄干什么?}試想一下,如果一個網(wǎng)站可以隨便進(jìn)去點贊等操作,那還要登錄干什么?
          博 主 也 在 學(xué) 習(xí) 階 段 , 如 若 發(fā) 現(xiàn) 問 題 , 請 告 知 , 非 常 感 謝 \textcolor{Orange}{博主也在學(xué)習(xí)階段,如若發(fā)現(xiàn)問題,請告知,非常感謝}博主也在學(xué)習(xí)階段,如若發(fā)現(xiàn)問題,請告知,非常感謝
          周 榜 也 到 了 26 , 哇 塞 ( o ゜ ▽ ゜ ) o ☆ , 順 便 提 一 下 今 天 庫 里 必 登 三 分 歷 史 第 一 \textcolor{blue}{周榜也到了26,哇塞(o゜▽゜)o☆,順便提一下今天庫里必登三分歷史第一}周榜也到了26,哇塞(o゜▽゜)o☆,順便提一下今天庫里必登三分歷史第一

          攔截器

              • 1.簡介
              • 2.自定義攔截器
              • 3. 登錄攔截
                • 3.1 先做一個頁面
                • 3.2 登錄攔截
              • 文末小驚喜

          1.簡介

          SpringMVC的處理器攔截器類似于Servlet開發(fā)中的過濾器Filter,用于對處理器進(jìn)行預(yù)處理和后處理。

          攔截器和過濾器的區(qū)別在于攔截器使AOP思想的具體應(yīng)用

          • 過濾器
            • servlet規(guī)范中的一部分,任何java web工程都可以使用
            • url-pattern中配置了/*之后,可以對所有要訪問的資源進(jìn)行攔截
            • 需要重寫方法
          • 攔截器
            • SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
            • 攔截器只會攔截訪問的控制器方法, 如果訪問的是jsp/html/css/image/js是不會進(jìn)行攔截的
            • 不需要重寫方法

          2.自定義攔截器

          ? ? > 新 建 一 個 M o d u l e , 添 加 w e b 支 持 \textcolor{OrangeRed}{--> 新建一個Module,添加web支持}??>新建一個Module,添加web支持

          ? ? > 配 置 w e b . x m l , a p p l i c a t i o n C o n t e x t . x m l , 添 加 一 個 c o n t r o l l e r 的 包 \textcolor{OrangeRed}{--> 配置web.xml,applicationContext.xml,添加一個controller的包}??>配置web.xmlapplicationContext.xml,添加一個controller的包

          ? ? > 編 寫 測 試 \textcolor{OrangeRed}{--> 編寫測試}??>編寫測試

          @RestController
          public class TestController {
              @GetMapping("/t1")
              public String test(){
                  System.out.println("TestController-->test()執(zhí)行了");
                  return "ok";
              }
          }
          12345678

          添加Artifact中的lib,以及配置Tomcat,啟動測試出現(xiàn),證明Spring配置好了

          ? ? > 編 寫 攔 截 器 \textcolor{OrangeRed}{--> 編寫攔截器}??>編寫攔截器

          package com.hxl.config;
          
          import org.springframework.web.servlet.HandlerInterceptor;
          import org.springframework.web.servlet.ModelAndView;
          
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          
          public class MyInterceptor implements HandlerInterceptor {
              //在請求處理的方法之前執(zhí)行
              //return true;執(zhí)行下一個攔截器
              //如果返回false就不執(zhí)行下一個攔截器
              public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                  System.out.println("------------處理前------------");
                  return true;
              }
              //在請求處理方法執(zhí)行之后執(zhí)行
              public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
                  System.out.println("------------處理后------------");
              }
              //在dispatcherServlet處理后執(zhí)行,做清理工作.
              public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
                  System.out.println("------------清理------------");
              }
          }
          12345678910111213141516171819202122232425

          ? ? > 在 a p p l i c a t i o n C o n t e x t . x m l 中 配 置 攔 截 器 \textcolor{OrangeRed}{--> 在applicationContext.xml中配置攔截器}??>在applicationContext.xml中配置攔截器

          <!--關(guān)于攔截器的配置-->
          <mvc:interceptors>
              <mvc:interceptor>
                  <!--/** 包括路徑及其子路徑-->
                  <!--/admin/* 攔截的是/admin/add等等這種 , /admin/add/user不會被攔截-->
                  <!--/admin/** 攔截的是/admin/下的所有-->
                  <mvc:mapping path="/**"/>
                  <!--bean配置的就是攔截器-->
                  <bean class="com.hxl.config.MyInterceptor"/>
              </mvc:interceptor>
          </mvc:interceptors>
          1234567891011

          前面的我們都不動,運行,我們可以看到效果

          那么接下來就用一個實例來體驗一下攔截器(登錄)

          在WEB-INF下的所有頁面或者資源,只能通過controller或者servlet進(jìn)行訪問

          3. 登錄攔截

          3.1 先做一個頁面

          ? ? > i n d e x . j s p \textcolor{OrangeRed}{--> index.jsp}??>index.jsp

          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <html>
            <head>
              <title>$Title$</title>
            </head>
            <body>
          
            <a href="${pageContext.request.contextPath}/goLogin">登錄</a>
            <a href="${pageContext.request.contextPath}/goMain">首頁</a>
          
            </body>
          </html>
          123456789101112

          ? ? > m a i n . j s p \textcolor{OrangeRed}{--> main.jsp}??>main.jsp

          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <html>
          <head>
              <title>Title</title>
          </head>
          <body>
          
          <h1>首頁</h1>
          
          </body>
          </html>
          1234567891011

          ? ? > l o g i n . j s p \textcolor{OrangeRed}{--> login.jsp}??>login.jsp

          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <html>
          <head>
              <title>登錄</title>
          </head>
          <body>
          
          <h1>登錄頁面</h1>
          
          <form action="${pageContext.request.contextPath}/login" method="post">
              用戶名:<input type="text" name="username">
              密碼:<input type="text" name="password">
              <input type="submit" value="登錄">
          </form>
          </body>
          </html>
          12345678910111213141516

          ? ? > L o g i n C o n t r o l l e r \textcolor{OrangeRed}{--> LoginController}??>LoginController

          package com.hxl.controller;
          
          import org.springframework.stereotype.Controller;
          import org.springframework.web.bind.annotation.RequestMapping;
          
          import javax.servlet.http.HttpSession;
          
          @Controller
          public class LoginController {
          
              @RequestMapping("/goMain")
              public String goMain(){
                  return "main";
              }
          
              @RequestMapping("/goLogin")
              public String goLogin(){
                  return "login";
              }
          
              @RequestMapping("/login")
              public String login(HttpSession session,String username,String password){
                  // 向session記錄用戶身份信息
                  System.out.println("接收前端==="+username);
                  session.setAttribute("user", username);
                  return "main";
              }
          }
          12345678910111213141516171819202122232425262728

          ? ? > 測 試 : \textcolor{OrangeRed}{--> 測試:}??>測試:

          因為在WEB-INF下的 頁面我們不能直接訪問,所以在index中進(jìn)行跳轉(zhuǎn),然后請求到login.jsp。此時我們在這里輸入,就會在session中攜帶賬號密碼。

          但此時是不符合的,因為我們還沒有登錄就可以去首頁,所以我們需要寫一個攔截器的功能

          3.2 登錄攔截

          ? ? > i n d e x . j s p \textcolor{OrangeRed}{--> index.jsp}??>index.jsp

          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <html>
            <head>
              <title>$Title$</title>
            </head>
            <body>
          
            <a href="${pageContext.request.contextPath}/user/goLogin">登錄</a>
            <a href="${pageContext.request.contextPath}/user/goMain">首頁</a>
          
            </body>
          </html>
          123456789101112

          ? ? > l o g i n . j s p \textcolor{OrangeRed}{--> login.jsp}??>login.jsp

          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <html>
          <head>
              <title>登錄</title>
          </head>
          <body>
          
          <h1>登錄頁面</h1>
          
          <form action="${pageContext.request.contextPath}/user/login" method="post">
              用戶名:<input type="text" name="username">
              密碼:<input type="text" name="password">
              <input type="submit" value="登錄">
          </form>
          </body>
          </html>
          12345678910111213141516

          ? ? > m a i n . j s p \textcolor{OrangeRed}{--> main.jsp}??>main.jsp

          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <html>
          <head>
              <title>Title</title>
          </head>
          <body>
          
          <h1>首頁</h1>
          <p>${username}</p>
          <p>
              <a href="${pageContext.request.contextPath}/user/goOut">注銷</a>
          </p>
          </body>
          </html>
          1234567891011121314

          ? ? > L o g i n I n t e r c e p t o r \textcolor{OrangeRed}{--> LoginInterceptor}??>LoginInterceptor

          此時我們?nèi)懸粋€登錄的攔截器,來判斷它到底什么時候進(jìn)行攔截

          package com.hxl.config;
          
          import org.springframework.web.servlet.HandlerInterceptor;
          
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          import javax.servlet.http.HttpSession;
          
          public class LoginInterceptor implements HandlerInterceptor {
              public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                  HttpSession session=request.getSession();
                  //放行:判斷什么情況下沒有登錄
                  //登錄頁面放行
                  if(request.getRequestURI().contains("goLogin")){
                      return true;
                  }
                  if(request.getRequestURI().contains("login")){
                      return true;
                  }
                  //用戶已登錄,第一次登錄的時候也是沒有session的。
                  if(session.getAttribute("user") !=null){
                      return true;
                  }
                  //判斷什么情況下沒有登錄
                  request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
                  return false;
              }
          }
          12345678910111213141516171819202122232425262728

          ? ? > L o g i n C o n t r o l l e r \textcolor{OrangeRed}{--> LoginController}??>LoginController

          這里面我們有一個類url,下面的請求都需要加上/user,在配置攔截器的時候可以加一個,只攔截user請求下的。以及注銷功能

          package com.hxl.controller;
          
          import org.springframework.stereotype.Controller;
          import org.springframework.ui.Model;
          import org.springframework.web.bind.annotation.RequestMapping;
          
          import javax.servlet.http.HttpSession;
          
          @Controller
          @RequestMapping("/user")
          public class LoginController {
          
              @RequestMapping("/goMain")
              public String goMain(){
                  return "main";
              }
          
              @RequestMapping("/goLogin")
              public String goLogin(){
                  return "login";
              }
          
              @RequestMapping("/login")
              public String login(HttpSession session, String username, String password, Model model){
                  // 向session記錄用戶身份信息
                  System.out.println("接收前端==="+username);
                  session.setAttribute("user", username);
                  model.addAttribute("username",username);
                  return "main";
              }
          
              @RequestMapping("/goOut")
              public String goOut(HttpSession session){
                  /*//銷毀,下面的好
                  session.invalidate();*/
                  //移除
                  session.removeAttribute("user");
                  return "main";
              }
          }
          12345678910111213141516171819202122232425262728293031323334353637383940

          ? ? > a p p l i c a t i o n C o n t e x t . x m l \textcolor{OrangeRed}{-->applicationContext.xml}??>applicationContext.xml

          <!--關(guān)于攔截器的配置-->
          <mvc:interceptors>
              <mvc:interceptor>
                  <!--/** 包括路徑及其子路徑-->
                  <!--/admin/* 攔截的是/admin/add等等這種 , /admin/add/user不會被攔截-->
                  <!--/admin/** 攔截的是/admin/下的所有-->
                  <mvc:mapping path="/**"/>
                  <!--bean配置的就是攔截器-->
                  <bean class="com.hxl.config.MyInterceptor"/>
              </mvc:interceptor>
          
              <mvc:interceptor>
                  <!--user下面的請求-->
                  <mvc:mapping path="/user/**"/>
                  <bean class="com.hxl.config.LoginInterceptor"/>
              </mvc:interceptor>
          </mvc:interceptors>
          1234567891011121314151617

          ? ? > 測 試 \textcolor{OrangeRed}{-->測試}??>測試

          此時我們啟動之后,如果沒有登錄,那么會重定向到goLogin頁面,然后登錄,登錄之后跳轉(zhuǎn)到main頁面,其中有注銷功能,沒有注銷之前可以去index頁面點擊首頁正常跳轉(zhuǎn),如果注銷了,session沒有了,那么就會跳轉(zhuǎn)到登錄頁面。

          面介紹了Spring Boot 如何整合定時任務(wù)已經(jīng)Spring Boot 如何創(chuàng)建異步任務(wù),不清楚的朋友可以看看之前的文章:https://www.cnblogs.com/zhangweizhong/category/1657780.html。

          接下來開始講 Spring Boot的重要功能:整合攔截器。以前我們在做mvc 項目時也使用到的是filter過濾器也就是攔截器。其實Spring Boot 中的攔截器和SpringMVC中的攔截器也是類似的,只是配置上有些區(qū)別。那么下面我們就來看看Spring Boot 是怎么配置攔截器的。

          一、攔截器配置

          創(chuàng)建InterceptorConfig 攔截器配置類,這個類主要是統(tǒng)一配置管理所有的攔截器。

          package com.weiz.config;
          
          import com.weiz.controller.interceptor.TwoInterceptor;
          import org.springframework.context.annotation.Configuration;
          import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
          
          import com.weiz.controller.interceptor.OneInterceptor;
          import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
          
          import javax.annotation.Resource;
          
          @Configuration
          public class InterceptorConfig implements WebMvcConfigurer {
          
              @Resource
              private OneInterceptor myInterceptor1;
          
              @Override
              public void addInterceptors(InterceptorRegistry registry) {
                  //添加要攔截的url                1                 攔截的路徑                                    放行的路徑
                  registry.addInterceptor(myInterceptor1).addPathPatterns("/admin/**").excludePathPatterns("/admin/login");
              }
          }

          說明:

          1、使用注解@Configuration配置攔截器

          2、繼承WebMvcConfigurer 接口

          3、重寫addInterceptors方法,添加需要的攔截器地址

          二、自定義攔截器

          前面創(chuàng)建了攔截器的配置管理類,接下來就應(yīng)該創(chuàng)建具體的攔截器。首先創(chuàng)建com.weiz.controller.interceptor包,并創(chuàng)建OneInterceptor攔截器。這個攔截器通過實現(xiàn) HandlerInterceptor 接口,達(dá)到請求攔截的作用。具體代碼如下:

          package com.weiz.controller.interceptor;
          
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          import org.springframework.web.servlet.HandlerInterceptor;
          import org.springframework.web.servlet.ModelAndView;
          
          
          public class OneInterceptor implements HandlerInterceptor  {
          
              /**
               * 在請求處理之前進(jìn)行調(diào)用(Controller方法調(diào)用之前)
               */
              @Override
              public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
                      Object object) throws Exception {
                  
                  System.out.println("被OneInterceptor攔截,放行...");return true;
              }
              
              /**
               * 請求處理之后進(jìn)行調(diào)用,但是在視圖被渲染之前(Controller方法調(diào)用之后)
               */
              @Override
              public void postHandle(HttpServletRequest request, HttpServletResponse response, 
                      Object object, ModelAndView mv)
                      throws Exception {
                  // TODO Auto-generated method stub
                  
              }
              
              /**
               * 在整個請求結(jié)束之后被調(diào)用,也就是在DispatcherServlet 渲染了對應(yīng)的視圖之后執(zhí)行
               * (主要是用于進(jìn)行資源清理工作)
               */
              @Override
              public void afterCompletion(HttpServletRequest request, HttpServletResponse response, 
                      Object object, Exception ex)
                      throws Exception {
                  // TODO Auto-generated method stub
                  
              }
          }

          說明:

          1、HandlerInterceptor接口有 3 個攔截方法:

          preHandle:Controller邏輯執(zhí)行之前進(jìn)行攔截

          postHandle:Controller邏輯執(zhí)行完畢但是視圖解析器還未進(jìn)行解析之前進(jìn)行攔截

          afterCompletion:Controller邏輯和視圖解析器執(zhí)行完畢進(jìn)行攔截

          2、實際開發(fā)中 一般preHandle 使用頻率比較高,postHandle 和 afterCompletion操作相對比較少。

          postHandle 是在視圖解析前進(jìn)行攔截,通過 Model 再次添加數(shù)據(jù)到 Request域中。

          afterCompletion 暫時沒有想到使用場景,如果有使用過的場景可以在下面評論區(qū)中進(jìn)行評論。


          測試

          在瀏覽器中,輸入配置管理器中攔截的地址:http://localhost:8088/th/index

          從上圖可以看出定義的攔截器生效了,打印出了攔截器里面的log 。

          最后

          以上,就把Spring Boot 如何使用攔截器介紹完了,是不是特別簡單。SpringBoot 2 整合攔截器和整合 Filter的操作很像,都是通過一個注冊類將其注入到Spring的上下文中,只不過Filter使用的是 FilterRegistrationBean 而攔截器使用的是 InterceptorRegistry。

          個人覺得比使用 xml 配置的方式更為簡單,如果你還沒有在 SpringBoot 項目中使用過攔截器,趕快來操作一下吧!

          這個系列課程的完整源碼,也會提供給大家。大家關(guān)注我的頭條號(章為忠學(xué)架構(gòu)),獲取這個系列課程的完整源碼。


          推薦閱讀:

          Spring Boot整合定時任務(wù)Task,一秒搞定定時任務(wù)

          SpringBoot入門系列(四)如何整合Thymeleaf模板引擎

          Spring Boot集成Redis代碼詳解,三步搞定!

          SpringBoot入門系列(三)資源文件屬性配置

          Spring Boot入門系列(六)Spring整合Mybatis詳解「附詳細(xì)步驟」

          springmvc攔截器是我們項目開發(fā)中用到的一個功能,常常用于對Handler進(jìn)行預(yù)處理和后處理。本案例來演示一個較簡單的springmvc攔截器的使用,并通過分析源碼來探究攔截器的執(zhí)行順序是如何控制的。

          1、springmvc攔截器使用

          1.1 項目初始搭建

          1.1.1 創(chuàng)建一個maven的war工程

          ? 該步驟不再截圖說明

          1.1.2 引入maven依賴

          <dependencies>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-context</artifactId>
                  <version>5.0.2.RELEASE</version>
              </dependency>
          
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-web</artifactId>
                  <version>5.0.2.RELEASE</version>
              </dependency>
          
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-webmvc</artifactId>
                  <version>5.0.2.RELEASE</version>
              </dependency>
          
              <dependency>
                  <groupId>javax.servlet</groupId>
                  <artifactId>servlet-api</artifactId>
                  <version>2.5</version>
                  <scope>provided</scope>
              </dependency>
          
              <dependency>
                  <groupId>javax.servlet.jsp</groupId>
                  <artifactId>jsp-api</artifactId>
                  <version>2.0</version>
                  <scope>provided</scope>
              </dependency>
          </dependencies>

          1.2.3 配置web.xml

          ? 配置springmvc核心控制器DispatcherServlet,由于需要加載springmvc.xml,所以需要創(chuàng)建一個springmvc.xml文件(文件參考源碼附件)放到classpath下

          <!-- 前端控制器(加載classpath:springmvc.xml 服務(wù)器啟動創(chuàng)建servlet) -->
          <servlet>
              <servlet-name>dispatcherServlet</servlet-name>
              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
              <!-- 配置初始化參數(shù),創(chuàng)建完DispatcherServlet對象,加載springmvc.xml配置文件 -->
              <init-param>
                  <param-name>contextConfigLocation</param-name>
                  <param-value>classpath:springmvc.xml</param-value>
              </init-param>
              <load-on-startup>1</load-on-startup>
          </servlet>
          <servlet-mapping>
              <servlet-name>dispatcherServlet</servlet-name>
              <url-pattern>/</url-pattern>
          </servlet-mapping>

          1.2 攔截器開發(fā)

          1.2.1 準(zhǔn)備兩個攔截器

          ? 兩個攔截器分別命名為MyInterceptor1、MyInterceptor2

          public class MyInterceptor1 implements HandlerInterceptor {
          
              public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
                  System.out.println("==1-1====前置攔截器1 執(zhí)行======");
                  return true; //ture表示放行
              }
          
              public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
                  System.out.println("==1-2=====后置攔截器1 執(zhí)行======");
              }
          
              public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
                  System.out.println("==1-3======最終攔截器1 執(zhí)行======");
              }
          }public class MyInterceptor2 implements HandlerInterceptor {
          
              public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
                  System.out.println("==2-1====前置攔截器2 執(zhí)行======");
                  return true; //ture表示放行
              }
          
              public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
                  System.out.println("==2-2=====后置攔截器2 執(zhí)行======");
              }
          
              public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
                  System.out.println("==2-3======最終攔截器2 執(zhí)行======");
              }
          }

          1.2.2 在springmvc.xml中攔截器

          <!--配置攔截器-->
          <mvc:interceptors>
              <!--配置攔截器-->
              <mvc:interceptor>
                  <mvc:mapping path="/**" />
                  <bean class="com.itheima.interceptor.MyInterceptor1" />
              </mvc:interceptor>
          
              <mvc:interceptor>
                  <mvc:mapping path="/**" />
                  <bean class="com.itheima.interceptor.MyInterceptor2" />
              </mvc:interceptor>
          </mvc:interceptors>

          這兩個攔截器攔截規(guī)則相同,并且配置順序攔截器1在攔截器2之前!

          1.3 測試攔截器效果

          1.3.1 準(zhǔn)備測試Controller

          @Controller
          public class BizController {
              @RequestMapping("testBiz")
              public String showUserInfo(Integer userId, Model model){
                  System.out.println(">>>>>業(yè)務(wù)代碼執(zhí)行-查詢用戶ID為:"+ userId);
                  User user=new User(userId);
                  user.setName("宙斯");
                  model.addAttribute("userInfo",user);
                  return "user_detail";
              }
          }

          該controller會轉(zhuǎn)發(fā)到user_detail.jsp頁面

          1.3.2 準(zhǔn)備user_detail.jsp

          <html>
          <head>
              <title>detail</title>
          </head>
          <body>
              用戶詳情:
              ${userInfo.id}:${userInfo.name}
          
              <%System.out.print(">>>>>jsp頁面的輸出為:");%>
              <%System.out.println(((User)request.getAttribute("userInfo")).getName());%>
          </body>
          </html>

          1.3.3 測試效果

          ? 啟動項目后,在地址欄訪問/testBiz?userId=1,然后查看IDE控制臺打印:

          ==1-1====前置攔截器1 執(zhí)行========2-1====前置攔截器2 執(zhí)行======>>>>>業(yè)務(wù)代碼執(zhí)行-查詢用戶ID為:1==2-2=====后置攔截器2 執(zhí)行========1-2=====后置攔截器1 執(zhí)行======>>>>>jsp頁面的輸出為:宙斯==2-3======最終攔截器2 執(zhí)行========1-3======最終攔截器1 執(zhí)行======

          通過打印日志發(fā)現(xiàn),攔截器執(zhí)行順序是: 攔截器1的前置>攔截器2的前置>業(yè)務(wù)代碼>攔截器2后置>攔截器1后置>攔截器2最終>攔截器1最終

          2、源碼分析

          ? 經(jīng)過測試發(fā)現(xiàn)攔截器執(zhí)行順序如下:

          攔截器1的前置>攔截器2的前置>業(yè)務(wù)代碼>攔截器2后置>攔截器1后置>攔截器2最終>攔截器1最終

          我們通過分析源碼來探究下攔截器是如何執(zhí)行的

          2.1 DispatcherServlet

          ? 當(dāng)瀏覽器發(fā)送/testBiz?userId=1的請求時,會經(jīng)過DispatcherServlet的doDispatch方法,我們將其取出并觀察其核心代碼(省略非關(guān)鍵代碼)

          protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
              //...
              try {
                  try {
                      ModelAndView mv=null;
                      Object dispatchException=null;
          
                      try {
                          processedRequest=this.checkMultipart(request);
                          multipartRequestParsed=processedRequest !=request;
                          //1.獲取執(zhí)行鏈
                          mappedHandler=this.getHandler(processedRequest);
                          if (mappedHandler==null) {
                              this.noHandlerFound(processedRequest, response);
                              return;
                          }
                          //2.獲取處理器適配器
                          HandlerAdapter ha=this.getHandlerAdapter(mappedHandler.getHandler());
          
                          //...
                          //【3】.執(zhí)行前置攔截器
                          if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                              return;
                          }
                          //4.執(zhí)行業(yè)務(wù)handler
                          mv=ha.handle(processedRequest, response, mappedHandler.getHandler());
                          if (asyncManager.isConcurrentHandlingStarted()) {
                              return;
                          }
                          this.applyDefaultViewName(processedRequest, mv);
                          //【5】.執(zhí)行后置攔截器
                          mappedHandler.applyPostHandle(processedRequest, response, mv);
                      } catch (Exception var20) {
                          dispatchException=var20;
                      } catch (Throwable var21) {
                          dispatchException=new NestedServletException("Handler dispatch failed", var21);
                      }
                      //【6】.處理頁面響應(yīng),并執(zhí)行最終攔截器
                      this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
                  } catch (Exception var22) {
                      this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
                  } catch (Throwable var23) {
                      this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
                  }
          
              }finally {
                  //...
              }
          }

          代碼中有關(guān)攔截器執(zhí)行的位置我都添加了注釋,其中注釋中標(biāo)識的步驟中,3、5、6步驟是攔截器的關(guān)鍵步驟

          其中,第一步中"獲取執(zhí)行鏈",執(zhí)行鏈內(nèi)容可以通過debug調(diào)試查看內(nèi)容:

          可以看到我們自定義的兩個攔截器按順序保存

          2.2 攔截器步驟解析

          ? 在doDispatch方法中,我們添加的注釋的第【3】、【5】、【6】步驟是對攔截器的執(zhí)行處理,現(xiàn)在分別來查看第【3】、【5】、【6】步驟執(zhí)行的具體方法的源碼

          2.2.1 第【3】步驟

          //3.執(zhí)行前置攔截器中的詳細(xì)代碼
          boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
              //獲得本次請求對應(yīng)的所有攔截器
              HandlerInterceptor[] interceptors=this.getInterceptors();
              if (!ObjectUtils.isEmpty(interceptors)) {
                  //按照攔截器順序依次執(zhí)行每個攔截器的preHandle方法.
                  //并且,interceptorIndex值會一次 + 1 (該值是給后面的最終攔截器使用的)
                  for(int i=0; i < interceptors.length; this.interceptorIndex=i++) {
                      HandlerInterceptor interceptor=interceptors[/color][i][color=black];
                      //只要每個攔截器不返回false,則繼續(xù)執(zhí)行,否則執(zhí)行最終攔截器
                      if (!interceptor.preHandle(request, response, this.handler)) {
                          this.triggerAfterCompletion(request, response, (Exception)null);
                          return false;
                      }
                  }
              }
              //最終返回true
              return true;
          }

          ? 我們可以看到攔截器的preHandler(前置處理)方法是按攔截器(攔截器1、攔截器2)順序執(zhí)行的,然后我們再來看步驟【5】

          2.2.2 第【5】步驟

          //5.執(zhí)行后置攔截器
          void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
              //獲得本次請求對應(yīng)的所有攔截器
              HandlerInterceptor[] interceptors=this.getInterceptors();
              if (!ObjectUtils.isEmpty(interceptors)) {
                  //按倒敘執(zhí)行每個攔截器的postHandle方法——所以我們看到先執(zhí)行的攔截器2的postHandle,再執(zhí)行攔截器1的postHandle
                  for(int i=interceptors.length - 1; i >=0; --i) {
                      HandlerInterceptor interceptor=interceptors[/color][color=black];
                      interceptor.postHandle(request, response, this.handler, mv);
                  }
              }
          }

          會發(fā)現(xiàn),后置處理是按照攔截器順序倒敘處理的!

          ? 我們最后來看下最終攔截器

          2.2.3 第【6】步驟

          //執(zhí)行的方法
          private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
              //...
          
              if (mv !=null && !mv.wasCleared()) {
                  //處理響應(yīng)
                  this.render(mv, request, response);
                  if (errorView) {
                      WebUtils.clearErrorRequestAttributes(request);
                  }
              } else if (this.logger.isDebugEnabled()) {
                  this.logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + this.getServletName() + "': assuming HandlerAdapter completed request handling");
              }
          
              if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                  if (mappedHandler !=null) {
                      //6、執(zhí)行攔截器的最終方法們
                      mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
                  }
          
              }
          }

          其中,有一個render()方法,該方法會直接處理完response。再后則是觸發(fā)triggerAfterCompletion方法:

          //6、執(zhí)行攔截器的最終方法
              void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception {
                  HandlerInterceptor[] interceptors=this.getInterceptors();
                  if (!ObjectUtils.isEmpty(interceptors)) {
                      //倒敘執(zhí)行每個攔截器(interceptorIndex為前置攔截器動態(tài)計算)的afterCompletion方法
                      for(int i=this.interceptorIndex; i >=0; --i) {
                          HandlerInterceptor interceptor=interceptors[/color][/i][color=black][i];
          
                          try {
                              interceptor.afterCompletion(request, response, this.handler, ex);
                          } catch (Throwable var8) {
                              logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
                          }
                      }
                  }
              }

          由此可以看到,攔截器的最終方法的執(zhí)行也是按照倒敘來執(zhí)行的,而且是在響應(yīng)之后。

          3、總結(jié)

          ? 攔截器常用于初始化資源,權(quán)限監(jiān)控,會話設(shè)置,資源清理等的功能設(shè)置,就需要我們對它的執(zhí)行順序完全掌握,我們通過源碼可以看到,攔截器類似于對我們業(yè)務(wù)方法的環(huán)繞通知效果,并且是通過循環(huán)收集好的攔截器集合來控制每個攔截器方法的執(zhí)行順序,進(jìn)而可以真正做到深入掌握攔截器的執(zhí)行機制!


          主站蜘蛛池模板: 国产香蕉一区二区在线网站| 国产剧情国产精品一区| 琪琪see色原网一区二区| 一区二区三区视频在线观看| 亚洲av乱码中文一区二区三区| 色妞色视频一区二区三区四区 | 国产精品视频分类一区| 亚洲日韩精品一区二区三区 | 亚洲国产精品综合一区在线| 一区二区三区在线播放视频| 精品一区精品二区| 国产产一区二区三区久久毛片国语 | 国产精品成人一区无码| 无码中文人妻在线一区| 国产福利91精品一区二区三区| 人妻无码一区二区三区免费| 天堂资源中文最新版在线一区| 精品少妇一区二区三区视频| 亚洲中文字幕无码一区| 在线视频一区二区三区三区不卡| 一区二区三区电影网| 日韩精品一区二区午夜成人版| 国产精品盗摄一区二区在线| 怡红院美国分院一区二区| 日韩免费一区二区三区在线 | 国产成人精品一区二区A片带套| 少妇一夜三次一区二区| 国产精品无码一区二区三区免费 | 中文字幕av日韩精品一区二区| 精品无码成人片一区二区98| 无码国产精品一区二区免费I6| 国产成人欧美一区二区三区| 美女免费视频一区二区| 中文字幕一区在线观看| 亚洲av综合av一区| 97久久精品无码一区二区| 美日韩一区二区三区| 日韩电影在线观看第一区| 丝袜人妻一区二区三区网站| 国产AV一区二区三区传媒| 中文字幕一区在线观看视频|