本文內容: Listener Filter 首發日期:2018-07-15 Listener 監聽器Listener負責監聽事件的發生。我們能在事件發生後執行一些自定義的操作,這就是監聽器的意義。 監聽器的本質是介面回調。 分類: 監聽域對象的創建:監聽三個域(request,session,con... ...
本文內容:
- Listener
- Filter
首發日期:2018-07-15
Listener
- 監聽器Listener負責監聽事件的發生。我們能在事件發生後執行一些自定義的操作,這就是監聽器的意義。
- 監聽器的本質是介面回調。
分類:
- 監聽域對象的創建:監聽三個域(request,session,context)的創建和銷毀 【這裡不討論這些域什麼時候創建什麼時候銷毀,因為太基礎了。】
- 監聽三個域的數據的創建:監聽三個域的數據的添加、移除、替換
- 監聽一個javabean在session域的存值的變化:監聽某個javabean在session域的值的存儲、移除、鈍化、活化
使用:
1.監聽域對象的創建與銷毀:
2.監聽三個域的數據的創建
3.監聽一個javabean在session域的存值的變化【這些監聽器不需要在web.xml中配置】【由於它要有javabean實現對應介面採用功能。但面對的對象是session,換了一個session後,並且這個session沒有那種數據,那麼是不會有響應的】
題外話:什麼是鈍化和活化,以及怎麼配置?
活化是指數據從硬碟到記憶體的過程;鈍化是指數據從記憶體到硬碟的過程。
由於數據要使用,所以數據在記憶體中沒有什麼問題。但為什麼需要鈍化呢?這是因為記憶體是有限的,一些很久不用的數據不應該占用可貴的記憶體資源。
數據預設是記憶體中的,鈍化需要進行配置(在tomcat裡面 conf/context.xml 裡面配置或在conf/Catalina/localhost/context.xml 配置或者在自己的web工程項目中的 META-INF/context.xml):【鈍化的配置還有更多參數,這裡不做詳細講解。有興趣自查。】
<Context>
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1" maxActiveSessions="1">
<Store className="org.apache.catalina.session.FileStore" directory="session"/>
</Manager>
</Context>鈍化已經配置好了,但如果想把數據重新取出來,bean必須實現Serializable.這樣才能活化成功
實現HttpSessionBindingListener介面的例子:
package work.domain; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; public class User implements HttpSessionBindingListener { private int age; private String name; private String gender; public User(int age, String name, String gender) { super(); this.age = age; this.name = name; this.gender = gender; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } @Override public void valueBound(HttpSessionBindingEvent arg0) { System.out.println("bean數據被綁定了!"); } @Override public void valueUnbound(HttpSessionBindingEvent arg0) { System.out.println("bean數據被解綁了"); } }
實現HttpSessionActivationListener介面的例子:
package work.domain; import java.io.Serializable; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionEvent; public class Person implements HttpSessionActivationListener,Serializable { private int age; private String name; private String gender; public Person(int age, String name, String gender) { super(); this.age = age; this.name = name; this.gender = gender; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } @Override public void sessionDidActivate(HttpSessionEvent arg0) { System.out.println("數據被活化了!"); } @Override public void sessionWillPassivate(HttpSessionEvent arg0) { System.out.println("數據被鈍化了!"); } }
作用:
- 由於監聽器是在事件發生後才觸發的,所以你可以自己考慮需要在事件觸發後執行哪些動作。
- 有些人會在context創建後,執行某些初始化操作。
- 有人會用session的創建來統計線上人數。【不過我覺得可能使用redis的bit可能更節省】
Filter
- Filter是過濾器的意思。
- 過濾器可以對請求進行過濾,過濾器要比Servlet早處理請求,只有過濾器對請求放行,Servlet才可以去處理請求。
- 由於過濾器可以預先處理請求,所以可以把一些任務交給過濾器來做,從而減少Servlet的處理消耗。
- 過濾器可以做到一些比如“和諧”、請求非法拒絕服務、統一數據編碼等功能。總的來說,過濾器的意義是提前處理。
使用:
1.定義一個類, 實現Filter介面(是servlet包中的Filter)
- init函數負責一些過濾器的初始化工作
- doFilter函數負責過濾工作,它有三個參數request,response, chain,request和response如你所想,它跟servlet中的沒什麼區別,chain可以理解成過濾鏈,它有一個doFilter函數,調用的時候傳入request和response,代表你對這個請求放行了!如果你不想放行就不要調用它!
- destroy函數是過濾器銷毀的時候調用的。
package work.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class MyFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("證明一下,你經過了過濾器!"); chain.doFilter(request, response);//這一步是放行! } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } }
2.在web.xml中配置過濾器:基本上與servlet的配置沒什麼區別,url-pattern也是一樣的用法。
使用註意:
- 多個過濾器的通過順序取決於web.xml中配置的過濾器的mapping的順序 。
- 在多個過濾器過濾過程中,只要有一個不通過,那麼後面的就不會再繼續了。
- 過濾器會在服務端啟動的時候就創建,會在服務端關閉時銷毀。
- web.xml中的filter-mapping中可以配置一個屬性dispatcher,它的值可以為REQUEST ,FORWARD,ERROR ,INCLUDE
-
- 這些值的意義是:REQUEST 代表只要是請求就過濾;FORWARD代表過濾所有請求轉向;ERROR代表過濾所有頁面錯誤時的跳轉;INCLUDE代表包含頁面時就過濾。
小例子:
利用過濾器來統一請求數據的編碼:
1.一般來說,對於post請求中的中文數據問題,可以使用request.setCharacterEncoding來解決,但如果每一個請求交給一個servlet來處理的話,就會在很多個servlet中加上這一個重覆多次的代碼(當然實際使用中,不會有那麼多servlet,會利用一些手段將多個功能彙集到一個servlet中)
2.所以為了處理n多個請求的編碼問題(這裡只演示一個),可以使用過濾器來統一處理。
package work.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class MyFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req=(HttpServletRequest)request; HttpServletResponse resp=(HttpServletResponse)response; String method = req.getMethod(); if("POST".equals(method)) { request.setCharacterEncoding("utf-8"); chain.doFilter(req, resp);//這一步是放行! } //簡單演示起見,不對get處理,tomcat8已經不需要了 } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } }