一、過濾器和攔截器的區別
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