Filter(过滤)与Listener(监听)

Filter : 过滤器

  • web中的过滤器 :
    • 当我们访问服务器的资源时 , 过滤器可以将请求拦截下来 , 完成一些特殊的功能 ,
  • 过滤器一般是完成一些通用的操作 ,
    • (比如登录的判断 , 只有登录了才能进行操作)
    • 设置编码的操作
    • 敏感字符的操作

Filter的快速入门 :

  • 步骤 :

    • (1)定义一个类 , 实现一个接口 : Filter

      • public class FilterDemo1 implements Filter {}
        
    • (2)复写方法

    • (3)配置拦截资源 :

      • 有两种配置方法:

      • ①web.xml

      • ②注解的方式 :

        • @WebFilter("/*")//访问所有资源之前 , 都要执行该过滤器 , 这里写的就是使用过滤器的资源路径
          public class FilterDemo1 implements Filter {}
          
    • (4)过滤器执行之后 , 要考虑是否放行 ,

    • public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
      	System.out.println("filterdemo1被执行了...");
      	//放行的代码实现 :
      filterChain.doFilter(servletRequest , servletResponse);
      }
      

Filter的细节 :

(1) web.xml配置

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

(2) 过滤器的执行流程

  • ①执行过滤器
  • ②执行放行后的资源 (位于放行语句前的位置)
  • ③回来执行过滤器放行代码后的代码

(3) 过滤器的生命周期方法

  • /**
         * 每一次请求被拦截资源时 , 会执行 , 执行多次
         * 具体的操作
         * @param request
         * @param response
         * @param chain
         * @throws ServletException
         * @throws IOException
         */
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
            System.out.println("doFilter...");
            chain.doFilter(request, response);
        }
    
        /**
         * 在服务器启动后会创建Filter对象 , 然后调用init方法
         * 一般用于加载资源
         * @param config
         * @throws ServletException
         */
        public void init(FilterConfig config) throws ServletException {
            System.out.println("init...");
        }
    
        /**
         * 在服务器关闭之前的时候 , Filter对象被销毁 , 
         * 如果服务器是正常关闭  , 会执行destroy方法
         * 一般进行释放资源
         */
        public void destroy() {
            System.out.println("destroy...");
        }
    

(4) 过滤器的配置详解

①拦截路径的配置
  • 1.具体的资源路径 : /index.jsp 只有访问index.jsp资源时 . 过滤器才会被执行
  • 2.目录拦截 : /user / * 访问 /user 下的所有资源时 , 过滤器会被执行
  • 3.后缀名拦截 : *.jsp 访问所有后缀名为jsp的时候 , 过滤器都会被执行
  • 4.拦截所有资源时 : / * 访问所有的资源时 , 过滤器都会被执行
②拦截方式的配置
  • 资源被访问的方式 :

    • 注解配置 :

      • 设置 : dispatcherTypes属性

      • //表示浏览器直接请求资源的时候 , 只有请求访问index.jsp的时候才执行过滤
        //@WebFilter(value = "/index.jsp" , dispatcherTypes = DispatcherType.REQUEST)
        //表示只有转发访问的的时候才执行 ,
        @WebFilter(value = "/index.jsp" , dispatcherTypes = DispatcherType.FORWARD)
        
    • 注意设置其他属性的时候 , 路径的前边要加value , 之前的是只有一个 , value省略了

      • REQUEST : 默认值 浏览器直接请求资源
      • FORWARD : 转发来访问资源
      • INCLUDE : 包含访问资源
      • ERROR : 错误跳转资源
      • ASYNC : 异步访问
    • 配置多个属性 :

      • @WebFilter(value = "/index.jsp" , dispatcherTypes = {DispatcherType.FORWARD , DispatcherType.REQUEST})
        //将属性以 { } 括起来 , 中间用 , 隔开即可 
        
    • 在xml文件中配置 :

    • <filter-mapping>
              <filter-name>demo1</filter-name>
              <url-pattern>/*</url-pattern>
              <dispatcher>REQUEST</dispatcher>
      </filter-mapping>
      

(5) 过滤器链 (配置多个过滤器)

  • 执行顺序 :
    • 如果有两个过滤器 : 过滤器1 和 过滤器2
      • 先执行过滤器1 ,
      • 在执行过滤器2 ,
      • 资源执行 ,
      • 执行过滤器2 ,
      • 执行过滤器1 .
  • 过滤器的先后顺序问题 :
    • 注解配置 :
    • 按照类名的字符串比较规则去比较的 , 值小的先执行 , 按照总首字母开始比较的顺序 , 一次往后比较 , 知道出现一个区分大小的位置为止 .
      • 如: AFilter 和 BFilter A<B 那么就是 AFilter先执行 ,
      • 如 : Filter6 和 Filter7 就是 Filter6 先执行 ,
      • 但是 如果是 : Filter6 和 Filter17 比较 , 就是Filter17先执行
    • web.xml配置
      • 谁的定义在上边 , 谁就先执行 ,

综合案例_登录验证 :

需求 :

  • 访问 一个资源 , 验证其是否登录了 ,
  • 如果登录了 , 则直接放行
  • 如果没有登录 , 则跳转到登录页面 , 提示 :您尚未登录 , 请先登录

1644323925034

package cn.sichen.web.filter;

import jakarta.servlet.*;
import jakarta.servlet.annotation.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;

/**
 * 登录有关的Filter
 */
@WebFilter("/*")
public class LoginFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        //1.强制转换Http相关的request
        HttpServletRequest request1 =  (HttpServletRequest) request;
        //2.获取资源的请求路径
        String URI = request1.getRequestURI();
        //1.判断是否包含登录相关的资源 , 要注意排除掉css/js/图片/验证码等资源
        if (URI.contains("/login.jsp")||URI.contains("LoginServlet")||URI.contains("/css/")||URI.contains("/js/")||URI.contains("/fonts/")||URI.contains("/checkCodeServlet")){
            //包含证明用户就是想登录 放行
            chain.doFilter(request , response);
        }else{
            //不包含 : 需要验证用户是否登录
            //3.从session中获取User
            HttpSession session = request1.getSession();
            Object main = session.getAttribute("main");
            if (main != null){
                //登录了 放行
                chain.doFilter(request,response);
            }else{
                request.setAttribute("login_error" , "您尚未登录 , 请登录!");
                request.getRequestDispatcher("/login.jsp").forward(request , response);
            }
        }
    }
    public void init(FilterConfig config) throws ServletException {
    }

    public void destroy() {
    }
}


综合案例_敏感词汇过滤 :

  • 对案例录入的数据进行敏感词汇过滤
  • 如果是敏感词汇 , 替换为***

1644333958747

分析 :

1.对request对象进行增强 , 增强获取参数相关参数即可 ,

2.放行 : 传递的是代理对象 ,

package cn.sichen.web.filter;

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.cglib.proxy.Proxy;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 敏感词汇过滤器
 */
@WebFilter("/*")
public class SensitiveWordsFilter implements Filter {
    
     //敏感词汇的list集合
    private List<String> list = new ArrayList<String>();

    public void init(FilterConfig config) throws ServletException {
        try {
            //1.加载敏感词汇的txt文件
            InputStream is = SensitiveWordsFilter.class.getClassLoader().getResourceAsStream("SensitiveWords.txt");
            //2.读取文件  注意 BufferedReader读取本地文件使用的编码是GBK的编码 , 所以使用本地文件的时候 , 也要将编码改为GBK
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
            //3.将文件的每一行数据添加到list中
            String line = null;
            //这里每次就是读取一行数据
            while ((line = bufferedReader.readLine()) != null) {
                list.add(line);
            }
            //关闭这个流
            bufferedReader.close();
            System.out.println(list);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    
    @Override
    public void doFilter(final ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        
        //1.创建代理对象 , 增强 getParameter这个方法
        ServletRequest proxy_request = (ServletRequest) Proxy.newProxyInstance(request.getClass().getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //判断是否是getParameter这个方法
                if (("getParameter").equals(method.getName())) {
                    //1.增强返回值 ,
                    //获取返回值
                    String value = (String) method.invoke(request, args);
                    if (value != null) {
                        for (String str : list) {
                            if (value.contains(str)) {
                                //替换敏感词汇
                                value = value.replaceAll(str, "***");
                            }
                        }
                    }
                    return value;
                }
                return method.invoke(request, args);
            }
        });
        //2.放行 , 传递的是代理对象 ,
        chain.doFilter(proxy_request, response);
    }
    public void destroy() {
    }
}

Listener : 监听器

概念 : JavaWeb的三大组件之一

  • 事件监听机制 :

    • 事件 : 一件事情
    • 事件源 : 事件发生的地方
    • 监听器 : 一个对象
    • 注册监听 : 将事件, 事件源 , 监听器 绑定在一起 , 当事件源上发生某个事件之后 , 执行监听器代码 ,
  • ServletContextListener : 监听ServletContext对象的创建和销毁

    • void contextDestroyed(ServletContextEvent sce) : ServletContext对象被销毁之前会调用该方法
    • void contextInitialized(ServletContextEvent sce) ; ServletContext对象创建之后会调用该方法
  • 实现 :

    • 步骤 :

      • 1.定义一个类去实现 ServletContextListener 这个接口 ,
      • 2.复写方法
      • 3.配置
    • web.xml的配置方式 : (配置比较简单)

      • <!--配置监听器-->
        <listener>
        <listener-class>cn.sichen.web.listener.ContextListener</listener-class>
        </listener>
        <!--在xml文件中指定参数加载路径 , 也就是-->
        <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/classes/applocationContext.xml</param-value>
        </context-param>
        
      • /**
             * 监听ServletContext对象创建的 , ServletContext对象在服务器启动之后自动创建
             * 在服务器启动后自动调用
             * @param sce
             */
            @Override
            public void contextInitialized(ServletContextEvent sce) {
                /* This method is called when the servlet context is initialized(when the Web application is deployed). */
                //加载资源文件
                //1.获取ServletContext对象
                ServletContext servletContext = sce.getServletContext();
                //2.加载资源文件
                String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
                //3.获取真实路径
                String realPath = servletContext.getRealPath(contextConfigLocation);
                //4.加载进内存
                try {
                    FileInputStream fis = new FileInputStream(realPath);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
                System.out.println("ServletContext这个对象被创建了...");
            }
        
            /**
             * 在服务器关闭的时候 , ServletContext对象被销毁 , 当服务器正常关闭的时候 , 调用该方法
             * @param sce
             */
            @Override
            public void contextDestroyed(ServletContextEvent sce) {
                /* This method is called when the servlet Context is undeployed or Application Server shuts down. */
                System.out.println("销毁ServletContext对象...");
            }
        
    • 注解的方式 : 这个方法不需要添加路径即可 ,直接加这个注解接口

      • @WebListener
        

调用该方法
* @param sce
/
@Override
public void contextDestroyed(ServletContextEvent sce) {
/
This method is called when the servlet Context is undeployed or Application Server shuts down. */
System.out.println(“销毁ServletContext对象…”);
}
```

  • 注解的方式 : 这个方法不需要添加路径即可 ,直接加这个注解接口

    • @WebListener
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值