JavaWeb中Filter过滤器和Listener监听器的使用

1.Filter过滤器

Servlet API中提供了一个Filter接口,在开发Web应用时,如果编写的Java类实现了这个接口,则把这个Java类称为过滤器Filter。
通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。

简单来说,就是浏览器请求服务器资源或服务器响应浏览器时,过滤器可以将这些请求和响应拦截下来,完成某些相应的操作。
一般用于完成通用的操作,例如:
①登录验证,只有登录成功后,才能访问资源。
②统一编码处理,在获取数据前,进行编码以解决乱码问题。
③敏感字符过滤。

1.1.Filter快速入门

实现步骤:
(1)定义一个Java类并实现Filter接口;
(2)在这个Java类中复写doFilter()方法;
(3)配置拦截路径:web.xml配置注解配置两种方法,选其中一种即可。
在这里插入图片描述

1.2.Filter的注解配置和web.xml配置

(1)注解配置。

导入javax.servlet.annotation.WebFilter;包,然后在类上使用注解@WebFilter("/*")即可。/*表示访问所有资源之前,都会执行该过滤器。

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

@WebFilter("/*")
public class FilterDemo 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("FilterDemo....");
        // 考虑是否放行
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
    }
}
(2)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">
    <filter>
        <filter-name>demo</filter-name>
        <filter-class>com.atlantis.filter.FilterDemo</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>demo</filter-name>
        <!-- 拦截路径 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

1.3.Filter过滤器执行流程和生命周期

方法描述
init()服务器启动后会创建一个Filter对象,调用init()方法。服务器帮你完成,只执行一次,多用于加载资源
doFilter()每一次请求被拦截资源时,都会被执行。执行多次
destroy()服务器关闭后会销毁Filter对象,如果服务器正常关闭,则会执行destroy()方法,只执行一次,多用于释放资源

在这里插入图片描述

1.4.Filter过滤器的配置详情

(1)配置拦截路径,@WebFilter("拦截路径")
拦截方式配置方法描述
拦截具体资源路径@WebFilter("/index.jsp")只有访问index.jsp资源时,过滤器才会被执行
拦截指定目录下资源@WebFilter("/user/*")访问 /user下的所有资源时,过滤器都会被执行
拦截指定后缀名资源@WebFilter("*.jsp")访问后缀名为jsp资源时,过滤器都会被执行
拦截所有资源@WebFilter("/*")访问所有资源时,过滤器都会被执行
(2)配置拦截方式,即拦截资源被访问的方式

①注解配置,设置dispatcherTypes属性。

dispatcherTypes属性中的属性值描述
REQUEST默认值,浏览器直接请求资源
FORWARD转发方式来访问资源
INCLUDE包含方式访问资源
ERROR错误跳转方式访问资源
ASYNC异步方式访问资源

在这里插入图片描述
②web.xml配置
在对应的filter-mapping标签下,设置<dispatcher></dispatcher>标签内的属性值即可。
在这里插入图片描述

1.5.Filter过滤器链

过滤器链:配置的多个过滤器。在这里,我们只需要了解在过滤器链中的每个过滤器的执行顺序即可。
下面案例:存在两个过滤器,FilterDemo和FilterDemo2。则它们的执行顺序是,FilterDemo1–>FilterDemo2–>访问资源(index.jsp)–>FilterDemo2–>FilterDemo1。
在这里插入图片描述
那么问题来了,为什么是FilterDemo先执行,FilterDemo2后执行?为什么不是FilterDemo2先执行呢。
所以,我们需要了解过滤器的先后顺序问题:
①注解配置下,按照类名的字符串比较规则(按照每个字符进行比较,a比b小,1比2小等等)进行比较,值小的先执行。如果还不能理解的话,看项目工程的文件目录结构,从上到下依次执行。
在这里插入图片描述
②web.xml配置下,按照定义的顺序来,谁先定义谁先开始执行。因为web.xml加载时,是从上往下加载,这样先遇到的过滤器就会被先执行。

1.6.Filter过滤器的简单案例

(1)登录验证

分析一下:访问项目的某个资源时,先验证是否登录。若登录过,则直接放行;若没有登录,则跳转登录界面,提示"请先登录"。

package com.atlantis.filter;

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("/*")
public class LoginFilter implements Filter {
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        // 1.将ServletRequest和ServletResponse强转
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        // 2.获取请求路径
        String uri = request.getRequestURI();
        // 3.判断是否包含登录相关资源路径,要注意排除css/js/图片等一些静态资源
        if (uri.contains("/login.jsp") || uri.contains("/login")) {
            // 4-1放行登录操作
            chain.doFilter(req, resp);
        } else {
            // 4-2不是登录操作,拦截下来
            // 获取session
            Object username = request.getSession().getAttribute("username");
            if (username != null) {
                // 已经登录过,则放行
                chain.doFilter(req, resp);
            } else {
                // 没有登录,则跳转到登录界面
                request.setAttribute("login_msg","请先登录!");
                request.getRequestDispatcher("/login.jsp").forward(request,response);
            }
        }
    }

    public void destroy() {
    }

    public void init(FilterConfig config) throws ServletException {
    }
}

在这里插入图片描述

(2)过滤敏感词汇(代理模式,动态代理)

分析一下:对录入的数据根据SensitiveWords.txt来进行敏感词汇过滤,如果是敏感词则替换为**表示。
我们首先需要对request对象进行增强,增强获取参数相关方法。然后放行传递代理对象。

package com.atlantis.filter;

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.List;

/**
 * 敏感词汇过滤器
 */
@WebFilter("/*")
public class SensitiveWordsFilter implements Filter {
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        // 1.创建代理对象,增强getParameter方法
        ServletRequest proxy_req = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 2.判断是否是getParameter方法
                if ("getParameter".equals(method.getName())) {
                    // 3.增强getParameter方法的返回值
                    // 获取返回值
                    req.setCharacterEncoding("utf-8");
                    String value = (String) method.invoke(req, args);
                    if (value != null) {
                        for (String str : SensitiveWordsList) {
                            // 将敏感词汇替换
                            if (value.contains(str)) {
                                value = value.replaceAll(str, "**");
                            }
                        }
                    }
                    // 返回过滤后的敏感词汇
                    return value;
                }
                // 判断是否是getParameterMap方法
                // 判断是否是getParameterValue方法

                // 若不满足,则原样返回数据
                return method.invoke(req, args);
            }
        });
        // 放行传递代理对象proxy_req
        chain.doFilter(proxy_req, resp);
    }

    // 敏感词汇的List集合
    private List<String> SensitiveWordsList = new ArrayList<String>();
    public void init(FilterConfig config) throws ServletException {
        try {
            // 获取SensitiveWords.txt的真实路径
            ServletContext context = config.getServletContext();
            String realPath = context.getRealPath("WEB-INF/classes/SensitiveWords.txt");
            // 读取SensitiveWords.txt文件,BufferedReader默认GBK编码
            BufferedReader bf = new BufferedReader(new FileReader(realPath));
            // 将文件每一行数据添加到敏感词汇的List集合SensitiveWordsList中
            String line = null;
            while ((line = bf.readLine()) != null) {
                SensitiveWordsList.add(line);
            }
            bf.close();
            System.out.println("敏感词汇:" + SensitiveWordsList);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void destroy() {
    }
}

在这里插入图片描述

2.Listener监听器

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

按监听的对象划分,可以分为:
①ServletContext对象监听器
②HttpSession对象监听器
③ServletRequest对象监听器
按监听的事件划分:
①对象自身的创建和销毁的监听器
②对象中属性的创建和消除的监听器
③session中的某个对象的状态变化的监听器

这里主要讲解一下ServletContextListener:监听ServletContext对象的创建和销毁。ServletContextListener一般用于加载整个项目的资源和配置文件等。

描述方法返回类型
ServletContext对象被销毁前调用该方法contextDestroyed(ServletContextEvent sce)void
ServletContext对象创建后调用该方法contextInitialized(ServletContextEvent sce)void

2.1.ServletContextListener监听器的使用步骤

(1)定义一个Java类,实现ServletContextListener接口;
(2)复写方法;
(3)配置:web.xml配置注解配置两种方法,选其中一种即可。

在web.xml中配置监听器。注意:监听器>过滤器>serlvet,配置的时候要注意先后顺序:

<?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.atlantis.listener.ContextLoaderListener</listener-class>
    </listener>
</web-app>

注解配置,监听器的配置可以直接在代码中通过注释来完成。

package com.atlantis.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener()
public class ContextLoaderListener implements ServletContextListener {
    // 监听ServletContext对象创建,ServletContext对象在服务器启动后自动创建
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        // 一般加载资源文件
        // 1.获取ServletContext对象
        ServletContext servletContext = servletContextEvent.getServletContext();
        // 2.加载资源文件
        String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
        // 3.获取真实路径
        String realPath = servletContext.getRealPath(contextConfigLocation);
        try {
            // 4.加载进内存
            FileInputStream fis = new FileInputStream(realPath);
            System.out.println(fis);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("ServletContext对象被创建了...");
    }

    // 监听ServletContext对象销毁,服务器正常关闭后该方法被调用
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("ServletContext对象被销毁了...");
    }
}

在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值