Spring MVC攔截器(Interceptor)解讀
在系統(tǒng)中,經(jīng)常需要在處理用戶請求之前和之后執(zhí)行一些行為,例如檢測用戶的權(quán)限,或者將請求的信息記錄到日志中,即平時(shí)所說的“權(quán)限檢測”及“日志記錄”。當(dāng)然不僅僅這些,所以需要一種機(jī)制,攔截用戶的請求,在請求的前后添加處理邏輯。
Spring MVC 提供了 Interceptor 攔截器機(jī)制,用于請求的預(yù)處理和后處理。
在開發(fā)一個(gè)網(wǎng)站時(shí)可能有這樣的需求:某些頁面只希望幾個(gè)特定的用戶瀏覽。對于這樣的訪問權(quán)限控制,應(yīng)該如何實(shí)現(xiàn)呢?攔截器就可以實(shí)現(xiàn)上述需求。在 Struts2 框架中,攔截器是其重要的組成部分,Spring MVC 框架也提供了攔截器功能。
過濾器(Filter) 與 攔截器(Interceptor)
Spring MVC 的攔截器(Interceptor)與 Java Servlet 的過濾器(Filter)類似,它主要用于攔截用戶的請求并做相應(yīng)的處理,通常應(yīng)用在權(quán)限驗(yàn)證、記錄請求信息的日志、判斷用戶是否登錄等功能上。
Filter
在Web程序中,注意到使用Filter的時(shí)候,F(xiàn)ilter由Servlet容器管理,任何java web工程都可以使用。它在Spring MVC的Web應(yīng)用程序中作用范圍如下:

上圖虛線框就是Filter2的攔截范圍,F(xiàn)ilter組件實(shí)際上并不知道后續(xù)內(nèi)部處理是通過Spring MVC提供的DispatcherServlet還是其他Servlet組件,因?yàn)镕ilter是Servlet規(guī)范定義的標(biāo)準(zhǔn)組件,它可以應(yīng)用在任何基于Servlet的程序中。
在url-pattern中配置了/*之后,可以對所有要訪問的資源進(jìn)行攔截
Interceptor
如果只基于Spring MVC開發(fā)應(yīng)用程序,還可以使用Spring MVC提供的一種功能類似Filter的攔截器:Interceptor。和Filter相比,Interceptor攔截范圍不是后續(xù)整個(gè)處理流程,而是僅針對Controller攔截:

上圖虛線框就是Interceptor的攔截范圍,注意到Controller的處理方法一般都類似這樣:
@Controller
public class Controller1 {
@GetMapping("/path/to/hello")
ModelAndView hello() {
...
}
}
所以,Interceptor的攔截范圍其實(shí)就是Controller方法,它實(shí)際上就相當(dāng)于基于AOP的方法攔截。因?yàn)镮nterceptor只攔截Controller方法,如果訪問的是jsp/html/css/image/js是不會(huì)進(jìn)行攔截的。 所以要注意,返回ModelAndView后,后續(xù)對View的渲染就脫離了Interceptor的攔截范圍。
使用Interceptor的好處是Interceptor本身是Spring管理的Bean,因此注入任意Bean都非常簡單。此外,可以應(yīng)用多個(gè)Interceptor,并通過簡單的@Order指定順序。
自定義攔截器
想要自定義攔截器,必須實(shí)現(xiàn) HandlerInterceptor 接口。
1、新建一個(gè)Moudule , springmvc-07-Interceptor , 添加web支持
2、配置web.xml 和 springmvc-servlet.xml 文件
3、創(chuàng)建一個(gè)MyInterceptor類,并實(shí)現(xiàn)HandlerInterceptor接口

上述攔截器的定義中實(shí)現(xiàn)了 HandlerInterceptor 接口,并實(shí)現(xiàn)了接口中的 3 個(gè)方法,說明如下。
- preHandle( ):該方法在控制器的處理請求方法前執(zhí)行,其返回值表示是否中斷后續(xù)操作,返回 true 表示繼續(xù)向下執(zhí)行,返回 false 表示中斷后續(xù)操作。
- postHandle( ):該方法在控制器的處理請求方法調(diào)用之后、解析視圖之前執(zhí)行,可以通過此方法對請求域中的模型和視圖做進(jìn)一步的修改。
- afterCompletion( ):該方法在控制器的處理請求方法執(zhí)行完成后執(zhí)行,即視圖渲染結(jié)束后執(zhí)行,可以通過此方法實(shí)現(xiàn)一些資源清理、記錄日志信息等工作。
4、在springmvc的配置文件中配置攔截器
<!--關(guān)于攔截器的配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--/** 包括路徑及其子路徑-->
<!--/admin/* 攔截的是/admin/add等等這種 , /admin/add/user不會(huì)被攔截-->
<!--/admin/** 攔截的是/admin/下的所有-->
<mvc:mapping path="/**"/>
<!--bean配置的就是攔截器-->
<bean class="com.kuang.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
5、編寫一個(gè)Controller,接收請求

6、前端 index.jsp
<a href="${pageContext.request.contextPath}/interceptor" rel="external nofollow" >攔截器測試</a>
7、啟動(dòng)tomcat 測試一下!

tomcat使用System.out.println亂碼問題
tomcat9日志中文打印正常,但涉及到Java虛擬機(jī)的代碼中文打印會(huì)亂碼?
Windows默認(rèn)編碼為gbk,涉及到j(luò)vm編碼tomcat也默認(rèn)為Windows編碼,
只需要配置一個(gè)地方就行了:
run—>edit configureurations----->vm options: -Dfile.encoding=UTF-8

驗(yàn)證用戶是否登錄 (認(rèn)證用戶)
實(shí)現(xiàn)思路
1、有一個(gè)登陸頁面,需要寫一個(gè)controller訪問頁面。
2、登陸頁面有一提交表單的動(dòng)作。需要在controller中處理。判斷用戶名密碼是否正確。如果正確,向session中寫入用戶信息。返回登陸成功。
3、攔截用戶請求,判斷用戶是否登陸。如果用戶已經(jīng)登陸。放行, 如果用戶未登陸,跳轉(zhuǎn)到登陸頁面
測試
web項(xiàng)目的WEB-INF目錄
WEB-INF是Java的WEB應(yīng)用的安全目錄。所謂安全就是客戶端無法訪問,只有服務(wù)端可以訪問的目錄。
如果想在頁面中直接訪問其中的文件,必須通過web.xml文件對要訪問的文件進(jìn)行相應(yīng)映射才能訪問。
- /WEB-INF/web.xml : Web應(yīng)用程序配置文件,描述了 servlet 和其他的應(yīng)用組件配置及命名規(guī)則。
- /WEB-INF/classes/ : 包含了站點(diǎn)所有用的 class 文件,包括 servlet class 和非servlet class,他們不能包含在 .jar文件中。
- /WEB-INF/lib/ : 存放web應(yīng)用需要的各種JAR文件,放置僅在這個(gè)應(yīng)用中要求使用的jar文件,如數(shù)據(jù)庫驅(qū)動(dòng)jar文件。
頁面放在WEB-INF目錄下面,這樣可以限制訪問,提高安全性.如JSP,html
編寫一個(gè)登陸頁面 login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<h1>登錄頁面</h1>
<hr>
<body>
<form action="${pageContext.request.contextPath}/user/login">
用戶名:<input type="text" name="username">
密碼:<input type="password" name="pwd">
<input type="submit" value="提交">
</form>
</body>
</html>
編寫一個(gè)登陸成功的頁面 success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>登錄成功頁面</h1>
<hr>
${user}
<a href="${pageContext.request.contextPath}/user/logout" rel="external nofollow" >注銷</a>
</body>
</html>
編寫一個(gè)Controller處理請求
package com.kuang.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("/user")
public class UserController {
//跳轉(zhuǎn)到登陸頁面
@RequestMapping("/jumplogin")
public String jumpLogin() throws Exception {
return "login";
}
//跳轉(zhuǎn)到成功頁面
@RequestMapping("/jumpSuccess")
public String jumpSuccess() throws Exception {
return "success";
}
//登陸提交
@RequestMapping("/login")
public String login(HttpSession session, String username, String pwd) throws Exception {
// 向session記錄用戶身份信息
System.out.println("接收前端==="+username);
session.setAttribute("user", username);
return "success";
}
//退出登陸
@RequestMapping("logout")
public String logout(HttpSession session) throws Exception {
// session 過期
session.invalidate();
return "login";
}
}
編寫用戶登錄攔截器
package com.kuang.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class LoginInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
// 如果是登陸頁面則放行
System.out.println("uri: " + request.getRequestURI());
if (request.getRequestURI().contains("login")) {
return true;
}
HttpSession session = request.getSession();
// 如果用戶已登陸也放行
if(session.getAttribute("user") != null) {
return true;
}
// 用戶沒有登陸跳轉(zhuǎn)到登陸頁面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
在Springmvc的配置文件中注冊攔截器
<!--關(guān)于攔截器的配置-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean id="loginInterceptor" class="com.kuang.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
在 index 頁面上測試跳轉(zhuǎn)!啟動(dòng)Tomcat 測試,未登錄攔截
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<h1>首頁</h1>
<hr>
<%--登錄--%>
<a href="${pageContext.request.contextPath}/user/jumplogin" rel="external nofollow" >登錄</a>
<a href="${pageContext.request.contextPath}/user/jumpSuccess" rel="external nofollow" >成功頁面</a>
</body>
</html>
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot使用AOP,內(nèi)部方法失效的解決方案
這篇文章主要介紹了SpringBoot使用AOP,內(nèi)部方法失效的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
Java使用組件編寫窗口實(shí)現(xiàn)網(wǎng)絡(luò)圖片顯示
這篇文章主要為大家詳細(xì)介紹了Java使用組件編寫窗口實(shí)現(xiàn)網(wǎng)絡(luò)圖片顯示的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02
解決使用stream將list轉(zhuǎn)map時(shí),key重復(fù)導(dǎo)致報(bào)錯(cuò)的問題
這篇文章主要介紹了解決使用stream將list轉(zhuǎn)map時(shí),key重復(fù)導(dǎo)致報(bào)錯(cuò)的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
基于spring-security 401 403錯(cuò)誤自定義處理方案
這篇文章主要介紹了基于spring-security 401 403錯(cuò)誤自定義處理方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
Guava自動(dòng)加載緩存LoadingCache使用實(shí)戰(zhàn)詳解
這篇文章主要為大家介紹了Guava自動(dòng)加載緩存LoadingCache使用實(shí)戰(zhàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
解析SpringBoot?搭建基于?MinIO?的高性能存儲服務(wù)的問題
Minio是Apache?License?v2.0下發(fā)布的對象存儲服務(wù)器,使用MinIO構(gòu)建用于機(jī)器學(xué)習(xí),分析和應(yīng)用程序數(shù)據(jù)工作負(fù)載的高性能基礎(chǔ)架構(gòu)。這篇文章主要介紹了SpringBoot?搭建基于?MinIO?的高性能存儲服務(wù),需要的朋友可以參考下2022-03-03

