SpringBoot使用Filters實現(xiàn)請求過濾和預處理
什么是過濾器
過濾器(Filter)是一種在Web應用中用于攔截和處理HTTP請求和響應的對象。
在Java Web開發(fā)中,過濾器是實現(xiàn)特定功能,如認證、日志記錄和字符編碼處理的重要工具。具體如下:
- 過濾器的基本概念
- 定義:過濾器是一種可以動態(tài)地攔截傳入的請求和傳出的響應,并對這些請求和響應進行預處理和后處理的對象。
- 作用:過濾器可以檢查和修改請求頭和響應頭、處理cookies、驗證用戶提交的數(shù)據(jù)等。
- 過濾器的工作原理
- 工作流程:當一個請求到達服務器時,它會首先通過過濾器鏈,每個過濾器都有機會對請求進行處理。如果請求通過了所有過濾器的檢驗,它最終會到達目標資源,如servlet或JSP頁面。
- 請求處理:在過濾器中可以通過修改請求對象來實現(xiàn)對請求數(shù)據(jù)的預處理,例如,可以對輸入數(shù)據(jù)進行解碼或者驗證。
- 響應處理:在放行請求后,還可以在過濾器中修改返回給用戶的響應數(shù)據(jù),例如,對輸出數(shù)據(jù)進行編碼或者壓縮。
- 過濾器的生命周期
- 初始化:
init
方法在過濾器創(chuàng)建時被調(diào)用,用于初始化操作。這個方法只運行一次,一般用來讀取配置文件和初始化資源。 - 過濾請求:
doFilter
方法是實際執(zhí)行過濾操作的地方,每次請求經(jīng)過過濾器時都會被調(diào)用。在這個方法中可以實現(xiàn)具體的過濾邏輯,并通過FilterChain
對象決定是否將請求傳遞到下一個過濾器或者目標資源。 - 銷毀:
destroy
方法在過濾器銷毀之前被調(diào)用,用于釋放資源。這也是只運行一次的方法,通常用于清理操作。
- 初始化:
- 過濾器的使用場景
- 身份驗證:用于檢查用戶是否已經(jīng)登錄,確保只有合法用戶才能訪問受保護的資源。
- 日志記錄:記錄每個請求的信息,如IP地址、訪問時間等,有助于網(wǎng)站管理和安全監(jiān)控。
- 字符編碼處理:解決不同字符集之間的兼容問題,避免出現(xiàn)亂碼。
- 輸入數(shù)據(jù)驗證:對用戶提交的數(shù)據(jù)進行格式和有效性驗證,防止非法輸入導致的安全問題。
- 如何配置和使用過濾器
- 注解方式:通過
@WebFilter
注解直接在過濾器類上指定攔截路徑,這種方法更簡單、直觀。 - XML配置:在
web.xml
文件中配置<filter>
和<filter-mapping>
元素,以定義過濾器及其應用場景。
- 注解方式:通過
綜上所述,過濾器在Web應用中起著至關(guān)重要的作用,從請求預處理到響應后處理,都能有效地提高應用的安全性、可用性和用戶體驗。對于開發(fā)人員而言,掌握過濾器的使用是提升Web應用質(zhì)量的重要手段。
為什么我們需要過濾器
過濾器在Web開發(fā)中扮演著至關(guān)重要的角色,它們用于增強、控制和修改HTTP請求和響應的處理。具體如下:
- 為什么需要過濾器
- 提高代碼重用性:通過使用過濾器可以避免在多個Servlet或JSP頁面中重復編寫相同的代碼,從而簡化了代碼維護并減少了冗余。
- 實現(xiàn)全局功能:過濾器可以全局處理所有請求,從而統(tǒng)一實現(xiàn)如字符編碼處理、敏感詞匯過濾等功能。
- 增強安全性:通過身份驗證和授權(quán),過濾器能夠阻止未經(jīng)授權(quán)的用戶訪問受保護的資源,提升應用的安全性。
- 提供更好的用戶體驗:例如,過濾器可以用于網(wǎng)站的統(tǒng)一登錄功能,用戶只需一次登錄即可訪問所有受保護的資源,而無需多次認證。
- 過濾器的工作原理及生命周期
- 工作流程:當一個請求到達服務器時,它會首先通過過濾器鏈,每個過濾器都有機會對請求進行處理。如果請求通過了所有過濾器的檢驗,它最終會到達目標資源,如servlet或JSP頁面。
- 請求處理:在過濾器中可以通過修改請求對象來實現(xiàn)對請求數(shù)據(jù)的預處理,例如,對輸入數(shù)據(jù)進行解碼或驗證。
- 響應處理:在放行請求后,還可以在過濾器中修改返回給用戶的響應數(shù)據(jù),例如,對輸出數(shù)據(jù)進行編碼或壓縮。
- 生命周期方法:過濾器的生命周期包括
init
、doFilter
和destroy
三個方法。init
方法在過濾器創(chuàng)建時調(diào)用,用于初始化操作;doFilter
方法在實際請求處理中被調(diào)用;destroy
方法在過濾器銷毀前調(diào)用,用于釋放資源。
- 過濾器的主要應用場景
- 字符編碼處理:通過過濾器可以統(tǒng)一設置請求和響應的字符編碼,避免出現(xiàn)亂碼問題。這在處理不同語言環(huán)境的應用中尤其重要。
- 權(quán)限驗證:過濾器可以檢查用戶是否已經(jīng)登錄或是否有權(quán)訪問某個資源。這樣,只有合法用戶才能訪問受保護的資源。
- 日志記錄:過濾器可以記錄每個請求的信息,如IP地址、訪問時間等,有助于網(wǎng)站管理和安全監(jiān)控。
- 輸入數(shù)據(jù)驗證:過濾器可以對用戶提交的數(shù)據(jù)進行格式和有效性驗證,防止非法輸入導致的安全問題。
- 敏感信息過濾:過濾器可以過濾掉請求和響應中的敏感信息,如SQL注入攻擊的字符串,確保數(shù)據(jù)傳輸?shù)陌踩?/li>
- 如何在Spring Boot中使用過濾器
- 創(chuàng)建過濾器類:實現(xiàn)
javax.servlet.Filter
接口,并覆蓋doFilter
方法以定義過濾器的邏輯。在doFilter
方法中,可以對請求和響應進行處理,并通過調(diào)用FilterChain.doFilter()
將請求傳遞給下一個過濾器或目標Servlet。 - 注冊過濾器:使用
@WebFilter
注解將過濾器類標記為過濾器,并通過urlPatterns
屬性指定要攔截的URL模式。如果不使用@WebFilter
注解,也可以通過在Spring Boot配置類中使用FilterRegistrationBean
來注冊過濾器。先創(chuàng)建一個FilterRegistrationBean
實例,然后設置過濾器實例,添加URL模式,并設置優(yōu)先級。
- 創(chuàng)建過濾器類:實現(xiàn)
- 過濾器與攔截器的區(qū)別
- 處理范圍:過濾器主要作用于Servlet容器層次,可以攔截所有到達Web應用的請求;而攔截器則作用于Spring MVC框架內(nèi),只能攔截由DispatcherServlet管理的請求。
- 執(zhí)行順序:過濾器的執(zhí)行順序依賴于它們在
web.xml
中的配置順序或通過@WebFilter
注解聲明的順序;攔截器的執(zhí)行順序則依賴于在Spring配置文件中的聲明順序。 - 功能實現(xiàn):過濾器更側(cè)重于請求的預處理和響應的后處理,比如字符編碼處理、文件上傳處理等;攔截器則更側(cè)重于視圖渲染前的控制器執(zhí)行流程,如權(quán)限檢查、表單驗證等。
綜上所述,過濾器在Web應用的開發(fā)中起著至關(guān)重要的作用。從請求預處理到響應后處理,過濾器都能有效地提高應用的安全性、可用性和用戶體驗。對于開發(fā)人員而言,掌握過濾器的使用是提升Web應用質(zhì)量的重要手段。
創(chuàng)建過濾器
要在Spring Boot中創(chuàng)建過濾器,您可以實現(xiàn)javax.servlet.Filter
接口或擴展OncePerRequestFilter
類。OncePerRequestFilter
確保您的過濾器每個請求只執(zhí)行一次。
@RestController @RequestMapping("/customer") public class CustomerController { @GetMapping public String getMessage(){ return "welcome to filter session"; } } @Component @Slf4j public class MessageFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { log.info("[MessageFilter] - Inside doFilter method"); log.info("Local Port : " + request.getLocalPort()); log.info("Server Name : " + request.getServerName()); HttpServletRequest httpServletRequest = (HttpServletRequest) request; log.info("Method Name : " + httpServletRequest.getMethod()); log.info("Request URI : " + httpServletRequest.getRequestURI()); log.info("Servlet Path : " + httpServletRequest.getServletPath()); chain.doFilter(request, response); } }
過濾器的順序
過濾器的應用順序可以通過@Order
注解或
@Component @Slf4j @Order(2) public class MessageFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { log.info("[MessageFilter] - Inside doFilter method"); log.info("Local Port : " + request.getLocalPort()); log.info("Server Name : " + request.getServerName()); HttpServletRequest httpServletRequest = (HttpServletRequest) request; log.info("Method Name : " + httpServletRequest.getMethod()); log.info("Request URI : " + httpServletRequest.getRequestURI()); log.info("Servlet Path : " + httpServletRequest.getServletPath()); chain.doFilter(request, response); } } @Component @Slf4j @Order(1) public class ProductFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { log.info("[ProductFilter] - Inside doFilter method"); log.info("Local Port : " + request.getLocalPort()); log.info("Server Name : " + request.getServerName()); HttpServletRequest httpServletRequest = (HttpServletRequest) request; log.info("Method Name : " + httpServletRequest.getMethod()); log.info("Request URI : " + httpServletRequest.getRequestURI()); log.info("Servlet Path : " + httpServletRequest.getServletPath()); chain.doFilter(request, response); } }
注意:如果您只想打印MessageFilter并跳過ProductFilter
要在訪問/customer API時僅顯示MessageFilter的日志,您需要有條件地繞過ProductFilter對/customer端點的過濾。您可以通過修改ProductFilter來跳過特定端點的過濾來實現(xiàn)這一點。
@Component @Slf4j @Order(1) // 確保此過濾器在MessageFilter之前執(zhí)行 public class ProductFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) request; String requestURI = httpServletRequest.getRequestURI(); if ("/customer".equals(requestURI)) { chain.doFilter(request, response); return; // 跳過過濾器的其余部分 } log.info("[ProductFilter] - Inside doFilter method"); log.info("Local Port : " + request.getLocalPort()); log.info("Server Name : " + request.getServerName()); log.info("Method Name : " + httpServletRequest.getMethod()); log.info("Request URI : " + requestURI); log.info("Servlet Path : " + httpServletRequest.getServletPath()); chain.doFilter(request, response); } }
注冊過濾器
@Configuration public class FilterConfig { @Bean public FilterRegistrationBean<MessageFilter> loggingFilter(){ FilterRegistrationBean<MessageFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new MessageFilter()); registrationBean.addUrlPatterns("/customer/*"); // 如果需要,指定URL模式 return registrationBean; } }
OncePerRequestFilter
public class ProductFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { log.info("[ProductFilter] - Inside doFilter method"); log.info("Local Port : " + request.getLocalPort()); log.info("Server Name : " + request.getServerName()); HttpServletRequest httpServletRequest = (HttpServletRequest) request; log.info("Method Name : " + httpServletRequest.getMethod()); log.info("Request URI : " + httpServletRequest.getRequestURI()); log.info("Servlet Path : " + httpServletRequest.getServletPath()); filterChain.doFilter(request, response); } }
簡單案例
1、建一個新的Java類,并實現(xiàn)javax.servlet.Filter
接口。例如,創(chuàng)建一個名為MyFilter
的類
import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { // 初始化代碼(可選) } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; // 在這里可以對請求進行預處理操作,例如檢查請求頭、參數(shù)等 // 繼續(xù)執(zhí)行過濾器鏈中的下一個過濾器或目標資源 chain.doFilter(request, response); // 在這里可以對響應進行后處理操作,例如修改響應頭、內(nèi)容等 } @Override public void destroy() { // 銷毀代碼(可選) } }
2、在Spring Boot應用程序的配置類上添加@Configuration
注解,并在該類中定義一個方法,該方法返回一個帶有@Bean
注解的FilterRegistrationBean
實例。這將注冊你的過濾器并將其添加到過濾器鏈中。
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<MyFilter> myFilter() { FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new MyFilter()); registrationBean.addUrlPatterns("/api/*"); // 設置過濾器應用于哪些URL模式 registrationBean.setOrder(1); // 設置過濾器的順序(數(shù)字越小,優(yōu)先級越高) return registrationBean; } }
在上面的示例中,我們?yōu)镸yFilter設置了URL模式/api/*,這意味著它將應用于所有以/api/開頭的請求。你可以根據(jù)需要調(diào)整URL模式。
3、現(xiàn)在,每當有匹配的請求到達時,MyFilter就會被調(diào)用,你可以在doFilter方法中編寫自定義的請求過濾和預處理邏輯。同樣地,你也可以在響應返回給客戶端之前對其進行后處理。
這樣,你就成功地在Spring Boot應用程序中實現(xiàn)了請求過濾和預處理功能。記得根據(jù)你的需求調(diào)整過濾器的邏輯和配置。
以上就是SpringBoot使用Filters實現(xiàn)請求過濾和預處理的詳細內(nèi)容,更多關(guān)于SpringBoot Filters過濾和預處理的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot項目部署時application.yml文件的加載優(yōu)先級和啟動腳本問題
Spring Boot在啟動時會根據(jù)一定的優(yōu)先級順序加載配置文件,優(yōu)先級從高到低依次是:命令行參數(shù)、Jar包外部config目錄下的配置文件、Jar包同級目錄下的配置文件、classpath下的/config目錄、classpath根路徑2024-09-09springboot的http.server.requests服務請求流程源碼
這篇文章主要為大家介紹了springboot的http.server.requests服務請求流程源碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12Java中ArrayList和LinkedList的區(qū)別
ArrayList和LinkedList在這個方法上存在一定的性能差異,本文就介紹了Java中ArrayList和LinkedList的區(qū)別,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-06-06