怎么做響應(yīng)式網(wǎng)站搜索百度
過濾器(Filter) | 監(jiān)聽器(Listener) | 攔截器(Interceptor) | |
---|---|---|---|
關(guān)注點(diǎn) | web請求 | 系統(tǒng)級別參數(shù)、對象 | Action(部分web請求) |
如何實(shí)現(xiàn) | 函數(shù)回調(diào) | 事件 | Java反射機(jī)制(動態(tài)代理) |
應(yīng)用場景 | 設(shè)置字符編碼 | 統(tǒng)計網(wǎng)站在線人數(shù) | 攔截未登錄用戶 |
URL級別的權(quán)限訪問控制 | 清除過期session | 審計日志 | |
過濾敏感詞匯 | |||
壓縮響應(yīng)信息 | |||
是否依賴servlet容器 | 依賴 | 依賴 | 不依賴 |
servlet提供的支持 | Filter接口 | ServletContextListerner抽象接口 | Action(部分web請求) |
HttpSessionListener抽象接口 | HandlerinterceptorAdapter類 | ||
Spring提供的支持 | HandlerInterceptor接口 | ||
級別 | 系統(tǒng)級 | 系統(tǒng)級 | 非系統(tǒng)級 |
Interceptor
攔截器是基于Java反射機(jī)制(動態(tài)代理)來實(shí)現(xiàn)的;可以控制請求的控制器和方法,但控制不了請求方法里的參數(shù)(用于處理頁面提交的請求響應(yīng)并進(jìn)行處理,如國際化,主題更換,過濾等)。
一般說到攔截器都是基于Spring框架下,自定義攔截器可以實(shí)現(xiàn)HandlerInterceptor接口或繼承抽象類HandlerInterceptorAdapter,并重寫3個方法即可。
public interface HandlerInterceptor {// preHandle請求執(zhí)行前執(zhí)行default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return true;}// postHandler請求結(jié)束后執(zhí)行,需preHandle方法返回true才執(zhí)行default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {}// afterCompletion是視圖渲染完成后才執(zhí)行,需preHandle返回true,常用于清理資源等工作default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {}
}
抽象類HandlerInterceptorAdapter實(shí)現(xiàn)AsyncHandlerInterceptor,而AsyncHandlerInterceptor繼承HandlerInterceptor,并增加方法afterConcurrentHandlingStarted
public interface AsyncHandlerInterceptor extends HandlerInterceptor {//default void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {}
}
注:HandlerInterceptorAdapter在Spring 5.3版本被標(biāo)記為廢棄。
無論是哪種方式,都需要添加配置使之生效:
@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// DemoInterceptorregistry.addInterceptor(new DemoInterceptor()).addPathPatterns("/**");super.addInterceptors(registry);}
}
另外Spring框架提供很多繼承HandlerInterceptorAdapter的常用攔截器類,如:
- UserRoleAuthorizationInterceptor,實(shí)現(xiàn)用戶登錄認(rèn)證的攔截功能,如果當(dāng)前用戶沒有通過認(rèn)證,會報403錯誤
- LocaleChangeInterceptor
- ThemeChangeInterceptor:6.0版本被廢棄
- ResourceUrlProviderExposingInterceptor
- ConversionServiceExposingInterceptor
- UriTemplateVariablesHandlerInterceptor
Filter
jakarta.servlet.Filter是Java原有接口:
public interface Filter {default void init(FilterConfig filterConfig) throws ServletException {} void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;default void destroy() {}
}
FilterChain,把所有的過濾器都放在FilterChain里邊,責(zé)任鏈模式。JavaDoc給出幾種過濾器的作用:
- Authentication Filters,即用戶訪問權(quán)限過濾
- Logging and Auditing Filters,日志過濾,可以記錄特殊用戶的特殊請求的記錄等
- Image conversion Filters
- Data compression Filters
- Encryption Filters
- Tokenizing Filters
- Filters that trigger resource access events
- XSL/T filters
- Mime-type chain Filter
Listener
EventListener空實(shí)現(xiàn),標(biāo)記接口。
/*** A tagging interface that all event listener interfaces must extend.* @since JDK1.1*/
public interface EventListener {
}
監(jiān)聽器就是一個實(shí)現(xiàn)特定接口的程序。用于監(jiān)聽一個Java對象的方法調(diào)用或者屬性變化。常用的監(jiān)聽器接口有三類:
1.Application級
對Servlet上下文進(jìn)行監(jiān)聽,用于監(jiān)聽ServletContext對象的創(chuàng)建和刪除以及屬性的添加、刪除、修改等操作,有兩個接口類:
- ServletContextAttributeListener源碼:
public interface ServletContextAttributeListener extends EventListener {// 當(dāng)程序把一個屬性存入application范圍時觸發(fā)該方法void attributeAdded(ServletContextAttributeEvent var1);// 當(dāng)程序把一個屬性從application范圍刪除時觸發(fā)該方法void attributeRemoved(ServletContextAttributeEvent var1);// 當(dāng)程序替換application范圍內(nèi)的屬性時將觸發(fā)該方法void attributeReplaced(ServletContextAttributeEvent var1);
}
- ServletContextListener,當(dāng)需要在處理任何客戶端請求之前進(jìn)行某個操作,并且希望在整個應(yīng)用過程中該操作一直可用,此時ServletContextListener接口將會起到作用。其源碼:
public interface ServletContextListener extends EventListener {// 創(chuàng)建ServletContext時,即Web應(yīng)用程序初始化后激發(fā)該方法void contextInitialized(ServletContextEvent var1);// 銷毀ServletContext時,即將結(jié)束銷毀激發(fā)該方法void contextDestroyed(ServletContextEvent var1);
}
2.Session級
對HTTP會話進(jìn)行監(jiān)聽,包括:session的創(chuàng)建和銷毀,session中屬性的增加、刪除、修改,session的active和passivate情況等,接口主要有4個:
- HttpSessionAttributeListener 該接口用于監(jiān)聽HttpSession(session)范圍內(nèi)屬性的改變,源碼:
public interface HttpSessionAttributeListener extends EventListener {// 當(dāng)在session中添加對象時觸發(fā)此操作void attributeAdded(HttpSessionBindingEvent var1);// 當(dāng)在session中刪除對象時觸發(fā)此操作void attributeRemoved(HttpSessionBindingEvent var1);// 當(dāng)在session中修改對象時觸發(fā)此操作void attributeReplaced(HttpSessionBindingEvent var1);
}
- HttpSessionListener 該接口用于監(jiān)聽session的創(chuàng)建和銷毀過程,源碼:
public interface HttpSessionListener extends EventListener {// 用戶與服務(wù)器的會話開始、創(chuàng)建時時觸發(fā)該方法void sessionCreated(HttpSessionEvent var1);// 用戶與服務(wù)器的會話斷開、銷毀時觸發(fā)該方法void sessionDestroyed(HttpSessionEvent var1);
}
一般情況下,HttpSessionActivationListener和HttpSessionBindingListener一起使用,這兩個監(jiān)聽器比較特殊,實(shí)現(xiàn)這兩個接口的類不需要在web.xml中進(jìn)行注冊,被鈍化的JavaBean對象會被持久化到存儲設(shè)備中,活化的JavaBean對象會被從存儲設(shè)備中恢復(fù),前提是該JavaBean對象實(shí)現(xiàn)Serializable接口。
- HttpSessionActivationListener 監(jiān)聽Active、unactive的事件,源碼:
public interface HttpSessionActivationListener extends EventListener {// 當(dāng)綁定到HttpSession對象中的對象將要隨HttpSession對象被鈍化之前,web服務(wù)器調(diào)用該對象的此方法void sessionWillPassivate(HttpSessionEvent var1);// 當(dāng)綁定到HttpSession對象中的對象將要隨HttpSession對象被活化之后,web服務(wù)器調(diào)用該對象的此方法void sessionDidActivate(HttpSessionEvent var1);
}
- HttpSessionBindingListener 監(jiān)聽被綁定到Session中和從Session中刪除的事件:
public interface HttpSessionBindingListener extends EventListener {// 當(dāng)對象被綁定到HttpSession對象中時,web服務(wù)器調(diào)用該對象的此方法,從而對象被設(shè)置到session中 void valueBound(HttpSessionBindingEvent var1);// 當(dāng)對象從HttpSession對象中解除綁定時,web服務(wù)器調(diào)用該對象的此方法,從而對象從session中被移除void valueUnbound(HttpSessionBindingEvent var1);
}
3.request級
對客戶端請求進(jìn)行監(jiān)聽,監(jiān)聽用戶的請求和request范圍內(nèi)屬性的變化,接口主要有2個:
- ServletRequestAttributeListener源碼:
// 用于監(jiān)聽request范圍內(nèi)屬性的變化
public interface ServletRequestAttributeListener extends EventListener {// 當(dāng)程序向request范圍內(nèi)添加屬性時觸發(fā)該方法void attributeAdded(ServletRequestAttributeEvent var1);// 當(dāng)程序在request范圍內(nèi)刪除屬性時觸發(fā)該方法void attributeRemoved(ServletRequestAttributeEvent var1);// 當(dāng)程序在request范圍內(nèi)的屬性被替換或修改時觸發(fā)該方法void attributeReplaced(ServletRequestAttributeEvent var1);
}
- ServletRequestListener源碼:
public interface ServletRequestListener extends EventListener {// 用戶請求到達(dá)、被初始化時觸發(fā)該方法void requestDestroyed(ServletRequestEvent var1);// 用戶請求結(jié)束、被銷毀時觸發(fā)該方法void requestInitialized(ServletRequestEvent var1);
}
區(qū)別
攔截器和過濾器
功能比較類似,過濾器和攔截器都是AOP的具體實(shí)現(xiàn)。區(qū)別:
攔截器是基于Java反射(動態(tài)代理)機(jī)制,過濾器是基于函數(shù)回調(diào);
攔截器不依賴與servlet容器,過濾器依賴于servlet容器;
攔截器只能對action請求起作用,而過濾器則可以對幾乎所有的請求起作用;
攔截器可以訪問action上下文、值棧里的對象,而過濾器不能訪問;
在action的生命周期中,攔截器可以多次被調(diào)用,而過濾器只能在容器初始化時被調(diào)用一次;
攔截器可以獲取IOC容器中的各個bean,而過濾器就不行,在攔截器里注入一個service,可以調(diào)用業(yè)務(wù)邏輯;
攔截器只能過濾請求,過濾器過濾范圍較大;
使用的主要是函數(shù)回調(diào),和框架無關(guān),可以控制最初的http請求,但是更細(xì)一點(diǎn)的類和方法控制不了。
一個請求過來,先由過濾器處理,看程序是否受理該請求。過濾器放過后,程序中的攔截器進(jìn)行處理, 處理完后進(jìn)入被AOP動態(tài)代理重新編譯過的主要業(yè)務(wù)類進(jìn)行處理。
Filter,Interceptor,Aspect 實(shí)際上都是對Aop的具體實(shí)現(xiàn)。都是對業(yè)務(wù)邏輯的提取。都可以實(shí)現(xiàn)權(quán)限檢查,日志記錄。不同的是使用的范圍不同,規(guī)范不同,深度不同。
過濾器和監(jiān)聽器
都是用于增強(qiáng)Web應(yīng)用的功能和擴(kuò)展性的重要組件,但它們的作用對象、觸發(fā)時機(jī)、接口實(shí)現(xiàn)以及用途有一定的差異
作用對象:過濾器作用于Servlet、JSP或其他Web資源的請求和響應(yīng)過程。它可以對請求進(jìn)行預(yù)處理,也可以對響應(yīng)進(jìn)行后處理,例如修改請求、過濾請求、修改響應(yīng)、過濾響應(yīng)等。
監(jiān)聽器則是用于監(jiān)聽Web應(yīng)用中的事件,如ServletContext、HttpSession、ServletRequest等對象的創(chuàng)建、銷毀、屬性變更等事件。
觸發(fā)時機(jī):過濾器在請求進(jìn)入Servlet之前進(jìn)行處理,也可以在響應(yīng)返回給客戶端之前進(jìn)行處理,因此它可以用來實(shí)現(xiàn)諸如權(quán)限控制、字符編碼轉(zhuǎn)換、日志記錄等功能。
監(jiān)聽器則是在特定事件發(fā)生時觸發(fā),例如 ServletContext 初始化、銷毀,HttpSession 創(chuàng)建、銷毀,ServletRequest 屬性變更等。
接口實(shí)現(xiàn):過濾器實(shí)現(xiàn)jakarta.servlet.Filter接口,重寫doFilter()方法來處理請求和響應(yīng)。
監(jiān)聽器實(shí)現(xiàn)jakarta.servlet.ServletContextListener、jakarta.servlet.http.HttpSessionListener、jakarta.servlet.ServletRequestListener等接口,根據(jù)需要監(jiān)聽相應(yīng)的事件。
用途:過濾器常用于對請求和響應(yīng)進(jìn)行過濾處理,如設(shè)置字符編碼、身份驗證、日志記錄等。
監(jiān)聽器常用于監(jiān)聽Web應(yīng)用中的事件,如初始化操作、銷毀操作、屬性變更等,用于執(zhí)行特定的邏輯。