一看就懂的Filter & Listener教程(附思维导图)

前言:本文章是Java Web后端技术系列的第六篇,主要介绍Filter和Listener的概念和使用。接下来将持续更新,感兴趣的小伙伴请持续关注。本人也是初接触Java Web方面的知识,尚有很多不足,如有错误还望指正!

Web的三大组件

Filter

介绍

当用户访问服务器资源时,过滤器将请求拦截下来,完成一些通用的操作
应用场景:登录验证、统一编码处理、敏感字符过滤

使用

基本使用

步骤
  1. 编写java类继承Filter接口
    a. 在这个类中定义拦截的规则
  2. 配置web.xml文件
    a. 设置要拦截的是对哪一个servlet的请求
    web.xml文件中的配置信息如下
	<filter>
		<!--拦截器的名字-->
        <filter-name>quickFilter</filter-name>
        <!--拦截器类-->
        <filter-class>com.filter.quickFilter</filter-class>
    </filter>
    <filter-mapping>
    	<!--拦截器名字-->
        <filter-name>quickFilter</filter-name>
        <!--下面的地址是浏览器访问这个servlet的地址,常用的是“/*”,表示对所有访问拦截-->
        <url-pattern>/TargetServlet</url-pattern>
    </filter-mapping>
例子

servlet类

@WebServlet("/TargetServlet")
public class TargetServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("访问到目标资源");

        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().write("访问到目标资源");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

拦截器类

public class quickFilter implements Filter {
    //初始化方法
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    /**
     * 过滤方法
     * @param servletRequest 请求对象
     * @param servletResponse 响应对象
     * @param filterChain 过滤器链(是否放行)
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("quickFilter拦截了请求");

        //放行
        filterChain.doFilter(servletRequest,servletResponse);
    }

    //销毁方法
    @Override
    public void destroy() {

    }
}

web.xml配置文件

<filter>
        <filter-name>quickFilter</filter-name>
        <filter-class>com.filter.quickFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>quickFilter</filter-name>
        <!--下面的地址是浏览器访问这个servlet的地址,常用的是“/*”,表示对所有访问拦截-->
        <url-pattern>/TargetServlet</url-pattern>
    </filter-mapping>

拦截路径的设置

  • 精准匹配
    • 用户访问指定目标资源(/targetServlet)时,过滤器进行拦截
  • 目录匹配
    • 用户访问指定目录下(/user/*)所有资源时,过滤器进行拦截
  • 后缀匹配
    • 用户访问指定后缀名(*.html)的资源时,过滤器进行拦截
  • 匹配所有
    • 用户访问该网站所有资源(/*)时,过滤器进行拦截

过滤器链

在这里插入图片描述
如果用户访问目标资源 /targetServlet时,需要经过 FilterA、FilterB
那么过滤器链执行顺序 (先进后出)

  1. 用户发送请求
  2. FilterA拦截,放行
  3. FilterB拦截,放行
  4. 执行目标资源 show.jsp
  5. FilterB增强响应
  6. FilterA增强响应
  7. 封装响应消息格式,返回到浏览器

过滤器链中执行的先后问题:配置文件 <filter-mapping> ,谁先声明,谁先执行

案例

使用filter统一编解码问题
在这里插入图片描述

思路

写一个过滤器对所有请求进行拦截,在过滤器中统一编解码的方式。

实现

要访问的servlet

public class wordsServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.获取表单中的信息
        String content = req.getParameter("content");
        //2.将请求参数的值输出到浏览器
        resp.getWriter().write("留言内容:"+content);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

过滤器

public class encodeFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //在过滤器中统一编解码方式
        //向下转型
        HttpServletRequest hsr = (HttpServletRequest) servletRequest;
        HttpServletResponse hsrp = (HttpServletResponse) servletResponse;
        //判断是否post请求
        //因为get请求服务器的解码方式是utf-8,与浏览器一致
        if (hsr.getMethod().equalsIgnoreCase("post")) {
            hsr.setCharacterEncoding("UTF-8");
        }
        hsrp.setContentType("text/html;charset=utf-8");
		//放行
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

前端代码

<%--
  Created by IntelliJ IDEA.
  User: Leo
  Date: 2020/9/20
  Time: 9:38
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  <h3>留言板</h3>
  <form action="/filter_demo/wordsServlet" method="post">
    <textarea name="content" id="text" cols="30" rows="10"></textarea>
    <input type="submit" value="提交留言"/><br/>
  </form>
  </body>
</html>

web.xml文件中的配置

 <servlet>
        <servlet-name>wordsServlet</servlet-name>
        <servlet-class>com.servlet.wordsServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>wordsServlet</servlet-name>
        <url-pattern>/wordsServlet</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>encodeFilter</filter-name>
        <filter-class>com.filter.encodeFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>encodeFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

原理

浏览器向tomcat服务器发起请求,tomcat服务器会生成两个对象:request和response,将它们传给filter,执行filter里面的逻辑决定是否放行,如果放行就把这两个对象传给目标servlet。响应也会进行拦截。
相当于在浏览器和目标servlet之间加了一道网,它们之间的通信(请求或响应)都要经过这道网的审查,进来可能会被拦截下来,但出去不会被拦截掉。

生命周期

  • 创建
    服务器启动项目加载,创建filter对象,执行init方法(只执行一次)
    初始化方法 public void init(FilterConfig config);
  • 运行(过滤拦截)
    用户访问被拦截目标资源时,执行doFilter方法
    执行拦截方法 public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain);
  • 销毁
    服务器关闭项目卸载时,销毁filter对象,执行destroy方法(只执行一次)
    销毁方法 public void destroy();
  • 补充:过滤器一定是优先于servlet创建的

总结

在这里插入图片描述

Listener

介绍

在我们的java程序中,有时也需要监视某些事情,一旦被监听的对象发生相应的变化,我们应该采取相 应的操作。
监听web三大域对象:HttpServletRequest、HttpSession、ServletContext
通过监听器监听三大域对象它们的创建和销毁
场景:历史访问次数、统计在线人数、系统启动时初始化配置信息

使用

ServletContextListener为例

步骤

  1. 创建一个类实现ServletContextListenner接口
  2. 实现ServletContextListennercontextInitializedcontextDestroyed方法。
  3. 给这个类在xml中配置

实现

public class MyServletContextListenner1 implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("服务器启动,servletContext被创建了");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("服务器停止,servletContext被销毁了");
    }
}
<listener>
	<listener-class>com.itheima.listenner.MyServletContextListenner1</listenerclass>
</listener>

同理:使用如下接口以相同的方式也可以监听到session对象和request对象的创建和销毁
HttpSessionListener:监听Httpsession域的创建于销毁的监听器
ServletRequestListener:监听ServletRequest域的创建于销毁的监听器

总结

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值