一、過濾器和攔截器的區別
1、過濾器和攔截器觸發時機不一樣,過濾器是在請求進入容器后,但請求進入servlet之前進行預處理的,請求結束回傳也是,是在servlet處理完后,回傳給前端之前,
2、攔截器可以獲取IOC容器中的各個bean,而過濾器就不行,因為攔截器是spring提供并管理的,spring的功能可以被攔截器使用,在攔截器里注入一個service,可以呼叫業務邏輯,而過濾器是JavaEE標準,只需依賴servlet api ,不需要依賴spring,
3、過濾器的實作基于回呼函式,而攔截器(代理模式)的實作基于反射
4、Filter是依賴于Servlet容器,屬于Servlet規范的一部分,而攔截器則是獨立存在的,可以在任何情況下使用,
5、Filter的執行由Servlet容器回呼完成,而攔截器通常通過動態代理(反射)的方式來執行,
6、Filter的生命周期由Servlet容器管理,而攔截器則可以通過IoC容器來管理,因此可以通過注入等方式來獲取其他Bean的實體,因此使用會更方便,
過濾器和攔截器非常相似,但是它們有很大的區別
最簡單明了的區別就是**過濾器可以修改request,而攔截器不能
過濾器需要在servlet容器中實作,攔截器可以適用于javaEE,javaSE等各種環境
攔截器可以呼叫IOC容器中的各種依賴,而過濾器不能
過濾器只能在請求的前后使用,而攔截器可以詳細到每個方法**
區別很多,大家可以去查下
總的來說
過濾器就是篩選出你要的東西,比如requeset中你要的那部分
攔截器在做安全方面用的比較多,比如終止一些流程
網上有一張圖片很不錯,這里拷過來給大家看一下
過濾器(Filter) :可以拿到原始的http請求,但是拿不到你請求的控制器和請求控制器中的方法的資訊,
攔截器(Interceptor):可以拿到你請求的控制器和方法,卻拿不到請求方法的引數,
切片(Aspect): 可以拿到方法的引數,但是卻拿不到http請求和回應的物件
二、過濾器
兩種方式:
1、使用spring boot提供的FilterRegistrationBean注冊Filter
2、使用原生servlet注解定義Filter
兩種方式的本質都是一樣的,都是去FilterRegistrationBean注冊自定義Filter
方式一: (使用spring boot提供的FilterRegistrationBean注冊Filter )
①、先定義Filter:
package com.corwien.filter; import javax.servlet.*; import java.io.IOException; public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // do something 處理request 或response // doFilter()方法中的servletRequest引數的型別是ServletRequest,需要轉換為HttpServletRequest型別方便呼叫某些方法 System.out.println("filter1"); // 呼叫filter鏈中的下一個filter HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; String ip = request.getRemoteAddr(); String url = request.getRequestURL().toString(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date d = new Date(); String date = sdf.format(d); System.out.printf("%s %s 訪問了 %s%n", date, ip, url); filterChain.doFilter(request, response); } @Override public void destroy() { } }
②、注冊自定義Filter
@Configuration public class FilterConfig { @Bean public FilterRegistrationBean registrationBean() { ** FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new** **MyFilter());** filterRegistrationBean.addUrlPatterns("/*"); return filterRegistrationBean; } }
方式一的①②步驟可以用下面這段代碼代替:
@Configuration public class FilterConfig { @Bean public **FilterRegistrationBean** registFilter() { **FilterRegistrationBean registration** **= new FilterRegistrationBean(); registration.setFilter(new** **LogCostFilter());** registration.addUrlPatterns("/*"); registration.setName("LogCostFilter"); registration.setOrder(1); return registration; } }
public class LogCostFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { long start = System.currentTimeMillis(); filterChain.doFilter(servletRequest,servletResponse); System.out.println("Execute cost="+(System.currentTimeMillis()-start)); } @Override public void destroy() { }
方式二:(使用原生servlet注解定義Filter )
// 注入spring容器 @Component // 定義filterName 和過濾的url @WebFilter(filterName = "my2Filter" ,urlPatterns = "/*") public class My2Filter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("filter2"); } @Override public void destroy() { } }
這里直接用@WebFilter就可以進行配置,同樣,可以設定url匹配模式,過濾器名稱等,這里需要注意一點的是@WebFilter這個注解是Servlet3.0的規范,并不是Spring boot提供的,除了這個注解以外,我們還需在啟動類中加另外一個注解:@ServletComponetScan,指定掃描的包,
三、攔截器的配置
實作攔截器可以通過繼承 HandlerInterceptorAdapter類也可以通過實作HandlerInterceptor這個介面,另外,如果preHandle方法return true,則繼續后續處理,
首先我們實作攔截器類:
public class LogCostInterceptor implements HandlerInterceptor { long start = System.currentTimeMillis(); @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { start = System.currentTimeMillis(); return true; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { System.out.println("Interceptor cost="+(System.currentTimeMillis()-start)); } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }
我們還需要實作HandlerInterceptor這個介面,這個介面包括三個方法,preHandle是請求執行前執行的,postHandler是請求結束執行的,但只有preHandle方法回傳true的時候才會執行,afterCompletion是視圖渲染完成后才執行,同樣需要preHandle回傳true,該方法通常用于清理資源等作業,除了實作上面的介面外,我們還需對其進行配置:
@Configuration public class InterceptorConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LogCostInterceptor()).addPathPatterns("/**"); super.addInterceptors(registry); } }
這里我們繼承了WebMVCConfigurerAdapter,這里我們重寫了addInterceptors這個方法,進行攔截器的配置,主要配置項就兩個,一個是指定攔截器,第二個是指定攔截的URL,
坑坑坑:
攔截器不生效常見問題:
1)是否有加@Configuration
2)攔截路徑是否有問題 ** 和 *
3)攔截器最后路徑一定要 “/**”, 如果是目錄的話則是 /*/
總結一下:創建攔截器需要兩步:
1、自定義攔截器
2、注冊攔截器
四、應用場景
攔截器是在DispatcherServlet這個servlet中執行的,因此所有的請求最先進入Filter,最后離開Filter,其順序如下,
Filter->Interceptor.preHandle->Handler->Interceptor.postHandle->Interceptor.afterCompletion->Filter
攔截器應用場景
攔截器本質上是面向切面編程(AOP),符合橫切關注點的功能都可以放在攔截器中來實作,主要的應用場景包括:
-
登錄驗證,判斷用戶是否登錄,
-
權限驗證,判斷用戶是否有權限訪問資源,如校驗token
-
日志記錄,記錄請求操作日志(用戶ip,訪問時間等),以便統計請求訪問量,
-
處理cookie、本地化、國際化、主題等,
-
性能監控,監控請求處理時長等,
-
通用行為:讀取cookie得到用戶資訊并將用戶物件放入請求,從而方便后續流程使用,還有如提取Locale、Theme資訊等,只要是多個處理器都需要的即可使用攔截器實作)
過濾器應用場景
1)過濾敏感詞匯(防止sql注入)
2)設定字符編碼
3)URL級別的權限訪問控制
4)壓縮回應資訊
看完三件事??
如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:
-
點贊,轉發,有你們的 『點贊和評論』,才是我創造的動力,
-
關注公眾號 『 java爛豬皮 』,不定期分享原創知識,
-
同時可以期待后續文章ing??
作者:Corwien
出處: https://segmentfault.com/a/1190000037755221
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/226041.html
標籤:其他
