第 15 章 攔截器

在實際項目中,攔截器的使用是非常普遍的账蓉,例如在購物網(wǎng)站中通過攔截器可以攔截未登錄的用戶枚碗,禁止其購買商品,或者使用它來驗證已登錄用戶是否有相應(yīng)的操作權(quán)限等铸本。 在 Struts 2 框架中肮雨,攔截器是其重要的組成部分,而 Spring MVC 中也提供了攔截器功能箱玷,通過配置即可對請求進(jìn)行攔截處理怨规。 本章將針對 Spring MVC 中攔截器的使用進(jìn)行詳細(xì)講解。

攔截器概述

Spring MVC 中的攔截器( Interceptor )類似于 Servlet 中的過濾器( Filter) 锡足,它主要用于攔截用戶請求并做相應(yīng)的處理波丰。 例如通過攔截器可以進(jìn)行權(quán)限驗證、記錄請求信息的日志舱污、判斷用戶是否登錄等呀舔。

  • 攔截器的定義

要使用 Spring MVC 中的攔截器,就需要對攔截器類進(jìn)行定義和配置扩灯。 通常攔截器類可以通過兩種方式來定義媚赖。 一種是通過實現(xiàn) Handlerlnterceptor 接口,或繼承 Handlerlnterceptor 接口的實現(xiàn)類(如 HandlerlnterceptorAdapter )來定義;另一種是通過實現(xiàn) WebRequestlnterceptor 接口珠插,或繼承 WebRequestlnterceptor 接口的實現(xiàn)類來定義惧磺。
以實現(xiàn) Handlerlnterceptor 接口的定義方式為例,自定義攔截器類的代碼如下所示捻撑。

public class Customlnterceptor implements HandlerInterceptor {
  @Override
  public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
          throws Exception {
  }
  @Override
  public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
          throws Exception {
  }
  @Override
  public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
      return false;
  }
}

從上述代碼可以看出磨隘,自定義的攔截器類實現(xiàn)了 Handlerlnterceptor 接口,并實現(xiàn)了接口中的三個方法顾患。 關(guān)于這三個方法的具體描述如下番捂。

  • preHandler() 方法:該方法會在控制器方法前執(zhí)行,其返回值表示是否中斷后續(xù)操作江解。 當(dāng) 其返回值為 true 時设预,表示繼續(xù)向下執(zhí)行;當(dāng)其返回值為 false 時,會中斷后續(xù)的所有操作(包括調(diào)用下一個攔截器和控制器類中的方法執(zhí)行等) 犁河。
  • postHandle()方法:該方法會在控制器方法調(diào)用之后鳖枕,且解析視圖之前執(zhí)行魄梯。 可以通過此 方法對請求域中的模型和視圖做出進(jìn)一步的修改。
  • afterCompletion()方法: 該方法會在整個請求完成宾符,即視圖渲染結(jié)束之后執(zhí)行酿秸。 可以通過此方法實現(xiàn)一些資源清理、記錄曰志信息等工作魏烫。
  • 攔截器的配置

要使自定義的攔截器類生效辣苏,還需要在 Spring MVC 的配置文件中進(jìn)行配置,配置代碼如下所示则奥。

  <!-- 配置攔截器  -->
  <mvc:interceptors>
  <!-- 使用bean直接定義<mvc:interceptors>下面的Interceptor將攔截所有請求  --> 
  <bean class="com.neuedu.interceptor.CustomInterceptor"/>
  <!-- 攔截器1 -->
  <mvc:interceptor>
      <!-- 配置攔截器作用的路徑  -->
      <mvc:mapping path="/**"/>
      <!-- 配置不需要攔截器作用的路徑  -->
      <mvc:exclude-mapping path=""/>
      <!-- 定義在<mvc:interceptor>下面的考润,表示對匹配路徑的請求才進(jìn)行攔截  -->
      <bean class="com.neuedu.interceptor.Interceptor1" />
  </mvc:interceptor>
  <!-- 攔截器2 -->
  <mvc:interceptor>
      <mvc:mapping path="/hello"/>
      <bean class="com.neuedu.interceptor.Interceptor2"/>
  </mvc:interceptor>
  ...
  </mvc:interceptors>

在上述代碼中, <mvc:interceptors>元素用于配置一組攔截器读处,其子元素<bean> 中定義的是全局?jǐn)r截器,它會攔截所有的請求;而<mvc:interceptor>元素中定義的是指定路徑的攔截器唱矛, 它會對指定路徑下的請求生效罚舱。 <mvc:interceptor>元素的子元素<mvc:mapping>用于配置攔截器作用的路徑,該路徑在其屬性 path 中定義绎谦。 如上述代碼中 path 的屬性值"/**"表示攔截所有路徑管闷,"/hello" 表示攔截所有以 "/hello" 結(jié)尾的路徑。 如果在請求路徑中包含不需要攔截的內(nèi)容窃肠,還可以通過<mvc:exclude-mapping>元素進(jìn)行配置包个。
需要注意的是, <mvc:interceptor> 中的子元素必須按照上述代碼的配置順序進(jìn)行編寫冤留, 即 <mvc:mapping ... /> ——> <mvc:exclude-mapping ... />——><bean ... />的順序碧囊,否則文件會報錯。

攔截器的執(zhí)行流程
  • 單個攔截囂的執(zhí)行流程

在運行程序時纤怒,攔截器的執(zhí)行是有一定順序的糯而,該順序與配置文件中所定義的攔截器的順序相關(guān)。 如果在項目中只定義了一個攔截器泊窘,那么該攔截器在程序中的執(zhí)行流程如圖所示熄驼。



從圖中可以看出,程序首先會執(zhí)行攔截器類中的 preHandle() 方法烘豹,如果該方法的返回值為 true 瓜贾,則程序會繼續(xù)向下執(zhí)行處理器中的方法,否則將不再向 下執(zhí)行;在業(yè)務(wù)處理器 ( 即控制器 Controller 類)處理完請求后携悯, 會執(zhí)行 postHandle() 方法崖疤,然后會通過 DispatcherServlet 向客戶端返回響應(yīng) ; 在 DispatcherServlet 處理完請求后,才會執(zhí)行 afterCompletion() 方法拂盯。
為了驗證上面所講解的攔截器執(zhí)行流程,下面通過一個案例來演示其使用奥秆,具體步驟如下。
( 1 ) 在 Eclipse 中咸灿,創(chuàng)建一個名為 springmvc05 的 Web 項目构订,將 Spring MVC 程序運行所需 JAR 包復(fù)制到項目的 lib 目錄中,并發(fā)布到類路徑下避矢。
( 2 ) 在 web.xml 中悼瘾,配置 Spring MVC 的前端過濾器和初始化加載配置文件等信息。
( 3 )在 src 目錄下审胸,創(chuàng)建一個 com.neuedu.controller 包亥宿,并在包中創(chuàng)建控制器類 HelloController,編輯后的代碼文件如下所示砂沛。

package com.neuedu.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
  /**
   * 頁面跳轉(zhuǎn)
   */
  @RequestMapping("/hello")
  public String Hello(){
      System.out.println("Hello!");
      return "success";
  }
}

( 4 )在 src 目錄下 烫扼,創(chuàng)建一個 com.neuedu.interceptor 包,并在包中創(chuàng)建攔截器類 Customlnterceptor碍庵。 該類需要實現(xiàn) Handlerlnterceptor 接口映企,并且在實現(xiàn)方法中需要編寫輸出語句來輸出信息,文件如下所示静浴。

package com.neuedu.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 實現(xiàn) 了 HandlerInterceptor 接口的自定義攔截器類
*/
public class Customlnterceptor implements HandlerInterceptor {
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception exception)
          throws Exception {
      System.out.println("Customlnterceptor...afterCompletion");
  }
  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView modelAndView)
          throws Exception {
      System.out.println("Customlnterceptor...postHandle");
  }
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
      System.out.println("Customlnterceptor...preHandle");
      //對攔截的請求進(jìn)行放行處理
      return true;
  }
}

( 5 ) 在 src 目錄下 堰氓,創(chuàng)建并配置 Spring MVC 的配置文件,文件如下所示苹享。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
   http://www.springframework.org/schema/mvc
   http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-4.3.xsd">
  <!-- 定義組件掃描器双絮,指定需要掃描的包  -->
  <context:component-scan base-package="com.neuedu.controller" />
  <!-- 配置視圖解析器  -->
  <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <!-- 設(shè)置前綴  -->
      <property name="prefix" value="/WEB-INF/jsp/" /> 
      <!-- 設(shè)置后綴  -->
      <property name="suffix" value=".jsp" /> 
  </bean>
  <!-- 配置攔截器  -->
  <mvc:interceptors>
      <!-- 使用bean直接定義<mvc:interceptors>下面的Interceptor將攔截所有請求  --> 
      <bean class="com.neuedu.interceptor.CustomInterceptor"/>
  </mvc:interceptors> 
</beans>

由于配置攔截器使用的是<mvc:interceptors>元素,所以需要配置 mvc 的 schema 信息得问。 本案例演示的是單個攔截器的執(zhí)行順序囤攀,所以這里只配置了一個全局的攔截器。
( 6 )在 WEB-INF 目錄下椭赋,創(chuàng)建一個 jsp 文件夾抚岗,并在該文件夾中創(chuàng)建一個頁面文件 success.jsp ,然后在頁面文件的<body>元素內(nèi)編寫任意顯示信息哪怔,如 "ok"宣蔚。
( 7 ) 將項目發(fā)布到 Tomcat 服務(wù)器并啟動,在瀏覽器中訪問地址 http://localhost:8880/springmvc05/hello 认境,程序正確執(zhí)行后胚委,瀏覽器會跳轉(zhuǎn)到 success.jsp 頁面,此時控制臺的輸出結(jié)果如圖所示叉信。


從圖中可以看出亩冬,程序先執(zhí)行了攔截器類中的 preHandle() 方法,然后執(zhí)行了控制器中 的 Hello() 方法,最后分別執(zhí)行了攔截器類中的 postHandle() 方法和 afterCompletion() 方法硅急。 這與上文所描述的單個攔截器的執(zhí)行順序是一致的覆享。

  • 多個攔截器的執(zhí)行流程

在大型的企業(yè)級項目中,通常不會只有一個攔截器营袜,開發(fā)人員可能會定義很多攔截器來實現(xiàn)不同的功能撒顿。 那么多個攔截器的執(zhí)行順序又是怎樣的呢?下面通過一張圖來描述多個攔截器的執(zhí)行流程(假設(shè)有兩個攔截器 Interceptor1 和 Interceptor2 ,并且在配置文件中荚板, Interceptor1 攔截器配置在前)凤壁,如圖所示。



從圖中可以看出跪另,當(dāng)有多個攔截器同時工作時拧抖,它們的 preHandle() 方法會按照配置文件中攔截器的配置順序執(zhí)行,而它們的 postHandle() 方法和 afterCompletion() 方法則會按照配置順序的反序執(zhí)行免绿。
為了驗證上述描述唧席,下面通過修改前面小節(jié)的案例來演示多個攔截器的執(zhí)行,具體步驟 如下针姿。
( 1 )在 com.neuedu. interceptor 包中袱吆,創(chuàng)建兩個攔截器類 Interceptor1 和 Interceptor2 ,這兩個攔截器類均實現(xiàn)了 Handlerlnterceptor 接口距淫,并重寫其中的方法,文件如下所示婶希。

package com.neuedu.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 以實現(xiàn)接口的方式定義攔截器
*/
public class Interceptor1 implements HandlerInterceptor {
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
      System.out.println("Interceptor1...preHandle");
      //對攔截的請求進(jìn)行放行處理
      return true;
  }
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception exception)
          throws Exception {
      System.out.println("Interceptor1...afterCompletion");
  }
  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView modelAndView)
          throws Exception {
      System.out.println("Interceptor1...postHandle");
  }
}
package com.neuedu.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 以實現(xiàn)接口的方式定義攔截器
*/
public class Interceptor2 implements HandlerInterceptor {
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
      System.out.println("Interceptor2...preHandle");
      //對攔截的請求進(jìn)行放行處理
      return true;
  }
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception exception)
          throws Exception {
      System.out.println("Interceptor2...afterCompletion");
  }
  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView modelAndView)
          throws Exception {
      System.out.println("Interceptor2...postHandle");
  }
}

( 2 )在配置文件 springmvc-config.xml 中的<mvc:interceptors>元素內(nèi)配置上面所定義的兩個攔截器榕暇,配置代碼如下所示。

        <!-- 攔截器1 -->
        <mvc:interceptor>
            <!-- 配置攔截器作用的路徑  -->
            <mvc:mapping path="/**"/>
            <!-- 配置不需要攔截器作用的路徑  -->
            <mvc:exclude-mapping path=""/>
            <!-- 定義在<mvc:interceptor>下面的喻杈,表示對匹配路徑的請求才進(jìn)行攔截  -->
            <bean class="com.neuedu.interceptor.Interceptor1" />
        </mvc:interceptor>
        <!-- 攔截器2 -->
        <mvc:interceptor>
            <mvc:mapping path="/hello"/>
            <bean class="com.neuedu.interceptor.Interceptor2"/>
        </mvc:interceptor>

在上述攔截器的配置代碼中彤枢,第一個攔截器會作用于所有路徑下的請求,而第二個攔截器會作用于以 "/hello" 結(jié)尾的請求筒饰。
小提示:為了不影響程序的輸出結(jié)果缴啡,可將上一小節(jié)案例中所配置的 Customlnterceptor 的攔截器配置注釋掉。
( 3 )發(fā)布項目到 Tomcat 服務(wù)器并啟動瓷们,在瀏覽器中訪問地址 http://localhost:8880/springmvc05/hello 业栅,控制臺中輸出的信息如圖所示。


從圖中可以看出谬晕,程序先執(zhí)行了前兩個攔截器類中的 preHandle() 方法碘裕,這兩個方法的執(zhí)行順序與配置文件中定義的順序相同;然后執(zhí)行了控制器類中的 Hello() 方法;最后執(zhí)行了兩個攔截器類中的 postHandle() 方法和 afterCompletion() 方法,且這兩個方法的執(zhí)行順序與配置文件中所定義的攔截器順序相反攒钳。

應(yīng)用案例一一實現(xiàn)用戶登錄權(quán)限驗證

本小節(jié)將通過攔截器來完成一個用戶登錄權(quán)限驗證的案例帮孔。 本案例中,只有登錄后的用戶才能訪問系統(tǒng)中的主頁面不撑,如果沒有登錄系統(tǒng)而直接訪問主頁面文兢,則攔截器會將請求攔截晤斩,并轉(zhuǎn)發(fā)到登錄頁面,同時在登錄頁面中給出提示信息姆坚。 如果用戶名或密碼錯誤澳泵,也會在登錄頁面給出相應(yīng)的提示信息。 當(dāng)已登錄的用戶在系統(tǒng)主頁中單擊"退出"鏈接時旷偿,系統(tǒng)同樣會回到登錄頁面烹俗。 該案例的整個執(zhí)行流程如圖所示。



了解了案例的整個執(zhí)行流程后萍程,接下來講解如何在項目中實現(xiàn)用戶登錄權(quán)限驗證幢妄,具體步驟 如下。
( 1 ) 在 src 目錄下茫负, 創(chuàng)建一個 com.neuedu.po 包蕉鸳,并在包中創(chuàng)建 User 類。 在 User 類中忍法,聲明 id潮尝、 username 和 password 屬性,并定義了各個屬性的 getter/setter 方法饿序,文件如下所示勉失。

package com.neuedu.po;
/**
* 用戶 POJO 類
*/
public class User {
  private Integer id;//id
  private String username;//用戶名
  private String password;//密碼
  public Integer getId() {
      return id;
  }
  public void setId(Integer id) {
      this.id = id;
  }
  public String getUsername() {
      return username;
  }
  public void setUsername(String username) {
      this.username = username;
  }
  public String getPassword() {
      return password;
  }
  public void setPassword(String password) {
      this.password = password;
  }
}

( 2 ) 在 com.neuedu.controller 包中, 創(chuàng)建控制器類 UserController原探,并在該類中定義向主頁跳轉(zhuǎn)乱凿、 向登錄頁面跳轉(zhuǎn)、執(zhí)行用戶登錄等操作的方法咽弦,文件如下所示徒蟆。

package com.neuedu.controller;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.neuedu.po.User;
@Controller
public class UserController {
  /**
   * 向用戶登錄頁面跳轉(zhuǎn)
   */
  @RequestMapping(value="/login",method=RequestMethod.GET)
  public String toLogin(){
      return "login";
  }
  /**
   * 用戶登錄
   */
  @RequestMapping(value="/login",method=RequestMethod.POST)
  public String login(User user,Model model,HttpSession session){
      //獲取用戶名和密碼
      String username = user.getUsername();
      String password = user.getPassword();
      //此處模擬從數(shù)據(jù)庫中獲取用戶名和密碼進(jìn)行判斷
      if(username != null && username.equals("xiaoxue") && password != null && password.equals("123456")){
          //將用戶對象添加到 Session
          session.setAttribute("USER_SESSION", user);
          //重定向到主頁面的跳轉(zhuǎn)方法
          return "redirect:main";
      }
      model.addAttribute("msg", "用戶名或密碼錯誤,請重新登錄型型!");
      return "login";
  }
  /**
   * 向用戶主頁面跳轉(zhuǎn)
   */
  @RequestMapping(value="/main")
  public String toMain(){
      return "main";
  }
  /**
   * 退出登錄
   */
  @RequestMapping(value = "/logout")  
  public String logout(HttpSession session){
      //清除session
      session.invalidate();
      //重定向到登錄頁面的跳轉(zhuǎn)方法
      return "redirect:login";
  }
}

在文件中段审,向用戶登錄頁面跳轉(zhuǎn)和用戶登錄方法的@RequestMapping 注解的 value 屬性值相同,但其 method 屬性值不同闹蒜,這是由于跳轉(zhuǎn)到登錄頁面接收的是 GET 方式提交的方法寺枉,而用戶登錄接收的是 POST 方式提交的方法。 在用戶登錄方法中嫂用,先通過 User 類型的參數(shù)獲取了用戶名和密碼型凳,然后通過 if 語句來模擬從數(shù)據(jù)庫中獲取到用戶名和密碼后的判斷。 如果存在此用戶嘱函,就將用戶信息保存到 Session 中甘畅,并重定向到主頁,否則跳轉(zhuǎn)到登錄頁面。
( 3 )在 com.neuedu.interceptor 包中疏唾,創(chuàng)建攔截器類 Loginlnterceptor蓄氧,編輯后的代碼文件如下所示。

package com.neuedu.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.neuedu.po.User;
public class LoginInterceptor implements HandlerInterceptor {
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
      //獲取請求的 URL
      String url = request.getRequestURI();
      //URL:除了login.jsp 是可以公開訪問的槐脏,其他的URL都進(jìn)行攔截控制
      if(url.indexOf("login")>=0){
          return true;
      }
      //獲取 Session
      HttpSession session = request.getSession();
      User user = (User)session.getAttribute("USER_SESSION");
      //判斷 Session 中是否有用戶數(shù)據(jù)喉童,如果有則返回true,繼續(xù)向下執(zhí)行
      if(user != null){
          return true;
      }
      // 不符合條件的給出提示信息顿天,并轉(zhuǎn)發(fā)到登錄頁面
      request.setAttribute("msg", "您還沒有登錄堂氯,請先登錄!");
      request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
      return false;
  }
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception exception)
          throws Exception {
  }
  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView modelAndView)
          throws Exception {
  }
}

在文件中的 preHandle() 方法中牌废,先獲取了請求的 URL咽白,然后通過 indexOf()方法判斷 URL 中是否有 "/Iogin" 字符串。 如果有鸟缕,則返回 true 晶框,即直接放行;如果沒有,則繼續(xù)向下執(zhí)行攔截處理懂从。 接下來獲取了 Session 中的用戶信息授段,如果 Session 中包含用戶信息,即表示用戶己登錄番甩,也直接放行;否則會轉(zhuǎn)發(fā)到登錄頁面侵贵,不再執(zhí)行后續(xù)程序。
( 4 )在配置文件的<mvc:interceptors>元素中缘薛,配置自定義的登錄攔截器信息模燥,代碼如下所示。

        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.neuedu.interceptor.LoginInterceptor" />
        </mvc:interceptor>

( 5 )在 WEB-INF 目錄下的 jsp 文件夾中掩宜,創(chuàng)建一個系統(tǒng)主頁面 main.jsp。 在該頁面中么翰,使用 EL 表達(dá)式獲取用戶信息牺汤,并且通過一個超鏈接來實現(xiàn)"退出"功能,文件如下所示浩嫌。

<%@ page language="java" contentType="text/html; charset=utf-8"
   pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>系統(tǒng)主頁</title>
</head>
<body>
  當(dāng)前用戶:${USER_SESSION.username}
  <a href="logout">退出</a>
</body>
</html>

( 6 )在 WEB-INF 目錄下的 jsp 文件夾中檐迟,創(chuàng)建一個登錄頁面 login.jsp ,在頁面中編寫一個用于實現(xiàn)登錄操作的 form 表單码耐,文件如下所示追迟。

<%@ page language="java" contentType="text/html; charset=utf-8"
   pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>用戶登錄</title>
</head>
<body>
  ${msg}
  <form action="login" method="post">
      用戶名:<input type="text" name="username"><br>
      密&nbsp;&nbsp;碼:<input type="password" name="password"><br>
      <input type="submit" value="登錄">
  </form>
</body>
</html>

( 7 )將項目發(fā)布到 Tomcat 服務(wù)器并啟動,在瀏覽器中訪問地址 http://localhost:8880/springmvc05/main 骚腥,其顯示效果如圖所示敦间。


從圖中可以看出,當(dāng)用戶未登錄而直接訪問主頁面肘,訪問請求會被登錄攔截器攔截廓块, 從而跳轉(zhuǎn)到登錄頁面厢绝,并提示用戶未登錄信息。 如果在用戶名輸入框中輸入 "jack" 带猴,密碼框中輸入 "123456" 昔汉,當(dāng)單擊"登錄"按鈕后,瀏覽器的顯示結(jié)果如圖所示拴清。

當(dāng)輸入正確的用戶名氣"xiaoxue" 和密碼 "123456" 靶病,并單擊"登錄"按鈕后,瀏覽器會跳轉(zhuǎn)到系統(tǒng)主頁面口予,如圖如圖所示娄周。

當(dāng)單擊圖中的"退出"鏈接后,用戶即可退出當(dāng)前系統(tǒng)苹威,系統(tǒng)會從主頁面重定向到登錄頁面昆咽。

本章小結(jié)

本章主要對 Spring MVC 中的攔截器使用進(jìn)行了詳細(xì)講解。 首先介紹了如何在 Spring MVC 項目中定義和配置攔截器牙甫,然后詳細(xì)講解了單個攔截器和多個攔截器的執(zhí)行流程掷酗,最后通過一個用戶登錄權(quán)限驗證的應(yīng)用案例演示了攔截器的實際應(yīng)用。 通過本章的學(xué)習(xí)窟哺,大家可以對 Spring MVC 中攔截器的定義和配置方式有一定的了解泻轰,能夠熟悉攔截器的執(zhí)行流程,并能夠掌握攔截器的使用且轨。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末浮声,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子旋奢,更是在濱河造成了極大的恐慌泳挥,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件至朗,死亡現(xiàn)場離奇詭異屉符,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)锹引,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門矗钟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人嫌变,你說我怎么就攤上這事吨艇。” “怎么了腾啥?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵东涡,是天一觀的道長冯吓。 經(jīng)常有香客問我,道長软啼,這世上最難降的妖魔是什么桑谍? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮祸挪,結(jié)果婚禮上锣披,老公的妹妹穿的比我還像新娘。我一直安慰自己贿条,他們只是感情好雹仿,可當(dāng)我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著整以,像睡著了一般胧辽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上公黑,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天邑商,我揣著相機(jī)與錄音,去河邊找鬼凡蚜。 笑死人断,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的朝蜘。 我是一名探鬼主播恶迈,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼谱醇!你這毒婦竟也來了暇仲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤副渴,失蹤者是張志新(化名)和其女友劉穎奈附,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體煮剧,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡桅狠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年轿秧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咨堤。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡菇篡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出一喘,到底是詐尸還是另有隱情驱还,我是刑警寧澤嗜暴,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站议蟆,受9級特大地震影響闷沥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜咐容,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一舆逃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧戳粒,春花似錦路狮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至苹祟,卻和暖如春砸抛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背树枫。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工直焙, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人团赏。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓箕般,卻偏偏與公主長得像,于是被迫代替她去往敵國和親舔清。 傳聞我的和親對象是個殘疾皇子丝里,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容