Java web三大核心组件之一Listener用来监听其他对象的状态改变然后触发相应的事件,三个被监听的域对象:ServletContext、HttpServletRequest、HttpSession
ServletContextListener监听器中提供两个方法:
public interface ServletContextListener extends EventListener {
// 容器初始化的时候执行一次
default void contextInitialized(ServletContextEvent sce) {
}
// 容器销毁的时候执行一次
default void contextDestroyed(ServletContextEvent sce) {
}
}
HttpSessionListener监听器中提供两个方法:
public interface HttpSessionListener extends EventListener {
// 当一个新的session对象创建的时候执行
default void sessionCreated(HttpSessionEvent se) {
}
// 当一个session对象失效的时候执行
default void sessionDestroyed(HttpSessionEvent se) {
}
}
在web应用中统计当前在线人数,传统的做法是利用一个计数器,用户登录的时候计数器加1,用户退出的时候计数器减1。这种方式的缺点是(1)用户如果没有点击退出按钮而是直接关闭浏览器,就不会触发计数器减1。(2)有些网站不需要登录。
好的解决办法是利用Servlet规范中的Listener监听器。对每一个访问服务器的客户端,J2EE应用服务器都会为它创建一个HttpSession对象。当浏览器第一个访问网站的时候,J2EE应用服务器会创建一个HttpSession对象,并触发HttpSession创建事件(HttpSessionEvent ),如果注册了HttpSessionListener 时间监听器,则会调用实现类重写的sessionCreated()方法。当这次会话超时之后,J2EE应用服务器会销毁相应的HttpSession对象,调用HttpSessionListener 实现类重写的sessionDestroyed()方法。
(1)index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>统计在线人数</title>
</head>
<body>
<h1>在线人数:${ccount}</h1>
</body>
</html>
(2)容器创建的时候,设置一个全局属性count作为计数器
@WebListener
public class OnlineCountServletContextListener implements ServletContextListener {
public void contextDestroyed(ServletContextEvent arg0) {
// TODO Auto-generated method stub
System.out.println("容器销毁");
}
public void contextInitialized(ServletContextEvent sce) {
System.out.println("容器创建");
sce.getServletContext().setAttribute("ccount", 0);
}
}
(3)HttpSessionListener 监听器
@WebListener
public class OnlineCountHttpSessionListener implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent hse) {
//上线
HttpSession session = hse.getSession();
System.out.println(session.getId()+"上线了。。。");
Integer ccount = (Integer) session.getServletContext().getAttribute("ccount");
ccount++;
session.getServletContext().setAttribute("ccount", ccount);
}
public void sessionDestroyed(HttpSessionEvent hse) {
//离线
HttpSession session = hse.getSession();
System.out.println(session.getId()+"离线了。。。");
Integer ccount = (Integer) session.getServletContext().getAttribute("ccount");
ccount--;
session.getServletContext().setAttribute("ccount", ccount);
}
}
(4)设置session的有效期
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>Archetype Created Web Applicationdisplay-name>
<session-config>
<session-timeout>1session-timeout>
session-config>
web-app>
session提高了安全性,它将关键数据存储在了服务器端,与cookie不同,cookie是把数据存储在了客户端浏览器
(1)session何时生效
Sessinon在用户访问第一次访问服务器时创建,需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session,可调用request.getSession(true)
强制生成Session
(2)session何时失效
HttpSession session = request.getSession();
session.invalidate();//注销该request的所有session
方式一:
<session-config> <!--分钟为单位-->
<session-timeout>1</session-timeout>
</session-config>
方式二:
request.getSession().setMaxInactiveInterval(-1);//永不过期
方式三:
tomcat也可以修改session过期时间,在server.xml中定义context时采用如下定义
<Context path="/livsorder"
docBase="/home/httpd/html/livsorder" defaultSessionTimeOut="3600"
isWARExpanded="true"
isWARValidated="false" isInvokerEnabled="true" isWorkDirPersistent="false"/>
(3)session的过期时间是从什么时候开始计算的?是从一登录就开始计算还是从停止活动开始计算?
从session不活动的时候开始计算,如果session一直活动,session就总不会过期
session基于cookie实现,当浏览器第一次访问服务器的时候,服务器会生成一个session,id为JSESSIONID,然后通过set-cookie响应头告诉客户端浏览器,浏览器会把这个session保存到本地内存,下次再请求服务器的时候,通过cookie请求头携带上session的key和value,服务端就能知道这是同一客户端。
cookie默认对于同一个浏览器来说是共享的,所以即使用同一浏览器打开多个窗口,还是被服务器认为是同一用户。