百木园-与人分享,
就是让自己快乐。

【JavaWeb-Servlet】笔记(4)--- 监听器接口;应用监听器接口 优化在线考试管理系统

Servlet 规范扩展 ------ 监听器接口


1、介绍:

1)一组来自于 Servlet 规范下的接口,共有8个接口。

2)监听器接口需要由开发人员亲自实现,Http服务器提供 jar 包并没有对应的实现类。

3)监听器接口用于监控【作用域对象生命周期变化时刻】以及【作用域对象共享数据变化时刻】。

 

2、作用域对象:

1)Servlet 规范中,在服务端内存中可以在某些条件下为两个 Servlet 之间提供数据共享方案的对象,被称为【作用域对象】。

2)Servlet 规范下作用域对象:

    ServletContext         【全局作用域对象】

    HttpSession              【会话作用域对象】

    HttpServletRequest  【请求作用域对象】

 

3、监听器接口实现类开发规范(三步):

1)根据监听的实际情况,选择对应监听器接口进行实现;

2)重写监听器接口声明【监听事件处理方法】;

3)在web.xml文件将监听器接口实现类注册到 Http 服务器。

 

4、ServletContextListener 接口:

1)作用:通过接口合法的检测全局作用域对象被初始化时刻以及被销毁时刻。

2)监听事件处理方法:

public void contextInitlized(){...}  //全局作用域对象被 Http 服务器初始化(创建)时被调用
public void contextDestory(){...}    //全局作用域对象被 Http 服务器销毁时被调用

 

5、ServletContextAttributeListener 接口:

1)作用:通过这个接口合法的检测全局作用域对象共享数据变化时刻。

2)监听事件处理方法:

public void contextAdd(){...}       //在全局作用域对象添加共享数据时,触发
public void contextReplaced(){...}  //在全局作用域对象更新共享数据时,触发
public void contextRemove(){...}    //在全局作用域对象删除共享数据时,触发

 

 实现监听器接口 --- 优化在线考试管理系统


  • 在线考试管理系统(未优化) 源代码:【JavaWeb-Servlet】编程(1)--- JavaSE+MySQL+JDBC+Servlet 实现在线考试管理系统(用户信息管理模块) 

 

  • 网站预览:

【JavaWeb-Servlet】笔记(4)--- 监听器接口;应用监听器接口 优化在线考试管理系统

 

  • 实现查询用户信息的代码块:
package com.burnyouth.controller;

import com.burnyouth.dao.UserDao;
import com.burnyouth.entity.User;
import jakarta.servlet.*;
import jakarta.servlet.http.*;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;

public class UserFindServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        UserDao dao = new UserDao();
        PrintWriter out = null;

        //1、【调用Dao】将查询命令推送到数据库服务器上,得到所有用户信息【List】
        Date startTime = new Date();//通过Date类,看看遍历用户信息会消耗多少时间?
        List<User> userList = dao.findAll();
        Date endTime = new Date();
        System.out.println(\"执行遍历用户信息耗费时间:\"+(endTime.getTime()-startTime.getTime())+\"毫秒\");

        //2、【调用响应对象】将用户信息结合<table>标签命令以二进制形式写入到响应体
        //设置响应头content-type属性
        response.setContentType(\"text/html;charset=utf-8\");
        out = response.getWriter();
        out.print(\"<table border=\'2\'>\");
        out.print(\"<tr>\");
        out.print(\"<td>用户编号</td>\");
        out.print(\"<td>用户姓名</td>\");
        out.print(\"<td>用户密码</td>\");
        out.print(\"<td>用户性别</td>\");
        out.print(\"<td>用户邮箱</td>\");
        out.print(\"<td>操作</td>\");
        out.print(\"</tr>\");
        for (User user : userList) {
            out.print(\"<tr>\");
            out.print(\"<td>\" + user.getUserId() + \"</td>\");
            out.print(\"<td>\" + user.getUserName() + \"</td>\");
            out.print(\"<td>******</td>\");
            out.print(\"<td>\" + user.getSex() + \"</td>\");
            out.print(\"<td>\" + user.getEmail() + \"</td>\");
            out.print(\"<td><a href=\'/myWeb/user/delete?userId=\"+user.getUserId()+\"\'>\" +
                    \"删除用户</a></td>\");
            out.print(\"</tr>\");
        }
        out.print(\"</table>\");
    }
}

 

  • 执行多次查询代码,IDEA 控制台:

【JavaWeb-Servlet】笔记(4)--- 监听器接口;应用监听器接口 优化在线考试管理系统

 

  • 问题描述:

       可以看到遍历一次用户信息时长基本稳定在 13 ~ 18 毫秒之间,如果这个管理系统的使用者只有一个人,当然用户的体验是非常好的,但这是不现实的,而当系统同时使用的用户人数达到几万时,有的用户就可能需要等待几分钟的时间,那用户体验感就非常差了,所以我们就需要应用适合的优化方案来提高系统的运行速度,而监听器接口 就刚好是一种优化方案。

       通过查阅资料发现,遍历用户信息大部分时间都耗费在了 Connection 通道的建立上,所以我们可以在服务器启动时,就预准备创建几个 Connection 接口,这样在执行遍历用户信息代码的时候,就不需要再创建 Connection 通道了。

 

  • 优化代码:

com.burnyouth.listener.Onelistener(监听器):

package com.burnyouth.listener;

import com.burnyouth.util.JdbcUtil;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class Onelistener implements ServletContextListener {
    /**
     * 在全局作用域对象创建时,创建 10 个 Connection 通道
     * @param sce 获取全局作用域对象
     */
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        //装10个通道的集合
        Map connections = new HashMap();
        
        //获取全局作用域对象
        ServletContext application = sce.getServletContext();
        
        for (int i = 0; i < 10; i++) {
            try {
                Connection connection = JdbcUtil.getConnection();
                //将创建好的通道放到集合里,并打上 true 标记(代表此通道为空闲状态)
                connections.put(connection, true);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        //最后将集合上交给全局作用域对象
        application.setAttribute(\"connections\", connections);

    }

    /**
     * 全局作用域对象销毁时,同时关闭 10 个 Connection 通道
     * @param sce 获取全局作用域对象
     */
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        //获取全局作用域对象
        ServletContext application = sce.getServletContext();
        
        //将集合取出来
        Map map = (Map) application.getAttribute(\"connections\");
        
        //将集合中的通道一个个地关闭
        Iterator it = map.keySet().iterator();
        while (it.hasNext()) {
            Connection connection = (Connection) it.next();
            if (connection != null) {
                JdbcUtil.close(connection,null,null);
            }
        }
    }
}

 

xml (仅展示将监听器注册到服务器的代码):

<listener>
    <listener-class>com.burnyouth.listener.Onelistener</listener-class>
</listener>

 

com.burnyouth.util.JdbcUtil(利用方法重载,添加了新的 getConnection() ,close() ):

package com.burnyouth.util;

import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletRequest;

import java.sql.*;
import java.util.Iterator;
import java.util.Map;

/**
 * JDBC工具类
 */

public class JdbcUtil {

    /**
     * 工具类的构造方法都应该是私有的
     * 因为工具类是需要频繁使用的,所以我们要避免代码的重复书写
     * 将工具类方法都设为静态的,再将构造方法私有化(这样想new都new不出来),直接采用类名调用
     */

    //静态代码块在类加载时执行,并且只执行一次
    static {
        try {
            Class.forName(\"com.mysql.cj.jdbc.Driver\");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private JdbcUtil() {
    }

    /**
     * 获取数据库连接对象
     *
     * @return 连接
     * @throws SQLException
     */
    //因为此方法是被调用的方法,所以出现异常直接上抛就行
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(\"jdbc:mysql://localhost:3306/burning_youth\"
                , \"root\", \"888\");
    }

    /**
     * 获取服务器在启动时,就创建好的 Connection 通道
     * @param request 网站的请求对象
     * @return Map集合中空闲的 Connection 通道
     * @throws SQLException
     */
    public static Connection getConnection(HttpServletRequest request) throws SQLException {
        //获取全局作用域对象:
        ServletContext application = request.getServletContext();

        //获取集合
        Map connections = (Map) application.getAttribute(\"connections\");
        Connection connection = null;

        //获取集合中空闲状态的 Connection 通道
        Iterator it = connections.keySet().iterator();
        while (it.hasNext()) {
            connection = (Connection) it.next();
            //查看通道状态
            boolean flag = (boolean) connections.get(connection);
            if (flag == true) {
                //找到空闲状态的通道后,更改状态
                connections.put(connection,false);
                //结束循环
                break;
            }
        }
        return connection;
    }

    /**
     * 关闭资源
     *
     * @param connection 连接资源
     * @param statement  数据库操作对象
     * @param resultSet  结果集
     */
    public static void close(Connection connection, Statement statement, ResultSet resultSet) {
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭资源,注意通道不要关闭,将状态更改为空闲状态即可
     * @param connection
     * @param statement
     * @param resultSet
     * @param request 网站的请求对象
     */
    public static void close(Connection connection, Statement statement,
                             ResultSet resultSet,HttpServletRequest request) {
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        //获取全局作用域对象
        ServletContext application = request.getServletContext();

        //获取集合
        Map connections = (Map) application.getAttribute(\"connections\");

        //更改通道状态
        connections.put(connection,true);
    }

}

 

com.burnyouth.dao.UserDao(仅展示优化后的 findAll() 代码):

public List findAll(HttpServletRequest request) {
        Connection connection = null;
        PreparedStatement ps = null;
        ResultSet resultSet = null;
        List userList = new ArrayList();
        try {
            //调用新方法
            connection = JdbcUtil.getConnection(request);
            String sql = \"select * from user\";
            ps = connection.prepareStatement(sql);
            resultSet = ps.executeQuery();
            while (resultSet.next()) {
                Integer userId = resultSet.getInt(\"userId\");
                String userName = resultSet.getString(\"userName\");
                String password = resultSet.getString(\"password\");
                String sex = resultSet.getString(\"sex\");
                String email = resultSet.getString(\"email\");
                User user = new User(userId, userName, password, sex, email);
                userList.add(user);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            //调用新方法
            JdbcUtil.close(connection, ps, resultSet,request);
        }
        return userList;
    }

 

  • 优化效果:效果有点顶了,快10倍不止啊 !!!    (❁´◡`❁)

 【JavaWeb-Servlet】笔记(4)--- 监听器接口;应用监听器接口 优化在线考试管理系统

 

随笔:


1、设计模式六大原则之一的开闭原则,禁止我们修改原来写好的代码,所以当我们优化代码功能时,并没有直接修改原来的方法体,而是在类中通过方法重载机制,写入了优化后的代码。

2、向一个项目中添加功能或者优化功能时,如果涉及到方法之间的调用问题,注意由根到顶的逻辑。

 


来源:https://www.cnblogs.com/Burning-youth/p/16010651.html
本站部分图文来源于网络,如有侵权请联系删除。

未经允许不得转载:百木园 » 【JavaWeb-Servlet】笔记(4)--- 监听器接口;应用监听器接口 优化在线考试管理系统

相关推荐

  • 暂无文章