zoukankan      html  css  js  c++  java
  • 记录搭建SSM框架中常用到的功能:(监听器)、过滤器和拦截器 以及相关的拓展内容的学习记录

    写在前面:

      其实现在更多的人在使用springboot框架来搭建项目,好处是简单方便拓展,但是想要学习以上说明的三个功能,我个人感觉还是从SSM框架进行切入,能够方便理解。另外,这篇博客更多的是记录如何使用,涉及原理的部分需要更多得学习。

    SSM框架和监听器、过滤器、拦截器 —— 监听器

    能帮助开发者监听web中的特定事件,比如ServletContext,HttpSession,ServletRequest的创建和销毁;变量的创建、销毁和修改等。可以在某些动作前后增加处理,实现监控。

    1.1 初识监听器,了解web.xml加载过程

    我们应该都知道,对于ssm搭建的javaWeb项目,一般都是使用Tomcat或Jboss等服务器容器来启动的,java项目启动配置弄好之后,启动容器,就可以将项目启动。一般 tomcat 或者 Jboss 都是先访问加载web项目的web.xml配置文件。

    容器一般是先加载该配置文件中的节点<context-param> 和 <listener>:

      <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-context.xml</param-value>
      </context-param>
      <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>

    紧接着容器会创建ServletContext,这是属于该web项目的上下文环境,所谓上下文环境其实也可以理解为一个容器,里面装着web的应用信息。注意一个web项目也只有一个ServletContext,其生命周期是

    • 创建:容器启动(将web应用加载到容器中)
    • 销毁:容器关闭,服务器shut down

    那这个ServletContext对象的作用是什么呢?

    • 获得web应用全局初始化参数,之后项目中便可以调用这些参数。
    • 可以通过这个context获得web项目中任何资源的绝对路径:

        string path= context.getrealpath(“相对于该web应用的相对路径”);注意:src下的文件被服务器内部加载会被放到WEB-INF/classes文件夹中。

          例:string path_c =context.getrealpath(“WEB-INF/classes/c.txt”)     

        也可以使用类加载器,专门加载classes文件夹下的文件。xxxservlet.class.getClassloader().getresource(“c.txt”).getpath();其中c.txt 是相对于classes的相对路径。

    • 它是一个域对象,域对象:存储数据的区域就是域对象。

      ServletContext域对象的作用范围是整个web应用(所有web应用中的自资源都可以向ServletContext对象中存储数据,而且数据可以共享)。

    首先容器以<context-param>中的<param-name>为键,<param-value>为值,将数据转换为键值对,存入ServletContext中;

    接着容器会创建<lisrtener>中的类实例,根据配置的class的类路径<listener-class>,来创建监听对象ContextLoaderListener,该对象中的 contextInitialized 是初始化方法,启动web时,调用该方法,得到ServletContextEventevent.getServletContext();

    public void contextInitialized(ServletContextEvent event){         
        this.initWebApplicationContext(event.getServletContext());
    }

    接着容器会读取<filter>节点,根据指定类路径来实例化过滤器;


    以上是在web项目还没有完全启动起来的时候,已经完成了工作。如果系统中有Servlet,则servlet是在第一次调用的时候被实例化的,且一般不会被容器销毁,他可以服务多个用户的请求。所以Servlet会被上面的元素初始化的要迟;

    总的来说,web.xml的加载顺序是:
    <context-param> —> <listener> —> <filter> —> <servlet>,如果web.xml中出现了相同的元素,则按照元素出现的先后顺序加载。

    1.2 要怎么编辑自定义监听器呢?

    从上述可以知道,想要SSM项目启动需要在web.xml中配置上监听器ContextLoaderListener,而该监听器的作用是 可以初始化<context-param>中的参数到ServletContext中。

    那么我们如果想要自定义监听器的话就可以参考ContextLoaderListener。我们先看一下该类中的源码是怎么实现的:

    package org.springframework.web.context;
    
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    
    public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
        public ContextLoaderListener() {
        }
    
        public ContextLoaderListener(WebApplicationContext context) {
            super(context);
        }
    
        public void contextInitialized(ServletContextEvent event) {
            this.initWebApplicationContext(event.getServletContext());
        }
    
        public void contextDestroyed(ServletContextEvent event) {
            this.closeWebApplicationContext(event.getServletContext());
            ContextCleanupListener.cleanupAttributes(event.getServletContext());
        }
    }

    可以看到该监听器继承了接口 ServletContextListener  ,接口中有两个需要实现的方法 contextInitialized 和 contextDestroyed:

    package javax.servlet;
    
    import java.util.EventListener;
    
    public interface ServletContextListener extends EventListener {
        void contextInitialized(ServletContextEvent var1);
    
        void contextDestroyed(ServletContextEvent var1);
    }

    很明显是初始化方法和销毁方法。据查询,该接口的实现类的对应的方法,将会在Tomcat 或者 Jboss 容器启动过程中进行回调。

    1.2.1 ServletContextListener 接口

    因此,如果我们想要在项目启动的时候 自定义加载初始化信息(如:配置数据库信息、设置计时器去定时执行任务等操作)监听器的话,

    可以参考在自定义的 Listener 类中去实现 ServletContextListener 接口,如:

    package com.shine.platform.listener;
    
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @Author: Shine EtherealWind
     * @Description:
     * @Date: create in 17:07 2021/7/29
     */
    public class TestMyListener implements ServletContextListener {
        @Override
        public void contextInitialized(ServletContextEvent servletContextEvent) {
            System.out.println("* 应用启动的时候 TestMyListener init... *");
            Map<String, String> sysRoles = new HashMap<>();
            sysRoles.put("ADMIN","管理员");
            sysRoles.put("NEWMAN", "小白用户");
            sysRoles.put("BIZUSER", "业务用户");
            servletContextEvent.getServletContext().setAttribute("SYS_ROLES", sysRoles);
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent servletContextEvent) {
        }
    }

    然后别忘记在web.xml中配置监听

    <listener>
        <listener-class>com.shine.platform.listener.TestMyListener</listener-class>
    </listener>

    就是在启动应用的时候加载TestMyListener 的初始化方法,可以将信息放到ServletContext中。

    那在应用层怎么调用呢?

    方法一:

    WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
    ServletContext servletContext = webApplicationContext.getServletContext();
    Map<String, String> sysRoles = (Map<String, String>)servletContext.getAttribute("SYS_ROLES");
    System.out.println("初始化监听器中设置的角色:" + sysRoles.get("ADMIN"));

    方法二:

    @RequestMapping(value = "/login")
        @ResponseBody
        public String login(User user, HttpServletRequest request){
            List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
    
            Map<String, String> sysRoles2 = (Map<String, String>)request.getServletContext().getAttribute("SYS_ROLES");
            System.out.println("初始化监听器中设置的角色:" + sysRoles2.get("BIZUSER"));
         return null; }

     而执行的结果中是能够得到期望结果的

     1.2.2 HttpSessionListener接口

    对于javaweb项目,当浏览器第一次访问服务器的时候,服务器就会创建一个session。如果我们想要监听当前网站的访问人数,实现对httpsession的监控又要怎么去做呢?

    java提供有HttpSessionListener来监听Httpsession。因此我们来实现该接口就可以做到监听session了

    package com.shine.platform.listener;
    
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    
    /**
     * @Author: Shine EtherealWind
     * @Description:
     * @Date: create in 9:54 2021/8/5
     */
    public class TestHttpSessionListener implements HttpSessionListener {
    
        private static int visitNum = 0;
    
        @Override
        public void sessionCreated(HttpSessionEvent httpSessionEvent) {
            System.out.println("会话创建的时候调用该方法 TestHttpSessionListener . sessionCreated");
            visitNum ++ ;
            System.out.println("当前系统访问用户数:"+visitNum);
        }
    
        @Override
        public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
            System.out.println("...destroy...");
            visitNum -- ;
            System.out.println("当前系统访问用户数:"+visitNum);
        }
    }

    注意:不要忘记web.xml里面的配置

      <listener>
        <listener-class>com.shine.platform.listener.TestHttpSessionListener</listener-class>
      </listener>

    在有浏览器第一次访问服务器的时候监听触发sessionCreated方法,而sessionDestroyed方法是在调用session.invalidate()方法时或者超过session有效期被触发

    其中session的有效期可以再web.xml中被配置,需要注意单位是分钟:

     1.2.3 ServletRequestListener接口

    该接口监听的是 ServletRequest 对象,

    当客户端向服务器发送一次请求,服务器就会调用初始化方法,

    当服务器对这个请求作出响应之后,就会调用销毁方法。

    用途:可以用来记录系统被访问的次数。

  • 相关阅读:
    BZOJ1862: [Zjoi2006]GameZ游戏排名系统
    BZOJXXXX: [IOI2000]邮局——四边形不等式优化初探
    BZOJ1801: [Ahoi2009]chess 中国象棋
    BZOJ1505: [NOI2004]小H的小屋
    BZOJ1899: [Zjoi2004]Lunch 午餐
    BZOJ1057: [ZJOI2007]棋盘制作
    BZOJ1100: [POI2007]对称轴osi
    BZOJ1123: [POI2008]BLO
    线性规划之单纯形讲解
    BZOJ 3265 志愿者招募加强版(单纯形)
  • 原文地址:https://www.cnblogs.com/EtherealWind/p/15097242.html
Copyright © 2011-2022 走看看