在springboot web項目開發(fā)過程中,我們通常需要對請求與響應(yīng)的內(nèi)容請求攔截處理,如進行請求日志記錄表鳍、UA檢查、用戶權(quán)限驗證祥诽、非法內(nèi)容過濾等功能譬圣,這時候過濾器與攔截器就派上用場。
本文帶大家講解springboot如何使用過濾器與攔截器以及兩者之間的區(qū)別原押。
過濾器
Servlet 過濾器可以動態(tài)地攔截請求和響應(yīng)胁镐,以變換或使用包含在請求或響應(yīng)中的信息。過濾器是一個實現(xiàn)了 javax.servlet.Filter 接口的 Java 類诸衔。javax.servlet.Filter 接口定義了三個方法:
public interface Filter {
default void init(FilterConfig filterConfig) throws ServletException {
}
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
default void destroy() {
}
}
序號 | 方法&描敘 |
---|---|
1 |
doFilter 該方法完成實際的過濾操作盯漂,當(dāng)客戶端請求方法與過濾器設(shè)置匹配的URL時,Servlet容器將先調(diào)用過濾器的doFilter方法笨农。FilterChain用戶訪問后續(xù)過濾器就缆。 |
2 |
init web 應(yīng)用程序啟動時,web 服務(wù)器將創(chuàng)建Filter 的實例對象谒亦,并調(diào)用其init方法竭宰,讀取web.xml配置空郊,完成對象的初始化功能,從而為后續(xù)的用戶請求作好攔截的準(zhǔn)備工作(filter對象只會創(chuàng)建一次切揭,init方法也只會執(zhí)行一次)狞甚。開發(fā)人員通過init方法的參數(shù),可獲得代表當(dāng)前filter配置信息的FilterConfig對象廓旬。 |
3 |
destroy Servlet容器在銷毀過濾器實例前調(diào)用該方法哼审,在該方法中釋放Servlet過濾器占用的資源。 |
SpringBoot使用過濾器
定義了一個簡單的過濾器
@Slf4j
public class LogFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req=(HttpServletRequest)servletRequest;
log.info(req.getRequestURI());
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
使用FilterRegistrationBean注冊過濾器
@Configuration
public class LogFilterConfiguration {
@Bean
public FilterRegistrationBean registrationBean(){
FilterRegistrationBean registrationBean=new FilterRegistrationBean();
registrationBean.setFilter(new LogFilter());
//匹配的過濾器
registrationBean.addUrlPatterns("/*");
//過濾器名稱
registrationBean.setName("logFilter");
//過濾器順序
registrationBean.setOrder(1);
return registrationBean;
}
}
使用Servlet3.0注解定義過濾器
@WebFilter(urlPatterns = "/*",filterName = "authFiler")
@Slf4j
public class AuthFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
log.info("進行權(quán)限校驗.........");
chain.doFilter(servletRequest,servletResponse);
}
}
兩種方式的區(qū)別:
- WebFilter這個注解并沒有指定執(zhí)行順序的屬性孕豹,其執(zhí)行順序依賴于Filter的名稱涩盾,是根據(jù)Filter類名(注意不是配置的filter的名字)的字母順序倒序排列
- @WebFilter指定的過濾器優(yōu)先級都高于FilterRegistrationBean配置的過濾器
- FilterRegistrationBean方式可以注入SpringBoot IOC容器中的Bean
攔截器
SpringBoot攔截器Interceptor類似 面向切面編程 中的 切面 和 通知,我們通過 動態(tài)代理 對一個 service()
方法添加 通知 進行功能增強励背。比如說在方法執(zhí)行前進行 初始化處理春霍,在方法執(zhí)行后進行 后置處理。攔截器 的思想和 AOP
類似叶眉,區(qū)別就是 攔截器 只能對 Controller
的 HTTP
請求進行攔截址儒。
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
序號 | 方法&描敘 |
---|---|
1 |
preHandle 該方法在controller接收請求處理request之前執(zhí)行,返回值為 boolean竟闪,返回值為 true 時接著執(zhí)行 postHandle() 和 afterCompletion() 方法离福;如果返回false則中斷執(zhí)行。 |
2 |
postHandle 在 controller 處理請求之后炼蛤, ModelAndView 處理前執(zhí)行妖爷,可以對 響應(yīng)結(jié)果 進行修改。 |
3 |
afterCompletion 在 DispatchServlet 對本次請求處理完成理朋,即生成 ModelAndView 之后執(zhí)行絮识。 |
定義一個簡單的攔截器
@Slf4j
public class LogHandler implements HandlerInterceptor {
private NamedThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<>("StopWatch-StartTime");
public LogHandler() {
super();
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
long beginTime = System.currentTimeMillis();//1、開始時間
startTimeThreadLocal.set(beginTime);//線程綁定變量(該數(shù)據(jù)只有當(dāng)前請求的線程可見)
return true;//繼續(xù)流程
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
long endTime = System.currentTimeMillis();
long beginTime = startTimeThreadLocal.get();//得到線程綁定的局部變量(開始時間)
long consumeTime = endTime - beginTime;
//3嗽上、消耗的時間
log.info(String.format("%s consume %d millis", request.getRequestURI(), consumeTime));
}
}
注冊攔截器
@Configuration
public class HandlerConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogHandler());
}
}
過濾器與攔截器區(qū)別
序號 | 區(qū)別 |
---|---|
1 | Filter是servlet規(guī)范次舌,使用范圍是web程序,攔截器不限于web程序兽愤,也可以用于Application彼念、Swing程序中 |
2 | Filter是servlet規(guī)范中定義,是servlet容器支持的浅萧。攔截器是Spring容器內(nèi)逐沙,是spring框架支持的 |
3 | 攔截器是Spring的一個組件,能夠使用spring中對象洼畅,如Service對象吩案、數(shù)據(jù)源、事務(wù)管理帝簇、通過IOC注入容器即可徘郭,filter則不能 |
4 | filter在servlet前后起作用靠益,攔截器能夠深入方法的前后,異常拋出前后残揉。 |
5 | 在springboot項目中一般優(yōu)先使用攔截器 |
千里之行胧后,始于足下。這里是SpringBoot教程系列第十二篇抱环,所有項目源碼均可以在我的GitHub上面下載源碼绩卤。