filter&listener

filter&listener

一、Filter

1.Filter概述

1.1什么是filter

​ Filter:一个实现了特殊接口(Filter)的Java类. 实现对请求资源(jsp,servlet,html,)的过滤的功能.

​ 过滤器是一个运行在服务器的程序, 优先于请求资源(Servlet或者jsp,html)之前执行. 过滤器是javaweb技术中最为实用的技术之一.

1.2 过滤器的作用

​ 对目标资源(Servlet,jsp)进行过滤.

​ 应用场景:登录权限检查,解决网站乱码,过滤敏感字符 …

2.Filter入门(重点)

2.1.步骤
2.1.1配置文件方式
  1. 创建一个类实现Filter接口
  2. 在web.xml配置FIlter的拦截路径
2.1.2注解方式
  1. 创建一个类实现Filter接口
  2. 在这个类上面添加@WebFilter(“拦截的路径”)

建议:可以直接new Filter

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-965PKNbh-1629121563198)(E:/Java/03-就业阶段_JAVAWEB阶段/03-就业阶段_JAVAWEB课件/day28_filter&listener/笔记/img/1556586460285.png)]

2.2.代码
2.2.1 通过xml配置方式
  • 创建一个类实现Filter接口
/**
 * - 创建一个类实现Filter接口
 * - 在web.xml对过滤器进行配置
 */
public class FilterDemo01 implements Filter {
    @Override
    //过滤的方法
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("FilterDemo01收到了请求...");
    }

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

    }


    @Override
    public void destroy() {

    }
}
  • 在web.xml对过滤器进行配置
<!--注册Filter-->
<filter>
    <filter-name>FilterDemo01</filter-name>
    <filter-class>com.itheima.web.filter.FilterDemo01</filter-class>
    </filter>
    <!--配置Filter过滤路径-->
    <filter-mapping>
    <filter-name>FilterDemo01</filter-name>
    <url-pattern>/demo01</url-pattern>
</filter-mapping>
2.2.2通过注解方式
  • 创建一个类实现Filter接口
  • 直接在这个类上面添加注解进行配置
@WebFilter("/demo02")
public class FilterDemo02 implements Filter{

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("FilterDemo02... 收到了请求");
    }

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

    }


    @Override
    public void destroy() {

    }
}

3.Filter的生命周期

3.1Filter生命周期介绍

​ 过滤器从创建到销毁的过程

3.2生命周期方法

​ init(FilterConfig):初始化

​ doFilter(ServletReqeust req,ServletResponse resp,FilterChain chain):执行过滤的方法

​ destroy():销毁

3.3Filter生命周期描述
  1. 服务器启动的时候, 会调用init()方法进行初始化【调用一次】
  2. 任何一次请求都会调用doFilter()方法进行过滤【路径相匹配】
  3. 服务器正常关闭或者项目从服务器移除, 调用destory()方法进行销毁【调用一次】

注意: 默认情况下,Servlet是来了第一次请求的时候 调用init()方法进行初始化.我们可以在Servlet里面设置启动项.

3.4 FilterConfig【了解】

获得过滤器的初始化参数

  • 配置初始化参数
<filter>
    <filter-name>myFilter01</filter-name>
    <filter-class>com.itheima.filter.MyFilter01</filter-class>

    <!--添加初始化参数-->
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>myFilter01</filter-name>
    <!--
             servlet的映射路径的目的是: 指定由哪个servlet去处理对应的请求
             过滤器的过滤路径的目的是: 指定过滤哪个或者哪些请求
        -->
    <url-pattern>/*</url-pattern>
</filter-mapping>
  • 在Filter的init()方法里面获得了
@Override
public void init(FilterConfig filterConfig) throws ServletException {
    //在filter对象初始化的时候,使用filterConfig对象获取web.xml配置文件中的初始化参数
    String encoding = filterConfig.getInitParameter("encoding");
    System.out.println("MyFilter01创建了..."+encoding);
}

4.映射路径

​ 假设有一个管理员权限的过滤器,它应该对用户发出的管理员功能的请求进行条件的过滤。但是当用户发出登录、注册等请求的时候,不应该进行过滤。所以我们过滤器,应该有选择的过滤器请求。这就需要学习配置过滤器不同的映射路径,从而让过滤器过滤希望过滤器的请求。

4.1完全路径匹配

以"/"开始

/demo01 ---> 过滤器只能拦截路径/demo01; 
4.2目录匹配

以"/"开始 以 *结束 .

/* --->当前项目下的所有的路径都可以拦截;   /aa/*  ---> 可以拦截 /aa/bb, /aa/bb/cc
4.3扩展名匹配

以"*"开始 例如: *.jsp *.do

*.do--->可以拦截路径的后缀是 do的 ;  *.jsp--->拦截所有JSP

4.4 缺省匹配

/ 除了jsp以外的资源都匹配

当前Filter里面不支持, Servlet里面可行的. 后面在Servlet里面遇到

5.拦截方式

​ 有了上面学习的映射路径,我们可以控制过滤器过滤指定的内容,但是我们在访问资源的时候,并不是每次都是之间访问,有时是以转发的方式访问的,这就需要我们要让过滤器可以区分不同的访问资源的方式,有不同的拦截方式。 是通过 DispatcherType 来指定的.

  • DispatcherType.REQUEST,默认值,过滤从浏览器发送过来的请求和重定向 不过滤转发

  • DispatcherType.FORWARD,只过滤转发过来的请求

  1. 通过dispatcherTypes配置拦截方式

    • DispatcherType.FORWARD: 【只】过滤转发

    • DispatcherType.REQUEST: 除了转发以为其它的都过滤(1.浏览器的直接请求 2.重定向)【默认值】

  2. 拦截方式的这个值,我们可以配置多个

@WebFilter(value = {"/demo06"},dispatcherTypes={DispatcherType.FORWARD,DispatcherType.REQUEST})

一般情况下, 转发我们不会过滤的. 转发属于服务器内部的行为. 直接使用默认值的情况偏多

6.过滤器链(filterChain)

​ 过滤器链作用:一个请求可能被多个过滤器所过滤,只有当所有过滤器都放行,请求才能到达目标资源,如果有某一个过滤器没有放行,那么请求则无法到达后续过滤器以及目标资源

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yfmkFdIe-1629121563203)(E:/Java/03-就业阶段_JAVAWEB阶段/03-就业阶段_JAVAWEB课件/day28_filter&listener/笔记/img/1534215879101.png)]

  1. 过滤器链执行顺序
    • 配置文件: 谁先配置filter-mapping 谁先执行
    • 注解方式: 按照Filter的首字母顺序 eg: AFilter BFilter A在B的前面, AFilter先执行
    • 如果既有注解方式配置的过滤器,又有配置文件方式配置的过滤器,那么配置文件方式配置的过滤器先进行过滤

案例一: 统一全网站请求的中文乱码的处理

1,需求分析

​ 在整个网站中,可能会有get请求或post请求向服务器提交参数.参数中往往有中文信息.在后台每个Servlet中都需要去处理乱码.

​ 我们想做的是:请求到达Servlet中.就可以直接调用getParameter方法获得请求参数,请求参数已经没有乱码了.

2,思路分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QH7qIOma-1629121563211)(E:/Java/03-就业阶段_JAVAWEB阶段/03-就业阶段_JAVAWEB课件/day28_filter&listener/笔记/img/1571567560219.png)]

3,代码实现
package com.itheima.filter;

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

/**
 * 包名:${PACKAGE_NAME}
 *
 * @author Leevi
 * 日期2020-07-17  10:41
 */
@WebFilter("/*")
public class EncodingFilter implements Filter {
    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //统一设置请求的编码方式为UTF-8
        req.setCharacterEncoding("UTF-8");
        chain.doFilter(req, resp);
    }

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

    }
}

案例二: 非法字符过滤

1,需求分析

​ 当用户发出非法言论的时候,提示用户言论非法。

​ 效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5AXGKANp-1629121563217)(E:/Java/03-就业阶段_JAVAWEB阶段/03-就业阶段_JAVAWEB课件/day28_filter&listener/笔记/img/tu_1.png)]

第一个版本
思路分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KBDsu3L1-1629121563218)(E:/Java/03-就业阶段_JAVAWEB阶段/03-就业阶段_JAVAWEB课件/day28_filter&listener/笔记/img/v1.jpg)]

代码实现
  • IllegalFilter
package com.itheima.filter;

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

/**
 * @author Leevi
 * 日期2020-10-18  10:09
 */
@WebFilter("/*")
public class IllegalCharFilter implements Filter {
    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //1. 获取客户端输入的内容
        String content = req.getParameter("content");
        if (content != null) {
            //2. 判断评论内容中是否有非法字符
            if (content.contains("你大爷")) {
                resp.setContentType("text/html;charset=UTF-8");
                //评论内容中有非法字符
                resp.getWriter().write("评论中包含非法字符,请重新评论");

                return;
            }
        }

        //如果请求参数中没有content,或者content中没有非法字符,都放行
        chain.doFilter(req, resp);
    }

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

    }
}

第二个版本
思路分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9TXbSxOI-1629121563220)(E:/Java/03-就业阶段_JAVAWEB阶段/03-就业阶段_JAVAWEB课件/day28_filter&listener/笔记/img/v2.jpg)]

代码实现
package com.itheima.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
 * @author Leevi
 * 日期2020-07-17  11:01
 */
@WebFilter("/*")
public class IllegalCharFilter implements Filter {
    private List<String> strList = new ArrayList<>();
    @Override
    public void destroy() {

    }
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //从strList中遍历出每一个字符串,然后进行比较
        //判断请求参数中是否包含非法字符
        String content = req.getParameter("content");
        if (content != null) {
            for (String str : strList) {
                if (content.contains(str)) {
                    //表示请求参数中有非法字符,则拦截
                    resp.getWriter().write("评论中包含非法字符,请重新评论!!!");
                    return;
                }
            }
        }
        chain.doFilter(req, resp);
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        //读取IllegalWords.txt里面的数据
        //1. 将IllegalWords.txt转换成字节输入流
        InputStream is = IllegalCharFilter.class.getClassLoader().getResourceAsStream("IllegalWords.txt");
        //2. 将字节输入流,包装成BufferReader
        try {
            BufferedReader bfr = new BufferedReader(new InputStreamReader(is,"UTF-8"));
            String  str = null;
            while (( str = bfr.readLine()) != null) {
                //每读到一个字符串,就将它存储到strList中
                strList.add(str);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

第三个版本
思路分析
  1. 动态代理的作用是:
    1. 在不修改类的源码的基础上,增强类的方法
    2. 可以减少重复代码,在执行方法之前添加前置操作、执行方法之后添加后置操作(Spring的AOP思想)
    3. 我们可以在不写接口的实现类的情况下,创建接口的对象(mybatis框架)
  2. 代理模式的分类:
    1. 静态代理
    2. 动态代理
  3. 静态代理和动态代理的区别:
    1. 静态代理中必须存在代理类
    2. 静态代理的代理关系是在编译的时候确定的,而动态代理的代理关系是在程序运行的时候才确定的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nZIciaBK-1629121563222)(E:/Java/03-就业阶段_JAVAWEB阶段/03-就业阶段_JAVAWEB课件/day28_filter&listener/笔记/img/v3.jpg)]

代码实现
package com.itheima.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
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;

/**
 * 包名:${PACKAGE_NAME}
 *
 * @author Leevi
 * 日期2020-07-17  11:01
 */
@WebFilter("/*")
public class IllegalCharFilter implements Filter {
    private List<String> strList = new ArrayList<>();
    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //放行之前,使用动态代理技术,增强req对象的方法
        //将req强转成HttpServletRequest
        HttpServletRequest request = (HttpServletRequest) req;
        //类加载器
        ClassLoader classLoader = req.getClass().getClassLoader();
        //被代理的接口: HttpServletRequest
        HttpServletRequest requestProxy = (HttpServletRequest) Proxy.newProxyInstance(classLoader, new Class[]{HttpServletRequest.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //增强getParameter()方法,其它方法还是调用被代理者原本的方法
                if (method.getName().equals("getParameter")) {
                    //要增强getParameter()方法,其实就是将请求参数值中的非法字符替换成*
                    //1. 获取请求参数值
                    String value = (String) method.invoke(request, args);
                    //2. 判断请求参数值中是否包含非法字符
                    for (String str : strList) {
                        if (value.contains(str)) {
                            //2.1 包含非法字符,就要将value中的非法字符替换成*
                            String start = "";
                            for (int i=0;i<str.length();i++){
                                start += "*";
                            }
                            value = value.replace(str,start);
                        }
                    }
                    return value;
                }
                //不用增强的方法,要调用被代理者原本的方法
                return method.invoke(request,args);
            }
        });

        //最后肯定要放行
        chain.doFilter(requestProxy, resp);
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        //读取IllegalWords.txt里面的数据
        //1. 将IllegalWords.txt转换成字节输入流
        InputStream is = IllegalCharFilter.class.getClassLoader().getResourceAsStream("IllegalWords.txt");
        //2. 将字节输入流,包装成BufferReader
        try {
            BufferedReader bfr = new BufferedReader(new InputStreamReader(is,"UTF-8"));
            String  str = null;
            while (( str = bfr.readLine()) != null) {
                //每读到一个字符串,就将它存储到strList中
                strList.add(str);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

二、监听器Listener

1.Listener概述

1.1什么是Listener

​ 监听器就是一个Java类,用来监听其他的JavaBean对象的变化

​ 在javaweb中监听器就是监听三个域对象的状态的。request,session,servletContext(application)

1.2监听器的应用

​ 主要在Swing编程

​ 在Android/ios大量应用

​ JS里面的事件

2.javaweb中的监听器

2.1 javaweb的监听器

​ javaweb的监听器:监听ServletContext,HttpSession,ServletRequest三个域对象状态

​ 事件源和监听器绑定的过程:通过配置web.xml完成

2.2 JavaWeb中的监听器类型
  • 三类8个

只讲解监听ServletContext的创建和销毁.

ServletContext是什么时候创建: 服务器启动的时候

ServletContext是什么时候销毁: 服务器关闭的时候

所以监听ServletContext创建和销毁,就能监听服务器的启动和关闭,就可以在服务器启动和关闭的时候执行一些代码(比如在服务器启动的时候读取Spring的配置文件,创建Spring的核心容器)

2.3JavaWeb的监听器使用步骤
  1. 创建一个类实现监听器接口
  2. 在web.xml进行配置(绑定)

3.监听ServletContext的创建和销毁的监听器

说明: 监听ServletContext对象的创建和销毁

  • 方法

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-734oVBC2-1629121563224)(E:/Java/03-就业阶段_JAVAWEB阶段/03-就业阶段_JAVAWEB课件/day28_filter&listener/笔记/img/tu_1-1568181485454.png)]

  • 问题

    ServletContext对象何时创建和销毁:应用在,它就在

    	创建:服务器启动时候(前提是这个项目在这个服务器里面).  服务器为每个WEB应用创建一个单独的ServletContext.
    
    	销毁:服务器关闭的时候,或者项目从服务器中移除.
    
  • 企业中应用

    ​ 初始化工作.

    ​ 加载配置文件:Spring框架,ContextLoaderListener

步骤:

  1. 创建一个类实现ServletContextListener
  2. 在web.xml配置

代码:

  • JAVA代码

    package com.work.listener;
    
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    
    /**
     * 包名:com.work.listener
     *
     * @author Leevi
     * 日期2020-07-17  14:38
     * 一、写一个类实现ServletContextListener接口,并重写方法
     * 方法1: contextInitialized()会在ServletContext对象创建的时候执行,也就是在服务器启动的时候
     * 方法2: contextDestroyed()会在ServletContext对象销毁的时候执行,也就是在服务器关闭的时候
     *
     * 二、在web.xml中配置监听器
     */
    public class MyContextListener implements ServletContextListener{
        @Override
        public void contextInitialized(ServletContextEvent sce) {
            System.out.println("监听到了服务器的启动....创建spring的核心容器");
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
            System.out.println("监听到了服务器的关闭....销毁spring的核心容器");
        }
    }
    
    
  • 配置(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_3_1.xsd"
             version="3.1">
        <listener>
            <listener-class>com.work.listener.MyContextListener</listener-class>
        </listener>
    </web-app>
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值