Spring中最简单的过滤器和监听器

news2024/11/18 2:40:06

1. 过滤器概念引入

在这里插入图片描述

        Filter也称之为过滤器,它是Servlet技术中最实用的技术,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能 处理编码。

        它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。使用Filter的完整流程:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。

过滤器如何实现功能

  1. 在HttpServletRequest到达 Servlet 之前,拦截客户的HttpServletRequest 。根据需要检查HttpServletRequest,也可以修改HttpServletRequest 头和数据。

  2. 在HttpServletResponse到达客户端之前,拦截HttpServletResponse 。根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。

  3. Filter接口中有一个doFilter方法,当开发人员编写好Filter,并配置对哪个web资源进行拦截后,Web服务器每次在调用web资源的service方法之前,都会先调用一下filter的doFilter方法,doFilter方法中有一个filterChain对象,用于继续传递给下一个filter,在传递之前我们可以定义过滤请求的功能,在传递之后,我们可以定义过滤响应的功能

2. 过滤器的定义和配置

采用三步走策略使用filter

  1. 开发后台资源 静态资源(html,css … …)或者动态资源(Servlet,Jsp)

  2. 开发Filter

  3. 在web.xml中配置Filter拦截哪些资源

开发Servlet

定义两个servlet

package com.test.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyServlet1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("myServlet1 执行了sevice方法");
        resp.setContentType("text/html;charset=UTF-8");
        resp.setCharacterEncoding("UTF-8");
        resp.getWriter().print("myServlet1响应的数据");
    }
}
package com.test.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyServlet2 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("myServlet2 执行了sevice方法");
        resp.setContentType("text/html;charset=UTF-8");
        resp.setCharacterEncoding("UTF-8");
        resp.getWriter().print("myServlet2响应的数据");
    }
}

开发Filter

package com.test.filter;
import javax.servlet.*;
import java.io.IOException;

public class MyFilter implements Filter {
    // 初始化方法
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    // 作出过滤的方法
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Filter doFilter 对请求作出过滤");
        // 通过一行代码 放行请求
        // 放行请求,交给过滤器链继续进行过滤 最后到达资源
        filterChain.doFilter(servletRequest, servletResponse);
        
        System.out.println("Filter doFilter 对响应作出过滤");
        
        servletResponse.getWriter().print("filter 追加一些数据");
    }
    // 销毁方法
    @Override
    public void destroy() {
    }
}

配置Filter

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>myServlet1</servlet-name>
        <servlet-class>com.test.servlet.MyServlet1</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>myServlet1</servlet-name>
        <url-pattern>/myServlet1.do</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>myServlet2</servlet-name>
        <servlet-class>com.test.servlet.MyServlet2</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>myServlet2</servlet-name>
        <url-pattern>/myServlet2.do</url-pattern>
    </servlet-mapping>
    <filter>
        <filter-name>filter1</filter-name>
        <filter-class>com.test.filter.MyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>filter1</filter-name>
        <!--对那个/些资源的请求和响应进行过滤-->
        <!--<url-pattern>/myServlet1.do</url-pattern>-->
        <servlet-name>myServlet1</servlet-name>
        <servlet-name>myServlet2</servlet-name>
        <!--<url-pattern>/</url-pattern>
        <url-pattern>/*</url-pattern>-->
    </filter-mapping>
</web-app>

3. 过滤器的生命周期

        同servlet对象一样,Filter对象的创建也是交给web服务器完成的,在web服务器创建和使用及最后销毁filter时,会调用filter对应的方法
构造方法:

实例化一个Filter对象的方法

初始化方法:

public void init(FilterConfig filterConfig);

        和我们编写的Servlet程序一样,Filter的创建和销毁由WEB服务器负责。 web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。

拦截请求方法

public void doFilter

        这个方法完成实际的过滤操作。当客户请求访问与过滤器关联的URL的时候,Servlet过滤器将先执行doFilter方法。FilterChain参数用于访问后续过滤器。

销毁方法:

public void destroy();

        Filter对象创建后会驻留在内存,当web应用移除或服务器停止时才销毁。在Web容器卸载 Filter 对象之前被调用。该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源。

  1. WEB 容器启动时,会对Filter进行构造并初始化 一次
  2. 每次请求目标资源时,都会执行doFilter的方法
  3. WEB容器关闭是,会销毁Filter对象
package com.test.filter;
import javax.servlet.*;
import java.io.IOException;

public class MyFilter implements Filter {
    public MyFilter(){
        System.out.println("MyFilter constructor invoked");
    }
    // 初始化方法
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("MyFilter init invoked");
    }
    // 作出过滤的方法
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Filter doFilter 对请求作出过滤");
        // 通过一行代码 放行请求
        // 放行请求,交给过滤器链继续进行过滤 最后到达资源
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("Filter doFilter 对响应作出过滤");
        servletResponse.getWriter().print("filter 追加一些数据");
    }
    // 销毁方法
    @Override
    public void destroy() {
        System.out.println("MyFilter destory invoked");
    }
}

4. 过滤器链的使用

        在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链。

在这里插入图片描述

        web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源。

        使用过滤器链的好处是我们可以将不同的过滤功能分散到多个过滤器中,分工明确,避免一个过滤器做太多的业务处理,降低了代码的耦合度,这体现了单一职责的设计原则,应用了责任链的代码设计模式.

        决定过滤器的执行顺序是由filter-mapping标签决定

准备多个Filter

package com.test.filter;
import javax.servlet.*;
import java.io.IOException;
import java.util.Enumeration;

public class MyFilter1 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("MyFilter1   在过滤请求 ");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("MyFilter1   在过滤响应");
    }
    @Override
    public void destroy() {
    }
}
package com.test.filter;
import javax.servlet.*;
import java.io.IOException;

public class MyFilter2 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("MyFilter2   在过滤请求 ");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("MyFilter2   在过滤响应");
    }
    @Override
    public void destroy() {
    }
}

配置Filter

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <filter>
        <filter-name>filter1</filter-name>
        <filter-class>com.test.filter.MyFilter1</filter-class>
       
    </filter>
    <filter>
        <filter-name>filter2</filter-name>
        <filter-class>com.test.filter.MyFilter2</filter-class>
    </filter>
    <!--这里的顺序决定了过滤器的顺序-->
    <filter-mapping>
        <filter-name>filter2</filter-name>
        <url-pattern>/myServlet1.do</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>filter1</filter-name>
        <url-pattern>/myServlet1.do</url-pattern>
    </filter-mapping>
</web-app>

5. 过滤器初始化参数

        同servlet一样,filter也可以通过web.xml进行初始化配置,在初始化时,将参数封装进入FilterConfig并在调用init方法时作为实参传入,我们可以在init方法中获取参数.FilterConfig接口为我们提供了如下功能

  1. String getFilterName();//得到filter的名称。

  2. String getInitParameter(String name);//返回定名称的初始化参数的值。如果不存在返回null.

  3. Enumeration getInitParameterNames();//返回过滤器的所有初始化参数的名字的枚举集合。

  4. public ServletContext getServletContext();//返回Servlet上下文对象的引用。

配置Filter初始化参数

<filter>
        <filter-name>filter1</filter-name>
        <filter-class>com.test.filter.MyFilter1</filter-class>
        <init-param>
            <param-name>realname</param-name>
            <param-value>xiaoming</param-value>
        </init-param>
        <init-param>
            <param-name>gender</param-name>
            <param-value>boy</param-value>
        </init-param>
        <init-param>
            <param-name>age</param-name>
            <param-value>10</param-value>
        </init-param>
        <init-param>
            <param-name>charset</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>

读取初始化参数

public class MyFilter1 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 获取初始化的一些参数
        String realname = filterConfig.getInitParameter("realname");
        System.out.println("realname:"+realname);
        Enumeration<String> pNames = filterConfig.getInitParameterNames();
        while(pNames.hasMoreElements()){
            String pName = pNames.nextElement();
            System.out.println(pName+":"+filterConfig.getInitParameter(pName));
        }
    }

6. 过滤器注解的应用

@WebFilter属性

在这里插入图片描述

package com.test.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;

@WebFilter(urlPatterns = "/myServlet1.do")
public class Filter0_MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("MyFilter0   在过滤请求 ");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("MyFilter0   在过滤响应");
    }
    @Override
    public void destroy() {
    }
}
package com.test.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;
import java.util.Enumeration;

@WebFilter(urlPatterns = "/myServlet1.do",initParams = {@WebInitParam(name="realname",value ="zhangsan"),@WebInitParam(name="charset",value ="utf-8")})
public class Filter1_MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 获取初始化的一些参数
        String realname = filterConfig.getInitParameter("realname");
        System.out.println("realname:"+realname);
        Enumeration<String> pNames = filterConfig.getInitParameterNames();
        while(pNames.hasMoreElements()){
            String pName = pNames.nextElement();
            System.out.println(pName+":"+filterConfig.getInitParameter(pName));
        }
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("MyFilter1   在过滤请求 ");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("MyFilter1   在过滤响应");
    }
    @Override
    public void destroy() {
    }
}

7. 案例开发之POST乱码处理

准备页面login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title%sSourceCode%lt;/title>
  </head>
  <body>
  please login ... ... <br/>
  <form action="loginController.do" method="post">
    用户名:<input type="text" name="user"> <br/>
    密码:<input type="password" name="pwd"><br/>
    <input type="submit" value="提交">
  </form>
  </body>
</html>

准备servlet,LoginController

package com.test.controller;
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(urlPatterns = "/loginController.do")
public class LoginController extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取用户名和密码
        String user = req.getParameter("user");
        String pwd = req.getParameter("pwd");
        System.out.println(user);
        System.out.println(pwd);
    }
}

准备过滤器

package com.test.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

public class Filter0_EncodingFilter implements Filter {
    private String charset;
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding(charset);
        // 放行
        filterChain.doFilter(servletRequest, servletResponse);
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        charset = filterConfig.getInitParameter("charset");
    }
    @Override
    public void destroy() {
    }
}

配置过滤器

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>com.test.filter.Filter0_EncodingFilter</filter-class>
        <init-param>
            <param-name>charset</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>*.do</url-pattern>
    </filter-mapping>
</web-app>

8. 案例开发之登录验证

        需求:通过过滤器控制,只有登录过之后可以反复进入welcome.jsp欢迎页,如果没有登录,提示用户进入登录页进行登录操作
准备实体类
User类

package com.test.pojo;
import java.io.Serializable;


public class User implements Serializable {
    private String username;
    private String password;
    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
    public User() {
    }
    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }
    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;
    }
}

准备一些页面和静态资源

在这里插入图片描述

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title%sSourceCode%lt;/title>
  </head>
  <body>
  <img src="static/img/logo.png">
  please login ... ... <br/>
  <form action="loginController.do" method="post">
    用户名:<input type="text" name="user"> <br/>
    密码:<input type="password" name="pwd"><br/>
    <input type="submit" value="提交">
  </form>
  </body>
</html>

welcome.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<img src="static/img/logo.png">
欢迎${user.username}登陆!!!
</body>
</html>

aaa.jsp 

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
this is page aaa
</body>
</html>

准备Controller代码

package com.test.controller;
import com.test.pojo.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(urlPatterns = "/loginController.do")
public class LoginController extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取用户名和密码
        String username = req.getParameter("user");
        String password = req.getParameter("pwd");
        System.out.println(username);
        System.out.println(password);
        // 链接数据库校验登录
        // 登录成功,将用户信息放入Session域
        User user =new User(username,password);
        req.getSession().setAttribute("user", user);
        // 跳转到欢迎页
        resp.sendRedirect("welcome.jsp");
    }
}

准备登录控制过滤器

package com.test.filter;
import com.test.pojo.User;
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(urlPatterns = "/*")// 任何资源都要进行过滤,
public class Filter1_LoginFilter  implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req=(HttpServletRequest)servletRequest;
        HttpServletResponse resp=(HttpServletResponse) servletResponse;
        //无论是否登录过,都要放行的资源   登录页  登录校验Controller 和一些静态资源
        String requestURI = req.getRequestURI();
        System.out.println(requestURI);
        if(requestURI.contains("login.jsp")|| requestURI.contains("loginController.do")|| requestURI.contains("/static/")){
            // 直接放行
            filterChain.doFilter(req,resp);
            // 后续代码不再执行
            return;
        }
        // 需要登录之后才能访问的资源,如果没登录,重定向到login.jsp上,提示用户进行登录
        HttpSession session = req.getSession();
        Object user = session.getAttribute("user");
        if(null != user){// 如果登录过 放行
            filterChain.doFilter(req,resp);
        }else{// 没有登录过,跳转至登录页
            resp.sendRedirect("login.jsp");
        }
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void destroy() {
    }
}

9. 监听器概念引入

在这里插入图片描述

什么是监听器?

        类似于前端的事件绑定,java中的监听器用于监听web应用中某些对象、信息的创建、销毁、增加,修改,删除等动作的发生,然后作出相应的响应处理。当范围对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。常用于统计在线人数和在线用户,系统加载时进行信息初始化,统计网站的访问量等等。

监听器怎么分类?

按监听的对象划分

  1. ServletContext对象监听器

  2. HttpSession对象监听器

  3. ServletRequest对象监听器

按监听的事件划分

  1. 对象自身的创建和销毁的监听器

  2. 对象中属性的创建和消除的监听器

  3. session中的某个对象的状态变化的监听器

一共有哪些监听器?分别处理的是什么事情?

        java中一共给我们提供了八个监听器接口,分别用于监听三个域对象,每个监听器都有专门监听的事件

Request

ServletRequestListener (处理request对象创建和销毁)
ServleRequestAttributeListener (处理域对象中的数据添加 替换 删除)
Session
HttpSessionListener (处理session对象创建和销毁)
HttpSessionAttributeListener (处理session域对象中的数据添加 修改 删除)
HttpSessionBindingListener (处理session对象监听器绑定和解绑定接口)
HttpSessionActivationListener (处理session对象钝化和活化状态接口)
Application
ServletContextListener (处理application对象创建和销毁)
ServletContextAttributeListener (处理application域对象中的数据添加 修改 删除)

监听器如何使用?

两步走使用

  1. 定义监听器,根据需求实现对应接口

  2. 在web.xml中配置监听器,让监听器工作

接下来我们就挨个认识一下每个监听器及内部方法的作用

10. Request域监听器

认识Requet域监听器

Requet域共有两个监听器接口,分别是

ServletRequestListener
ServleRequestAttributeListener

接下来我们就认识一些每个接口和接口中每个方法的用处

定义监听器类

package com.test.listener;
import javax.servlet.*;

public class MyRequestListener implements ServletRequestListener, ServletRequestAttributeListener {
    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        // 监听HttpServletRequest对象的销毁  项目中任何一个Request对象的销毁都会触发该方法的执行
        ServletRequest servletRequest = sre.getServletRequest();
        System.out.println("request"+servletRequest.hashCode()+"对象销毁了");
    }
    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        // 监听HttpServletRequest对象的创建并初始化 项目中任何一个Request对象的创建并初始化都会触发该方法的执行
        ServletRequest servletRequest = sre.getServletRequest();
        System.out.println("request"+servletRequest.hashCode()+"对象初始化");
    }
    @Override
    public void attributeAdded(ServletRequestAttributeEvent srae) {
        // 任何一个Request对象中调用 setAttribute方法增加了数据都会触发该方法
        ServletRequest servletRequest = srae.getServletRequest();
        String name = srae.getName();
        Object value = srae.getValue();
        System.out.println("request"+servletRequest.hashCode()+"对象增加了数据:"+name+"="+value);
    }
    @Override
    public void attributeRemoved(ServletRequestAttributeEvent srae) {
       // 任何一个Request对象中调用 removeAttribute方法移除了数据都会触发该方法
        ServletRequest servletRequest = srae.getServletRequest();
        String name = srae.getName();
        Object value = srae.getValue();
        System.out.println("request"+servletRequest.hashCode()+"对象删除了数据:"+name+"="+value);
    }
    @Override
    public void attributeReplaced(ServletRequestAttributeEvent srae) {
        // 任何一个Request对象中调用 setAttribute方法修改了数据都会触发该方法
        ServletRequest servletRequest = srae.getServletRequest();
        String name = srae.getName();
        Object value = srae.getValue();
        Object newValue=servletRequest.getAttribute(name);
        System.out.println("request"+servletRequest.hashCode()+"对象增修改了数据:"+name+"="+value+"设置为:"+newValue);
    }
}

配置监听器 使用web.xml 或者通过@WebListener注解都可以

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    
    <listener>
        <listener-class>com.test.listener.MyRequestListener</listener-class>
    </listener>
</web-app>

准备Servlet

@WebServlet(urlPatterns = "/myServlet3.do")
public class MyServlet3 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setAttribute("name", "zhangsan");
        req.setAttribute("name", "lisi");
        req.removeAttribute("name");
    }
}

11. Session域监听器

Session域共有四个监听器接口,分别是

  1. HttpSessionListener
  2. HttpSessionAttributeListener
  3. HttpSessionBindingListener
  4. HttpSessionActivationListener

接下来我们就认识一些每个接口和接口中每个方法的用处

监听器代码

HttpSessionListener
HttpSessionAttributeListener

package com.test.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

@WebListener
public class MySessionListener implements HttpSessionListener , HttpSessionAttributeListener {
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("任何一个Session对象创建");
    }
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("任何一个Session对象的销毁");
    }
    @Override
    public void attributeAdded(HttpSessionBindingEvent se) {
        System.out.println("任何一个Session对象中添加了数据");
    }
    @Override
    public void attributeRemoved(HttpSessionBindingEvent se) {
        System.out.println("任何一个Session对象中移除了数据");
    }
    @Override
    public void attributeReplaced(HttpSessionBindingEvent se) {
        System.out.println("任何一个Session对象中修改了数据");
    }
}

HttpSessionBindingListener

package com.test.listener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

/*
* 可以监听具体的某个session对象的事件的
*
* HttpSessionListener 只要在web.xml中配置或者通过@WebListener注解就可以注册监听所有的Session对象
* HttpSessionBindingListener 必须要通过setAttribute方法和某个session对象绑定之后,监听单独的某个Session对象
* */
public class MySessionBindingListener implements HttpSessionBindingListener {
    // 绑定方法
    /*
    session.setAttribute("mySessionBindingListener",new MySessionBindingListener())
     */
    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        System.out.println("监听器和某个session对象绑定了");
    }
    // 解除绑定方法
    /*
    * 当发生如下情况,会触发该方法的运行
    * 1 session.invalidate(); 让session不可用
    * 2 session到达最大不活动时间,session对象回收 ;
    * 3 session.removeAttribute("mySessionBindingListener");手动解除绑定
    * */
    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
    }
}

HttpSessionActivationListener

package com.test.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;


public class MySessionActivationListener implements HttpSessionActivationListener {
    @Override
    public void sessionWillPassivate(HttpSessionEvent se) {
        System.out.println("session即将钝化");
    }
    @Override
    public void sessionDidActivate(HttpSessionEvent se) {
        System.out.println("session活化完毕");
    }
}

12. Application域监听器

认识Application域监听器

Application域共有两个监听器接口,分别是

ServletContextListener
ServletContextAttributeListener

接下来我们就认识一些每个接口和接口中每个方法的用处

监听器代码

 package com.test.listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class MyApplicationListener implements ServletContextListener , ServletContextAttributeListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("ServletContext创建并初始化了");
    }
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("ServletContext销毁了");
    }
    @Override
    public void attributeAdded(ServletContextAttributeEvent scae) {
        System.out.println("ServletContext增加了数据");
    }
    @Override
    public void attributeRemoved(ServletContextAttributeEvent scae) {
        System.out.println("ServletContext删除了数据");
    }
    @Override
    public void attributeReplaced(ServletContextAttributeEvent scae) {
        System.out.println("ServletContext修改了数据");
    }
}

13. 案例开发_记录请求日志

认识Application域监听器

Application域共有两个监听器接口,分别是

ServletContextListener
ServletContextAttributeListener

接下来我们就认识一些每个接口和接口中每个方法的用处

监听器代码

 package com.test.listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
 * @Author: Ma HaiYang
 * @Description: MircoMessage:Mark_7001
 */
public class MyApplicationListener implements ServletContextListener , ServletContextAttributeListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("ServletContext创建并初始化了");
    }
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("ServletContext销毁了");
    }
    @Override
    public void attributeAdded(ServletContextAttributeEvent scae) {
        System.out.println("ServletContext增加了数据");
    }
    @Override
    public void attributeRemoved(ServletContextAttributeEvent scae) {
        System.out.println("ServletContext删除了数据");
    }
    @Override
    public void attributeReplaced(ServletContextAttributeEvent scae) {
        System.out.println("ServletContext修改了数据");
    }
}

14. 案例开发_统计实时在线人数在这里插入图片描述

需求:
1当任何一个账户处于登录状态时,在线统计总数+1,离线时-1
2通过session监听器实现计数,但是在线人数要保存在Application域中

准备监听器

package com.test.listener;
import javax.servlet.ServletContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;


@WebListener
public class OnLineNumberListener implements HttpSessionListener  {
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        // 向application域中 增加一个数字
        HttpSession session = se.getSession();
        ServletContext application = session.getServletContext();
        Object attribute = application.getAttribute("count");
        if(null == attribute){// 第一次放数据
            application.setAttribute("count", 1);
        }else{
            int count =(int)attribute;
            application.setAttribute("count", ++count);
        }
    }
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        // 向application域中 减少一个数字
        HttpSession session = se.getSession();
        ServletContext application = session.getServletContext();
        int count =(int)application.getAttribute("count");
        application.setAttribute("count", --count);
    }
}

准备销毁监听的servlet

package com.test.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(urlPatterns = "/logout.do")
public class Logout extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        session.invalidate();
    }
}

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title%sSourceCode%lt;/title>
  </head>
  <body>
  当前在线人数为:${applicationScope.count}
  </body>
</html>

分别用不同的客户端访问index.jsp 和logout.do测试 即可

15. 案例开发_项目重启免登录

Session序列化和反序列化

1、序列化与反序列

把对象转化为字节序列的过程称为序列化(保存到硬盘,持久化)

把字节序列转化为对象的过程称为反序列化(存放于内存)

2、序列化的用途

把对象的字节序列永久保存到硬盘上,通常放到一个文件中。

把网络传输的对象通过字节序列化,方便传输本节作业

3、实现步骤
要想实现序列化和反序列化需要手动配置

A、新建文件如图所示:

B、 Context.xml中文件如下

<?xml version="1.0" encoding="UTF-8"?>

  <Context>
       <Manager className="org.apache.catalina.session.PersistentManager">
         <Store className="org.apache.catalina.session.FileStore" directory="d:/session"/>
      </Manager>
  </Context> 

C、注意实体类必须实现serializable 接口

开发过程
1 准备实体类

 package com.test.pojo;
import java.io.Serializable;

public class User  implements Serializable {
    private String username;
    private String pwd;
    }

2 开发登录信息输入页面

 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title%sSourceCode%lt;/title>
  </head>
  <body>
  <form action="loginController.do" method="post">
    用户名:<input type="text" name="user"> <br/>
    密码:<input type="password" name="pwd"><br/>
    <input type="submit" value="提交">
  </form>
  </body>
</html>

3、开发登录信息验证Servlet

 package com.test.controller;
import com.msb.listener.MySessionActivationListener;
import com.msb.pojo.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("/loginController.do")
public class LoginController extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("user");
        String pwd = req.getParameter("pwd");
        // user
        User user =new User(username,pwd);
        // session
        HttpSession session = req.getSession();
        session.setAttribute("user", user);
    }
}

4、 开发校验当前是否已经登录的Controller

 package com.test.controller;
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(urlPatterns = "/loginCheckController.do")
public class LoginCheckController extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 判断是否登录
        HttpSession session = req.getSession();
        Object user = session.getAttribute("user");
        Object listener = session.getAttribute("listener");// 获得对应的监听器
        String message ="";
        if(null != user){
            message="您已经登录过";
        }else{
            message="您还未登录";
        }
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().println(message);
    }
}

5测试, 先登录,然后请求loginCheckController.do 校验是否登录过,然后重启项目,再起请求loginCheckController.do 校验是否登录过,发现重启后,仍然是登录过的

6监听钝化和活化

准备监听器

 package com.test.listener;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;
import java.io.Serializable;

public class MySessionActivationListener implements HttpSessionActivationListener, Serializable {
    @Override
    public void sessionWillPassivate(HttpSessionEvent se) {
        System.out.println(se.getSession().hashCode()+"即将钝化");
    }
    @Override
    public void sessionDidActivate(HttpSessionEvent se) {
        System.out.println(se.getSession().hashCode()+"已经活化");
    }
}

登录时绑定监听器

 @WebServlet("/loginController.do")
public class LoginController extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("user");
        String pwd = req.getParameter("pwd");
        // user
        User user =new User(username,pwd);
        // session
        HttpSession session = req.getSession();
        session.setAttribute("user", user);
        // 绑定监听器
        session.setAttribute("listener", new MySessionActivationListener());
    }
}

重启项目 重复测试即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/804048.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文看完智能视频监控系统的工作原理及场景应用

智能视频监控系统的原理是利用摄像机采集视频信号&#xff0c;并通过相关的AI模型算法实时分析视频内容&#xff0c;提取出有用信息&#xff0c;如人脸、车牌号码、移动物体等&#xff0c;并进行识别及特征提取&#xff0c;最终形成监控报警、实时监控、历史录像回放等应用。 智…

【JAVA】 String 类简述笔记

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️初识JAVA】 文章目录 前言String类创建一个String类 常用方法字符串长度 length() 方法连接字符串 concat() 方法创建格式化字符串 format()功能 前言 string是C、java、VB等编程语言中的字符串&…

项目报错clone2.weekday is not a fuction

ant-design-vue中的dayjs版本和我项目中的dayjs版本不一样 项目中的dayjs版本号 ant-design-vue中的dayjs版本号"dayjs": “^1.11.9” 解决方法&#xff1a; 将项目中的版本号更新"dayjs": “^1.11.9” yarn add dayjs^1.11.9

lc162.寻找峰值

由于题目假设nums[-1]和nums[n]等于负无穷 如果nums[i]>nums[i1]&#xff0c;即nums[-1]<nums[i]>nums[i1]&#xff0c;那么在[0,i]区间内一定存在峰值 如果nums[i]<nums[i1]&#xff0c;即nums[i]<nums[i1]>nums[n]&#xff0c;那么在[i1,n-1]区间内一定存…

dubbo原理框架设计

dubbo原理框架设计 &#xff08;1&#xff09;config 配置层&#xff1a;对外配置接口&#xff0c;以 ServiceConfig, ReferenceConfig 为中心&#xff0c;可以直接初始化配置类&#xff0c;也可以通过 spring 解析配置生成配置类。 &#xff08;2&#xff09;proxy 服务代理…

如何使用postman判断返回结果是否正确

针对一个接口&#xff0c;我们在知道参数以及参数对应的结果时&#xff0c;可以通过postman进行判断&#xff0c;验证返回数据是否与预期数据相等。这样可以使我们的接口测试更加的方便简洁。 1、准备数据。 postman可以接受的文件格式如图所示&#xff0c;一般来说可以将我们…

mysql(五)主从配置

目录 前言 一、MySQL Replication概述 二、MySQL复制类型 三、部署MySQL主从异步复制 总结 前言 为了实现MySQL的读写分离&#xff0c;可以使用MySQL官方提供的工具和技术&#xff0c;如MySQL Replication&#xff08;复制&#xff09;、MySQL Group Replication&#xff08;组…

【读点论文】PP-YOLOE: An evolved version of YOLO,面向友好部署的模型设计,为项目后续产业落地提供了更加有效的参考

PP-YOLOE: An evolved version of YOLO Abstract 在本报告中&#xff0c;我们介绍了PP-YOLOE&#xff0c;一种具有高性能和友好部署的工业最先进的目标探测器。我们在之前的PP-YOLOv2的基础上进行优化&#xff0c;采用无锚模式&#xff0c;更强大的骨干和颈部配备CSPRepResSt…

【C语言数据结构】模拟·顺序表·总项目实现

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

文件系统总结

《本文件系统默认linux文件系统》 一、文件系统基本概念 文件系统是操作系统中负责存取和管理信息的模块&#xff0c;它用统一的方式管理用户和系统信息的存储、检索、更新、共享和保护&#xff0c;并为用户提供一整套方便有效的文件使用和操作方法文件系统是操作系统中管理文…

【Quartus FPGA】EMIF DDR3 读写带宽测试

在通信原理中&#xff0c;通信系统的有效性用带宽来衡量&#xff0c;带宽定义为每秒传输的比特数&#xff0c;单位 b/s&#xff0c;或 bps。在 DDR3 接口的产品设计中&#xff0c;DDR3 读/写带宽是设计者必须考虑的指标。本文主要介绍了 Quartus FPGA 平台 EMIF 参数配置&#…

JAVA基础多线程-模拟线程死锁以及预防和避免死锁

引言 线程死锁描述的是这样一种情况&#xff1a;多个线程同时被阻塞&#xff0c;它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞&#xff0c;因此程序不可能正常终止。 一&#xff0c;模拟死锁 示例代码&#xff1a; public class LockT1 {Object o …

最全面的msvcp110.dll丢失修复方法分享,快速修复msvcp110.dll文件

今天主要给大家详细的介绍一下msvcp110.dll丢失修复的方法&#xff0c;因为在网上看到很多人因为这个问题而烦恼&#xff0c;其实这个问题不难解决的&#xff0c;下面就给大家分享多种方法&#xff0c;一起来看看吧。 一. 修复msvcp110.dll丢失的方法 重新安装相关程序 首先&…

干翻Dubbo系列第四篇:Dubbo3第一个应用程序细节补充

前言 不从恶人的计谋&#xff0c;不站罪人的道路&#xff0c;不坐亵慢人的座位&#xff0c;惟喜爱耶和华的律法&#xff0c;昼夜思想&#xff0c;这人便为有福&#xff01;他要像一棵树栽在溪水旁&#xff0c;按时候结果子&#xff0c;叶子也不枯干。凡他所做的尽都顺利。 如…

从源码分析Handler面试问题

Handler 老生常谈的问题了&#xff0c;非常建议看一下Handler 的源码。刚入行的时候&#xff0c;大佬们就说 阅读源码 是进步很快的方式。 Handler的基本原理 Handler 的 重要组成部分 Message 消息MessageQueue 消息队列Lopper 负责处理MessageQueue中的消息 消息是如何添加…

githack的安装步骤+一次错误体验

一.githack的安装步骤 1.要在Kali Linux上安装GitHack工具&#xff0c;您可以按照以下步骤操作&#xff1a; 打开终端并使用以下命令克隆GitHack存储库&#xff1a; git clone https://github.com/lijiejie/GitHack.git2.进入GitHack目录&#xff1a; cd GitHack3.安装依赖项…

『HarmonyOS』万物互联,分布式操作系统

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位喜欢写作&#xff0c;计科专业大二菜鸟 &#x1f3e1;个人主页&#xff1a;starry陆离 &#x1f552;首发日期&#xff1a;2022年7月5日星期二 &#x1f30c;上期文章&#xff1a;『首期文章』 &#x1f4da;订阅专栏&…

leetcode刷题(柠檬水找零、接雨水、宝石与石头、将数组和减半的最少操作次数、更新数组后处理求和查询、删除每行中的最大值、并行课程③)

目录 1、柠檬水找零 2、接雨水 3、宝石与石头 4、将数组和减半的最少操作次数 5、更新数组后处理求和查询 6、删除每行中的最大值 7、并行课程③ 1、柠檬水找零 class Solution:def lemonadeChange(self, bills: List[int]) -> bool:dollars [0, 0] # 美元数组&am…

每日一题——有序链表去重

题目 删除给出链表中的重复元素&#xff08;链表中元素从小到大有序&#xff09;&#xff0c;使链表中的所有元素都只出现一次。 例如&#xff1a;给出的链表为1→1→2,返回1→2。 给出的链表为1→1→2→3→3,返回1→2→3。 数据范围&#xff1a;链表长度满足 0≤n≤100&#…

深度学习训练营之DCGAN网络学习

深度学习训练营之DCGAN网络学习 原文链接环境介绍DCGAN简单介绍生成器&#xff08;Generator&#xff09;判别器&#xff08;Discriminator&#xff09;对抗训练 前置工作导入第三方库导入数据数据查看 定义模型初始化权重定义生成器generator定义判别器 模型训练定义参数模型训…