Spring MVC攔截器和跨域請求使用詳解
一、攔截器簡介
SpringMVC的攔截器(Interceptor)也是AOP思想的一種實現(xiàn)方式。它與Servlet的過濾器(Filter)功能類似,主要用于攔截用戶的請求并做相應(yīng)的處理,通常應(yīng)用在權(quán)限驗證、記錄請求信息的日志、判斷用戶是否登錄等功能上。攔截器和過濾器的區(qū)別
- 攔截器是SpringMVC組件,而過濾器是Servlet組件。
- 攔截器不依賴Web容器,過濾器依賴Web容器。
- 攔截器只能對控制器請求起作用,而過濾器則可以對所有的請求起作用。
- 攔截器可以直接獲取IOC容器中的對象,而過濾器就不太方便獲取。
二、攔截器使用
接下來我們使用SpringMVC攔截器,首先使用maven創(chuàng)建SprinMVC的web項目
2.1 控制器方法
package com.example.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class MyController1 { @RequestMapping ("/m1") public String m1(){ System.out.println("控制器方法"); return "result"; } }
2.2 編寫攔截器類
創(chuàng)建攔截器類,該類實現(xiàn)HandlerInterceptor接口,需要重寫三個方法:
- preHandle:請求到達(dá)Controller前執(zhí)行的方法,返回值為true通過攔截器,返回值為false被攔截器攔截。
- postHandle:跳轉(zhuǎn)到JSP前執(zhí)行的方法
- afterCompletion:跳轉(zhuǎn)到JSP后執(zhí)行的方法
package com.example.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Scanner; public class MyInterceptor implements HandlerInterceptor { // 請求到達(dá)Controller前執(zhí)行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.print("請求到達(dá)Controller前\t"); // 如果return false則無法到達(dá)Controller // 控制臺輸入決定是否進(jìn)入Controller System.out.print("控制臺輸入決定是否進(jìn)入Controller: "); Scanner scanner = new Scanner(System.in); boolean flag; flag = scanner.nextBoolean(); return flag; } // 跳轉(zhuǎn)JSP前執(zhí)行,此時可以向Request域添加數(shù)據(jù) @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.print("跳轉(zhuǎn)JSP前\t"); /*System.out.print("控制臺輸入決定是否添加數(shù)據(jù): "); Scanner scanner = new Scanner(System.in); boolean flag; flag = scanner.nextBoolean(); if(flag)*/ request.setAttribute("name","HQX"); } // 跳轉(zhuǎn)JSP后執(zhí)行,此時已經(jīng)不能向Request域添加數(shù)據(jù) @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("跳轉(zhuǎn)到JSP后"); request.setAttribute("age",10); } }
OK,首先我們這里到達(dá)控制器前和是否進(jìn)入控制器還有是否跳轉(zhuǎn)JSP,跳轉(zhuǎn)到JSP后都有對應(yīng)的提示。
2.3 JSP頁面
result.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>結(jié)果</title> </head> <body> <h3>name:${requestScope.name}</h3> <h3>age:${requestScope.age}</h3> </body> </html>
這里把我們控制臺輸入的name響應(yīng)到前端頁面,但是age注定是沒有屬性的,因為跳轉(zhuǎn)到JSP后才添加注定是沒有意義的。
2.4 配置攔截器
接下來我們需要在SpringMVC核心配置文件中配置攔截器
<!-- 配置攔截器--> <mvc:interceptors> <mvc:interceptor> <!-- 配置攔截器的作用路徑--> <mvc:mapping path="/**"/> <!-- 攔截器對象 --> <bean class="com.itbaizhan.interceptor.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors>
2.5 測試結(jié)果
OK,第一次輸入true后后面的提示信息也是可以出來的。已經(jīng)成功攔截了
2.6 全局?jǐn)r截器
全局?jǐn)r截器可以攔截所有控制器處理的URL,作用等于/**,配置方式如下:
<!-- 配置攔截器 --> <mvc:interceptors> <!-- 全局?jǐn)r截器 --> <bean class="com.itbaizhan.interceptor.MyInterceptor"> </bean> </mvc:interceptors>
三、攔截器鏈與執(zhí)行順序
如果一個URL能夠被多個攔截器所攔截,全局?jǐn)r截器最先執(zhí)行,其他攔截器根據(jù)配置文件中配置的從上到下執(zhí)行,但是我實操下來發(fā)現(xiàn)并不是這樣。接下來我來驗證一下我的想法,再配置一個攔截器2:
3.1 攔截器2
package com.example.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Scanner; public class MyInterceptor2 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.print("攔截器2:請求到達(dá)Controller前\t"); // 如果return false則無法到達(dá)Controller // 控制臺輸入決定是否進(jìn)入Controller System.out.print("控制臺輸入決定是否進(jìn)入Controller: "); Scanner scanner = new Scanner(System.in); boolean flag; flag = scanner.nextBoolean(); return flag; } // 跳轉(zhuǎn)JSP前執(zhí)行,此時可以向Request域添加數(shù)據(jù) @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.print("攔截器2:跳轉(zhuǎn)JSP前\t"); /*System.out.print("控制臺輸入決定是否添加數(shù)據(jù): "); Scanner scanner = new Scanner(System.in); boolean flag; flag = scanner.nextBoolean(); if(flag)*/ request.setAttribute("age","10"); } // 跳轉(zhuǎn)JSP后執(zhí)行,此時已經(jīng)不能向Request域添加數(shù)據(jù) @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("攔截器2:跳轉(zhuǎn)到JSP后"); request.setAttribute("age",10); } }
這里再配置一個攔截器,為了更能體現(xiàn)攔截器的攔截順序。
3.2 配置攔截器鏈
<!-- 配置攔截器--> <mvc:interceptors> <!-- 攔截器1 --> <mvc:interceptor> <!-- 配置攔截器的作用路徑(沒有該作用路徑標(biāo)簽則是全局?jǐn)r截器) --> <mvc:mapping path="/m1"/> <!-- 攔截器對象 --> <bean class="com.example.interceptor.MyInterceptor"/> </mvc:interceptor> <!-- 攔截器2 --> <mvc:interceptor> <!-- 配置攔截器的作用路徑(沒有該作用路徑標(biāo)簽則是全局?jǐn)r截器) --> <mvc:mapping path="/m1"/> <!-- 攔截器對象 --> <bean class="com.example.interceptor.MyInterceptor2"/> </mvc:interceptor> <!-- 全局?jǐn)r截器 --> <bean class="com.example.interceptor.GlobalInterceptor"/> </mvc:interceptors>
我們這里測試的攔截器1,2攔截路徑都是/m1,我們把全局?jǐn)r截器放在最后看一下執(zhí)行順序是如何的,如果按照上面的說法的話,則應(yīng)該先提示全局?jǐn)r截器,再攔截器1,攔截器2的提示信息。接下來我們來看一下實際結(jié)果吧。
3.3 測試結(jié)果
我們可以看到當(dāng)訪問/m1的時候,首先進(jìn)入控制器前出現(xiàn)的順序是攔截器1,然后攔截器2,最后是全局?jǐn)r截器,然后跳轉(zhuǎn)JSP前的順序才是全局?jǐn)r截器、攔截器2,攔截器1,跳轉(zhuǎn)JSP后的也是如此。
四、攔截器過濾敏感詞案例
接下來我們編寫一個攔截器案例,需求如下:在系統(tǒng)中,我們需要將所有響應(yīng)中的一些敏感詞替換為 *** ,此時可以使用攔截器達(dá)到要求:
4.1 編寫控制方法
@RequestMapping("/m2") public String m2(Model model){ model.addAttribute("name","大笨蛋"); return "result"; }
4.2 創(chuàng)建敏感詞攔截器
package com.example.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Map; import java.util.Set; public class SensitiveWordInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // 敏感詞列表 String[] sensitiveWords = {"壞人","暴力","笨蛋"}; // model中所有數(shù)據(jù) if(modelAndView!=null) { Map<String, Object> model = modelAndView.getModel(); Set<Map.Entry<String, Object>> entries = model.entrySet(); // 遍歷model for (Map.Entry<String, Object> entry : entries) { String key = entry.getKey(); String value = entry.getValue().toString(); // 將model值和敏感詞列表遍歷比對 for (String sensitiveWord : sensitiveWords) { // 如果model包含敏感詞,則替換 if (value.contains(sensitiveWord)) { String newStr = value.replaceAll(sensitiveWord, "***"); model.put(key, newStr); } } } } } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
4.3 配置攔截器
<!-- 敏感詞攔截器 --> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.example.interceptor.SensitiveWordInterceptor"/> </mvc:interceptor>
4.4 測試結(jié)果
OK,我們可以發(fā)現(xiàn)笨蛋確實是被換成了***。
五、跨域請求
5.1 同源策略
同源策略是瀏覽器的一個安全功能。同源,指的是兩個URL的協(xié)議,域名,端口相同。瀏覽器出于安全方面的考慮,不同源的客戶端腳本在沒有明確授權(quán)的情況下,不能讀寫對方資源。哪些不受同源策略限制:
- 頁面中的 <a> 跳轉(zhuǎn)、表單提交不會受到同源策略限制的。
- 靜態(tài)資源引入也不會受到同源策略限制。如嵌入到頁面中的 <script src=""> , <img src=""> ,<link href=""> 等。
最容易收到同源策略影響的就是Ajax請求。
5.2 跨域請求
當(dāng)請求URL的協(xié)議、域名、端口三者中任意一個與當(dāng)前頁面URL不同時即為跨域。瀏覽器執(zhí)行JavaScript腳本時,會檢查當(dāng)前請求是否同源,如果不是同源資源,就不會被執(zhí)行。
當(dāng)前頁面URL | 被請求頁面URL | 是否跨域 | 原因 |
https://www.csdn.net/ | https://www.csdn.net/index.html | 否 | |
https://www.csdn.net/ | http://www.csdn.net/index.html | 跨域 | 協(xié)議不同 |
http://www.csdn.com/ | http://www.baidu.com/ | 跨域 | 主域名不同 |
http://csdn.csdn.net/ | http://www.csdn.net/ | 跨域 | 子域名不同 |
http://www.csdn.net:8080 | http://www.csdn.net:8081 | 跨域 | 端口號不同 |
5.3 控制器接收跨域請求
SpringMVC提供了注解@CrossOrigin解決跨域問題。用法如下:
控制器方法
@RequestMapping("/m3") @ResponseBody @CrossOrigin("http://localhost:8080") public String m3(){ System.out.println("測試跨域請求"); return "success"; }
編寫JSP頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>跨域請求</title> <script src="js/jquery-2.1.1.min.js"></script> <script> $(function (){ $("#btn").click(function (){ $.get("http://localhost:8080/m3",function (data){ console.log(data); }) /*$.get("http://127.0.0.1:8080/m3",function (data){ console.log(data); })*/ }) }) </script> </head> <body> <button id="btn" >異步請求</button> </body> </html>
測試結(jié)果
當(dāng)注釋掉跨域注解時,運行是這樣的。因為是沒有跨域,但是當(dāng)我們使用127.0.0.1時就會報錯。
使用127.0.0.1時,且沒有添加注解時的運行結(jié)果是這樣的:可以看到這時就不能成功success了
當(dāng)添加到注解后,無論是8080還是127.0.0.1都能夠成功success了
到此這篇關(guān)于Spring MVC攔截器和跨域請求的文章就介紹到這了,更多相關(guān)Spring MVC攔截器和跨域請求內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java字節(jié)碼框架ASM的深入學(xué)習(xí)
這篇文章主要給大家介紹了java中字節(jié)碼框架ASM的相關(guān)資料,文中介紹的非常詳細(xì),相信對大家的理解和學(xué)習(xí)具有一定的參考借鑒價值,有需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧。2017-01-01Java基礎(chǔ)之toString的序列化 匿名對象 復(fù)雜度精解
序列化即為把內(nèi)存中的對象轉(zhuǎn)換為字節(jié)寫入文件或通過網(wǎng)絡(luò)傳輸?shù)竭h(yuǎn)端服務(wù)器,本章節(jié)將帶你了解Java toString的序列化 匿名對象 復(fù)雜度,需要的朋友可以參考下2021-09-09java如何發(fā)送get請求獲取數(shù)據(jù)(附代碼)
這篇文章主要給大家介紹了關(guān)于java如何發(fā)送get請求獲取數(shù)據(jù)的相關(guān)資料,Java中的GET請求方法是HTTP協(xié)議中的一種請求方式,用于向服務(wù)器請求獲取資源,需要的朋友可以參考下2023-10-10