您好,登錄后才能下訂單哦!
本篇內容介紹了“過濾器Filter和攔截器HandlerIntercepter的區別及用法”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
最近在代碼中,看到有同事既在用攔截器又在用過濾器做登錄校驗,就覺得很暈,似乎二者都可以實現業務需求,但是到底采用哪種方式較好呢,二者又有什么區別?
依賴于servlet容器,在實現上基于函數回調,可以對幾乎所有請求進行過濾,一個過濾器實例只能在容器初始化時調用,它是隨你的web應用啟動而啟動的,只初始化一次,以后就可以攔截相關的請求,只有當你的web應用停止或重新部署的時候才能銷毀。
使用過濾器的目的是用來做一些過濾操作,獲取我們想要獲取的數據,比如:在過濾器中修改字符編碼;在過濾器中修改HttpServletRequest的一些參數,包括:過濾低俗文字、危險字符等。
依賴于web框架,在SpringMVC中就是依賴于SpringMVC框架。在實現上基于Java的反射機制,屬于面向切面編程(AOP)的一種運用。
由于攔截器是基于web框架的調用,因此可以使用Spring的依賴注入(DI)進行一些業務操作,而不用修改handler自身的實現。但是缺點是只能對controller請求進行攔截,對其他的一些比如直接訪問靜態資源的請求則沒辦法進行攔截處理。
①攔截器是基于java的反射機制的,而過濾器是基于函數回調。
②攔截器不依賴與servlet容器,過濾器依賴與servlet容器。
③攔截器只能對action請求起作用,而過濾器則可以對幾乎所有的請求起作用。
④攔截器可以訪問action上下文、值棧里的對象,而過濾器不能訪問。
⑤在action的生命周期中,攔截器可以多次被調用(這里是指攔截器里的三個方法是可以在一次action中的不同時期調用,細粒度控制),而過濾器只能一次請求過濾一次,不能在不同的生命周期里作用。
⑥攔截器可以獲取IOC容器中的各個bean,而過濾器就不行,這點很重要,在攔截器里注入一個service,可以調用業務邏輯。
在javax.servlet.Filter接口中定義了3個方法: void init(FilterConfig filterConfig) 用于完成過濾器的初始化 void destroy() 用于過濾器銷毀前,完成某些資源的回收 void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) 實現過濾功能,該方法對每個請求增加額外的處理
public class FilterUtil implements Filter{ @SuppressWarnings("unused") private FilterConfig filterConfig; @Override public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; System.out.println("過濾器Filter初始化"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) { throw new ServletException("FilterUtil just supports HTTP requests"); } HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; httpRequest.setCharacterEncoding(this.filterConfig.getInitParameter("encoding")); httpResponse.setCharacterEncoding(this.filterConfig.getInitParameter("encoding")); chain.doFilter(httpRequest, httpResponse); } @Override public void destroy() { System.out.println("過濾器Filter銷毀"); } }
web.xml配置:
<filter> <filter-name>encodingFilter</filter-name> <!-- <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> --> <filter-class>com.cn.util.FilterUtil</filter-class> <async-supported>true</async-supported> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
chain.doFilter(request, response)這個方法的調用作為分水嶺。事實上調用Servlet的doService()方法是在chain.doFilter(request, response)這個方法中進行的。
preHandle()這個方法是在過濾器的chain.doFilter(request, response)方法的前一步執行。 postHandle()方法之后,在return ModelAndView之前進行,可以操控Controller的ModelAndView內容。 afterCompletion()方法是在過濾器返回給前端前一步執行,也就是在[chain.doFilter(request, response)][System.out.println("after...")]之間執行。
注意:重定向:會在當前頁面代碼執行完畢后,跳轉到指定的頁面執行其他代碼。 轉 發:在本頁面代碼執行到轉發語句后,即跳轉到指定的頁面執行其他代碼,執行完畢后返回接著執行轉發語句后的代碼。
/** * 用戶身份認證的攔截器 */ public class LoginInterceptor implements HandlerInterceptor { @Value("${TT_TOKEN_KEY}") private String TT_TOKEN_KEY; @Value("${SSO_URL}") private String SSO_URL; @Autowired private UserLoginService loginservice; //在進入目標方法之前執行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //用戶的身份認證在此驗證 //1.取cookie中的token //1.從cookie中獲取用戶的token String token = CookieUtils.getCookieValue(request, TT_TOKEN_KEY); //2.判斷token是否存在, if(StringUtils.isEmpty(token)){ //3.如果不存在,說明沒登錄 ---》重定向到登錄的頁面 //request.getRequestURL().toString():就是訪問的URL localhost:8092/order/order-cart.html response.sendRedirect(SSO_URL+"/page/login?redirect="+request.getRequestURL().toString()); return false; } //4.如果token存在,調用SSO的服務 查詢用戶的信息(看是否用戶已經過期) TAotaoresult result = loginservice.getUserByToken(token); if(result.getStatus()!=200){ //5.用戶已經過期 --》重定向到登錄的頁面 response.sendRedirect(SSO_URL+"/page/login?redirect="+request.getRequestURL().toString()); return false; } //6.用戶沒過期(說明登錄了)--》放行 //設置用戶信息到request中 ,目標方法的request就可以獲取用戶的信息 request.setAttribute("USER_INFO", result.getData()); return true; } //在進入目標方法之后,在返回modelandview之前執行 //共用變量的一些設置。 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // TODO Auto-generated method stub } //返回modelandview之后,渲染到頁面之前 //異常處理 ,清理工作 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // TODO Auto-generated method stub } }
SpringMVC的機制是由同一個Servlet來分發請求給不同的Controller,其實這一步是在Servlet的service()方法中執行的。所以過濾器、攔截器、service()方法,dispatche'r()方法的執行順序如下
攔截器更加適合做細粒度的Handler控制,尤其是一些公共處理代碼,授權校驗等,過濾器更加適合請求內容和視圖內容的相關處理,比如multipart 表單,GZIP壓縮等。 回頭在看之前的疑惑,最佳的解決方案是使用攔截器做登錄校驗。
“過濾器Filter和攔截器HandlerIntercepter的區別及用法”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。