Web组件:Servlet & Listener & Filter

1 前言

1.1 内容概要

  1. 掌握ServletContextListener的使用,并且理解其执行时机
  2. 掌握Filter的使用,并且理解其执行时机
  3. 能够使用Filter解决一些实际的问题

1.2 前置知识准备

  • Servlet的执行

  • ServletContext的功能和使用

2 Web组件

JavaEE的三大Web组件

  1. Servlet → 处理请求对应的业务
  2. Listener → 监听器
  3. Filter → 过滤器

2.1 Listener监听器

顾名思义就是监听东西的,其实和命名有关系,我们提供的是什么监听器就是监听什么的。

UserListener 就是监听User

监听器在监听到主体做了XX事情,就会触发对应的事件。

2.2 ServletContextListener

监听的主体就是ServletContext,当发现ServletContext做了事情,监听器就会执行该事件特定的方法

  • ServletContext如果初始化,则会执行监听器的初始化方法
  • ServletContext如果销毁,则会执行监听器的销毁方法
  1. 如果我们想要在应用程序启动的过程中,实现一些自定义的代码,需要方法ServletContextListener的监听ServletContext初始化的方法对应的执行方法 → 监听器的初始化方法,会在应用程序启动的时候执行,主要做一些资源的初始化
  2. 如果我们想要在应用程序关闭的过程中,实现一些自定义的代码,放在监听器的销毁方法 → 监听器的销毁方法,会在应用程序关闭(卸载的时候执行) ,主要做资源的释放

2.3 执行过程

当应用程序启动的过程中,逐步加载Web组件

  • 首先会加载ServletContext和Listener组件
    • ServletContext伴随着应用程序初始化,它开始初始化,然后ServletContextListener监听到ServletContext初始化,会执行Listener的Initialized方法
  • 然后初始化loadOnStartup为正数的Servlet

改造之前的业务代码,之前整合MyBatis时,SqlSessionFactory的初始化是通过Servlet的生命周期init方法,当前可以通过ServletContextListener,在应用程序启动的时候,执行contextInitialized方法,在该方法中进行SqlSessionFactory初始化过程,并将其放到ServletContext中

java 复制代码
@WebListener
public class CustomServletContextListener implements ServletContextListener {
    // 当ServletContext初始化的时候执行
    // 应用程序启动的时候向ServletContext中塞入一些数据
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        ServletContext servletContext = servletContextEvent.getServletContext();
        SqlSessionFactory sqlSessionFactory = null;
        try {
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.xml"));
            System.out.println("ServletContext初始化");
            System.out.println("sqlSessionFactory = " + sqlSessionFactory);
        } catch (IOException e) {
            e.printStackTrace();
        }
        servletContext.setAttribute("SqlSessionFactory",sqlSessionFactory);
    }

    // 当ServletContext销毁的时候执行
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("ServletContext销毁");

    }
}
java 复制代码
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {

    SqlSessionFactory sqlSessionFactory;

    @Override
    public void init() throws ServletException {
        ServletContext servletContext = getServletContext();
        sqlSessionFactory = (SqlSessionFactory) servletContext.getAttribute("SqlSessionFactory");
        System.out.println("Servlet初始化");
        System.out.println("sqlSessionFactory = " + sqlSessionFactory);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}

提供Listener,其实主要就是去初始化这个ServletContext

SpringMVC就是基于这样的特点去实现的

3 Filter

Filter是一个执行过滤任务的一个对象。它既可以作用于Request对象,也可以作用于Response对象,或者两者均作用。

也就是Servlet中获取请求之前,Servlet响应之后

3.1 Filter和Servlet的执行

URL-Pattern和Servlet之间存在着映射关系,URL-Pattern和Filter之间也存在着映射关系。

  • 1个URL-Pattern只能对应一个Servlet,但是可以对应多个Filter
  • Servlet和URL-Pattern之间是一对多的关系,但是URL-Pattern和Servlet之间是一对一

其实就意味着一件事,当我们发起一个请求的时候,其实就是一个URL-Pattern对应的请求

  • 对应1个Servlet
  • 对应多个Filter

如果只有一个过滤器那么执行流程如下

多个过滤器,就是就组成了一个过滤器的链,依次执行过滤器

如果增加上对应的方法

有一个问题,是否每一次都会继续执行到下一个拦截器或Servlet?不一定,去界定是否为放行状态

doFilter这个方法中,提供了一个形参,形参叫filterChain,filterChain中提供了一个doFilter方法,如果执行这个方法就是放行,如果不执行,则中断流程

3.2 使用

java 复制代码
/**
 * localhost:8080/demo5/hello
 * localhost:8080/demo5/bye
 * URL-Pattern对于上面两个请求都能起作用,那么我们的URL-Pattern可以设置为 /*
 */
@WebFilter("/*")
public class URLPrintFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String url = request.getRequestURL().toString();
        System.out.println("url = " + url);
        System.out.println("Filter的前半部分");
        //放行
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("Filter的后半部分");
    }

    @Override
    public void destroy() {

    }
}

就算没有Servlet,仍然是可以执行到Filter的


Filter能否继续执行,取决于FilterChain的doFilter方法是否执行

3.3 案例

3.3.1 给请求和响应设置字符集

Post请求中文乱码

request.setCharacterEncoding("utf-8")

响应的时候,响应的字符中文乱码

response.setContentType("text/html;charset=utf-8")

java 复制代码
@WebFilter("/*")
public class CharacterEncodingFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        request.setCharacterEncoding("utf-8");
        //response.setContentType("text/html;charset=utf-8");
        response.setContentType("application/json;charset=utf-8");
        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

3.3.2 登录案例

Http://localhost:8080/demo6/user/login

Http://localhost:8080/demo6/user/info

在Session中是否有存储用户的信息

  1. login登录实现的什么事情?
    1. 验证用户传入的用户名和密码,和数据库中存储的信息是否一致
    2. 验证如果成功,将用户信息存到Session里面
  2. info查看用户信息实现的是什么事情
    1. 从Session中取出信息,分析是否取出了信息
    2. 如果取出了信息,说明登录成功了,根据取出的信息查询用户的具体信息
    3. 如果没有取出信息,提示未登录的json数据
  3. order/list 查询当前用户的订单信息
    1. 从Session中取出信息,分析是否取出了信息
    2. 如果取出了信息,说明登录成功了,根据取出的信息查询用户的订单信息
    3. 如果没有取出信息,提示未登录的json数据
  4. 发现了2a和3a做的是相同的事情,2c和3c做的也实现相同的事情,相同的事情我们可以提取到Filter中
  5. 如果我提取到了Filter中 2中只有2b ,3中只有3b

4 小结

4.1 Web组件

  • 核心是Servlet,处理核心业务
  • Listener,用来做资源的初始化
  • Filter,在Servlet处理前后增加通用的处理
相关推荐
hackeroink8 分钟前
【2024版】最新推荐好用的XSS漏洞扫描利用工具_xss扫描工具
前端·xss
迷雾漫步者2 小时前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-2 小时前
验证码机制
前端·后端
燃先生._.3 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖4 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235244 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240255 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar5 小时前
纯前端实现更新检测
开发语言·前端·javascript
寻找沙漠的人6 小时前
前端知识补充—CSS
前端·css