一篇學(xué)會攔截器的騷操作
文末本文轉(zhuǎn)載自微信公眾號「程序員千羽 」,作者程序員千羽。轉(zhuǎn)載本文請聯(lián)系程序員千羽公眾號。
GitHub:https://github.com/nateshao/ssm/tree/master/110-springmvc-intercepter
什么是攔截器?
Spring MVC中的攔截器(Interceptor)類似于Servlet中的過濾器(Filter),它主要用于攔截用戶請求并作相應(yīng)的處理。例如通過攔截器可以進(jìn)行權(quán)限驗(yàn)證、記錄請求信息的日志、判斷用戶是否登錄等。
要使用Spring MVC中的攔截器,就需要對攔截器類進(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 {
- /**
- * 該方法會在控制器方法前執(zhí)行,其返回值表示是否中斷后續(xù)操作。
- * 當(dāng)其返回值為true時,表示繼續(xù)向下執(zhí)行;
- * 當(dāng)其返回值為false時,會中斷后續(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");
- //對攔截的請求進(jìn)行放行處理
- return true;
- }
- /**
- * 該方法會在控制器方法調(diào)用之后,且解析視圖之前執(zhí)行。
- * 可以通過此方法對請求域中的模型和視圖做出進(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");
- }
- /**
- * 該方法會在整個請求完成,即視圖渲染結(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截器,攔截所有請求 -->
- <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)行編寫,否則文件會報(bào)錯。
2. 攔截器的執(zhí)行流程
在運(yùn)行程序時,攔截器的執(zhí)行是有一定順序的,該順序與配置文件中所定義的攔截器的順序相關(guān)。
單個攔截器,在程序中的執(zhí)行流程如下圖所示:
多個攔截器的執(zhí)行流程
“多個攔截器(假設(shè)有兩個攔截器Interceptor1和Interceptor2,并且在配置文件中, Interceptor1攔截器配置在前),在程序中的執(zhí)行流程如下圖所示:
3. 應(yīng)用案例
案例說明 : 實(shí)現(xiàn)用戶登錄權(quán)限驗(yàn)證
“案例中,只有登錄后的用戶才能訪問系統(tǒng)中的主頁面,如果沒有登錄系統(tǒng)而直接訪問主頁面,則攔截器會將請求攔截,并轉(zhuǎn)發(fā)到登錄頁面,同時在登錄頁面中給出提示信息。如果用戶名或密碼錯誤,也會在登錄頁面給出相應(yīng)的提示信息。當(dāng)已登錄的用戶在系統(tǒng)主頁中單擊“退出”鏈接時,系統(tǒng)同樣會回到登錄頁面。
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
- * @微信公眾號 程序員千羽
- * @個人網(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 {
- // 獲取請求的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 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
- * @微信公眾號 程序員千羽
- * @個人網(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")) {
- // 將用戶對象添加到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";
- }
- }
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é)
這一篇文章主要對Spring MVC中的攔截器使用進(jìn)行了詳細(xì)講解。
首先介紹了如何在Spring MVC項(xiàng)目中定義和配置攔截器,然后詳細(xì)講解了單個攔截器和多個攔截器的執(zhí)行流程,最后通過一個用戶登錄權(quán)限驗(yàn)證的應(yīng)用案例演示了攔截器的實(shí)際應(yīng)用。
最后我們可以對Spring MVC中攔截器的定義和配置方式有一定的了解,能夠熟悉攔截器的執(zhí)行流程,并能夠掌握攔截器的使用。