七、監聽器和國際化
Servlet
Listener
Filter
一、JavaWeb監聽器
-
它是一個介面,內容由我們來實現;
-
它需要註冊,例如註冊在按鈕上!
-
監聽器中的方法,會在特殊事件發生時被呼叫!
觀察者:
-
事件源:小偷
-
事件:偷東西
-
監聽器:警察;監聽器中的方法:抓捕
JavaWeb中的監聽器
事件源:三大域
-
ServletContext
-
生命週期監聽:
ServletContextListener
,它有兩個方法,一個在出生時呼叫,一個在死亡時呼叫
//建立SErvletcontext時 void contextInitialized(ServletContextEvent sce)://銷燬Servletcontext時 void contextDestroyed(ServletContextEvent sce):
-
¨屬性監聽:ServletContextAttributeListener,它有三個方法,一個在新增屬性時呼叫,一個在替換屬性時呼叫,最後一個是在移除屬性時呼叫。
//新增屬性時; void attributeAdded(ServletContextAttributeEvent event): //替換屬性時; void attributeReplaced(ServletContextAttributeEvent event): //移除屬性時; void attributeRemoved(ServletContextAttributeEvent event):
-
HttpSession
-
生命週期監聽:HttpSessionListener,它有兩個方法,一個在出生時呼叫,一個在死亡時呼叫;
//建立session時 void sessionCreated(HttpSessionEvent se): //銷燬session時 void sessionDestroyed(HttpSessionEvent se):
-
屬性監聽:HttpSessioniAttributeListener,它有三個方法,一個在新增屬性時呼叫,一個在替換屬性時呼叫,最後一個是在移除屬性時呼叫。
//新增屬性時; void attributeAdded(HttpSessionBindingEvent event)://替換屬性時 void attributeReplaced(HttpSessionBindingEvent event): //移除屬性時 void attributeRemoved(HttpSessionBindingEvent event):
-
ServletRequest
-
生命週期監聽:ServletRequestListener,它有兩個方法,一個在出生時呼叫,一個在死亡時呼叫
-
//建立request時 void requestInitialized(ServletRequestEvent sre): //銷燬request時 void requestDestroyed(ServletRequestEvent sre):
-
屬性監聽:ServletRequestAttributeListener,它有三個方法,一個在新增屬性時呼叫,一個在替換屬性時呼叫,最後一個是在移除屬性時呼叫
//新增屬性時 void attributeAdded(ServletRequestAttributeEvent srae): //替換屬性時 void attributeReplaced(ServletRequestAttributeEvent srae): //移除屬性時 void attributeRemoved(ServletRequestAttributeEvent srae):
javaWeb中完成編寫監聽器
-
寫一個監聽器類:要求必須去實現某個監聽器介面;
-
註冊,是在web.xml中配置來完成註冊!
1.1、JavaWeb監聽器概述
在JavaWeb被監聽的事件源為:ServletContext、HttpSession、ServletRequest,即三大域物件。
-
監聽域物件“建立”與“銷燬”的監聽器;
-
監聽域物件“操作域屬性”的監聽器;
-
監聽HttpSession的監聽器。
1.2、建立與銷燬監聽器
建立與銷燬監聽器一共有三個:
-
ServletContextListener:Tomcat啟動和關閉時呼叫下面兩個方法
-
public void contextInitialized(ServletContextEvent evt):ServletContext物件被建立後呼叫;
-
public void contextDestroyed(ServletContextEvent evt):ServletContext物件被銷燬前呼叫;
-
-
HttpSessionListener:開始會話和結束會話時呼叫下面兩個方法
-
public void sessionCreated(HttpSessionEvent evt):HttpSession物件被建立後呼叫;
-
public void sessionDestroyed(HttpSessionEvent evt):HttpSession物件被銷燬前呼叫;
-
-
ServletRequestListener:開始請求和結束請求時呼叫下面兩個方法
-
public void requestInitiallized(ServletRequestEvent evt):ServletRequest物件被建立後呼叫;
-
public void requestDestroyed(ServletRequestEvent evt):ServletRequest物件被銷燬前呼叫。
-
1.3、事件物件
-
ServletContextEvent:ServletContext getServletContext();
-
HttpSeessionEvent:HttpSession getSession();
-
ServletRequestEvent:
-
ServletRequest getServletRequest()
-
ServletContext getServletContext()
-
編寫測試例子:
-
編寫MyServletContextListener類,實現ServletContextListener介面;
-
在web.xml檔案中部署監聽器;
-
為了看到session銷燬的效果,在web.xml檔案中設定session失效時間為1分鐘;
/* * ServletContextListener實現類 * contextDestroyed() -- 在ServletContext物件被銷燬前呼叫 * contextInitialized() -- -- 在ServletContext物件被建立後呼叫 * ServletContextEvent -- 事件類物件 * 該類有getServletContext(),用來獲取ServletContext物件,即獲取事件源物件 */ public class MyServletContextListener implements ServletContextListener { public void contextDestroyed(ServletContextEvent evt) { System.out.println("銷燬ServletContext物件"); } public void contextInitialized(ServletContextEvent evt) { System.out.println("建立ServletContext物件"); } }
/* * HttpSessionListener實現類 * sessionCreated() -- 在HttpSession物件被建立後被呼叫 * sessionDestroyed() -- -- 在HttpSession物件被銷燬前呼叫 * HttpSessionEvent -- 事件類物件 * 該類有getSession(),用來獲取當前HttpSession物件,即獲取事件源物件 */ public class MyHttpSessionListener implements HttpSessionListener { public void sessionCreated(HttpSessionEvent evt) { System.out.println("建立session物件"); } public void sessionDestroyed(HttpSessionEvent evt) { System.out.println("銷燬session物件"); } }
/* * ServletRequestListener實現類 * requestDestroyed() -- 在ServletRequest物件被銷燬前呼叫 * requestInitialized() -- 在ServletRequest物件被建立後呼叫 * ServletRequestEvent -- 事件類物件 * 該類有getServletContext(),用來獲取ServletContext物件 * 該類有getServletRequest(),用來獲取當前ServletRequest物件,即事件源物件 */ public class MyServletRequestListener implements ServletRequestListener { public void requestDestroyed(ServletRequestEvent evt) { System.out.println("銷燬request物件"); } public void requestInitialized(ServletRequestEvent evt) { System.out.println("建立request物件"); } }
<listener> <listener-class>cn.jdy.listener.MyServletContextListener</listener-class> </listener> <listener> <listener-class>cn.jdy.listener.MyHttpSessionListener</listener-class> </listener> <listener> <listener-class>cn.jdy.listener.MyServletRequestListener</listener-class> </listener> <session-config> <session-timeout>1</session-timeout> </session-config>
1.4、操作域屬性的監聽器
當對域屬性進行增、刪、改時,執行的監聽器一共有三個:
-
ServletContextAttributeListener:在ServletContext域進行增、刪、改屬性時呼叫下面方法。
-
public void attributeAdded(ServletContextAttributeEvent evt)
-
public void attributeRemoved(ServletContextAttributeEvent evt)
-
public void attributeReplaced(ServletContextAttributeEvent evt)
-
-
HttpSessionAttributeListener:在HttpSession域進行增、刪、改屬性時呼叫下面方法
-
public void attributeAdded(HttpSessionBindingEvent evt)
-
public void attributeRemoved (HttpSessionBindingEvent evt)
-
public void attributeReplaced (HttpSessionBindingEvent evt)
-
-
ServletRequestAttributeListener:在ServletRequest域進行增、刪、改屬性時呼叫下面方法
-
public void attributeAdded(ServletRequestAttributeEvent evt)
-
public void attributeRemoved (ServletRequestAttributeEvent evt)
-
public void attributeReplaced (ServletRequestAttributeEvent evt)
-
下面對這三個監聽器的事件物件功能進行介紹:
-
ServletContextAttributeEvent
-
String getName():獲取當前操作的屬性名;
-
Object getValue():獲取當前操作的屬性值;
-
ServletContext getServletContext():獲取ServletContext物件。
-
-
HttpSessionBindingEvent
-
String getName():獲取當前操作的屬性名;
-
Object getValue():獲取當前操作的屬性值;
-
HttpSession getSession():獲取當前操作的session物件。
-
-
ServletRequestAttributeEvent
-
String getName():獲取當前操作的屬性名;
-
Object getValue():獲取當前操作的屬性值;
-
ServletContext getServletContext():獲取ServletContext物件;
-
ServletRequest getServletRequest():獲取當前操作的ServletRequest物件。
-
public class MyListener implements ServletContextAttributeListener, ServletRequestAttributeListener, HttpSessionAttributeListener { public void attributeAdded(HttpSessionBindingEvent evt) { System.out.println("向session中新增屬性:" + evt.getName() + "=" + evt.getValue()); } public void attributeRemoved(HttpSessionBindingEvent evt) { System.out.println("從session中移除屬性:" + evt.getName() + "=" + evt.getValue()); } public void attributeReplaced(HttpSessionBindingEvent evt) { System.out.println("修改session中的屬性:" + evt.getName() + "=" + evt.getValue()); } public void attributeAdded(ServletRequestAttributeEvent evt) { System.out.println("向request中新增屬性:" + evt.getName() + "=" + evt.getValue()); } public void attributeRemoved(ServletRequestAttributeEvent evt) { System.out.println("從request中移除屬性:" + evt.getName() + "=" + evt.getValue()); } public void attributeReplaced(ServletRequestAttributeEvent evt) { System.out.println("修改request中的屬性:" + evt.getName() + "=" + evt.getValue()); } public void attributeAdded(ServletContextAttributeEvent evt) { System.out.println("向context中新增屬性:" + evt.getName() + "=" + evt.getValue()); } public void attributeRemoved(ServletContextAttributeEvent evt) { System.out.println("從context中移除屬性:" + evt.getName() + "=" + evt.getValue()); } public void attributeReplaced(ServletContextAttributeEvent evt) { System.out.println("修改context中的屬性:" + evt.getName() + "=" + evt.getValue()); } }
public class ListenerServlet extends BaseServlet { public String contextOperation(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext context = this.getServletContext(); context.setAttribute("a", "a"); context.setAttribute("a", "A"); context.removeAttribute("a"); return "/index.jsp"; } /////////////////////////////// public String sessionOperation(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); session.setAttribute("a", "a"); session.setAttribute("a", "A"); session.removeAttribute("a"); return "/index.jsp"; } /////////////////////////////// public String requestOperation(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setAttribute("a", "a"); request.setAttribute("a", "A"); request.removeAttribute("a"); return "/index.jsp"; } }
<body> <a href="<c:url value='/ListenerServlet?method=contextOperation'/>">SevletContext操作屬性</a> <br/> <a href="<c:url value='/ListenerServlet?method=sessionOperation'/>">HttpSession操作屬性</a> <br/> <a href="<c:url value='/ListenerServlet?method=requestOperation'/>">ServletRequest操作屬性</a> | </body>
1.5、HttpSession的監聽器
還有兩個與HttpSession相關的特殊的監聽器,這兩個監聽器的特點如下:
-
不用在web.xml檔案中部署;
-
這兩個監聽器不是給session新增,而是給Bean新增。即讓Bean類實現監聽器介面,然後再把Bean物件新增到session域中。
下面對這兩個監聽器介紹一下:
-
HttpSessionBindingListener:當某個類實現了該介面後,可以感知本類物件新增到session中,以及感知從session中移除。例如讓Person類實現HttpSessionBindingListener介面,那麼當把Person物件新增到session中,或者把Person物件從session中移除時會呼叫下面兩個方法:
-
public void valueBound(HttpSessionBindingEventevent):當把監聽器物件新增到session中會呼叫監聽器物件的本方法;
-
public void valueUnbound(HttpSessionBindingEvent event):當把監聽器物件從session中移除時會呼叫監聽器物件的本方法;
-
這裡要注意,HttpSessionBindingListener監聽器的使用與前面介紹的都不相同,當該監聽器物件新增到session中,或把該監聽器物件從session移除時會呼叫監聽器中的方法。並且無需在web.xml檔案中部署這個監聽器。
示例步驟:
-
編寫Person類,讓其實現HttpSessionBindingListener監聽器介面;
-
編寫Servlet類,一個方法向session中新增Person物件,另一個從session中移除Person物件;
-
在index.jsp中給出兩個超連結,分別訪問Servlet中的兩個方法。
public class Person implements HttpSessionBindingListener { private String name; private int age; private String sex; public Person(String name, int age, String sex) { super(); this.name = name; this.age = age; this.sex = sex; } public Person() { super(); } public String toString() { return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public void valueBound(HttpSessionBindingEvent evt) { System.out.println("把Person物件存放到session中:" + evt.getValue()); } public void valueUnbound(HttpSessionBindingEvent evt) { System.out.println("從session中移除Pseron物件:" + evt.getValue()); } }
public class ListenerServlet extends BaseServlet { public String addPerson(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Person p = new Person("zhangSan", 23, "male"); request.getSession().setAttribute("person", p); return "/index.jsp"; } public String removePerson(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.getSession().removeAttribute("person"); return "/index.jsp"; }
<body> <a href="<c:url value='/ListenerServlet?method=addPerson'/>">addPerson</a> <br/> <a href="<c:url value='/ListenerServlet?method=removePerson'/>">removePerson</a> <br/> </body>
-
HttpSessionActivationListener:Tomcat會在session從時間不被使用時鈍化session物件,所謂鈍化session,就是把session通過序列化的方式儲存到硬碟檔案中。當用戶再使用session時,Tomcat還會把鈍化的物件再活化session,所謂活化就是把硬碟檔案中的session在反序列化回記憶體。當session被Tomcat鈍化時,session中儲存的物件也被純化,當session被活化時,也會把session中儲存的物件活化。如果某個類實現了HttpSessionActiveationListener介面後,當物件隨著session被鈍化和活化時,下面兩個方法就會被呼叫:
-
public void sessionWillPassivate(HttpSessionEvent se):當物件感知被活化時呼叫本方法;
-
public void sessionDidActivate(HttpSessionEvent se):當物件感知被鈍化時呼叫本方法;
-
HttpSessionActivationListener監聽器與HttpSessionBindingListener監聽器相似,都是感知型的監聽器,例如讓Person類實現了HttpSessionActivationListener監聽器介面,並把Person物件新增到了session中後,當Tomcat鈍化session時,同時也會鈍化session中的Person物件,這時Person物件就會感知到自己被鈍化了,其實就是呼叫Person物件的sessionWillPassivate()方法。當用戶再次使用session時,Tomcat會活化session,這時Person會感知到自己被活化,其實就是呼叫Person物件的sessionDidActivate()方法。
注意,因為鈍化和活化session,其實就是使用序列化和反序列化技術把session從記憶體儲存到硬碟,和把session從硬碟載入到記憶體。這說明如果Person類沒有實現Serializable介面,那麼當session鈍化時就不會鈍化Person,而是把Person從session中移除再鈍化!這也說明session活化後,session中就不在有Person物件了。
示例步驟:
-
先不管HttpSessionActivationListener監聽器介面,先來配置Tomcat鈍化session的引數,把下面配置檔案放到tomcat\conf\catalina\localhost目錄下!檔名稱為專案名稱。
<Context> <Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1"> <Store className="org.apache.catalina.session.FileStore" directory="mysession"/> </Manager> </Context>
訪問專案的index.jsp頁面,這會使Tomcat建立Session物件,然後等待一分鐘後,檢視Tomcat\work\Catalina\localhost\listener\mysession目錄下是否會產生檔案,如果產生了,說明鈍化session的配置成功了,可以開始下一步了。
-
建立Person類,讓Person類實現HttpSessionActivationListener和Serializable介面:
public class Person implements HttpSessionActivationListener, Serializable { private String name; private int age; private String sex; public Person(String name, int age, String sex) { super(); this.name = name; this.age = age; this.sex = sex; } public Person() { super(); } public String toString() { return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public void sessionDidActivate(HttpSessionEvent evt) { System.out.println("session已經活化"); } public void sessionWillPassivate(HttpSessionEvent evt) { System.out.println("session被鈍化了!"); } }
-
與上例一樣,編寫Servlet,提供兩個方法:一個向session中新增Person物件,另一個從session中移除Person物件:
public class ListenerServlet extends BaseServlet { public String addPerson(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Person p = new Person("zhangSan", 23, "male"); request.getSession().setAttribute("person", p); return "/index.jsp"; } public String removePerson(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.getSession().removeAttribute("person"); return "/index.jsp"; } }
-
在index.jsp頁面中給出訪問addPerson()和removePerson()的方法:
<body> <a href="<c:url value='/ListenerServlet?method=addPerson'/>">addPerson</a> <br/> <a href="<c:url value='/ListenerServlet?method=removePerson'/>">removePerson</a> <br/> </body>
-
開啟index.jsp頁面,這時Tomcat會建立session,必須在1分鐘之前點選addPerson連結,這能保證在session被鈍化之前把Person物件新增到session中;
-
等待一分鐘,這時session會被鈍化,也就會呼叫Person的sessionWillPassivate();
-
重新整理一下index.jsp頁面,這會使session活化,會呼叫Person的sessionDidActivate()方法。
二、國際化
2.1、什麼是國際化
國際化就是可以把頁面中的中文變成英文。例如在頁面中的登入表單:
2.2、理解國際化
想把頁面中的文字修改,那麼就不能再使用硬編碼,例如下面的頁面中都是硬編碼:
上圖中的中文想轉換成英文,那麼就需要把它們都變成活編碼:
2.3、Locale類
建立Locale類物件:
-
new Locale(“zh”, “CN”);
-
new Locale(“en”, “US”);
你一定對zh、CN或是en、US並不陌生,zh、en表示語言,而CN、US表示國家。一個Locale物件表示的就是語言和國家。
2.4、ResourceBundle類
ReourceBundle類用來獲取配置檔案中的內容。 下面是兩個配置檔案內容: res_zh_CN.properties
res_en_US.properties
public class Demo1 { @Test public void fun1() { ResourceBundle rb = ResourceBundle.getBundle("res", new Locale("zh", "CN" )); String username = rb.getString("msg.username"); String password = rb.getString("msg.password"); System.out.println(username); System.out.println(password); } @Test public void fun2() { ResourceBundle rb = ResourceBundle.getBundle("res", new Locale("en", "US" )); String username = rb.getString("msg.username"); String password = rb.getString("msg.password"); System.out.println(username); System.out.println(password); } }
ResourceBundle的getBundle()方法需要兩個引數:
-
第一個引數:配置檔案的基本名稱
-
第二個引數:Locale
getBundle()方法會通過兩個引數來鎖定配置檔案!
2.5、頁面國際化
其實頁面國際化也是同一道理,只需要通過切換Locale來切換配置檔案。我們寫一個MessageUtils類,內部需要ResourceBundle的例項。
我們再寫一個過濾器MessageFilter,它會通過引數建立Locale物件,傳遞給MessageUtils,然後在頁面中使用MessageUtils來獲取文字資訊。
public class MessageUtils { private static String baseName = "res"; private static Locale locale; public static String getText(String key) { return ResourceBundle.getBundle(baseName, locale).getString(key); } public static Locale getLocale() { return locale; } public static void setLocale(Locale locale) { MessageUtils.locale = locale; } }
public class MessageFilter implements Filter { public void destroy() { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String l = req.getParameter("request_locale"); Locale locale = null; if(l != null && !l.isEmpty()) { String[] strs = l.split("_"); locale = new Locale(strs[0], strs[1]); req.getSession().setAttribute("WW_TRANS_I18N_LOCALE", locale); } else { locale = (Locale)req.getSession().getAttribute("WW_TRANS_I18N_LOCALE"); } if(locale == null) { locale = req.getLocale(); } MessageUtils.setLocale(locale); chain.doFilter(request, response); } public void init(FilterConfig fConfig) throws ServletException { } }
login.jsp
<body> <h1><%=MessageUtils.getText("msg.login") %></h1> <form action="<c:url value='/index.jsp'/>" method="post"> <%=MessageUtils.getText("msg.username")%>:<input type="text" name="username"/><br/> <%=MessageUtils.getText("msg.password")%>:<input type="password" name="password"/><br/> <input type="submit" value='<%=MessageUtils.getText("msg.login")%>'/> </form> </body>
index.jsp
<body> <p><%=MessageUtils.getText("hello") + ":" +request.getParameter("username") %>:</p> </body>
2.6、NumberFormat
NumberFormat類用來對數字進行格式化,我們只需要使用String format(double)一個方法即可。下面是獲取NumberFormat例項的方法:
-
NumberFormat format = NumberFormat.getNumberFormat()
-
NumberFormat format = NumberFormat.getNumberFormat(Locale)
-
NumberFormat format = NumberFormat.getCurrentcyFormat()
-
NumberFormat format = NumberFormat.getCurrentcyFormat(Locale)
-
NumberFormat format = NumberFormat.getPercentFormat()
-
NumberFormat format = NumberFormat.getPercentFormat(Locale)
2.7、DateFormat
DateFormat類用來對日期進行格式化,我們只需要使用String format(Date)一個方法即可。下面是獲取DateFormat例項的方法:
-
DateFormat format = DateFormat.getDateFormat();
-
DateFormat format = DateFormat.getTimeFormat();
-
DateFormat format = DateFormat.getDateTimeFormat();
-
DateFormat format = DateFormat.getDateFormat(int style, Locale locale);
-
DateFormat format = DateFormat.getTimeFormat(int style, Locale locale);
-
DateFormat format = DateFormat.getDateTimeFormat(int style, Locale locale);
其中style是對日期的長、中、短,以及完整樣式。
-
SHORT;
-
MEDIUM;
-
LONG;
-
FULL
2.8、MessageFormat
MessageFormat可以把模式中的{N}使用引數來替換。我們把{N}稱之為點位符。其中點位符中的N是從0開始的整數。 MessageFormat.format(String pattern, Object… params),其中pattern中可以包含0~n個點位符,而params表示對點位符的替換文字。注意,點位符需要從0開始。 String p = “{0}或{1}錯誤”; String text = MessageFormat.format(p, “使用者名稱”, “密碼”);