溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

過(guò)濾器Filter和攔截器HandlerIntercepter的區(qū)別及用法

發(fā)布時(shí)間:2021-06-23 09:30:06 來(lái)源:億速云 閱讀:606 作者:chen 欄目:大數(shù)據(jù)

本篇內(nèi)容介紹了“過(guò)濾器Filter和攔截器HandlerIntercepter的區(qū)別及用法”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

        最近在代碼中,看到有同事既在用攔截器又在用過(guò)濾器做登錄校驗(yàn),就覺(jué)得很暈,似乎二者都可以實(shí)現(xiàn)業(yè)務(wù)需求,但是到底采用哪種方式較好呢,二者又有什么區(qū)別?

一、原理

        1. 過(guò)濾器:

        依賴(lài)于servlet容器,在實(shí)現(xiàn)上基于函數(shù)回調(diào),可以對(duì)幾乎所有請(qǐng)求進(jìn)行過(guò)濾,一個(gè)過(guò)濾器實(shí)例只能在容器初始化時(shí)調(diào)用,它是隨你的web應(yīng)用啟動(dòng)而啟動(dòng)的,只初始化一次,以后就可以攔截相關(guān)的請(qǐng)求,只有當(dāng)你的web應(yīng)用停止或重新部署的時(shí)候才能銷(xiāo)毀。

        使用過(guò)濾器的目的是用來(lái)做一些過(guò)濾操作,獲取我們想要獲取的數(shù)據(jù),比如:在過(guò)濾器中修改字符編碼;在過(guò)濾器中修改HttpServletRequest的一些參數(shù),包括:過(guò)濾低俗文字、危險(xiǎn)字符等。

        2.攔截器:

        依賴(lài)于web框架,在SpringMVC中就是依賴(lài)于SpringMVC框架。在實(shí)現(xiàn)上基于Java的反射機(jī)制,屬于面向切面編程(AOP)的一種運(yùn)用。

        由于攔截器是基于web框架的調(diào)用,因此可以使用Spring的依賴(lài)注入(DI)進(jìn)行一些業(yè)務(wù)操作,而不用修改handler自身的實(shí)現(xiàn)。但是缺點(diǎn)是只能對(duì)controller請(qǐng)求進(jìn)行攔截,對(duì)其他的一些比如直接訪(fǎng)問(wèn)靜態(tài)資源的請(qǐng)求則沒(méi)辦法進(jìn)行攔截處理。

        3.過(guò)濾器和攔截器的區(qū)別:

    ①攔截器是基于java的反射機(jī)制的,而過(guò)濾器是基于函數(shù)回調(diào)。

    ②攔截器不依賴(lài)與servlet容器,過(guò)濾器依賴(lài)與servlet容器。

    ③攔截器只能對(duì)action請(qǐng)求起作用,而過(guò)濾器則可以對(duì)幾乎所有的請(qǐng)求起作用。

    ④攔截器可以訪(fǎng)問(wèn)action上下文、值棧里的對(duì)象,而過(guò)濾器不能訪(fǎng)問(wèn)。

    ⑤在action的生命周期中,攔截器可以多次被調(diào)用(這里是指攔截器里的三個(gè)方法是可以在一次action中的不同時(shí)期調(diào)用,細(xì)粒度控制),而過(guò)濾器只能一次請(qǐng)求過(guò)濾一次,不能在不同的生命周期里作用。

    ⑥攔截器可以獲取IOC容器中的各個(gè)bean,而過(guò)濾器就不行,這點(diǎn)很重要,在攔截器里注入一個(gè)service,可以調(diào)用業(yè)務(wù)邏輯。

二、 代碼說(shuō)明

        1. 過(guò)濾器:

在javax.servlet.Filter接口中定義了3個(gè)方法:

void init(FilterConfig filterConfig) 用于完成過(guò)濾器的初始化

void destroy() 用于過(guò)濾器銷(xiāo)毀前,完成某些資源的回收

void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) 實(shí)現(xiàn)過(guò)濾功能,該方法對(duì)每個(gè)請(qǐng)求增加額外的處理
public class FilterUtil implements Filter{  
 
 @SuppressWarnings("unused")  
 private FilterConfig filterConfig;  
 @Override 
 public void init(FilterConfig filterConfig) throws ServletException {  
 this.filterConfig = filterConfig;  
        System.out.println("過(guò)濾器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("過(guò)濾器Filter銷(xiāo)毀");  
    }  
 
}

    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)這個(gè)方法的調(diào)用作為分水嶺。事實(shí)上調(diào)用Servlet的doService()方法是在chain.doFilter(request, response)這個(gè)方法中進(jìn)行的。

        2. 攔截器:

preHandle()這個(gè)方法是在過(guò)濾器的chain.doFilter(request, response)方法的前一步執(zhí)行。

  postHandle()方法之后,在return ModelAndView之前進(jìn)行,可以操控Controller的ModelAndView內(nèi)容。

  afterCompletion()方法是在過(guò)濾器返回給前端前一步執(zhí)行,也就是在[chain.doFilter(request, response)][System.out.println("after...")]之間執(zhí)行。

        注意:重定向:會(huì)在當(dāng)前頁(yè)面代碼執(zhí)行完畢后,跳轉(zhuǎn)到指定的頁(yè)面執(zhí)行其他代碼。 轉(zhuǎn) 發(fā):在本頁(yè)面代碼執(zhí)行到轉(zhuǎn)發(fā)語(yǔ)句后,即跳轉(zhuǎn)到指定的頁(yè)面執(zhí)行其他代碼,執(zhí)行完畢后返回接著執(zhí)行轉(zhuǎn)發(fā)語(yǔ)句后的代碼。

/**
 * 用戶(hù)身份認(rèn)證的攔截器
 */
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;
	
	//在進(jìn)入目標(biāo)方法之前執(zhí)行
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		
		//用戶(hù)的身份認(rèn)證在此驗(yàn)證
		
		//1.取cookie中的token 
		//1.從cookie中獲取用戶(hù)的token 
		String token = CookieUtils.getCookieValue(request, TT_TOKEN_KEY);
		//2.判斷token是否存在,
		if(StringUtils.isEmpty(token)){
			//3.如果不存在,說(shuō)明沒(méi)登錄   ---》重定向到登錄的頁(yè)面
			//request.getRequestURL().toString():就是訪(fǎng)問(wèn)的URL localhost:8092/order/order-cart.html
			response.sendRedirect(SSO_URL+"/page/login?redirect="+request.getRequestURL().toString());
			return false;
		}
		//4.如果token存在,調(diào)用SSO的服務(wù) 查詢(xún)用戶(hù)的信息(看是否用戶(hù)已經(jīng)過(guò)期)
		TAotaoresult result = loginservice.getUserByToken(token);
		if(result.getStatus()!=200){
			//5.用戶(hù)已經(jīng)過(guò)期  --》重定向到登錄的頁(yè)面
			response.sendRedirect(SSO_URL+"/page/login?redirect="+request.getRequestURL().toString());
			return false;
		}
		//6.用戶(hù)沒(méi)過(guò)期(說(shuō)明登錄了)--》放行
		//設(shè)置用戶(hù)信息到request中 ,目標(biāo)方法的request就可以獲取用戶(hù)的信息
		request.setAttribute("USER_INFO", result.getData());
		return true;
	}
	
	//在進(jìn)入目標(biāo)方法之后,在返回modelandview之前執(zhí)行
	//共用變量的一些設(shè)置。
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		// TODO Auto-generated method stub

	}

	//返回modelandview之后,渲染到頁(yè)面之前
	//異常處理 ,清理工作
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		// TODO Auto-generated method stub

	}

}

三、執(zhí)行順序

      SpringMVC的機(jī)制是由同一個(gè)Servlet來(lái)分發(fā)請(qǐng)求給不同的Controller,其實(shí)這一步是在Servlet的service()方法中執(zhí)行的。所以過(guò)濾器、攔截器、service()方法,dispatche'r()方法的執(zhí)行順序如下

過(guò)濾器Filter和攔截器HandlerIntercepter的區(qū)別及用法

四、使用建議

        攔截器更加適合做細(xì)粒度的Handler控制,尤其是一些公共處理代碼,授權(quán)校驗(yàn)等,過(guò)濾器更加適合請(qǐng)求內(nèi)容和視圖內(nèi)容的相關(guān)處理,比如multipart 表單,GZIP壓縮等。 回頭在看之前的疑惑,最佳的解決方案是使用攔截器做登錄校驗(yàn)。

“過(guò)濾器Filter和攔截器HandlerIntercepter的區(qū)別及用法”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI