Spring使用@Filter注解創(chuàng)建自定義過濾器
簡介
Spring 框架提供了各種強(qiáng)大的功能來構(gòu)建健壯且可擴(kuò)展的應(yīng)用程序。 Spring 中鮮為人知但非常有用的注解之一是 @Filter,它支持自定義過濾器,可以將其應(yīng)用于 Spring 應(yīng)用程序以實(shí)現(xiàn)不同的目的,例如日志記錄、身份驗(yàn)證等。 在這篇文章中,我們將深入研究如何使用 Spring 的 @Filter 注解來創(chuàng)建自定義過濾器。
Spring Filters簡介
過濾器在 Web 開發(fā)中發(fā)揮著至關(guān)重要的作用,尤其是在基于 Spring 的 Web 應(yīng)用程序的上下文中。當(dāng)我們談?wù)?Spring 時(shí),我們主要集中在依賴注入、AOP(面向切面?編程)和 Data JPA 等功能上,而忽略了一些像Filter這樣的無名英雄。過濾器在許多方面都發(fā)揮了作用,例如安全、日志記錄、轉(zhuǎn)換以及各種其他類型的預(yù)處理和后處理活動(dòng)。
過濾器在 Web 應(yīng)用程序中的重要性
如果需要強(qiáng)制執(zhí)行訪問控制(身份驗(yàn)證和授權(quán))、記錄傳入或輸出的 HTTP 請(qǐng)求和響應(yīng),或者在請(qǐng)求和響應(yīng)正文到達(dá)控制器或到達(dá)客戶端之前對(duì)其進(jìn)行操作,那么過濾器就發(fā)揮了作用。它們?yōu)闄M切關(guān)注點(diǎn)提供了一個(gè)集中處理,確保不必在應(yīng)用程序的多個(gè)部分中寫相同的邏輯,從而生成更干凈、更易于維護(hù)的代碼。
過濾器如何融入 Spring 生態(tài)系統(tǒng)
在 Spring 生態(tài)系統(tǒng)中,過濾器充當(dāng)著 Servlet 管道中的攔截器,這意味著它們有權(quán)在請(qǐng)求到達(dá)控制器之前(預(yù)處理)和響應(yīng)離開控制器之后(后處理)執(zhí)行操作。 Spring 與 Java Servlet 規(guī)范很好地保持一致,因此,您可以在 Spring 應(yīng)用程序中使用本機(jī) Servlet 過濾器。然而,Spring 更進(jìn)一步,提供了一種使用注解及其強(qiáng)大的依賴注入功能來定義過濾器的優(yōu)雅方法。
@Filter 有什么作用
Spring 中的 @Filter 注釋(或用于類似目的的自定義注解)用于定義可以注冊并應(yīng)用于傳入請(qǐng)求的過濾器。它允許您將過濾邏輯與核心應(yīng)用程序邏輯完全分離,提供一種優(yōu)雅的方式將自定義操作添加到請(qǐng)求-響應(yīng)周期。使用@Filter,您可以簡潔地表達(dá)特定的一段代碼旨在充當(dāng)過濾器,從而使代碼更易于理解和維護(hù)。
Servlet 過濾器與 Spring 過濾器
為什么要使用 Spring 特定的過濾器而不是標(biāo)準(zhǔn) Servlet 過濾器。雖然 Servlet 過濾器功能強(qiáng)大并且可以完成很多工作,但 Spring 過濾器受益于 Spring 的生態(tài)系統(tǒng),例如它的依賴注入功能,它允許您將 Spring 管理的 bean 直接連接到過濾器類中。這是傳統(tǒng) Servlet 過濾器無法做到的事情。
實(shí)踐
在本節(jié)中,我們將著眼于從頭開始設(shè)置 Spring Boot 項(xiàng)目,重點(diǎn)關(guān)注包含必要的依賴項(xiàng)和配置以支持過濾器的使用。我們將討論兩種設(shè)置項(xiàng)目的方法:使用 Spring Initializr 和手動(dòng)設(shè)置。
剖析過濾器
了解過濾器的結(jié)構(gòu)對(duì)于充分利用其功能至關(guān)重要。基于 Spring 的應(yīng)用程序中的過濾器可以與 Java 的本機(jī) Servlet Filter 保持一致,也可以使用 Spring 的特定功能來實(shí)現(xiàn)更加自定義的方法。要掌握過濾器的本質(zhì),就必須探索其核心方法——過濾器鏈,以及如何正確配置過濾器。
過濾器中的核心方法
Spring(或一般的 Java Web 應(yīng)用程序)中的典型過濾器本質(zhì)上是一個(gè) Java 類,它實(shí)現(xiàn)了 javax.servlet 包中的 Filter 接口。該接口定義了三個(gè)方法:
init(FilterConfig filterConfig)
該方法在過濾器的生命周期內(nèi)僅被調(diào)用一次。您可以在此處放置初始化邏輯,例如分配資源。 FilterConfig 對(duì)象提供對(duì)過濾器配置參數(shù)的訪問,您可以使用此對(duì)象來獲取 Spring 配置中定義的初始化參數(shù)。
doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
這是過濾器的主要邏輯,每次請(qǐng)求響應(yīng)都會(huì)調(diào)用這個(gè)方法。ServletRequest和ServletResponse分別表示輸入請(qǐng)求和輸出回復(fù),在此方法中調(diào)用chain.doFilter會(huì)將請(qǐng)求和響應(yīng)傳給過濾器鏈中的下一個(gè)實(shí)體(過濾器鏈或者目標(biāo)資源例如控制器)
destory()
當(dāng)過濾器停止服務(wù)或者程序關(guān)閉時(shí)調(diào)用。通常做的是一些清理資源的工作,例如關(guān)閉數(shù)據(jù)庫連接、關(guān)閉文件等。
理解FilterChain(過濾器鏈)
過濾器鏈表示是請(qǐng)求和響應(yīng)經(jīng)過的一系列的的過濾器,就和一根鏈條一樣。過濾器添加到鏈中的順序很重要,如果Filter A修改了請(qǐng)求對(duì)象,那么鏈中的下一個(gè)Filter B將接收修改后的請(qǐng)求。
如何在Spring中配置Filter
雖然可以使用@Component注解配置Filter class使得sping可以自動(dòng)檢測并應(yīng)用,但這會(huì)造成過濾器應(yīng)用到每個(gè)請(qǐng)求。為了進(jìn)行更精細(xì)的控制,可以使用 FilterRegistrationBean,這個(gè)類可以配置過濾器應(yīng)用到哪個(gè)Url或者Servlet。
下面是示例
@Bean
public FilterRegistrationBean<CustomFilter> loggingFilter() {
FilterRegistrationBean<CustomFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new CustomFilter());
registrationBean.addUrlPatterns("/api/*");
return registrationBean;
}
這個(gè)例子中,我們的過濾器只對(duì)以api開頭的請(qǐng)求有效。
一個(gè)簡單的日志過濾器
為了將所有這些概念聯(lián)系在一起,讓我們回顧一下簡單的日志過濾器示例:
import javax.servlet.*;
import java.io.IOException;
public class LoggingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化
System.out.println("Logging Filter initialized");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("Request received at " + new java.util.Date());
chain.doFilter(request, response);
System.out.println("Response sent at " + new java.util.Date());
}
@Override
public void destroy() {
// 清理資源
System.out.println("Logging Filter destroyed");
}
}
在這個(gè)例子中,實(shí)現(xiàn)了三個(gè)主要的方法,init()輸出了一些初始化方法,doFilter記錄了請(qǐng)求進(jìn)來的時(shí)間和響應(yīng)回復(fù)的時(shí)間,destory()記錄了資源清理的時(shí)間。
使用@Filter創(chuàng)建自定義過濾器
使用@Filter注解創(chuàng)建自定義過濾器給程序添加特定的功能是非常有效的,這種自定義過濾器以聲明的方式在特定方法或者路由上應(yīng)用過濾器,是代碼更加簡介且容易維護(hù)。
創(chuàng)建@Filter注解
第一步是創(chuàng)建 @Filter 注解本身。這將是一個(gè)標(biāo)記注解,用于標(biāo)識(shí)哪些控制器或方法應(yīng)受到過濾器的影響
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Filter {
String value() default "";
}
創(chuàng)建一個(gè)@Filter過濾器類
現(xiàn)在,讓我們創(chuàng)建一個(gè)將執(zhí)行實(shí)際邏輯的自定義過濾器類。要使用 @Filter 注釋,自定義過濾器類應(yīng)檢查其是否存在。
import org.springframework.core.annotation.AnnotationUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class CustomFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String path = httpRequest.getRequestURI();
Class<?> controller =
if (controller != null && AnnotationUtils.findAnnotation(controller, Filter.class) != null) {
System.out.println("Custom filter applied");
}
chain.doFilter(request, response);
}
}
注冊自定義過濾器
為了讓自定義過濾器正常工作,我們需要注冊它。您可以使用 Spring 的 FilterRegistrationBean 以編程方式實(shí)現(xiàn)。
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<CustomFilter> customFilterRegistration() {
FilterRegistrationBean<CustomFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new CustomFilter());
registrationBean.addUrlPatterns("/*"); // Apply to all routes
return registrationBean;
}
}
通過此配置,自定義過濾器將應(yīng)用于所有路由。您可以更改 addUrlPatterns 方法參數(shù)來限制應(yīng)應(yīng)用過濾器的路由。
使用自定義過濾器注解
現(xiàn)在自定義過濾器和 @Filter 注解已準(zhǔn)備就緒,現(xiàn)在可以注解控制器或特定方法。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Filter("Some Value")
public class MyController {
@GetMapping("/hello")
public String hello() {
return "Hello, World!";
}
}
使用場景和最佳實(shí)踐
過濾器為 Spring Boot 應(yīng)用程序提供了強(qiáng)大的自定義功能,并且可以通過多種方式利用它們來滿足不同的需求。下面,我們將介紹一些使用過濾器的常見用例,并研究實(shí)施過濾器時(shí)要遵循的最佳實(shí)踐。
使用場景
認(rèn)證與授權(quán):過濾器是在允許請(qǐng)求繼續(xù)發(fā)送到控制器之前執(zhí)行身份驗(yàn)證和授權(quán)檢查的理想工具。這可確保只有授權(quán)用戶才能訪問應(yīng)用程序的特定部分。
記錄和監(jiān)控:過濾器可以記錄有關(guān)請(qǐng)求和響應(yīng)的基本信息,例如 IP 地址、標(biāo)頭、有效負(fù)載大小和執(zhí)行時(shí)間。這些信息有利于調(diào)試和監(jiān)控。
數(shù)據(jù)轉(zhuǎn)換: 可以使用過濾器來轉(zhuǎn)換請(qǐng)求和響應(yīng)數(shù)據(jù),例如,通過添加默認(rèn)參數(shù)、執(zhí)行數(shù)據(jù)轉(zhuǎn)換或使用附加信息豐富響應(yīng)。
速率限制:過濾器可以通過計(jì)算給定時(shí)間范圍內(nèi)來自特定客戶端的請(qǐng)求數(shù)量來幫助限制速率,然后根據(jù)這些計(jì)數(shù)阻止或允許請(qǐng)求。
最佳實(shí)踐
把事情簡單化:過濾器不適合復(fù)雜業(yè)務(wù)邏輯。它們應(yīng)該盡可能輕量級(jí),以確保它們不會(huì)成為性能瓶頸。
注意過濾器鏈: 永遠(yuǎn)記住調(diào)用 chain.doFilter(request, response) 來繼續(xù)執(zhí)行過濾器鏈。否則,請(qǐng)求將被阻止,并且無法到達(dá)預(yù)期的效果。
執(zhí)行順序: 過濾器注冊和執(zhí)行的順序很重要。如果處理依賴于先前的過濾器,請(qǐng)確保設(shè)置順序。
徹底測試 : 過濾器與每個(gè)傳入請(qǐng)求和傳出響應(yīng)交互。因此,嚴(yán)格的測試對(duì)于確保它們在各種條件下表現(xiàn)出預(yù)期的效果至關(guān)重要。
利用 Spring 的靈活性: Spring Boot 允許通過多種方式來注冊和應(yīng)用過濾器。利用這種靈活性來創(chuàng)建模塊化且可維護(hù)的代碼。
總結(jié)
在這篇文章中,我們了解了在 Spring 應(yīng)用程序中使用過濾器的要點(diǎn)和復(fù)雜性。從了解過濾器的結(jié)構(gòu)到設(shè)置 Spring Boot 項(xiàng)目,再到使用專門的 @Filter 注釋創(chuàng)建自定義過濾器,我們涵蓋了很多信息。我們還深入研究了過濾器非常有用的現(xiàn)實(shí)用例,以及實(shí)施過濾器時(shí)要遵循的最佳實(shí)踐。
當(dāng)您開發(fā)和維護(hù) Spring Boot 應(yīng)用程序時(shí),過濾器提供了一種強(qiáng)大的模塊化方法來處理各種橫切問題,例如日志記錄、身份驗(yàn)證和數(shù)據(jù)轉(zhuǎn)換等。了解如何正確實(shí)現(xiàn)和使用過濾器可以極大地增強(qiáng)應(yīng)用程序的功能、安全性和整體質(zhì)量。
以上就是Spring使用@Filter注解創(chuàng)建自定義過濾器的詳細(xì)內(nèi)容,更多關(guān)于Spring Filter自定義過濾器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot事件發(fā)布與監(jiān)聽超詳細(xì)講解
今天去官網(wǎng)查看spring boot資料時(shí),在特性中看見了系統(tǒng)的事件及監(jiān)聽章節(jié),所以下面這篇文章主要給大家介紹了關(guān)于SpringBoot事件發(fā)布和監(jiān)聽的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-11-11
Elasticsearch8.1中的Script使用實(shí)例深入解讀
這篇文章主要為大家介紹了Elasticsearch8.1中的Script使用實(shí)例深入解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
springboot接口返回?cái)?shù)據(jù)類型全面解析
這篇文章主要介紹了springboot接口返回?cái)?shù)據(jù)類型問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12
java中@DateTimeFormat和@JsonFormat注解的使用
本文主要介紹了java中@DateTimeFormat和@JsonFormat注解的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08
Java數(shù)組轉(zhuǎn)換為List的四種方式
這篇文章主要介紹了Java開發(fā)技巧數(shù)組轉(zhuǎn)List的四種方式總結(jié),每種方式結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09

