过滤器监听器的使用(Filter和Listener)

一、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>
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皮卡丘不断更

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值