Filter & Listener

Filter:过滤器

快速入门

# 概念
  * 生活中的过滤器:净水器、空气净化器、土匪
  * Web中的过滤器:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能

# 作用
  * 一般用于完成通用的操作。如:登陆验证、同一编码处理、敏感字符过滤……

# 快速入门
  1)定义一个类,实现接口 Filter(javax.servlet.filter)
  2)复写方法
  3)配置拦截路径
    ① 注解:@WebFilter("拦截路径")
    ② web.xml

<filter>
    <filter-name>demo1</filter-name>
    <filter-class>cn.itcast.web.filter.FilterDemo1</filter-class>
</filter>
<filter-mapping>
    <filter-name>demo1</filter-name>
    <!-- 拦截路径 -->
    <url-pattern>/*</url-pattern>
</filter-mapping>

过滤器细节

# 过滤器执行流程
  1)执行过滤器中放行前的代码
  2)访问放行后的页面
  3)执行过滤器中放行后的代码

# 过滤器生命周期方法
  1)init():在服务器启动后,会创建 Filter对象,然后调用 init()方法,只执行一次,用于加载资源
  2)doFilter()每一次请求被拦截时都会执行,能执行多次
  3)destroy():在服务器正常关闭后,Filter对象被销毁,会调用 destroy()方法,只执行一次,用于释放资源

package cn.itcast.web.filter;

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

@WebFilter("/*")
public class FilterDemo3 implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("doFilter");
        chain.doFilter(req, resp);
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        System.out.println("init");
    }

    @Override
    public void destroy() {
        System.out.println("destroy");
    }
}
View Code 

# 过滤器配置详解
  * 拦截路径配置
    ① 具体资源路径拦截:  /index.jsp   只有访问 index.jsp 资源时,过滤器才会被执行
    ② 目录拦截:  /user/*    访问 /user 下的所有资源,过滤器都会被执行
    ③ 后缀名拦截:  *.jsp    访问所有后缀名为 .jsp资源时,过滤器都会被执行
    ④ 拦截所有资源 /*   访问所有资源时,过滤器都会被执行

package cn.itcast.web.filter;

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

//@WebFilter("/index.jsp")
//@WebFilter("/user/*")
//@WebFilter("*.jsp")
public class FilterDemo4 implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("filterDemo4...");
        chain.doFilter(req, resp);
    }

    @Override
    public void init(FilterConfig config) throws ServletException {

    }

    @Override
    public void destroy() {

    }
}
View Code 

  * 拦截方式配置:资源被访问的方式
    * 注解配置:设置 dispatcherTypes属性
      ① REQUEST:默认值,只有浏览器直接请求资源时拦截
      ② FORWARD:只有转发访问资源时拦截
      ③ INCLUDE:只有包含访问资源时拦截
      ④ ERROR:只有错误跳转资源时拦截
      ⑤ ASYNC:只有异步访问资源时拦截

package cn.itcast.web.filter;

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

//@WebFilter(value = "/index.jsp", dispatcherTypes = DispatcherType.REQUEST)
@WebFilter(urlPatterns = "/index.jsp", dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD})
public class FilterDemo5 implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("Demo555555");
        chain.doFilter(req, resp);
    }

    @Override
    public void init(FilterConfig config) throws ServletException {

    }

    @Override
    public void destroy() {

    }
}
View Code

    * web.xml 配置
      * 设置 <dispatcher>标签体内容即可

# 过滤器链(配置多个过滤器)
  * 执行顺序:如果有两个过滤器
    ① 过滤器1
    ② 过滤器2
    ③ 资源执行
    ④ 过滤器2
    ⑤ 过滤器1

  * 过滤器执行先后顺序:
    * 注解配置:按照类名的字符串比较规则,值小的先执行
    * web.xml配置:<filter-mapping>定义在前边的优先执行

案例

# 案例1_验证登录
  需求:
    ① 访问 day17_case案例的资源,验证其是否登录
    ② 如果登录了,则直接放行
    ③ 如果没有登录,则跳转到登录页面,提示:“您尚未登录,请先登录”

package cn.itcast.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@WebFilter(value = "/*")
public class LoginFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        // 获取资源的请求路径
        HttpServletRequest request = (HttpServletRequest) req;
        String uri = request.getRequestURI();

        // 判断是否包含登录相关的资源路径
        if (uri.contains("/login.hsp") || uri.contains("/loginServlet") || uri.contains("/css/")
                || uri.contains("/js/") || uri.contains("/fonts/") || uri.contains("/checkCodeServlet")) {
            // 包含,表名用户就是想要登录
            chain.doFilter(req, resp);
        } else {
            // 不包含,需要验证用户是否已经登录
            Object user = request.getSession().getAttribute("user");
            if (user != null) {
                chain.doFilter(req, resp);
            } else {
                request.setAttribute("login_msg", "您尚未登录,请登录");
                request.getRequestDispatcher("/login.jsp").forward(request, resp);
            }
        }


    }

    @Override
    public void init(FilterConfig config) throws ServletException {

    }

    @Override
    public void destroy() {

    }
}
View Code

# 案例2_敏感词汇过滤
  * 需求:
    ① 对 day17_case案例录入的数据进行敏感词汇过滤
    ② 敏感词汇参考《敏感词汇.txt》
    ③ 如果是敏感词汇,则替换为 ***

  * 分析:
    ① 对 request对象进行增强,增强获取参数的相关方法
    ② 放行,传递代理对象

  * 增强对象的功能:
    ① 装饰设计模式
    ② 代理设计模式:
      * 真实对象为被代理的对象,代理对象代理真实对象,达到增强真实对象功能的目的
      * 实现方式:
        1)静态代理:有一个类文件描述代理模式
        2)动态代理:在内存中形成代理类

  * 实现代理的步骤:
    ① 代理对象和真实对象实现相同的接口
    ② 代理对象 = Proxy.newProxyInstance()
    ③ 使用代理对象调用方法
    ④ 增强方法

  * 增强方法
    ① 扩展参数列表
    ② 改变返回值类型
    ③ 增强方法执行逻辑

package cn.itcast.web.filter;

import javafx.scene.shape.VLineTo;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 敏感词汇过滤
 */
@WebFilter(value = "/*")
public class SensitiveWordsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        // 创建代理对象,增强getParameter()方法
        ServletRequest proxy_req = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                // 增强getParameter()
                if (method.getName().equals("getParameter")) {
                    String value = (String) method.invoke(req, objects);
                    if (value != null) {
                        for (String s : list) {
                            if (value.contains(s)) {
                                value = value.replaceAll(s, "***");
                            }
                        }
                    }
                }

                return method.invoke(req, objects);
            }
        });

        chain.doFilter(proxy_req, resp);
    }

    private List<String> list = new ArrayList<>();

    @Override
    public void init(FilterConfig config) throws ServletException {
        try {
            // 加载文件
            String realPath = config.getServletContext().getRealPath("WEB-INF/classes/敏感词汇.txt");
            // 读取文件
            BufferedReader br = new BufferedReader(new FileReader(realPath));
            // 将文件的每一行数据添加到list中
            String line = null;
            while ((line = br.readLine()) != null) {
                list.add(line);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void destroy() {

    }
}
View Code 

Listener:监听器

# 概念:Web的三大组件之一 

# 事件监听机制
  * 事件:一件事情
  * 事件源:事件发生的地方
  * 监听器:一个对象
  * 注册监听将事件、事件源、监听器绑定在一起。当事件源上发生某个事件后,执行监听器代码

# ServletContextListener:监听ServletContext对象的创建和销毁
  * 方法:
    * void contextDestroyed(ServletContextEvent sce):ServletContext对象被销毁之前会调用该方法
    * void contextInitialized(ServletContextEvent sce):ServletContext对象创建后会调用该方法

  * 步骤:
    ① 定义一个类,实现 ServletContextListener接口
    ② 复写方法
    ③ 配置
      * web.xml

<listener>
         <listener-class>
            cn.itcast.web.listener.ContextLoaderListener
        </listener-class>
</listener>

      * 注解:@WebListener

package cn.itcast.web.listener;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRequest;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import javax.servlet.http.HttpSessionBindingEvent;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

@WebListener()
public class ContextLoaderListener implements ServletContextListener,
        HttpSessionListener, HttpSessionAttributeListener {

    public ContextLoaderListener() {
    }


    /**
     * 监听ServletContext对象的创建,ServletContext对象在服务器启动后创建
     * <p>
     * 因此,方法在服务器启动后自动调用
     *
     * @param sce
     */
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // 获取ServletContext对象
        ServletContext servletContext = sce.getServletContext();

        // 加载资源文件
        String contextConfig = servletContext.getInitParameter("contextConfigLocation");

        // 获取真实路径
        String realPath = servletContext.getRealPath(contextConfig);

        // 加载进内存
        try {
            FileInputStream fis = new FileInputStream(realPath);
            System.out.println(fis);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println("ServletContext对象被创建了。。。");
    }

    /**
     * 在服务器关闭后,ServletContext对象被销毁后,自动调用该方法
     *
     * @param sce
     */
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("ServletContext对象被销毁了。。。");

    }

    // -------------------------------------------------------
    // HttpSessionListener implementation
    // -------------------------------------------------------
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        /* Session is created. */
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        /* Session is destroyed. */
    }

    // -------------------------------------------------------
    // HttpSessionAttributeListener implementation
    // -------------------------------------------------------
    @Override
    public void attributeAdded(HttpSessionBindingEvent sbe) {
      /* This method is called when an attribute 
         is added to a session.
      */
    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent sbe) {
      /* This method is called when an attribute
         is removed from a session.
      */
    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent sbe) {
      /* This method is invoked when an attibute
         is replaced in a session.
      */
    }
}
View Code
原文地址:https://www.cnblogs.com/zhaochuming/p/13602135.html