java web中的攔截器、過濾器和監聽器

目錄

 

介紹一下

過濾器實現

攔截器實現

Servlet監聽器實現


介紹一下

1、過濾器和攔截器(只針對Servlet的Filter接口和SpringMVC的HandlerInterceptor接口,不針對其它實現方式,手擼服務器的大神再見)

過濾器和攔截器都是將客戶端的請求進行攔截處理,然後將請求轉交給下一資源。其處理方式如下圖所示。

攔截器和過濾都能實現相同的功能,那麼具體差別在哪裏呢? 

(現在網上很多都是相互摘抄,錯誤一大堆,感覺沒有營養,所以談談自己的使用看法,不談實現)

a、過濾器依賴web容器實現,攔截器依賴mvc框架實現,也就導致其作用順序是不同的,另外就是過濾器的作用域應該是包裹攔截器的(即過濾器在攔截器之前執行(親自驗證))。另外Filter接口提供了init()方法和destroy()方法,相對來說想在web容器初始化和銷燬的時候實現一些業務邏輯,過濾器相對簡單一些。

它們之間體現的一個包裹關係如下圖所示(圖是複製的,謝謝原圖作者)。

https://images2017.cnblogs.com/blog/330611/201710/330611-20171023144517066-24770749.png

b、在現在Spring大行其道的情況下,過濾器和攔截器都可以交給IoC管理,從而使用依賴注入(很多文章說不行,是錯誤的,但是在過濾器的init()和destroy()方法中避免使用依賴注入,因爲IoC的生命週期和web容器的生命週期是不一樣的,總之,避免在IoC沒有初始化之前去使用IoC)。在SpringMVC中封裝的攔截器靈活性更強,使用更加容易,優先考慮攔截器。

注意

Filter接口中使用的是javax.servlet.ServletRequest和javax.servlet.ServletResponse,HandlerInterceptor接口中使用的是javax.servlet.http.HttpServletRequest和javax.servlet.http.HttpServletResponse。

HttpServletRequest繼承自ServletRequest,HttpServletResponse繼承自ServletResponse。當然HttpServletRequest和HttpServletResponse功能更加強大。

在Filter中是可以將ServletRequest和ServletResponse強轉成HttpServletRequest和HttpServletResponse的。

都知道,向上轉型是絕對安全的,而向下轉型不一定安全。這裏能這麼做,是因爲它們都是接口,要獲取一個接口的實例,只能實例化它們的實現類。在tomcat中,只有一個實現類,分別是由org.apache.catalina.connector.RequestFacade和org.apache.catalina.connector.ResponseFacade去實現。

2、監聽器(這裏主指Servlet監聽器)

在Servlet中已經定義好了一些事件,監聽器主要作用於監聽Servlet的有效事件。作用是監聽由於Web應用中狀態改變而引起的Servlet容器產生的相應事件,然後接受並處理這些事件。

過濾器實現

爲了方便,在SpringBoot項目中實現。

1、實現Filter接口

//@Order(value=1) 用於多個Filter指定過濾器順序
@WebFilter(filterName="myFilter1", urlPatterns= {"/*"})//標記過濾器,攔截所有請求
public class MyFilter1 implements Filter {
	
	/**
	 * 	過濾器初始化方法,該方法在過濾器初始化時調用(即容器加載時)
	 * 	@param filterConfig  FilterConfig也是接口對象 由Servlet容器實現,主要
	 * 			用於獲取過濾器中的配置信息,其常用方法聲明如下:
	 * 			String getFilterName 獲取過濾器名字
	 * 			ServletContext getServletContext() 獲取Servlet上下文
	 * 			String getInitParameter(String name) 獲取過濾器的初始化參數值
	 * 			Enumeration getInitParameterNames() 獲取過濾器的所有初始化參數
	 * */
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		//TODO 沒有業務邏輯則不寫相應的實現
	}

	/**
	 * 	對請求進行過濾處理(也就是主要實現過濾功能的方法)
	 * 	@param chain FilterChain接口也是由Servlet容器實現。
	 * 			其只有一個方法,如下:
	 * 			void doFilter(ServletRequest request, ServletResponse response)
	 * 			該方法用於將過濾後的請求傳遞給下一個過濾器。如果是最後一個過濾器,則將請求轉交給目標資源。
     * @param request ServletRequest可強轉爲HttpServletRequest ,其都由Servlet實現
	 * @param response ServletResponse可強轉爲HttpServletResponse,因爲其都由Servlet實現
	 * */
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		//TODO 具體的過濾邏輯實現--比如登錄權限驗證、字符編碼過濾等
		
		/*
		 * 	將請求轉交給下一過濾器或其它目標資源
		 * 	注:如果沒有調用此方法,則請求會在此處終止(也不會響應客戶端)。
		 * 	可以直接使用response直接響應客戶端(比如在權限驗證不通過的時候)。
		 * */
		chain.doFilter(request, response);
	}

	/**
	 * 	過濾器銷燬方法,以便釋放資源(即關閉容器時調用)
	 * */
	@Override
	public void destroy() {
		//TODO 沒有業務邏輯則不寫相應的實現
	}
}

2、在啓動類上加上Servlet註解掃描

@SpringBootApplication
@ServletComponentScan//Servlet註解掃描
public class App {

	public static void main(String[] args) {
		SpringApplication.run(App.class, args);
	}
}

攔截器實現

爲了方便,在SpringBoot項目中實現。

1、實現HandlerInterceptor接口

/**
 * 	可將其標記爲Spring的組件
 * 	或在註冊攔截器的時候利用構造方法傳遞其它Spring的組件(如其它Service層或Dao層)
 * */
//@Order(value=1)//用於多個攔截器指定執行順序
public class MyHandlerInterceptor1 implements HandlerInterceptor {

	/**
	 *  <p>該方法就是進行攔截處理的,將在Controller方法處理之前調用
	 *  <p>該方法返回True時攔截器纔會繼續往下執行,返回false則會結束整個請求
	 *  <p>可以直接使用response或全局異常攔截直接響應客戶端
	 * */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// TODO 具體的攔截邏輯 --比如登錄權限校驗、非法敏感字符校驗等
		//根據不同的邏輯返回boolean類型即可  也可直接使用response或全局異常攔截直接響應客戶端
		return HandlerInterceptor.super.preHandle(request, response, handler);
	}

	/**
	 *  <p>該方法將在處理請求完成後(即Controller方法調用之後)視圖渲染之前的處理操作
	 *  <p>該方法只能在當前類的preHandle()方法返回true時纔會執行
	 * */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		// TODO 沒有相關業務邏輯 則不用重寫此方法
		HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
	}

	/**
	 * <p>該方法將在整個請求和相應動作完成之後執行(即視圖渲染之後)
	 * <p>該方法只能在當前類的preHandle()方法返回true時纔會執行
	 * */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		// TODO 沒有相關業務邏輯 則不用重寫此方法
		HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
	}
}

2、註冊攔截器,實現WebMvcConfigurer接口。

@Configuration
public class InterceptConfig implements WebMvcConfigurer {

	@Override
    public void addInterceptors(InterceptorRegistry registry) {
		//註冊攔截器 可利用構造方法傳遞一些參數
		registry.addInterceptor(new MyHandlerInterceptor1())
				//攔截所有請求
                .addPathPatterns("/**");
                //還可排除一些靜態資源請求攔截
                //.excludePathPatterns(null);
}

Servlet監聽器實現

1、實現Servlet中定義的監聽器接口,如ServletContextListener(Servlet還定義了其它監聽器)

/**
 * <p>Servlet監聽器
 * <p>@WebListener註解只有一個屬性 用於描述這個監聽器 可以默認不要
 * */
@WebListener(value = "監聽Servlet上下文的創建和刪除")
public class MyListener implements ServletContextListener {

	/**
	 * <p>通知正在收聽的對象,應用程序已經被加載及初始化
	 * */
	@Override
	public void contextInitialized(ServletContextEvent sce) {
		//TODO 沒有相應的業務邏輯 則不寫實現
	}

	/**
	 * <p>通知正在收聽的對象,應用程序已經被銷燬(即關閉)
	 * */
	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		//TODO 沒有相應的業務邏輯 則不寫實現
	}
}

2、在啓動類上加上Servlet註解掃描

@SpringBootApplication
@ServletComponentScan//Servlet註解掃描
public class App {

	public static void main(String[] args) {
		SpringApplication.run(App.class, args);
	}
}

3、Servlet其它監聽器

Servlet監聽器的功能就是監聽由於Web應用中狀態改變而引起的Servlet容器產生的相應事件,

比如利用HttpSessionBindingListener統計在線人數

除了上述的ServletContextListener,還有以下監聽器(共8個)。如下表所示:

Servlet上下文監聽 ServletContextListener  主要監聽Servlet上下文的創建和刪除
ServletContextAttributeListener 主要監聽Servlet上下文屬性的增加、刪除和修改
HTTP會話監聽 HttpSessionListener 主要監聽HTTP會話創建和銷燬
HttpSessionActivationListener 實現監聽HTTP會話active和passivate
HttpSessionAttributeListener 實現監聽HTTP會話中屬性的設置請求
HttpSessionBindingListener 實現監聽HTTP會話中對象的綁定信息
Servlet請求監聽 ServletRequestListener 實現監聽客戶端的請求
ServletRequestAttributeListener 實現講臺客戶端請求屬性變化

ServletContextAttributeListener

public class MyListener2 implements ServletContextAttributeListener {

	/**
	 * <p>當有對象加入Application範圍時,通知正在收聽的對象
	 * */
	@Override
	public void attributeAdded(ServletContextAttributeEvent scae) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>當有對象從Application範圍中移除,通知正在收聽的對象
	 * */
	@Override
	public void attributeRemoved(ServletContextAttributeEvent scae) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>擋在Application的範圍有對象取代另一個對象時,通知正在收聽的對象
	 * */
	@Override
	public void attributeReplaced(ServletContextAttributeEvent scae) {
		// TODO Auto-generated method stub
	}
}

HttpSessionListener

public class MyListener2 implements HttpSessionListener {

	/**
	 * <p>通知正在收聽的對象,session已經被加載及初始化
	 * */
	@Override
	public void sessionCreated(HttpSessionEvent se) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>通知正在收聽的對象,session已經被載出銷燬
	 * @param se HttpSessionEvent的主要方法是getSession(),可以使用
	 * 	該方法回傳一個session對象
	 * */
	@Override
	public void sessionDestroyed(HttpSessionEvent se) {
		// TODO Auto-generated method stub
	}
}

HttpSessionActivationListener

public class MyListener2 implements HttpSessionActivationListener {

	/**
	 * <p>通知正在收聽的對象,它的session已經被變爲無效狀態
	 * */
	@Override
	public void sessionWillPassivate(HttpSessionEvent se) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>通知正在收聽的對象,它的session已經變爲有效狀態
	 * */
	@Override
	public void sessionDidActivate(HttpSessionEvent se) {
		// TODO Auto-generated method stub
	}
}

HttpSessionAttributeListener

public class MyListener2 implements HttpSessionAttributeListener {

	/**
	 * <p>當有對象加入session範圍時,通知正在收聽的對象
	 * */
	@Override
	public void attributeAdded(HttpSessionBindingEvent se) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>當有對象從session範圍移除時,通知正在收聽的對象
	 * @param se HttpSessionBindingEvent類主要有3個方法
	 * getName()、getSession()、getValues()
	 * */
	@Override
	public void attributeRemoved(HttpSessionBindingEvent se) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>當在session的範圍有對象取代另一個對象時,通知正在收聽的對象
	 * */
	@Override
	public void attributeReplaced(HttpSessionBindingEvent se) {
		// TODO Auto-generated method stub
	}
}

HttpSessionBindingListener

public class MyListener2 implements HttpSessionBindingListener {

	/**
	 * <p>當有對象加入session範圍時會被自動調用
	 * */
	@Override
	public void valueBound(HttpSessionBindingEvent event) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>當有對象從session的範圍內移除時會被自動調用
	 * */
	@Override
	public void valueUnbound(HttpSessionBindingEvent event) {
		// TODO Auto-generated method stub
	}
}

ServletRequestListener

public class MyListener2 implements ServletRequestListener {

	/**
	 * <p>通知正在收聽的對象,ServletRequest已經被加載及初始化
	 * */
	@Override
	public void requestInitialized(ServletRequestEvent sre) {
		// TODO Auto-generated method stub
	}
	
	/**
	 * <p>通知正在收聽的對象,ServletRequest已經被載出銷燬
	 * */
	@Override
	public void requestDestroyed(ServletRequestEvent sre) {
		// TODO Auto-generated method stub
	}
}

ServletRequestAttributeListener

public class MyListener2 implements ServletRequestAttributeListener {

	/**
	 * <p>當有對象加入request範圍時,通知正在收聽的對象
	 * */
	@Override
	public void attributeAdded(ServletRequestAttributeEvent srae) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>當有對象從request範圍移除時,通知正在收聽的對象
	 * */
	@Override
	public void attributeRemoved(ServletRequestAttributeEvent srae) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>當在request範圍內有對象取代另一個對象時,通知正在收聽的對象
	 * */
	@Override
	public void attributeReplaced(ServletRequestAttributeEvent srae) {
		// TODO Auto-generated method stub
	}
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章