一篇學會攔截器的騷操作
文末本文轉載自微信公眾號「程序員千羽 」,作者程序員千羽。轉載本文請聯系程序員千羽公眾號。
GitHub:https://github.com/nateshao/ssm/tree/master/110-springmvc-intercepter
什么是攔截器?
Spring MVC中的攔截器(Interceptor)類似于Servlet中的過濾器(Filter),它主要用于攔截用戶請求并作相應的處理。例如通過攔截器可以進行權限驗證、記錄請求信息的日志、判斷用戶是否登錄等。
要使用Spring MVC中的攔截器,就需要對攔截器類進行定義和配置。通常攔截器類可以通過兩種方式來定義。
- 第一種:通過實現HandlerInterceptor接口,或繼承HandlerInterceptor接口的實現類(如HandlerInterceptorAdapter)來定義。
- 第二種:通過實現WebRequestInterceptor接口,或繼承WebRequestInterceptor接口的實現類來定義。
以實現HandlerInterceptor接口方式為例,自定義攔截器類的代碼如下:
- public class CustomInterceptor implements HandlerInterceptor {
- /**
- * 該方法會在控制器方法前執行,其返回值表示是否中斷后續操作。
- * 當其返回值為true時,表示繼續向下執行;
- * 當其返回值為false時,會中斷后續的所有操作。
- * @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");
- //對攔截的請求進行放行處理
- return true;
- }
- /**
- * 該方法會在控制器方法調用之后,且解析視圖之前執行。
- * 可以通過此方法對請求域中的模型和視圖做出進一步的修改。
- * @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");
- }
- /**
- * 該方法會在整個請求完成,即視圖渲染結束之后執行。
- * 可以通過此方法實現一些資源清理、記錄日志信息等工作。
- * @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的配置文件中進行配置。
- <mvc:interceptors>
- <!-- 全局攔截器,攔截所有請求 -->
- <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”結尾的路徑 -->
- <mvc:mapping path="/hello"/>
- <bean class="com.nateshao.interceptor.Interceptor2"/>
- </mvc:interceptor>
- ...
- </mvc:interceptors>
注意:< mvc:interceptor >中的子元素必須按照上述代碼的配置順序進行編寫,否則文件會報錯。
2. 攔截器的執行流程
在運行程序時,攔截器的執行是有一定順序的,該順序與配置文件中所定義的攔截器的順序相關。
單個攔截器,在程序中的執行流程如下圖所示:
多個攔截器的執行流程
“多個攔截器(假設有兩個攔截器Interceptor1和Interceptor2,并且在配置文件中, Interceptor1攔截器配置在前),在程序中的執行流程如下圖所示:
3. 應用案例
案例說明 : 實現用戶登錄權限驗證
“案例中,只有登錄后的用戶才能訪問系統中的主頁面,如果沒有登錄系統而直接訪問主頁面,則攔截器會將請求攔截,并轉發到登錄頁面,同時在登錄頁面中給出提示信息。如果用戶名或密碼錯誤,也會在登錄頁面給出相應的提示信息。當已登錄的用戶在系統主頁中單擊“退出”鏈接時,系統同樣會回到登錄頁面。
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>系統主頁</title>
- </head>
- <body>
- 當前用戶:${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
- * @微信公眾號 程序員千羽
- * @個人網站 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 {
- // 獲取請求的URL
- String url = request.getRequestURI();
- // URL:除了login.jsp是可以公開訪問的,其它的URL都進行攔截控制
- if (url.indexOf("/login") >= 0) {
- return true;
- }
- // 獲取Session
- HttpSession session = request.getSession();
- User user = (User) session.getAttribute("USER_SESSION");
- // 判斷Session中是否有用戶數據,如果有,則返回true,繼續向下執行
- if (user != null) {
- return true;
- }
- // 不符合條件的給出提示信息,并轉發到登錄頁面
- request.setAttribute("msg", "您還沒有登錄,請先登錄!");
- 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
- * @微信公眾號 程序員千羽
- * @個人網站 www.nateshao.cn
- * @博客 https://nateshao.gitee.io
- * @GitHub https://github.com/nateshao
- * @Gitee https://gitee.com/nateshao
- * Description:
- */
- @Controller
- public class UserController {
- /**
- * 向用戶登錄頁面跳轉
- */
- @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();
- // 此處模擬從數據庫中獲取用戶名和密碼后進行判斷
- if (username != null && username.equals("nateshao")
- && password != null && password.equals("123456")) {
- // 將用戶對象添加到Session
- session.setAttribute("USER_SESSION", user);
- // 重定向到主頁面的跳轉方法
- return "redirect:main";
- }
- model.addAttribute("msg", "用戶名或密碼錯誤,請重新登錄!");
- return "login";
- }
- /**
- * 向用戶主頁面跳轉
- */
- @RequestMapping(value = "/main")
- public String toMain() {
- return "main";
- }
- /**
- * 退出登錄
- */
- @RequestMapping(value = "/logout")
- public String logout(HttpSession session) {
- // 清除Session
- session.invalidate();
- // 重定向到登錄頁面的跳轉方法
- 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>系統主頁</title>
- </head>
- <body>
- 當前用戶:${USER_SESSION.username}
- <a href="${pageContext.request.contextPath }/logout">退出</a>
- </body>
- </html>
驗證
瀏覽器輸入:http://localhost:8080/110_springmvc_interceptor_war_exploded/main
輸入用戶名密碼
總結
這一篇文章主要對Spring MVC中的攔截器使用進行了詳細講解。
首先介紹了如何在Spring MVC項目中定義和配置攔截器,然后詳細講解了單個攔截器和多個攔截器的執行流程,最后通過一個用戶登錄權限驗證的應用案例演示了攔截器的實際應用。
最后我們可以對Spring MVC中攔截器的定義和配置方式有一定的了解,能夠熟悉攔截器的執行流程,并能夠掌握攔截器的使用。