第5章:作為Web應用:屬性和監聽者/5.2 Servlet監聽器
-
監聽器介面彙總
- 上下文相關
- 初始化完成或者銷燬監聽器:ServletContextListener
- 新增、刪除或者替換一個屬性監聽器:ServletContextAttributeListener(屬性相關)
- 會話有關:
- 跟蹤併發使用者數量、跟蹤活動的會話監聽器:HttpSessionListener
- 物件繫結到會話或者物件從會話刪除監聽器:HttpSessionBindingListener
- 物件所繫結的會話從一個JVM遷移到另外一個JVM時通知:HttpSessionActivationListener
- 增加、刪除或者替換一個會話屬性監聽器:HttpSessionAttributeListener(屬性相關)
- 請求相關:
- 請求到來時監聽器:ServletRequestListener
- 增加、刪除或者替換一個請求屬性監聽器:ServletRequestAttributeListener(屬性相關)
-
上下文監聽器(ServletContextListener)--監聽器觸發時機
- ServletContextListener介面:
- 作用:在初始化ServletContext物件時觸發的一個事件,可用於在這個時刻建立一些全域性物件,比如資料庫連線物件。由於ServletContext初始化時Servlet還沒有形成,也就是不會接受外面的請求,所以該事件常用於在請求到來之前初始化一些物件
- 觸發時機:
- 容器在初始化完成ServletContext物件後
- 讀取web.xml檔案,如果發現監聽類實現了ServletContextListener介面(比如:MyServletContextListener類),則分別生成兩個物件
- 生成監聽類物件
- 類來源:使用者自定義類:比如 MyServletContextListener
- 類實現的介面:ServletContextListener
- 構造方法:預設無引數構造方法
- 生成事件類物件
- 類來源:容器自動生成
- 類實現的介面:ServletContextEvent
- 構造方法:引數為ServletContext物件的構造方法
- 生成監聽類物件
- 觸發後效果:使用者自定義監聽類(比如:MyServletContextListener )就擁有了ServletContext物件,進而可以通過ServletContext物件設定某些屬性到上下文中
-
上下文監聽器(ServletContextListener)--例項講解
- 例項操作
- 實體物件類
package model; public class Dog { private String string; public Dog(String str){ string = str; } public String getBeer(){ return string; } }
- 實現ServletContextListener介面的類MyServletContextListener ,生成實體物件並儲存到ServletContext屬性中
package listener; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import model.Dog; public class MyServletContextListener implements ServletContextListener{ @Override public void contextInitialized(ServletContextEvent sce){ ServletContext servletContext = sce.getServletContext(); Dog dog = new Dog(servletContext.getInitParameter("dog-desc")); //設定servletContext屬性,在servlet類中可以獲取 servletContext.setAttribute("dog", dog); System.out.println("日誌測試:在建立完成servletContext時會觸發呼叫監聽類"); } @Override public void contextDestroyed(ServletContextEvent sce){ } }
- 新建listenersc.html,跳轉到MyServletListener類的POST方法
<html> <body> <h1 align="center">Beer Selection Page</h1> <form method="POST" action="MyServletListener.do"> Select beer characteristics <p> Color: <select name="color" size="1"> <option value="light">one</option> <option value="amber">two</option> <option value="write">three</option> <option value="black">four</option> </select> <br> <br> <center> <input type="SUBMIT"> </center> </form> </body> </html>
- MyServletListenerTest類從ServletContext 屬性中獲取實體物件,並且回顯屬性到介面
package web; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import model.Dog; public class MyServletListenerTest extends HttpServlet { /** * Constructor of the object. */ public MyServletListenerTest() { super(); } /** * Destruction of the servlet. <br> */ public void destroy() { super.destroy(); // Just puts "destroy" string in log // Put your code here } /** * The doGet method of the servlet. <br> * * This method is called when a form has its tag value method equals to get. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">"); out.println("<HTML>"); out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>"); out.println(" <BODY>"); out.print(" This is "); out.print(this.getClass()); out.println(", using the GET method"); out.println(" </BODY>"); out.println("</HTML>"); out.flush(); out.close(); } /** * The doPost method of the servlet. <br> * * This method is called when a form has its tag value method equals to post. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">"); out.println("<HTML>"); out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>"); out.println(" <BODY>"); out.print(" This is "); out.print(this.getClass()); out.println(", using the POST method"); //從ServletContext中獲取Dog的屬性並且列印在介面 ServletContext servletContext = getServletContext(); try { Dog dog = (Dog)servletContext.getAttribute("dog"); String str = ""; str = dog.getBeer(); //列印Dog物件 out.println("Dog:" + str); } catch (Exception e) { // TODO: handle exception System.out.println("獲取Dog物件失敗"); } out.println(" </BODY>"); out.println("</HTML>"); out.flush(); out.close(); } /** * Initialization of the servlet. <br> * * @throws ServletException if an error occurs */ public void init() throws ServletException { // Put your code here } }
- 配置web.xml
<!-- 上下文設定 --> <context-param> <param-name>dog-desc</param-name> <param-value>my dog test</param-value> </context-param> <!-- 設定監聽類 --> <listener> <listener-class>listener.MyServletContextListener</listener-class> </listener>
- 測試:
- tomcat啟動的試試就進行了初始化
- 地址:http://localhost:8089/myWeb3/listenersc.html
- 結果:
-
上下文屬性監聽器(ServletContextAttributeListener)--觸發時機:
- ServletContextAttributeListener介面:
- 作用:監聽ServletContex物件的屬性增加、刪除、或者替換的觸發
- 觸發時機:當ServletContex物件呼叫以下幾個方法時都會觸發:
- 新增:public void setAttribute(String, Object)
- 刪除:public void removeAttribute(String)
- 替換:public void setAttribute(String, Object) 對重複的值就是替換
- 觸發結果:可獲取屬性的名稱,屬性的值對應的物件
-
上下文屬性監聽器(ServletContextAttributeListener)--例項講解
- 定義類MyServletContextAttributeListener實現ServletContextAttributeListener介面
package listener; import javax.servlet.ServletContextAttributeEvent; import javax.servlet.ServletContextAttributeListener; import model.Dog; public class MyServletContextAttributeListener implements ServletContextAttributeListener{ public void attributeAdded(ServletContextAttributeEvent scab){ System.out.println("attributeAdded:dog被這個方法呼叫時觸發:getServletContext().setAttribute"); String name = scab.getName(); if(name.equals("dog")){ Dog dog = (Dog)scab.getValue(); System.out.println("從新增屬性事件中獲取屬性物件:Dog,它的值是:"+ dog.getBeer()); } } public void attributeRemoved(ServletContextAttributeEvent scab){ System.out.println("attributeRemoved:dog被這個方法呼叫時觸發:getServletContext().RemoveAttribute"); } public void attributeReplaced(ServletContextAttributeEvent scab){ System.out.println("attributeReplaced:dog被這個方法呼叫時觸發:getServletContext().setAttribute"); } }
- 從web.xml中定義監聽類
<!-- 設定監聽類 --> <listener> <listener-class>listener.MyServletContextAttributeListener</listener-class> </listener>
- 測試重複呼叫ServletContext的setAttribute/removeAttribute方法,看觸發情況
- 方法呼叫:
//設定servletContext屬性,在servlet類中可以獲取 servletContext.setAttribute("dog", dog); //這次應該是替換 servletContext.setAttribute("dog", dog); //刪除屬性 servletContext.removeAttribute("dog"); //又新增屬性 servletContext.setAttribute("dog", dog);
- 測試結果:
attributeAdded:dog被這個方法呼叫時觸發:getServletContext().setAttribute
從新增屬性事件中獲取屬性物件:Dog,它的值是:my dog test
attributeReplaced:dog被這個方法呼叫時觸發:getServletContext().setAttribute
attributeRemoved:dog被這個方法呼叫時觸發:getServletContext().RemoveAttribute
attributeAdded:dog被這個方法呼叫時觸發:getServletContext().setAttribute
從新增屬性事件中獲取屬性物件:Dog,它的值是:my dog test
attributeAdded:dog被這個方法呼叫時觸發:getServletContext().setAttribute
- 方法呼叫:
-
會話跟蹤監聽器(HttpSessionListener)---觸發時機
- HttpSessionListener介面:
- 作用:新增會話或者銷燬會話的時候觸發
- 觸發時機:
- 新增會話:請求引數HttpServletRequest request呼叫 getSession() 方法時觸發新增會話
- 觸發結果:可進行會話儲存等操作
-
會話跟蹤監聽器(HttpSessionListener)--例項講解
- 定義類MyHttpSessionListener實現HttpSessionListener介面
package listener; import java.util.Enumeration; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class MyHttpSessionListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent se) { // TODO Auto-generated method stub HttpSession httpSession = se.getSession(); System.out.println("新建立session:" + httpSession.getId()); Enumeration<String> enumeration= httpSession.getAttributeNames(); while(enumeration.hasMoreElements()){ System.out.println(enumeration.nextElement()); } } @Override public void sessionDestroyed(HttpSessionEvent se) { // TODO Auto-generated method stub } }
- 從web.xml中定義監聽類
<!-- 設定會話建立/銷燬監聽類 --> <listener> <listener-class>listener.MyHttpSessionListener</listener-class> </listener>
- 測試在任何的servlet類中呼叫request.getSession()方法,只看到建立一個會話
- 從BeerSelect類中建立
- BeerSelect類的doPost方法獲取session
System.out.println("======進來本介面即<<BeerSelect.java>>建立會話======"); request.getSession();
- 測試結果:
======進來本介面即<<BeerSelect.java>>建立會話======
新建立session:3B82DAB9952B1100C22588E747B8ADEF
======進來本介面<<<MyServletListenerTest.java>>>即建立會話======
- BeerSelect類的doPost方法獲取session
- 從MyServletListenerTest類中建立
- MyServletListenerTest類的doPost方法獲取session
System.out.println("======進來本介面<<<MyServletListenerTest.java>>>即建立會話======"); request.getSession();
- 測試結果:
======進來本介面<<<MyServletListenerTest.java>>>即建立會話======
新建立session:3DF0918D468CD76A25DFA94440CD2265
======進來本介面即<<BeerSelect.java>>建立會話======
- MyServletListenerTest類的doPost方法獲取session
- 從BeerSelect類中建立
-
物件繫結到會話監聽器(HttpSessionBindingListener)--觸發時機
- HttpSessionBindingListener介面:
- 作用:某個物件作為引數傳入session.setAttribute或者session.RemoveAttribute方法移除該物件時觸發該物件進行相關操作,
- 觸發時機:
- 新增會話:某個物件作為引數傳入session.setAttribute
- 刪除會話:session.RemoveAttribute方法移除該物件時觸發
- 觸發結果:比如把該物件儲存起來
-
物件繫結到會話監聽器(HttpSessionBindingListener)--例項講解
- 自定義類MyHttpSessionBindingListener實現HttpSessionBindingListener介面
package listener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; public class MyHttpSessionBindingListener implements HttpSessionBindingListener { private String strString ; public MyHttpSessionBindingListener(String str){ strString = str; } @Override public void valueBound(HttpSessionBindingEvent event) { // TODO Auto-generated method stub System.out.println("MyHttpSessionBindingListener類被繫結:它的傳入引數為:"+ strString + "它的屬性名稱為:"+ event.getName()); } @Override public void valueUnbound(HttpSessionBindingEvent event) { // TODO Auto-generated method stub System.out.println("MyHttpSessionBindingListener類被取消繫結:它的傳入引數為:"+ strString + "它的屬性名稱為:"+ event.getName()); } }
- 通過session.setAttribute方法設定自定義物件
HttpSession session = request.getSession(); System.out.println("<<BeerSelect.java>>設定屬性:"); String name = "HttpSessionBindingListener——NAME"; session.setAttribute(name, new MyHttpSessionBindingListener(" OKOKOK "));
- 通過session.RemoveAttribute方法取消自定義物件
System.out.println("<<BeerSelect.java>>取消屬性:"); session.removeAttribute(name);
- 測試:
- 設定時觸發繫結事件
<<BeerSelect.java>>設定屬性:
MyHttpSessionBindingListener類被繫結:它的傳入引數為: OKOKOK 它的屬性名稱為:HttpSessionBindingListener——NAME
- 取消時觸發取繫結事件
<<BeerSelect.java>>取消屬性:
MyHttpSessionBindingListener類被取消繫結:它的傳入引數為: OKOKOK 它的屬性名稱為:HttpSessionBindingListener——NAME
- 設定時觸發繫結事件
- 注意:如果被物件被重置,也就是屬性名稱不變,但是物件變了,這時候HttpSessionBindingListener會受到兩個事件,一個是繫結事件,另外一個是原物件的取消事件