过滤器和监听器

第一章:Filter

1.1-概述

Java filter ,Java过滤器能够对目标资源的请求和响应进行截取。

一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤...

1.2-快速入门

使用步骤

  1. 定义一个类,实现接口Filter
  2. 重写接口Filter中的方法
  3. 配置拦截路径
    • web.xml配置
    • 注解配置

代码1-web.xml配置

Filter实现类代码

package cn.it;

import javax.servlet.*;
import java.io.IOException;
public class Test01Filter implements Filter {
  public void destroy() {
    System.out.println("服务器正常关闭执行4...");
  }

  public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
    System.out.println("开始过滤请求2...");
    chain.doFilter(req, resp);  // 放行
    System.out.println("开始过滤响应3...");
  }


  public void init(FilterConfig config) throws ServletException {
    System.out.println("服务启动开始执行1....init");
  }

}

web.xml配置

<?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>test01</filter-name>
        <!--过滤器程序路径-->
        <filter-class>cn.it.Test01Filter</filter-class>
    </filter>
    <filter-mapping>
        <!--过滤器名称-->
        <filter-name>test01</filter-name>
        <!--拦截的资源路径-->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

代码2-注解配置

package cn.it;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter("/*")
public class Test02Filter implements Filter {
  public void destroy() {
    System.out.println("服务器正常关闭4...");
  }

  public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
    System.out.println("开始过滤请求2...");
    chain.doFilter(req, resp);
    System.out.println("开始过滤响应3...");
  }


  public void init(FilterConfig config) throws ServletException {
    System.out.println("服务启动开始执行1....init");
  }

}

1.3-过滤器执行流程

  1. init方法:在服务器启动后,会创建Filter对象,然后调用init方法。只执行一次。用于加载资源。
  2. doFilter方法:每一次请求被拦截资源时,会执行。执行多次。
  3. destroy方法:在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭,则会执行destroy方法。只执行一次。用于释放资源

1.4-拦截路径详细配置

  1. 具体资源路径: /index.jsp , 只有访问index.jsp资源时,过滤器才会被执行。
    . 拦截目录: /user/*, 访问/user下的所有资源时,过滤器都会被执行
  2. 后缀名拦截: *.jsp ,访问所有后缀名为jsp资源时,过滤器都会被执行
    . 拦截所有资源:/* , 访问所有资源时,过滤器都会被执行

1.5-访问资源的方式详细配置

注解配置:设置dispatcherTypes属性-@WebFilter(value= "/*",dispatcherTypes = DispatcherType.REQUEST)

  1. REQUEST:默认值。浏览器直接请求资源
  2. FORWARD:转发访问资源
  3. INCLUDE:包含访问资源
  4. ERROR:错误跳转资源
  5. ASYNC:异步访问资源

web.xml配置

<?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>test01</filter-name>
        <filter-class>cn.it.Test01Filter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>test01</filter-name>
        <url-pattern>/*</url-pattern>
        <!--取值:REQUEST、ERROR、FORWARD、INCLUDE、ASYNC-->
        <dispatcher>ASYNC</dispatcher>
    </filter-mapping>
</web-app>

1.6-多个过滤器执行顺序问题

注解配置:按照类名的字符串比较规则比较,值小的先执行

  • 如: AFilter 和 BFilter,AFilter就先执行了。

web.xml配置: <filter-mapping>谁定义在上边,谁先执行

1.7-敏感词过滤

需求

代码

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  <form action="${pageContext.request.contextPath}/WordsServlet" method="post">
    <textarea name="info" id="" cols="30" rows="10"></textarea>
    <input type="submit" value="提交">
  </form>
  </body>
</html>

过滤器

package cn.filters;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
@WebFilter("/WordsServlet")
public class WordsFilter implements Filter {
  public void destroy() {
  }

  public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
    req.setCharacterEncoding("utf-8");
    // 创建代理对象,实现对req对象中方法的增强
    ServletRequest req2 = (ServletRequest)Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(method.getName().equals("getParameter")){
          String value = (String) method.invoke(req,args);
          for (String s : list) {
            if(value.contains(s)){
              value = value.replaceAll(s,"***");
            }
          }
          System.out.println(value);
          return value;
        }
        return method.invoke(req,args);
      }

    });
    // 放行
    chain.doFilter(req2, resp);
  }
  // 定义list存放敏感词列表
  private List<String> list = new ArrayList<>();
  public void init(FilterConfig config) throws ServletException {
    // 获取ServletContext对象
    ServletContext servletContext = config.getServletContext();
    // 获取敏感词文本真实路径
    String path = servletContext.getRealPath("/WEB-INF/classes/word.txt");
    // 读取并添加到列表中
    try (BufferedReader reader = new BufferedReader(new FileReader(path))){
      String line = null;
      while ((line=reader.readLine())!=null){
        list.add(line);
      }

    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }

  }

}

servlet

package cn.servlets;
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("/WordsServlet")
public class WordsServlet extends HttpServlet {
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // 获取请求的参数
    String content = request.getParameter("info");
    // 设置到request对象中
    request.setAttribute("info",content);
    // 转发显示页读取
    request.getRequestDispatcher("/show.jsp").forward(request,response);
  }

  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    this.doPost(request, response);
  }
}

show.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>显示信息</h1>
<div>${requestScope.info}</div>
</body>
</html>

敏感词文件

笨蛋
混蛋
...

第二章:监听器

2.1-概述

是指专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生变化时,立即采取相应的行动 。

web监听器由servlet规范提供的,它可以监听客户端的请求,服务端的操作,监听的对象包括ServletContext,HttpSession,ServletRequest三个预对象(内置对象),分别对应aplication,session,request。

2.2-内置对象

JSP中一共预先定义了9个这样的内置对象,分别为:request、response、session、application、out、pagecontext、config、page、exception
内置对象(又叫隐含对象)特点:

  • 由JSP规范提供,不用编写者实例化。
  • 通过Web容器实现和管理
  • 所有JSP页面均可使用
  • 只有在脚本元素的表达式或代码段中才可使用(<%=使用内置对象%>或<%使用内置对象%>)

request对象

request 对象是 javax.servlet.httpServletRequest类型的对象。 该对象代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据。(包括头信息、系统信息、请求方式以及请求参数等)。request对象的作用域为一次请求。

session对象

session 对象是由服务器自动创建的与用户请求相关的对象。服务器为每个用户都生成一个session对象,用于保存该用户的信息,跟踪用户的操作状态。session对象内部使用Map类来保存数据,因此保存数据的格式为“Key/value”。 session对象的value可以是复杂的对象类型,而不仅仅局限于字符串类型。

application对象

application 对象可将信息保存在服务器中,直到服务器关闭,否则application对象中保存的信息会在整个应用中都有效。与session对象相比,application对象生命周期更长,类似于系统的“全局变量”。

2.3-监听器的作用

  1. 统计在线人数和在线用户
  2. 系统启动时加载初始化信息
  3. 统计网站访问量
  4. 跟Spring结合

2.4-快速入门

首先,创建一个实现监听器接口的类

package com.java.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class FirstListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("contextInitialized");
        // 初始化时获取相关的配置参数
    	String name = servletContextEvent.getServletContext().getInitParameter("appName");
    	System.out.println("应用程序的名字是:"+name);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("contextDestroyed");
    }
}

其次,配置web.xml或使用注解进行注册

<?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.java.listener.FirstListener</listener-class>
    </listener>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    <login-config>
        <auth-method>BASIC</auth-method>
    </login-config>
    <!--初始化参数-->
    <context-param>
        <param-name>appName</param-name>
        <param-value>ServeletLisenerAPP</param-value>
    </context-param>
</web-app>

或者

@WebListener
public class FirstListener implements ServletContextListener {
    ...
}

启动Tomcat

启动tomcat,控制台输出如下,说明当web应用启动时会自动创建一个application对象,且只有一个

关闭Tomcat

如下表示当前应用销毁

2.5-监听器的启动顺序

2.6-监听器的分类

按监听的对象划分

  1. 用于监听应用程序环境对象(ServletContext)的事件监听器
  2. 用于监听用户会话对象(HttpSession)的事件监听器
  3. 用于监听请求消息对象(ServletRequest)的事件监听器

按监听的事件划分

监听域对象自身的创建和销毁的事件监听器

监听域对象中的属性的增加和删除的时间监听器

2.7-ServletContext的创建与销毁

ServletContext实现了ServletContextListener用于监听它的创建与销毁事件,一个web项目可以定义多个ServletContextListener,但一个web项目只有一个ServletContext对象。
ServletContextListener有两个事件处理方法,这两个方法都会传入ServletContextEvent事件对象,可以获取ServletContext对象以及一些初始化参数。ServletContextListener主要用途:可以做定时器,加载全局属性对象,创建全局的数据库连接,加载一些缓存信息。

2.8-HttpSession的创建与销毁

与ServletContext类似,HttpSession实现了HttpSessionListener用于监听它的创建与销毁事件,一个web项目可以定义多个HttpSessionListener,但一个web项目只有一个HttpSession对象。HttpSessionEvent事件对象,可以获取当前被创建的HttpSession对象。HttpSessionListener主要用途:统计在线人数,记录访问日志。

Session创建:用户打开浏览器第一次访问我们应用时,这次会话web容器会分配一个session,可以在session中保存一些信息

Session销毁:1.手动点退出,关闭服务器 2.关闭浏览器一段时间直到session过期 3.不关闭浏览器,session超时

2.9-ServletRequest的创建与销毁

ServletRequest实现了ServletRequestListener用于监听它的创建与销毁事件,一个web项目可以定义多个ServletRequestListener,但一个web项目只有一个ServletRequest对象。ServletRequestListener主要用途:读取request里的参数,记录访问历史,路径。

原文地址:https://www.cnblogs.com/lpl666/p/12129827.html