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处理前后增加通用的处理
相关推荐
Json_1817901448017 分钟前
电商拍立淘按图搜索API接口系列,文档说明参考
前端·数据库
风尚云网40 分钟前
风尚云网前端学习:一个简易前端新手友好的HTML5页面布局与样式设计
前端·css·学习·html·html5·风尚云网
木子020443 分钟前
前端VUE项目启动方式
前端·javascript·vue.js
GISer_Jing1 小时前
React核心功能详解(一)
前端·react.js·前端框架
捂月1 小时前
Spring Boot 深度解析:快速构建高效、现代化的 Web 应用程序
前端·spring boot·后端
深度混淆1 小时前
实用功能,觊觎(Edge)浏览器的内置截(长)图功能
前端·edge
Smartdaili China1 小时前
如何在 Microsoft Edge 中设置代理: 快速而简单的方法
前端·爬虫·安全·microsoft·edge·社交·动态住宅代理
秦老师Q1 小时前
「Chromeg谷歌浏览器/Edge浏览器」篡改猴Tempermongkey插件的安装与使用
前端·chrome·edge
滴水可藏海1 小时前
Chrome离线安装包下载
前端·chrome
m51271 小时前
LinuxC语言
java·服务器·前端