攔截過濾器模式
表示層請求處理機制接收許多不同型別的請求,這些請求需要不同型別的處理。有些請求只是轉發到適當的處理程式元件,而其他請求必須在進一步處理之前進行修改,稽核或解壓縮。
攔截過濾器模式的最好例子之一是Spring Security 的 DelegatingFilterProxy,它將攔截HTTP請求並進行身份驗證檢查。Spring安全性構建在過濾器鏈上。
讓我們看看攔截過濾器模式如何透過示例解決問題。為簡單起見,這種模式分為若干部分,如問題,動因,解決方案,實施等。
問題
(問題部分描述了開發人員面臨的設計問題)
需要對客戶端Web請求和響應進行預處理和後處理。當請求進入Web應用程式時,它通常必須在主處理階段之前透過多個入口測試。例如,
- 客戶端是否已透過身份驗證?
- 客戶端是否有有效的會話?
- 客戶端的IP地址是否來自可信網路?
- 請求路徑是否違反任何約束?
- 客戶端使用什麼編碼來傳送資料?
- 我們是否支援客戶端的瀏覽器型別?其中一些檢查是測試,導致是或否答案,確定是否繼續處理。其他檢查將輸入資料流操作為適合於處理的形式。您希望對客戶端Web請求和響應進行預處理和後處理。
動因
(本節描述了列出影響問題和解決方案的原因和動機。動因列表顯示了人們可能選擇並使用模式的理由)
- 您希望跨請求進行集中、通用的處理,例如檢查每個請求的資料編碼方案,記錄有關每個請求的資訊或壓縮傳出響應。
- 您希望預處理和後處理元件與核心請求處理服務鬆散耦合,以方便不引人注目的新增和刪除。
- 您希望預處理和後處理元件彼此獨立且自包含以便於重用。
解決方案
(此處解決方案部分簡要介紹瞭解決方案的方法,並詳細介紹瞭解決方案)
使用攔截過濾器作為可插拔過濾器來預處理和後處理請求和響應。過濾器管理器將鬆散耦合的過濾器組合在一個鏈中,將控制權委託給適當的過濾器。透過這種方式,您可以以各種方式新增、刪除和組合這些過濾器,而無需更改現有程式碼。
結構
類圖
序列圖
參與者
過濾器 (Filter)- 在請求處理程式執行請求之前或之後執行特定任務的過濾器。
過濾鏈(Filter Chain) - 過濾鏈帶有多個過濾器,有助於在目標上按照定義的順序執行它們。
目標 (Target )- 目標物件是請求處理程式
過濾器管理器(Filter Manager) - 過濾器管理器管理過濾器和過濾器鏈。
客戶端(Client) - 客戶端是向Target物件傳送請求的物件。
執行
第1步: 建立過濾器(Filter)介面。
public interface Filter { public void execute(String request); } |
第2步: 建立具體過濾器 - AuthenticationFilter,DebugFilter。
public class AuthenticationFilter implements Filter { public void execute(String request){ System.out.println("Authenticating request: " + request); } } |
public class DebugFilter implements Filter { public void execute(String request){ System.out.println("request log: " + request); } } |
第3步: 建立目標(Target )
public class Target { public void execute(String request){ System.out.println("Executing request: " + request); } } |
第4步: 建立過濾鏈(Filter Chain)
import java.util.ArrayList; import java.util.List; public class FilterChain { private List<Filter> filters = new ArrayList<Filter>(); private Target target; public void addFilter(Filter filter){ filters.add(filter); } public void execute(String request){ for (Filter filter : filters) { filter.execute(request); } target.execute(request); } public void setTarget(Target target){ this.target = target; } } |
第5步: 建立過濾器管理器(FilterManager)
public class FilterManager { FilterChain filterChain; public FilterManager(Target target){ filterChain = new FilterChain(); filterChain.setTarget(target); } public void setFilter(Filter filter){ filterChain.addFilter(filter); } public void filterRequest(String request){ filterChain.execute(request); } } |
第6步: 建立客戶端(Client)
public class Client { FilterManager filterManager; public void setFilterManager(FilterManager filterManager){ this.filterManager = filterManager; } public void sendRequest(String request){ filterManager.filterRequest(request); } } |
步驟7: 使用客戶端演示攔截過濾器設計模式
public class InterceptingFilterDemo { public static void main(String args) { FilterManager filterManager = new FilterManager(new Target()); filterManager.setFilter(new AuthenticationFilter()); filterManager.setFilter(new DebugFilter()); Client client = new Client(); client.setFilterManager(filterManager); client.sendRequest("HOME"); } } |
第8步: 驗證輸出。
Authenticating request: HOME request log: HOME Executing request: HOME |
標準過濾策略
servlet 2.3規範包括一個標準機制,用於構建過濾器鏈,並從這些鏈中不顯眼地新增和刪除過濾器。
過濾器圍繞介面構建,並透過修改Web應用程式的部署描述符以宣告方式新增或刪除。
javax.servlet.Filter(介面)
過濾器是對資源請求(servlet或靜態內容)或資源響應(或兩者)執行過濾任務的物件。過濾器在doFilter方法中執行過濾。
每個Filter都可以訪問FilterConfig物件,從中可以獲取其初始化引數,例如,可以使用ServletContext的引用,以載入過濾任務所需的資源。
過濾器在Web應用程式的部署描述符中配置。
本設計中已確定的示例如下:
- 驗證過濾器
- 記錄和稽核過濾器
- 影像轉換過濾器
- 資料壓縮過濾器
- 加密過濾器
- 標記過濾器
- 觸發資源訪問事件的過濾器
- XSL / T過濾器
- Mime型鏈式過濾器
javax.servlet.FilterChain(介面)
FilterChain是servlet容器向開發人員提供的物件,它提供對資源的篩選請求的呼叫鏈的檢視。過濾器使用FilterChain呼叫鏈中的下一個過濾器,或者如果呼叫過濾器是鏈中的最後一個過濾器,則呼叫鏈末尾的資源。
示例
這個策略的示例是建立一個過濾器,它對任何編碼型別的請求進行預處理,以便在核心請求處理程式碼中對每個請求進行類似的處理。為什麼有必要這樣做?包含檔案上載的HTML表單使用與大多數表單不同的編碼型別。
因此,透過simplegetParameter()呼叫無法獲得伴隨上載的表單資料 。所以,我們建立了兩個預處理請求的過濾器,將所有編碼型別轉換為單一的一致格式。我們選擇的格式是將所有表單資料作為請求屬性提供。
示例1 - 基本過濾器 - 標準過濾策略
public class BaseEncodeFilter implements javax.servlet.Filter { private javax.servlet.FilterConfig myFilterConfig; public BaseEncodeFilter() { } public void doFilter( javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse, javax.servlet.FilterChain filterChain) throws java.io.IOException, javax.servlet.ServletException { filterChain.doFilter(servletRequest, servletResponse); } public javax.servlet.FilterConfig getFilterConfig() { return myFilterConfig; } public void setFilterConfig( javax.servlet.FilterConfig filterConfig) { myFilterConfig = filterConfig; } } |
public class StandardEncodeFilter extends BaseEncodeFilter { // Creates new StandardEncodeFilter public StandardEncodeFilter() { } public void doFilter(javax.servlet.ServletRequest servletRequest,javax.servlet.ServletResponse servletResponse,javax.servlet.FilterChain filterChain) throws java.io.IOException, javax.servlet.ServletException { String contentType = servletRequest.getContentType(); if ((contentType == null) || contentType.equalsIgnoreCase( "application/x-www-form-urlencoded")) { translateParamsToAttributes(servletRequest, servletResponse); } filterChain.doFilter(servletRequest, servletResponse); } private void translateParamsToAttributes( ServletRequest request, ServletResponse response) { Enumeration paramNames = request.getParameterNames(); while (paramNames.hasMoreElements()) { String paramName = (String) paramNames.nextElement(); String values; values = request.getParameterValues(paramName); System.err.println("paramName = " + paramName); if (values.length == 1) request.setAttribute(paramName, values[0]); else request.setAttribute(paramName, values); } } } |
示例2- MultipartEncodeFilter - 標準過濾策略
public class MultipartEncodeFilter extends BaseEncodeFilter { public MultipartEncodeFilter() { } public void doFilter(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse,javax.servlet.FilterChain filterChain) throws java.io.IOException, javax.servlet.ServletException { String contentType = servletRequest.getContentType(); // Only filter this request if it is multipart // encoding if (contentType.startsWith( "multipart/form-data")){ try { String uploadFolder = getFilterConfig().getInitParameter( "UploadFolder"); if (uploadFolder == null) uploadFolder = "."; /** The MultipartRequest class is: * Copyright (C) 2001 by Jason Hunter * <jhunter@servlets.com>. All rights reserved. **/ MultipartRequest multi = new MultipartRequest(servletRequest, uploadFolder, 1 * 1024 * 1024 ); Enumeration params = multi.getParameterNames(); while (params.hasMoreElements()) { String name = (String)params.nextElement(); String value = multi.getParameter(name); servletRequest.setAttribute(name, value); } Enumeration files = multi.getFileNames(); while (files.hasMoreElements()) { String name = (String)files.nextElement(); String filename = multi.getFilesystemName(name); String type = multi.getContentType(name); File f = multi.getFile(name); // At this point, do something with the // file, as necessary } } catch (IOException e) { LogManager.logMessage( "error reading or saving file"+ e); } } // end if filterChain.doFilter(servletRequest, servletResponse); } // end method doFilter() } |
部署描述符 - 標準過濾策略
<filter> <filter-name>StandardEncodeFilter</filter-name> <display-name>StandardEncodeFilter</display-name> <description></description> <filter-class> corepatterns.filters.encodefilter. StandardEncodeFilter</filter-class> </filter> <filter> <filter-name>MultipartEncodeFilter</filter-name> <display-name>MultipartEncodeFilter</display-name> <description></description> <filter-class>corepatterns.filters.encodefilter. MultipartEncodeFilter</filter-class> <init-param> <param-name>UploadFolder</param-name> <param-value>/home/files</param-value> </init-param> </filter> <filter-mapping> <filter-name>StandardEncodeFilter</filter-name> <url-pattern>/EncodeTestServlet</url-pattern> </filter-mapping> <filter-mapping> <filter-name>MultipartEncodeFilter</filter-name> <url-pattern>/EncodeTestServlet</url-pattern> </filter-mapping> |
後果
- 使用鬆散耦合的處理程式集中控制
- 提高可重用性
- 宣告性和靈活的配置
- 資訊共享效率低下
適用性
使用擷取過濾器模式時
- 系統使用預處理或後處理請求
- 系統應該執行身份驗證/授權/記錄或跟蹤請求,然後將請求傳遞給相應的處理程式
- 您需要一種模組化方法來配置預處理和後處理方案
相關文章
- 極簡架構模式-攔截過濾器模式架構模式過濾器
- Spring 過濾器和攔截器Spring過濾器
- 攔截器(Interceptor)與過濾器(Filter)過濾器Filter
- SpringBoot 攔截器、過濾器、監聽器Spring Boot過濾器
- 聊一聊過濾器與攔截器過濾器
- spring中的過濾器與攔截器Spring過濾器
- springBoot的過濾器,監聽器,攔截器Spring Boot過濾器
- 談談 Spring 的過濾器和攔截器Spring過濾器
- SpringBoot實現過濾器、攔截器與切片Spring Boot過濾器
- springboot系列文章之過濾器 vs 攔截器Spring Boot過濾器
- 過濾器 Filter 與 攔截器 Interceptor 的區別過濾器Filter
- SpringBoot中的過濾器和攔截器的實現Spring Boot過濾器
- spring boot 新增自定義監聽器、過濾器、攔截器Spring Boot過濾器
- 過濾器、攔截器、AOP、ControllerAdvcie執行順序對比過濾器Controller
- Solon 的過濾器 Filter 和兩種攔截器 Handler、 Interceptor過濾器Filter
- 監聽器,過濾器,攔截器的執行過程和對比過濾器
- Java Filter過濾器(攔截路徑的配置+攔截方式的配置+生命週期+多個過濾器的先後執行順序)JavaFilter過濾器
- springmv的過濾器和攔截器的區別是什麼Spring過濾器
- 過濾器和攔截器有啥區別,這次會了!過濾器
- 過濾器 和 攔截器 6 個區別,別再傻傻分不清了過濾器
- 過濾器 和 攔截器 6個區別,別再傻傻分不清了過濾器
- 萬字長文帶你徹底學會攔截器與過濾器過濾器
- 過濾器攔截器攔截了request後,controller的@RequestBody 無法獲取request內容,報錯 Required request body is missing 的根源過濾器ControllerUI
- Spring 攔截器和過濾器中自動注入為 null 的原因及解決方案Spring過濾器Null
- Springboot通過攔截器攔截請求資訊收集到日誌Spring Boot
- Spring MVC 中的攔截器的使用“攔截器基本配置” 和 “攔截器高階配置”SpringMVC
- sql攔截器SQL
- SpringMVC攔截器SpringMVC
- Mybatis 攔截器MyBatis
- axios 攔截器iOS
- spring攔截器Spring
- axios攔截器iOS
- MyBatis攔截器MyBatis
- Spring Boot使用過濾器和攔截器分別實現REST介面簡易安全認證Spring Boot過濾器REST
- SpringMVC攔截器,設定不攔截的URLSpringMVC
- Java設計模式-過濾器模式Java設計模式過濾器
- SpringMVC-攔截器SpringMVC
- gRPC(3):攔截器RPC