一、Filter(过滤器)
1.1、概述
过滤器是⼀个对象,它对资源(servlet或静态内容)的请求或资源的响应执⾏过滤任务,或同时对两者执
⾏过滤任务。过滤器在doFilter⽅法中执⾏过滤。过滤器是⼀个服务器端的组件,它可以截取客户端的请求和
服务端的响应信息,并对这些信息进⾏过滤。
1.2、使用
方式一
使⽤web.xml注册过滤器
1、 创建⼀个普通类实现Filter接⼝
2、重写Filter接⼝中的三个⽅法
3、在web.xml⽂件中注册过滤器
- 过滤器代码
public class FirstFilter implements Filter {
/*初始化*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("初始化过滤器");
}
/*过滤*/
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//放⾏之前
System.out.println("过滤请器放⾏之前");
//放⾏访问⽬标资源
chain.doFilter(request,response);
//放⾏之后
System.out.println("过滤请器放⾏之后");
}
/*销毁*/
@Override
public void destroy() {
System.out.println("过滤器被销毁");
}
web.xml注册过滤器:
<!--注册过滤器-->
<filter>
<!--过滤器名称-->
<filter-name>FirstFilter</filter-name>
<!--过滤器完整路径-->
<filter-class>com.offcn.sevlet.FirstFilter</filter-class>
</filter>
<!--配置过滤路径-->
<filter-mapping>
<!--过滤器名称-->
<filter-name>FirstFilter</filter-name>
<!--过滤器过滤的路径,如果是"/*"表示所有资源都要被过滤-->
<url-pattern>/*</url-pattern>
</filter-mapping>
方式二
使⽤注解⽅式注册过滤器
1、创建⼀个普通类实现Filter接⼝
2、重写Filter接⼝中的三个⽅法
3、 使⽤注解注册过滤器
- 案例代码
package com.offcn.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("*.do")
public class SecondFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("second初始化过滤器");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("second过滤器放⾏之前");
chain.doFilter(request,response);
System.out.println("second过滤器放⾏之后");
}
@Override
public void destroy() {
System.out.println("second销毁过滤器");
}
}
//这⾥我们可以直接通过@WebFilter("/*")注解的⽅式进⾏过滤器的注册。
说明:过滤器常⽤的路径配置格式有以下三种
1、/*过滤所有的服务器端资源
2、*.do表示过滤所有以.do结尾的服务器端资源
3、/hello 只能过滤hello这个路径的服务器端资源
1.3、特点
⼀个过滤器可以过滤多个servlet或者请求路径
web.xml
<!--注册过滤器-->
<filter>
<!--过滤器名称-->
<filter-name>FirstFilter</filter-name>
<!--过滤器完整路径-->
<filter-class>com.offcn.filter.FirstFilter</filter-class>
</filter>
<!--配置第⼀个过滤路径-->
<filter-mapping>
<!--过滤器名称-->
<filter-name>FirstFilter</filter-name>
<!--过滤器过滤的路径,如果是/*表示所有资源都要被过滤-->
<url-pattern>/hello</url-pattern>
</filter-mapping>
<!--配置第⼆个过滤路径-->
<filter-mapping>
<!--过滤器名称-->
<filter-name>FirstFilter</filter-name>
<!--过滤器过滤的路径,如果是/*表示所有资源都要被过滤-->
<url-pattern>/demo.do</url-pattern>
</filter-mapping>
//注解:
@WebFilter(urlPatterns = {
"/hello","/demo.do"})
过滤器默认情况下只过滤重定向的路径,不过滤转发路径。
web.xml⽅式配置:
<filter-mapping>
<!--过滤器名称-->
<filter-name>ThirdFilter</filter-name>
<!--过滤器过滤的路径,如果是/*表示所有资源都要被过滤-->
<url-pattern>/second</url-pattern>
<!--设置过滤转发路径-->
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
//注解⽅式配置:
@WebFilter(urlPatterns = {
"/one","/second"},dispatcherTypes =
DispatcherType.FORWARD)
1.4、使用场景
过滤器快速创建
@WebFilter(filterName = "EncodingFilter",urlPatterns = "/*",
dispatcherTypes ={
DispatcherType.REQUEST, // 浏览器直接请求的资源,会执行过滤
DispatcherType.FORWARD, // 在发生转发请求时,如果转发请求的资源,则执行过滤
DispatcherType.INCLUDE // 包含访问资源则执行过滤
} )
public class EncodingFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
chain.doFilter(request, response);
}
编码过滤器
@WebFilter(filterName = "EncodingFilter",urlPatterns = "/*",
dispatcherTypes ={
DispatcherType.REQUEST, // 浏览器直接请求的资源,会执行过滤
DispatcherType.FORWARD, // 在发生转发请求时,如果转发请求的资源,则执行过滤
DispatcherType.INCLUDE // 包含访问资源则执行过滤
} )
public class EncodingFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
chain.doFilter(request, response);
}
}
登录拦截过滤器
- 方式一参考:
package com.offcn.filter;
import com.offcn.bean.Admin;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebFilter("/*")
public class LoginContrlFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
//将请求和响应对象进⾏向下转型
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
HttpSession session = request.getSession();
//获取session中的信息
Admin admin = (Admin) session.getAttribute("admin");
//判断哪些资源不需要过滤
//获取请求的资源名称
String requestURI = request.getRequestURI();
String sourceName = requestURI.substring(requestURI.lastIndexOf("/") + 1);
//除了登录和注册相关的资源不需要过滤,其他都需要登录成功后才可以访问
if(sourceName.equals("login.jsp")||sourceName.equals("login")||sourceName.equals("register.jsp")||sourceName.equals("register")) {
//放⾏
chain.doFilter(req,resp);
}else{
//判断是否为空
if (admin==null){
//跳转到登录⻚⾯进⾏先登录
response.sendRedirect("login.jsp");
}else{
//放⾏
chain.doFilter(req,resp);
}
}
}
@Override
public void destroy() {
}
}
- 方式二参考:
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebFilter(filterName = "LoginFilter",urlPatterns = "/*",dispatcherTypes = {
DispatcherType.REQUEST,
DispatcherType.INCLUDE,
DispatcherType.FORWARD
})
public class LoginFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
// 登录控制判断
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
//2 获取请求路径
String url = req.getRequestURL().toString();
if(url.contains("login.jsp") || url.contains("register.jsp")){
//放行
chain.doFilter(req, resp);
}else {
HttpSession session = req.getSession();
User user1 = (User) session.getAttribute("user");
//判断是否登录
String username = req.getParameter("name");
String pwd = req.getParameter("password");
//调用业务层 处理业务 返回结果
UserService service = new UserService();
User user = service.queryUser(username,pwd);
if(user==null&&user1==null){
resp.sendRedirect("login.jsp");
}else {
//放行
chain.doFilter(req, resp);
}
}
}
}
过滤器解决跨域问题
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(filterName = "Filter1",urlPatterns = "/*")
public class Filter1 implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletResponse resp = (HttpServletResponse) response;
HttpServletRequest req = (HttpServletRequest) request;
// 不使⽤*,⾃动适配跨域域名,避免携带Cookie时失效
String origin = req.getHeader("Origin");
resp.setHeader("Access-Control-Allow-Origin", origin);
// ⾃适应所有⾃定义头
String headers = req.getHeader("Access-Control-Request-Headers");
resp.setHeader("Access-Control-Allow-Headers", headers);
resp.setHeader("Access-Control-Expose-Headers", headers);
// 允许跨域的请求⽅法类型
resp.setHeader("Access-Control-Allow-Methods", "*");
// 预检命令(OPTIONS)缓存时间,单位:秒
resp.setHeader("Access-Control-Max-Age", "3600");
// 明确许可客户端发送Cookie,不允许删除字段即可
resp.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(req, resp);
}
}
过滤器处理自动登录(cookie)
1、从login.jsp页面获取标识
<div id="bigBox">
<h1>用户登录</h1>
<div class="inputBox">
<div class="inputText">
账户:<input id="username" name="name" />
</div>
<div class="inputText">
密码:<input id="password-always-checkbox" type="password" name="password"/>
</div>
<a href="register.jsp">
<input type="button" class="inputButton" value="注册" >
</a>
<input type="submit" class="inputButton" value="登录"/>
<input type="checkbox" name="auto"> 自动登录
</div>
</div>
2、处理登录的servlet,登陆成功后的操作
@WebServlet(name = "LoginServlet", value = "/Login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
//获取账号密码
String name = request.getParameter("name");
String password = request.getParameter("password");
System.out.println(name);
System.out.println(password);
UserService userService = new UserService();
User user = userService.queryUser(name,password);
if (user==null){
System.out.println("登陆失败");
}else {
//登录成功 重定向到首页
// ---------设置自动登录功能
Cookie cookie2 = new Cookie("JSESSIONID", session.getId());
cookie2.setMaxAge(60*60*24);
String auto = request.getParameter("auto"); // 获取自动登录的标识
Cookie cookie1 = new Cookie("auto", "auto");
session.setAttribute("user",user); // ---把当前登录的对象传给session
if (auto!=null){
// 如果cookie值存在的话,给cookie设定时间
cookie1.setMaxAge(60*60);
response.addCookie(cookie1);
response.addCookie(cookie2);
}else {
// 如果不存在 销毁
cookie1.setMaxAge(0);
}
//重定向到首页
response.sendRedirect("query");
}
}
}
3、创建过滤器,过滤登录页:根据是否获取到标识判断是否直接跳转到首页
@WebFilter(filterName = "AutoLoginFilter" , urlPatterns = "/login.jsp")
public class AutoLoginFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
HttpSession session = req.getSession(); //获取session 以便登录成功的对象
User user = (User) session.getAttribute("user");
Cookie[] cookies = req.getCookies();
// 设置标识 ,默认失败:没有查询到标识
boolean flog = false;
for (Cookie cookie : cookies) {
System.out.println(cookie);
if ("auto".equals(cookie.getName())){
flog = true; // 查询到标识的话,更改标志,为成功
}
}
if (flog){
// 如果标志为true 说明获取到标识,自动登录
// 校验:根据 对象中的账号密码 查询数据库中的账号密码 查到为自动登录,没查到,放行到登录页
UserService userService = new UserService();
User istrue = userService.queryUser(user.getName(), user.getPassword());
System.out.println("自动登录过滤器:==="+istrue.toString());
if (istrue!=null){
resp.sendRedirect("index.jsp");
}else {
chain.doFilter(request, response);
}
}else {
chain.doFilter(request, response);
}
}
}
二、Listener(监听器)
2.1、概述
监听器就是特定的Java接⼝,主要⽤于监听某个对象的状态变化的组件。
2.2、分类
第⼀维度:按照被监听的对象划分:ServletRequest域 、HttpSession域 、 ServletContext域
第⼆维度:监听的内容分:域对象的创建与销毁的、域对象的属性变化的、绑定到HttpSession域中某个对象状态的
2.3、原理
原理图:
1、事件源:被监听的对象,即:request、session、servletContext三⼤域对象。
2、监听器:监听事件源对象,事件源对象状态的变化都会触发监听器。
3、注册监听器:将监听器与事件源进⾏绑定,有两种注册⽅式:web.xml 或 @WebListener注解
4、事件:域对象发⽣改变
2.4、使用
1、定义⼀个普通类实现监听器接⼝;
2、重写监听器接⼝⽅法;
3、注册监听器:配置 web.xml 或 @WebListener注解
2.4.1、ServletContextListener
⽤来监听ServletContext域对象的创建和销毁。
package com.offcn.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyServletContextListener implements ServletContextListener {
//创建⽅法
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("ServletContextListener监听器被创建");
}
//销毁⽅法
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("ServletContextListener监听器被销毁");
}
}
注册监听器:
<listener>
<listener-class>com.offcn.listener.MyServletContextListener</listener-class>
</listener>
测试:
当tomcat服务器开启时执⾏被创建的⽅法contextInitialized,服务器被关闭时执⾏被销毁的⽅法
contextDestroyed。
2.4.2、HttpSessionListener
HttpSessionListener监听器:⽤来监听HttpSession域对象的创建和销毁。
Session何时创建:Servlet中是request.getSession() ,JSP⻚⾯中⾃带Session。
Session何时销毁:⾮正常关闭服务器,Session过期,session.invalidate()
package com.offcn.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener
public class MyHttpSessionListener implements HttpSessionListener {
//创建⽅法
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
System.out.println("HttpSessionListener监听器被创建");
}
//销毁⽅法
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
System.out.println("HttpSessionListener监听器被销毁");
}
}
注册监听器:
在MyHttpSessionListener监听器类的上⽅添加注解@WebListener
测试:直接访问index.jsp⻚⾯,由于session是jsp的内置对象,意味着在访问index.jsp⻚⾯时创建了
session对象,因此会触发监听器的创建⽅法。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html> <head> <title>测试</title>
</head> <body> <h2>测试HttpSessionListener监听器</h2>
</body>
</html>
测试session对象的销毁:
⽅式1:可以在web.xml⽂件中配置⼀下session的有效期,让期在1分钟过期,当超过1分钟没有操作服务器⻚
⾯就会触发销毁⽅法;
<session-config>
<session-timeout>1</session-timeout>
</session-config>
⽅式2:执⾏session.invalidate()⽅法强制销毁session
<% session.invalidate();%>
2.4.3、ServletRequestListener
ServletRequestListener监听器:⽤来监听ServletRequest域对象的创建和销毁。
Request何时创建:请求发起时创建
Request何时销毁:响应结束时销毁
package com.offcn.listener;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
@WebListener
public class MyServletRequestListener implements ServletRequestListener {
@Override
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
System.out.println("ServletRequestListener监听器被创建");
//通过事件参数获取被监听的对象
ServletRequest servletRequest = servletRequestEvent.getServletRequest();
HttpServletRequest request = (HttpServletRequest) servletRequest;
//可以获取请求对象的相关信息
System.out.println(request.getMethod());
}
@Override
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
System.out.println("ServletRequestListener监听器被销毁");
}
}
注册监听器
在MyServletRequestListener监听器类的上⽅添加注解@WebListener
测试:创建⼀个jsp⻚⾯request.jsp,在该⻚⾯使⽤request做⼀次转发操作,先触发创建⽅法,转发结束后
触发销毁⽅法。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html> <head> <title>测试request监听器</title>
</head> <body> <h2>测试ServletRequestListener监听器</h2>
<%
request.getRequestDispatcher("index.jsp").forward(request,response);
%>
</body>
</html>
2.4.4、ServletContextAttributeListener
ServletContextAttributeListener监听器:监听ServletContext中属性的变化。
2.4.4、ServletRequestAttributeListener
ServletRequestAttributeListener 监听器:监听ServletRequest中属性的变化。
2.4.5、HttpSessionAttributeListener
HttpSessionAttributeListener监听器: 监听HttpSession中属性的变化。
以下是此类监听器对域中属性进⾏不同操作时所触发的⽅法:
1、attributeAdded监听属性添加 — 当数据范围对象没有该属性,第⼀次添加时会⾃动触发调⽤执⾏
2、 attributeRemoved 监听属性移除 — 从⼀个数据范围对象删除⼀个已经存在的属性时会⾃动触发执
⾏。
3、attributeReplaced监听属性替换 — 当⼀个数据范围已经存在⼀个属性,向数据范围添加相同名称属
性时⾃动触发替换⽅法。
- 举例:HttpSessionAttributeListener监听器为例,其他两个同理。
1、创建⼀个普通类,实现HttpSessionAttributeListener接⼝,并重写内部的三个⽅法。
package com.offcn.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
@WebListener
public class MyHttpSessionAttributeListener implements
HttpSessionAttributeListener {
//监听添加新的属性信息
@Override
public void attributeAdded(HttpSessionBindingEvent event) {
System.out.println("被添加的属性名:"+event.getName()+",属性的值:"+event.getSession().getAttribute(event.getName()));
}
//监听移除属性信息
@Override
public void attributeRemoved(HttpSessionBindingEvent event) {
System.out.println("被移除的属性名:"+event.getName()+",属性的值:"+event.getSession().getAttribute(event.getName()));
}
//监听对已存在书属性的替换
@Override
public void attributeReplaced(HttpSessionBindingEvent event) {
System.out.println("被替换的属性名:"+event.getName()+",属性的值:"+event.getSession().getAttribute(event.getName()));
}
}
2、注册监听器:在MyHttpSessionAttributeListener监听器类的上⽅添加注解@WebListener
3、测试监听器:创建⼀个jsp⻚⾯session.jsp,在该⻚⾯中分别对session域做添加,移除,替换的操作,这样就会触发不同的⽅法执⾏。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html> <head>
<title>Session监听器</title>
</head> <body>
<%
//添加新属性
session.setAttribute("age",23);
//替换属性
session.setAttribute("age",35);
//移除属性
session.removeAttribute("age");
%>
</body>
</html>
2.4.7、HttpSessionBindingListener
实现HttpSessionBindingListener接⼝的Java对象,可以感知⾃身被绑定到Session或者从Session中解除绑定。
1、创建⼀个学⽣类Student实现HttpSessionBindingListener接⼝,并重写内部两个⽅法。
package com.offcn.listener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
public class Student implements HttpSessionBindingListener {
private int id;//学号
private String name;//姓名
public Student() {
}
public Student(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println(httpSessionBindingEvent.getName()+"对象被绑定到Session中");
}
@Override
public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println(httpSessionBindingEvent.getName()+"对象从Session中解除绑定");
}
}
2、测试:创建⼀个jsp⻚⾯,创建学⽣对象并分别绑定和移除Session进⾏测试。
<%@ page import="com.offcn.listener.Student" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>HttpSessionBindingListener</title>
</head>
<body>
<h2>测试HttpSessionBindingListener监听器</h2>
<%
Student stu1 = new Student(1,"张三");
//将学⽣对象绑定到Session中会触发valueBound⽅法
session.setAttribute("stu1",stu1);
//从session中移除会触发valueUnbound⽅法
session.removeAttribute("stu1");
%>
</body>
</html>
2.4.8、HttpSessionActivationListener
实现HttpSessionActivationListener接⼝的Java对象,可以感知从内存被钝化到硬盘,从硬盘活化到内存中。
钝化时机:服务器关闭或重启,指定时间内(⻓时间)不操作服务器。
活化时机:服务器再次开启。
1、创建⼀个⽼师类Teacher实现HttpSessionActivationListener接⼝,并重写内部两个⽅法。
package com.offcn.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;
import java.io.Serializable;
public class Teacher implements HttpSessionActivationListener, Serializable {
private int age;//年龄
private String name;//姓名
public Teacher() {
}
public Teacher(int age, String name) {
this.age = age;
this.name = name;
}
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;
}
@Override
public void sessionWillPassivate(HttpSessionEvent httpSessionEvent) {
System.out.println(httpSessionEvent.getSession().getId()+"已钝化");
}
@Override
public void sessionDidActivate(HttpSessionEvent httpSessionEvent) {
System.out.println(httpSessionEvent.getSession().getId()+"已活化");
}
}
2、配置tomcat根⽬录下conf⽂件夹⾥的context.xml⽂件,其中directory="e:\test"表示⾃定义钝化⽂件的存储路径,maxIdleSwap="1"表示超过1分钟未操作服务器会⾃动钝化。
<Manager className="org.apache.catalina.session.PersistentManager"
saveOnRestart="true" maxIdleSwap="1"> <Store className="org.apache.catalina.session.FileStore" directory="e:\test"/>
</Manager>
3、测试:创建⼀个test01.jsp⻚⾯,向session中保存⼀个⽼师对象
<body> <h2>测试HttpSessionActivationListener监听器</h2> <%
Teacher teacher = new Teacher(45,"韩红");
session.setAttribute("teacher",teacher);
%>
</body>
4、再创建⼀个test02.jsp⻚⾯获取活化后session中的数据是否存在
<body> <h2>获取session的数据</h2>
${sessionScope.teacher.name}<br>
${sessionScope.teacher.age}<br>
</body>
⾸先运⾏test01.jsp⻚⾯,向session中存⼊⽼师信息,然后关闭服务器或通过设置maxIdleSwap="1"等待1分钟不操作服务器, 都会触发钝化⽅法执⾏,同时在指定的路径e:\test下会看到⼀个.session⽂件,将session中的数据钝化到该⽂件中。
然后重新启动服务器,再次访问test01.jsp,此时会触发活化⽅法将.session⽂件中的数据读取到内存,这⾥再访问test02.jsp,会读取到数据。
特别注意:
实现这两个接⼝的类不需要有 web.xml ⽂件或注解中进⾏注册监听器,都是由Session⾃主完成的。
2.5、使用场景
统计在线人数
思路:
通过ServletContextListener监听,当Web应⽤上下⽂启动时,在ServletContext中添加⼀个List集合,⽤来准备存放在线的⽤户名;然后,可以通过HttpSessionAttributeListener监听器,当⽤户登录成功,把⽤户名设置到Session中时,同时将⽤户名存放到ServletContext中的List列表中;最后通过HttpSessionListener监听,当⽤户注销会话时,将⽤户名从应⽤上下⽂范围中的List列表中删除。
实现步骤:
1、创建监听器,分别实现ServletContextListener、HttpSessionAttributeListener接口
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import java.util.LinkedList;
import java.util.List;
// 实现ServletContextListener , HttpSessionAttributeListener 接口 用来监听session域中的添加,删除,修改
public class OnlineListener implements ServletContextListener , HttpSessionAttributeListener {
ServletContext sc;
@Override
public void contextInitialized(ServletContextEvent sce) {
// 当系统启动的时候 获取ServletContext(),然后创建集合 并上传到全局
sc = sce.getServletContext();
sc.setAttribute("list",new LinkedList<>());
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
@Override
public void attributeAdded(HttpSessionBindingEvent se) {
List<User> list = (List) sc.getAttribute("list");
// 判断 添加的user是否等于session共享域中的user的名字
if ("user".equals(se.getName())){
// 如果相等,就把session中user对应的值,添加到集合中
list.add((User) se.getValue());
}
sc.setAttribute("list",list);
}
@Override
public void attributeReplaced(HttpSessionBindingEvent se) {
List<User> list = (List) sc.getAttribute("list");
// 判断 添加的user是否等于共享域中的user的名字
if ("user".equals(se.getName())){
list.add((User) se.getValue());
}
sc.setAttribute("list",list);
}
@Override
public void attributeRemoved(HttpSessionBindingEvent se) {
List<User> list = (List) sc.getAttribute("list");
list.remove(se.getValue());
sc.setAttribute("list",list);
}
}
2、在登录的Servlet中操作session
@WebServlet(name = "LoginServlet", value = "/Login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
//获取账号密码
String name = request.getParameter("name");
String password = request.getParameter("password");
System.out.println(name);
System.out.println(password);
UserService userService = new UserService();
User user = userService.queryUser(name,password);
if (user==null){
System.out.println("登陆失败");
}else {
//登录成功 重定向到首页
// ---------统计在线人数
System.out.println("登陆成功");
session.setAttribute("user",user); // ---把对象上传到session
session.setAttribute("name",name);
// request.getRequestDispatcher("query").forward(request,response);
response.sendRedirect("query");
}
}
}
3、创建用户注销登录的Servlet
@WebServlet(name = "LogoutServlet", value = "/logout")
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
// 清除session对象
session.removeAttribute("user");
response.sendRedirect("login.jsp");
}
}
4、在首页创建显示在线人数的 div
<div>
<h2>用户名:${user.name}</h2>
<h3>当前在线人数:${list.size()}</h3>
<h3>当前在线用户:</h3>
<c:forEach items="${list}" var="users">
<b>${users.name}</b>
</c:forEach>
</div>