一、瞭解監聽器
1.1 什麼是監聽器
監聽器就是一個實現了特定接口的Java類。這個Java類用來監聽另一個Java類的方法調用或者屬性改變。當被監聽的對象的發生上述的事件後。監聽器某個方法就會立即執行。
1.1.1 監聽器的組件
監聽器可以大致分爲四個組件(方便理解)
- 事件源:事件發生的源頭
- 監聽器:監聽事件發生
- 綁定:將監聽器綁定到事件源
- 事件:能夠觸發監聽器的事
1.2 什麼是Servlet監聽器
在Servlet的規範中定義了多種類型的監聽器。監聽器用來分別監聽 ServletContext、HttpSession、ServletRequest三個域對象的
1.2.1 Servlet監聽器的組件
Servlet監聽器的組件大致分爲四個組件
- 事件源:request域對象、session域對象、ServletContext域對象
- 監聽器:Servlet三種監聽器
- 綁定:配置web.xml
- 事件:域對象發生改變
1.3 Servlet監聽器的分類
Servlet規範中提供了8個監聽器
按功能進行劃分將其分成三類,如下:
- 一類:監聽三個域對象的創建和銷燬的監聽器
- 二類:監聽三個域對象的屬性變更的監聽器。(屬性添加、屬性移除、屬性替換)
- 三類:監聽HttpSession對象中的JavaBean的狀態的改變。(綁定、解除綁定、鈍化、活化)
二、監聽器的開發步驟
- 自定義類實現一類監聽器
- 重寫監聽器中的方法
- 配置xml配置文件或註解配置
/**
* 監聽器開發步驟
*/
public class FirstListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
/**
* 監聽ServletContext域的初始化,隨着服務器的啓動
*/
System.out.println("ServletContext初始化");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
//監聽ServletContext域的銷燬,隨着服務器的關閉
System.out.println("ServletContext銷燬");
}
}
三、監聽器的配置方式
3.1 xml配置
<listener>
<listener-class>com.mylifes1110.java.listener.FirstListener</listener-class>
</listener>
3.2 註解配置
@WebListener,加了該註解默認配置了監聽器
package com.mylifes1110.java.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
* 監聽器開發步驟
*/
@WebListener
public class FirstListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
/**
* 監聽ServletContext域的初始化,隨着服務器的啓動
*/
System.out.println("ServletContext初始化");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
/**
* 監聽ServletContext域的銷燬,隨着服務器的關閉
*/
System.out.println("ServletContext銷燬");
}
}
四、一類監聽器
監聽三個域對象(ServletContext、Session、Request)的創建與銷燬
4.1 監聽ServletContext域對象
- 實現ServletContextListener接口並覆蓋方法
- 監聽服務器啓動的時候創建ServletContext對象時
- 監聽服務器關閉的時候ServletContext對象被銷燬掉時
package com.mylifes1110.java.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
* 監聽ServletContext
*/
@WebListener
public class TestServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
/**
* 監聽ServletContext域的初始化,隨着服務器的啓動
*/
System.out.println("ServletContext初始化");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
/**
* 監聽ServletContext域的銷燬,隨着服務器的關閉
*/
System.out.println("ServletContext銷燬");
}
}
4.2 監聽Session域對象
- 實現HttpSessionListener接口並覆蓋方法
- 監聽服務器端第一次調用getSession方法時
- 監聽session過期或調用了invalidate方法
package com.mylifes1110.java.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* 監聽HttpSession
*/
@WebListener
public class TestHttpSessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
System.out.println("Session創建");
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
System.out.println("Session銷燬");
}
}
Servlet測試
package com.mylifes1110.java.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet(name = "TestSessionServlet", value = "/tss")
public class TestSessionServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//創建Session對象
HttpSession session = request.getSession();
System.out.println(session.getId());
//銷燬Session對象
session.invalidate();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
4.3 監聽Request域對象
- 實現ServletRequestListener接口並覆蓋方法
- 監聽客戶的向服務器發送了一次請求而創建這一個request對象
- 監聽當服務器爲這次請求作出了響應之後的request對象銷燬
package com.mylifes1110.java.listener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
/**
* 監聽ServletRequest
*/
@WebListener
public class TestServletRequestListener implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
System.out.println("Request對象創建");
}
@Override
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
System.out.println("Request對象銷燬");
}
}
Servlet測試
package com.mylifes1110.java.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "TestRequestServlet", value = "/trs")
public class TestRequestServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String requestURI = request.getRequestURI();
System.out.println(requestURI);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
五、二類監聽器
監聽三個域對象的屬性變更的監聽器(屬性添加、屬性移除、屬性替換)
5.1 監聽ServletContext屬性
- 實現ServletContextAttributeListener接口並覆蓋方法
- 監聽ServletContext域中的屬性變更
package com.mylifes1110.java.listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.annotation.WebListener;
/**
* 監聽ServletContext域中的屬性變更
*/
@WebListener
public class TestServletContextAttributeListener implements ServletContextAttributeListener {
/**
* 監聽ServletContext域對象中屬性的添加
*/
@Override
public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("ServletContext Added");
}
/**
* 監聽ServletContext域對象中屬性的移除
*/
@Override
public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("ServletContext Removed");
}
/**
* 監聽ServletContext域對象中屬性的替換
*/
@Override
public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("ServletContext Replaced");
}
}
Servlet測試
package com.mylifes1110.java.servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "TestServletContextAttributeServlet", value = "/tscas")
public class TestServletContextAttributeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = getServletContext();
//添加
servletContext.setAttribute("name", "ziph");
//替換
servletContext.setAttribute("name", "join");
//移除
servletContext.removeAttribute("name");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
5.2 監聽Session屬性
- 實現HttpSessionAttributeListener接口並覆蓋方法
- 監聽HttpSession域中的屬性變更
package com.mylifes1110.java.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
/**
* 監聽Session域中的屬性變更
*/
@WebListener
public class TestHttpSessionAttributeListener implements HttpSessionAttributeListener {
@Override
public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("Session Added");
}
@Override
public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("Session Removed");
}
@Override
public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("Session Replaced");
}
}
Servlet測試
package com.mylifes1110.java.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* 注意:銷燬和移除都能觸發監聽器的attributeRemoved方法
*/
@WebServlet(name = "TestSessionAttributeServlet", value = "/tsas")
public class TestSessionAttributeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
StringBuffer buffer = new StringBuffer();
buffer.append("ziph");
//添加
session.setAttribute("name", buffer);
buffer.append(" is very good!");
//替換
session.setAttribute("name", buffer);
//移除
session.removeAttribute("name");
//銷燬
session.invalidate();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
5.3 監聽Request屬性
- 實現ServletRequestAttributeListener接口並覆蓋方法
- 監聽ServletRequest中的屬性變更
事件分析:
- 事件源:JavaBean對象
- 監聽器:HttpSessionBingingListener監聽器
- 綁定:JavaBean對象實現HttpSessionBingbingListener接口(所以纔不需要配置xml)
- 時間:JavaBean對象在Session中狀態發生改變
package com.mylifes1110.java.listener;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.annotation.WebListener;
/**
* 監聽Request域中的屬性變更
*/
@WebListener
public class TestServletRequestAttributeListener implements ServletRequestAttributeListener {
@Override
public void attributeAdded(ServletRequestAttributeEvent servletRequestAttributeEvent) {
System.out.println("Request Added");
}
@Override
public void attributeRemoved(ServletRequestAttributeEvent servletRequestAttributeEvent) {
System.out.println("Request Removed");
}
@Override
public void attributeReplaced(ServletRequestAttributeEvent servletRequestAttributeEvent) {
System.out.println("Request Replaced");
}
}
Servlet測試
package com.mylifes1110.java.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "TestServletRequestAttributeServlet", value = "/tsras")
public class TestServletRequestAttributeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
StringBuffer buffer = new StringBuffer();
buffer.append("ziph");
//添加
request.setAttribute("name", buffer);
buffer.append("marry");
//替換
request.setAttribute("name", buffer);
//移除
request.removeAttribute("name");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
六、三類監聽器
- HttpSessionBindingListener監聽HttpSession中的JavaBean的狀態(綁定和解除綁定狀態)
- 注意:該監聽器不需要xml配置和註解配置
package com.mylifes1110.java.bean;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
/**
* 三類監聽器HttpSessionBingingListener
*/
public class User implements HttpSessionBindingListener {
private int id;
private String username;
private String password;
public User() {
}
public User(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
@Override
public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("User對象綁定");
}
@Override
public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("User對象解綁");
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
Servlet測試
package com.mylifes1110.java.servlet;
import com.mylifes1110.java.bean.User;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet(name = "TestHttpSessionBingingListenerServlet", value = "/thsbls")
public class TestHttpSessionBingingListenerServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
//綁定
session.setAttribute("user", new User(1, "ziph", "123456"));
//解綁
session.removeAttribute("user");
//銷燬也是解綁的一種
// session.invalidate();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
七、瀏覽器記錄登錄認數綜合案例
當一個用戶登錄成功後,將這個用戶記錄到在線人數中;同時,如果這個用戶註銷登錄就從在線 人數中移除。遵循網頁站點瀏覽器訪問原則。
原理: 使用三類監聽器來監聽User實體類對象在Session中的綁定域解綁來控制在線人數
- 綁定:在線認數+1(登錄)
- 解綁:在線人數-1(註銷)
- 注意: 在登錄成功後我們需要使用重定向來跳轉登錄頁面。因爲我們使用轉發的話,在登錄後重新發起請求則請求轉發內部處理會重新登錄一次,所以會增加在線人數(+1)。爲了避免此問題,在跳轉登錄頁面的時候我們使用重定向技術!
login.html登錄頁面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陸頁面</title>
</head>
<body>
<form action="/firstlistener/login" method="post">
賬號:<input type="text" name="username"><br>
密碼:<input type="password" name="password"><br>
<button type="submit">登錄</button>
</form>
</body>
</html>
EncodingFilter過濾器解決亂碼問題的xml配置信息
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.mylifes1110.java.onlinenumbersdemo.filter.EncodingFilter</filter-class>
<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>
EncodingFilter過濾器解決亂碼問題代碼
package com.mylifes1110.java.onlinenumbersdemo.filter;
import javax.servlet.*;
import java.io.IOException;
/**
* 通用Filter解決亂碼問題
*/
public class EncodingFilter implements Filter {
private String encoding = null;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
encoding = filterConfig.getInitParameter("encoding");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding(encoding);
servletResponse.setContentType("text/html;charset=utf-8");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
User實體類對象(三類監聽器監聽,控制在線人數)
package com.mylifes1110.java.onlinenumbersdemo.bean;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
/**
* 監聽器監聽JavaBean對象
*/
public class User implements HttpSessionBindingListener {
private int id;
private String username;
private String password;
public User() {
}
public User(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
/**
* 處理統計登錄人數
*/
@Override
public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) {
ServletContext servletContext = httpSessionBindingEvent.getSession().getServletContext();
Integer count = (Integer) servletContext.getAttribute("count");
if (count == null) {
count = 1;
} else {
count++;
}
servletContext.setAttribute("count", count);
}
/**
* 處理統計註銷人數
*/
@Override
public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) {
ServletContext servletContext = httpSessionBindingEvent.getSession().getServletContext();
Integer count = (Integer) servletContext.getAttribute("count");
count--;
servletContext.setAttribute("count", count);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
LoginServlet登錄處理
package com.mylifes1110.java.onlinenumbersdemo.servlet;
import com.mylifes1110.java.onlinenumbersdemo.bean.User;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 登錄處理
*/
@WebServlet(name = "LoginServlet", value = "/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
if ("ziph".equals(username) && "123456".equals(password)) {
User user = new User();
user.setUsername(username);
user.setPassword(password);
request.getSession().setAttribute("user", user);
response.sendRedirect("/firstlistener/show");
} else {
request.getRequestDispatcher("/login.html").forward(request, response);
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
ShowServlet響應展示頁面
package com.mylifes1110.java.onlinenumbersdemo.servlet;
import com.mylifes1110.java.onlinenumbersdemo.bean.User;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 展示頁面
*/
@WebServlet(name = "ShowServlet", value = "/show")
public class ShowServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
User user = (User) request.getSession().getAttribute("user");
StringBuffer buffer = new StringBuffer();
if (user == null) {
buffer.append("對不起,您還沒有登錄! <a href='/firstlistener/login.html'>請登錄</a><br>");
} else {
buffer.append("歡迎" + user.getUsername() + "回家! <a href='/firstlistener/logout'>註銷</a><br>");
}
Integer count = (Integer) getServletContext().getAttribute("count");
if (count == null) {
buffer.append("在線人數爲:0");
} else {
buffer.append("在線人數爲:" + count);
}
response.getWriter().println(buffer.toString());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
LogoutServlet註銷功能
package com.mylifes1110.java.onlinenumbersdemo.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 註銷功能
*/
@WebServlet(name = "LogoutServlet", value = "/logout")
public class LogoutServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getSession().removeAttribute("user");
request.getRequestDispatcher("/show").forward(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
LogoutServlet註銷功能
package com.mylifes1110.java.onlinenumbersdemo.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 註銷功能
*/
@WebServlet(name = "LogoutServlet", value = "/logout")
public class LogoutServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getSession().removeAttribute("user");
request.getRequestDispatcher("/show").forward(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
還請客官多多點贊支持!👍持續分享中…