我們一個一個的的來!!!
一、什麼是過濾器??
過濾器就是過濾的作用,在web開發中過濾一些我們指定的url。它能夠在請求傳送給 Servlet 之前,對 ServletRequest 和 ServletResponse 做檢查和修改,起到了過濾的作用。那麼它能幫我們過濾什麼呢?那功能可就多了:
比如過攔截掉我們不需要的接口請求
修改請求(request)和響應(response)內容
完成CORS跨域請求等等。過濾器的工作流程去下圖所示:
1.1 如何在springboot中實現過濾器(兩個步驟)
第一步 自定義過濾器
由於spring boot中的過濾器屬於servlet容器,所以自定義的類必須繼承Filter接口。
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 req = (HttpServletRequest) request;
System.out.println("MyFilter: "+ req.getRequestURI());
chain.doFilter(request, response);//這裏是對請求放行,程序繼續執行!
}
@Override
public void destroy() {
}
}
ps:注意這裏需要將ServletRequest強轉爲HttpServletRequest,不然後面會出問題!!
第二步 註冊過濾器(這裏有三個方法)
方法一: 在配置類中實現一個 FilterRegistrationBean 對象
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean<MyFilter> abcFilter() {
FilterRegistrationBean<MyFilter> filterRegBean = new FilterRegistrationBean<>();
filterRegBean.setFilter(new MyFilter());//設置過濾器 對應上面的過濾器
filterRegBean.addUrlPatterns("/*"); //在這裏指定過濾地址
//如果出現多個過濾器,order可以設置過濾器執行順序。 1>2>3 這裏的LOWEST_PRECEDENCE是最低優先級
filterRegBean.setOrder(Ordered.LOWEST_PRECEDENCE);
return filterRegBean;
}
}
方法2:使用@Component 和@Order 註解註冊
@Order(Ordered.LOWEST_PRECEDENCE -1)
@Component
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 req = (HttpServletRequest) request;
System.out.println("MyFilter: "+ req.getRequestURI());
chain.doFilter(request, response);//這步使得請求能夠繼續傳導下去,如果沒有的話,請求就在此結束
}
@Override
public void destroy() {
}
}
這種方法的缺點是不能再指定 UrlPatterns,默認的 URL 模式就是/*
方法三: 使用@WebFilter 和@ServletComponentScan 註解,@WebFilter 註解是 Servlet3.0 中的註解,SpringBoot 能夠支持該註解,通過@ServletComponentScan 註解,能夠掃描並註冊到 Servlet 容器中
@WebFilter(urlPatterns="/api/*")
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 req = (HttpServletRequest) request;
System.out.println("MyFilter: "+ req.getRequestURI());
chain.doFilter(request, response);//這步使得請求能夠繼續傳導下去,如果沒有的話,請求就在此結束
}
@Override
public void destroy() {
}
}
還需要在springboot啓動類中加入@ServletComponentScan註解
@ServletComponentScan
@SpringBootApplication
public class SpringbootlearnApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootlearnApplication.class, args);
}
}
@WebFilter 方式,可以支持 UrlPatterns 的設置,但是不支持 Order 的設置。
綜上所述,第 1 種方法是最靈活的,也是最常用的一種。
二、攔截器
上面我們看了過濾的配置方法,下面我們來看一下攔截器的。網上常用的是實現HandlerInterceptor接口,這裏我用的是另一種差不多的方法繼承HandlerInterceptorAdapter。(建議用HandlerInterceptorAdapter,可以根據需求覆蓋方法)
自定義DjmIntercepter類
public class DjmIntercepter extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle調用");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
System.out.println("postHandle調用");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
}
}
ps:主要包括三個方法,preHandle是請求執行前執行的,postHandler是請求結束執行的,但只有preHandle方法返回true的時候纔會執行,afterCompletion是視圖渲染完成後才執行,同樣需要preHandle返回true,該方法通常用於清理資源等工作。afterConcurrentHandlingStarted用的比較少 大家可以自行百度!! 然後需要配置WebConfigurer類,通過實現WebMvcConfigurer接口。
WebConfigurer類 註冊自定義攔截器
@Configuration
public class WebConfigurer implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//用於攔截靜態資源
}
@Bean
public HttpMessageConverter<String> responseBodyConverter() {
return new StringHttpMessageConverter(Charset.forName("UTF-8"));
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(responseBodyConverter());
}
/**
* 這個方法用來註冊攔截器,我們自己寫好的攔截器需要通過這裏添加註冊才能生效
* @param registry 攔截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new DjmIntercepter()).addPathPatterns("/*");
super.addInterceptors(registry);
}
}
然後啓動項目,在任意地址運行。結果如下:
MyFilter: /ddddd
preHandle調用
postHandle調用
preHandle調用
postHandle調用
通過以上的例子,想必大家也知道了過濾器與攔截器的一些區別。下面我給大家總結一下:
1、過濾器和攔截器觸發時機不一樣,過濾器是在請求進入容器後,但請求進入servlet之前進行預處理的。請求結束返回也是,是在servlet處理完後,返回給前端之前。
2、攔截器可以獲取IOC容器中的各個bean,而過濾器就不行,因爲攔截器是spring提供並管理的,spring的功能可以被攔截器使用,在攔截器裏注入一個service,可以調用業務邏輯。而過濾器是JavaEE標準,只需依賴servlet api ,不需要依賴spring。
這裏有一張圖很好的展示了過濾器與攔截器的使用:
3、過濾器的實現基於回調函數。而攔截器(代理模式)的實現基於反射,代理分靜態代理和動態代理,動態代理是攔截器的簡單實現。
何時使用攔截器?何時使用過濾器?
如果是非spring項目,那麼攔截器不能用,只能使用過濾器。
如果是處理controller前後,既可以使用攔截器也可以使用過濾器。
如果是處理dispaterServlet前後,只能使用過濾器。
以上就是spring boot中過濾器與攔截器的實現與區別!!!!