一篇學(xué)會(huì)攔截器的騷操作
文末本文轉(zhuǎn)載自微信公眾號(hào)「程序員千羽 」,作者程序員千羽。轉(zhuǎn)載本文請(qǐng)聯(lián)系程序員千羽公眾號(hào)。
GitHub:https://github.com/nateshao/ssm/tree/master/110-springmvc-intercepter
什么是攔截器?
Spring MVC中的攔截器(Interceptor)類似于Servlet中的過濾器(Filter),它主要用于攔截用戶請(qǐng)求并作相應(yīng)的處理。例如通過攔截器可以進(jìn)行權(quán)限驗(yàn)證、記錄請(qǐng)求信息的日志、判斷用戶是否登錄等。
要使用Spring MVC中的攔截器,就需要對(duì)攔截器類進(jìn)行定義和配置。通常攔截器類可以通過兩種方式來定義。
- 第一種:通過實(shí)現(xiàn)HandlerInterceptor接口,或繼承HandlerInterceptor接口的實(shí)現(xiàn)類(如HandlerInterceptorAdapter)來定義。
 - 第二種:通過實(shí)現(xiàn)WebRequestInterceptor接口,或繼承WebRequestInterceptor接口的實(shí)現(xiàn)類來定義。
 
以實(shí)現(xiàn)HandlerInterceptor接口方式為例,自定義攔截器類的代碼如下:
- public class CustomInterceptor implements HandlerInterceptor {
 - /**
 - * 該方法會(huì)在控制器方法前執(zhí)行,其返回值表示是否中斷后續(xù)操作。
 - * 當(dāng)其返回值為true時(shí),表示繼續(xù)向下執(zhí)行;
 - * 當(dāng)其返回值為false時(shí),會(huì)中斷后續(xù)的所有操作。
 - * @param request
 - * @param response
 - * @param handler
 - * @return
 - * @throws Exception
 - */
 - @Override
 - public boolean preHandle(HttpServletRequest request,
 - HttpServletResponse response, Object handler) throws Exception {
 - System.out.println("CustomInterceptor...preHandle");
 - //對(duì)攔截的請(qǐng)求進(jìn)行放行處理
 - return true;
 - }
 - /**
 - * 該方法會(huì)在控制器方法調(diào)用之后,且解析視圖之前執(zhí)行。
 - * 可以通過此方法對(duì)請(qǐng)求域中的模型和視圖做出進(jìn)一步的修改。
 - * @param request
 - * @param response
 - * @param handler
 - * @param modelAndView
 - * @throws Exception
 - */
 - @Override
 - public void postHandle(HttpServletRequest request,
 - HttpServletResponse response, Object handler,
 - ModelAndView modelAndView) throws Exception {
 - System.out.println("CustomInterceptor...postHandle");
 - }
 - /**
 - * 該方法會(huì)在整個(gè)請(qǐng)求完成,即視圖渲染結(jié)束之后執(zhí)行。
 - * 可以通過此方法實(shí)現(xiàn)一些資源清理、記錄日志信息等工作。
 - * @param request
 - * @param response
 - * @param handler
 - * @param ex
 - * @throws Exception
 - */
 - @Override
 - public void afterCompletion(HttpServletRequest request,
 - HttpServletResponse response, Object handler,
 - Exception ex) throws Exception {
 - System.out.println("CustomInterceptor...afterCompletion");
 - }
 - }
 
要使自定義的攔截器類生效,還需要在Spring MVC的配置文件中進(jìn)行配置。
- <mvc:interceptors>
 - <!-- 全局?jǐn)r截器,攔截所有請(qǐng)求 -->
 - <bean class="com.nateshao.interceptor.CustomInterceptor"/>//
 - <mvc:interceptor>
 - <!-- **配置,表示攔截所有路徑 -->
 - <mvc:mapping path="/**"/>
 - <!-- 配置不需要攔截的路徑 -->
 - <mvc:exclude-mapping path=""/>
 - <bean class="com.nateshao.interceptor.Interceptor1"/>
 - </mvc:interceptor>
 - <mvc:interceptor>
 - <!-- /hello表示攔截所有以“/hello”結(jié)尾的路徑 -->
 - <mvc:mapping path="/hello"/>
 - <bean class="com.nateshao.interceptor.Interceptor2"/>
 - </mvc:interceptor>
 - ...
 - </mvc:interceptors>
 
注意:< mvc:interceptor >中的子元素必須按照上述代碼的配置順序進(jìn)行編寫,否則文件會(huì)報(bào)錯(cuò)。
2. 攔截器的執(zhí)行流程
在運(yùn)行程序時(shí),攔截器的執(zhí)行是有一定順序的,該順序與配置文件中所定義的攔截器的順序相關(guān)。
單個(gè)攔截器,在程序中的執(zhí)行流程如下圖所示:
多個(gè)攔截器的執(zhí)行流程
“多個(gè)攔截器(假設(shè)有兩個(gè)攔截器Interceptor1和Interceptor2,并且在配置文件中, Interceptor1攔截器配置在前),在程序中的執(zhí)行流程如下圖所示:
3. 應(yīng)用案例
案例說明 : 實(shí)現(xiàn)用戶登錄權(quán)限驗(yàn)證
“案例中,只有登錄后的用戶才能訪問系統(tǒng)中的主頁面,如果沒有登錄系統(tǒng)而直接訪問主頁面,則攔截器會(huì)將請(qǐng)求攔截,并轉(zhuǎn)發(fā)到登錄頁面,同時(shí)在登錄頁面中給出提示信息。如果用戶名或密碼錯(cuò)誤,也會(huì)在登錄頁面給出相應(yīng)的提示信息。當(dāng)已登錄的用戶在系統(tǒng)主頁中單擊“退出”鏈接時(shí),系統(tǒng)同樣會(huì)回到登錄頁面。
login.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8"
 - pageEncoding="UTF-8"%>
 - <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="${pageContext.request.contextPath }/logout">退出</a>
 - </body>
 - </html>
 
LoginInterceptor.java
- package com.nateshao.interceptor;
 - import com.nateshao.po.User;
 - import org.springframework.web.servlet.HandlerInterceptor;
 - import org.springframework.web.servlet.ModelAndView;
 - import javax.servlet.http.HttpServletRequest;
 - import javax.servlet.http.HttpServletResponse;
 - import javax.servlet.http.HttpSession;
 - /**
 - * @date Created by 邵桐杰 on 2021/10/22 12:50
 - * @微信公眾號(hào) 程序員千羽
 - * @個(gè)人網(wǎng)站 www.nateshao.cn
 - * @博客 https://nateshao.gitee.io
 - * @GitHub https://github.com/nateshao
 - * @Gitee https://gitee.com/nateshao
 - * Description: 登錄攔截器
 - */
 - public class LoginInterceptor implements HandlerInterceptor {
 - @Override
 - public boolean preHandle(HttpServletRequest request,
 - HttpServletResponse response, Object handler) throws Exception {
 - // 獲取請(qǐng)求的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", "您還沒有登錄,請(qǐng)先登錄!");
 - request.getRequestDispatcher("/WEB-INF/jsp/login.jsp")
 - .forward(request, response);
 - return false;
 - }
 - @Override
 - public void postHandle(HttpServletRequest request,
 - HttpServletResponse response, Object handler,
 - ModelAndView modelAndView) throws Exception {
 - }
 - @Override
 - public void afterCompletion(HttpServletRequest request,
 - HttpServletResponse response, Object handler, Exception ex)
 - throws Exception {
 - }
 - }
 
UserController.java
- package com.nateshao.controller;
 - import com.nateshao.po.User;
 - 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 javax.servlet.http.HttpSession;
 - /**
 - * @date Created by 邵桐杰 on 2021/10/22 12:47
 - * @微信公眾號(hào) 程序員千羽
 - * @個(gè)人網(wǎng)站 www.nateshao.cn
 - * @博客 https://nateshao.gitee.io
 - * @GitHub https://github.com/nateshao
 - * @Gitee https://gitee.com/nateshao
 - * Description:
 - */
 - @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("nateshao")
 - && password != null && password.equals("123456")) {
 - // 將用戶對(duì)象添加到Session
 - session.setAttribute("USER_SESSION", user);
 - // 重定向到主頁面的跳轉(zhuǎn)方法
 - return "redirect:main";
 - }
 - model.addAttribute("msg", "用戶名或密碼錯(cuò)誤,請(qǐng)重新登錄!");
 - 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";
 - }
 - }
 
main.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8"
 - pageEncoding="UTF-8"%>
 - <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="${pageContext.request.contextPath }/logout">退出</a>
 - </body>
 - </html>
 
驗(yàn)證
瀏覽器輸入:http://localhost:8080/110_springmvc_interceptor_war_exploded/main
輸入用戶名密碼
總結(jié)
這一篇文章主要對(duì)Spring MVC中的攔截器使用進(jìn)行了詳細(xì)講解。
首先介紹了如何在Spring MVC項(xiàng)目中定義和配置攔截器,然后詳細(xì)講解了單個(gè)攔截器和多個(gè)攔截器的執(zhí)行流程,最后通過一個(gè)用戶登錄權(quán)限驗(yàn)證的應(yīng)用案例演示了攔截器的實(shí)際應(yīng)用。
最后我們可以對(duì)Spring MVC中攔截器的定義和配置方式有一定的了解,能夠熟悉攔截器的執(zhí)行流程,并能夠掌握攔截器的使用。





















 
 
 










 
 
 
 