1. 程式人生 > 其它 >Spring MVC攔截器(Interceptor)

Spring MVC攔截器(Interceptor)

在系統中,經常需要在處理使用者請求之前和之後執行一些行為,例如檢測使用者的許可權,或者將請求的資訊記錄到日誌中,即平時所說的“許可權檢測”及“日誌記錄”。當然不僅僅這些,所以需要一種機制,攔截使用者的請求,在請求的前後新增處理邏輯。

Spring MVC 提供了 Interceptor 攔截器機制,用於請求的預處理和後處理。

在開發一個網站時可能有這樣的需求:某些頁面只希望幾個特定的使用者瀏覽。對於這樣的訪問許可權控制,應該如何實現呢?攔截器就可以實現上述需求。在 Struts2 框架中,攔截器是其重要的組成部分,Spring MVC 框架也提供了攔截器功能。

Spring MVC 的攔截器(Interceptor)與 Java Servlet 的過濾器(Filter)類似,它主要用於攔截使用者的請求並做相應的處理,通常應用在許可權驗證、記錄請求資訊的日誌、判斷使用者是否登入等功能上。

攔截器的定義

在 Spring MVC 框架中定義一個攔截器需要對攔截器進行定義和配置,主要有以下 2 種方式。

  1. 通過實現 HandlerInterceptor 介面或繼承 HandlerInterceptor 介面的實現類(例如 HandlerInterceptorAdapter)來定義;
  2. 通過實現 WebRequestInterceptor 介面或繼承 WebRequestInterceptor 介面的實現類來定義。


本節以實現 HandlerInterceptor 介面的定義方式為例講解自定義攔截器的使用方法。示例程式碼如下。

package net.biancheng.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 TestInterceptor implements HandlerInterceptor {
    @Override
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("afterCompletion方法在控制器的處理請求方法執行完成後執行,即檢視渲染結束之後執行");

    }

    @Override
    public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle方法在控制器的處理請求方法呼叫之後,解析檢視之前執行");
    }

    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle方法在控制器的處理請求方法呼叫之前執行");
        return false;
    }
}

上述攔截器的定義中實現了 HandlerInterceptor 介面,並實現了介面中的 3 個方法,說明如下。

  • preHandle( ):該方法在控制器的處理請求方法前執行,其返回值表示是否中斷後續操作,返回 true 表示繼續向下執行,返回 false 表示中斷後續操作。
  • postHandle( ):該方法在控制器的處理請求方法呼叫之後、解析檢視之前執行,可以通過此方法對請求域中的模型和檢視做進一步的修改。
  • afterCompletion( ):該方法在控制器的處理請求方法執行完成後執行,即檢視渲染結束後執行,可以通過此方法實現一些資源清理、記錄日誌資訊等工作。

攔截器的配置

讓自定義的攔截器生效需要在 Spring MVC 的配置檔案中進行配置,配置示例程式碼如下:

<!-- 配置攔截器 -->
<mvc:interceptors>
    <!-- 配置一個全域性攔截器,攔截所有請求 -->
    <bean class="net.biancheng.interceptor.TestInterceptor" /> 
    <mvc:interceptor>
        <!-- 配置攔截器作用的路徑 -->
        <mvc:mapping path="/**" />
        <!-- 配置不需要攔截作用的路徑 -->
        <mvc:exclude-mapping path="" />
        <!-- 定義<mvc:interceptor>元素中,表示匹配指定路徑的請求才進行攔截 -->
        <bean class="net.biancheng.interceptor.Interceptor1" />
    </mvc:interceptor>
    <mvc:interceptor>
        <!-- 配置攔截器作用的路徑 -->
        <mvc:mapping path="/gotoTest" />
        <!-- 定義在<mvc:interceptor>元素中,表示匹配指定路徑的請求才進行攔截 -->
        <bean class="net.biancheng.interceptor.Interceptor2" />
    </mvc:interceptor>
</mvc:interceptors>

在上述示例程式碼中,元素說明如下。

  • <mvc:interceptors>:該元素用於配置一組攔截器。
  • <bean>:該元素是 <mvc:interceptors> 的子元素,用於定義全域性攔截器,即攔截所有的請求。
  • <mvc:interceptor>:該元素用於定義指定路徑的攔截器。
  • <mvc:mapping>:該元素是 <mvc:interceptor> 的子元素,用於配置攔截器作用的路徑,該路徑在其屬性 path 中定義。path 的屬性值為/**時,表示攔截所有路徑,值為/gotoTest時,表示攔截所有以/gotoTest結尾的路徑。如果在請求路徑中包含不需要攔截的內容,可以通過 <mvc:exclude-mapping> 子元素進行配置。


需要注意的是,<mvc:interceptor> 元素的子元素必須按照 <mvc:mapping.../>、<mvc:exclude-mapping.../>、<bean.../> 的順序配置。

示例

下面通過攔截器來完成一個使用者登入許可權驗證的 Web 應用,具體要求如下:只有成功登入的使用者才能訪問系統的主頁面 main.jsp,如果沒有成功登入而直接訪問主頁面,則攔截器將請求攔截,並轉發到登入頁面 login.jsp。當成功登入的使用者在系統主頁面中單擊“退出”連結時回到登入頁面。

本節示例基於《@Controller和@RequestMapping註解》一節的 springmvcDemo2 應用實現,具體實現步驟如下。

1)建立 POJO 類

在 springmvcDemo2 的 net.biancheng.pojo 包中建立 User 類,程式碼如下。

package net.biancheng.po;

public class User {
    private String name;
    private String pwd;
    /**省略setter和getter方法*/
}

2)建立控制器類

在 springmvcDemo2的 net.biancheng.controller 包中建立控制器類 UserController,程式碼如下。

package net.biancheng.controller;

import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import net.biancheng.po.User;

@Controller
public class UserController {
    /**
     * 登入頁面初始化
     */
    @RequestMapping("/toLogin")
    public String initLogin() {
        return "login";
    }

    /**
     * 處理登入功能
     */
    @RequestMapping("/login")
    public String login(User user, Model model, HttpSession session) {
        System.out.println(user.getName());
        if ("bianchengbang".equals(user.getName()) && "123456".equals(user.getPwd())) {
            // 登入成功,將使用者資訊儲存到session物件中
            session.setAttribute("user", user);
            // 重定向到主頁面的跳轉方法
            return "redirect:main";
        }
        model.addAttribute("msg", "使用者名稱或密碼錯誤,請重新登入! ");
        return "login";
    }

    /**
     * 跳轉到主頁面
     */
    @RequestMapping("/main")
    public String toMain() {
        return "main";
    }

    /**
     * 退出登入
     */
    @RequestMapping("/logout")
    public String logout(HttpSession session) {
        // 清除 session
        session.invalidate();
        return "login";
    }
}

3)建立攔截器類

在 springmvcDemo2的 net.biancheng.interceptor 包中建立攔截器類 LoginInterceptor,程式碼如下。

package net.biancheng.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;

public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // 獲取請求的URL
        String url = request.getRequestURI();
        // login.jsp或登入請求放行,不攔截
        if (url.indexOf("/toLogin") >= 0 || url.indexOf("/login") >= 0) {
            return true;
        }
        // 獲取 session
        HttpSession session = request.getSession();
        Object obj = session.getAttribute("user");
        if (obj != null)
            return true;
        // 沒有登入且不是登入頁面,轉發到登入頁面,並給出提示錯誤資訊
        request.setAttribute("msg", "還沒登入,請先登入!");
        request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
        return false;
    }

    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
        // TODO Auto-generated method stub
    }

    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
            throws Exception {
        // TODO Auto-generated method stub
    }
}

4)配置攔截器

在 WEB-INF 目錄下建立配置檔案 springmvc-servlet.xml 和 web.xml。web.xml 的程式碼和 springmvcDemo2 一樣,這裡不再贅述。在 springmvc-servlet.xml 檔案中配置攔截器 LoginInterceptor,程式碼如下。

<!-- 配置攔截器 -->
<mvc:interceptors>
    <mvc:interceptor>
        <!-- 配置攔截器作用的路徑 -->
        <mvc:mapping path="/**" />
        <bean class="net.biancheng.interceptor.LoginInterceptor" />
    </mvc:interceptor>
</mvc:interceptors>

5)建立檢視 JSP 頁面

在 WEB-INF 目錄下建立資料夾 jsp,並在該資料夾中建立 login.jsp 和 main.jsp。

login.jsp 的程式碼如下:

<%@ 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="${pageContext.request.contextPath }/login" method="post">
        使用者名稱:<input type="text" name="name" /><br>
        密碼:<input type="password" name="pwd" /><br>
        <input type="submit" value="登入" />
    </form>
</body>
</html>

main.jsp 的程式碼如下:

<%@ 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>
    歡迎 ${user.name },登入程式設計幫!<br />
    <a href="${pageContext.request.contextPath }/logout">退出</a>
</body>
</html>

6)釋出並測試應用

首先將 springmvcDemo2 應用釋出到 Tomcat 伺服器並啟動 Tomcat 伺服器,然後通過地址“http://localhost:8080/springmvcDemo2/main”測試應用,執行效果如圖 1 所示。


圖 1沒有登入直接訪問主頁面的效果


從圖 1 可以看出,當用戶沒有登入而直接訪問系統主頁面時請求將被登入攔截器攔截,返回到登入頁面,並提示資訊。如果使用者在使用者名稱框中輸入“bianchengbang”,在密碼框中輸入“123456”,單擊“登入”按鈕後瀏覽器的顯示結果如圖 2 所示。如果輸入的使用者名稱或密碼錯誤,瀏覽器的顯示結果如圖 3 所示。


圖 2成功登入的效果

圖 3使用者名稱或密碼錯誤


當單擊圖 2 中的“退出”連結後,系統將從主頁面返回到登入頁面。

from

http://c.biancheng.net/spring_mvc/interceptor.html