|
|
|
@ -16,177 +16,101 @@ import java.util.HashMap;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 字典初始化监视器 用的是服务器监听,每次项目启动,都会调用这个类
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 字典初始化监视器
|
|
|
|
|
* 用的是服务器监听机制,实现了 `ServletContextListener`
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* 接口,意味着该类会监听 Servlet 上下文的相关事件(启动和销毁)。
|
|
|
|
|
* 每次项目启动时,Servlet 容器都会自动调用这个类的相应方法,
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* 用于执行一些初始化操作,例如加载字典表数据并进行预处理,以及启动相关的线程等,
|
|
|
|
|
* 确保在项目运行过程中相关的字典数据和线程等资源处于可用状态,为后续业务逻辑的正常执行提供支持。
|
|
|
|
|
* 这是一个字典初始化监视器类,它实现了ServletContextListener接口,利用服务器监听机制,在每次项目启动时都会被调用,
|
|
|
|
|
* 主要负责完成字典表数据的初始化工作以及启动一个自定义的线程(MyThreadMethod)。在项目停止时,也能相应地记录相关日志信息,
|
|
|
|
|
* 整体在整个项目的生命周期中,对于字典表数据的准备以及特定线程的启动管理起着关键作用,确保相关功能在合适的时机得以执行。
|
|
|
|
|
*/
|
|
|
|
|
// 使用@WebListener注解将该类标记为一个Web监听器,使其能够被Web容器识别并在对应的生命周期事件(如项目启动、停止等)发生时被调用,
|
|
|
|
|
// 从而执行相应的逻辑,在这里就是进行字典初始化以及线程启动等操作。
|
|
|
|
|
@WebListener
|
|
|
|
|
public class DictionaryServletContextListener implements ServletContextListener {
|
|
|
|
|
|
|
|
|
|
// 创建一个日志记录器,用于记录该类在执行过程中的相关信息,
|
|
|
|
|
//
|
|
|
|
|
// 比如服务器启动、停止时的状态,字典表初始化的进度以及线程启动等操作情况,
|
|
|
|
|
// 方便在开发、调试以及运行时查看操作详情、排查问题等。
|
|
|
|
|
// 创建一个静态的Logger对象,用于记录日志信息,通过LoggerFactory.getLogger方法传入当前类的Class对象来获取,
|
|
|
|
|
// 后续可以使用这个logger在不同的生命周期方法中记录如项目启动、停止、字典表初始化等各个阶段的关键信息,方便排查问题以及了解程序执行情况。
|
|
|
|
|
private static final Logger logger = LoggerFactory.getLogger(DictionaryServletContextListener.class);
|
|
|
|
|
|
|
|
|
|
// 定义一个 `MyThreadMethod` 类型的成员变量,
|
|
|
|
|
//
|
|
|
|
|
// 从名称推测可能是用于执行特定业务逻辑的线程相关类,
|
|
|
|
|
// 在后续的 `contextInitialized` 方法中会根据情况实例化并启动该线程,
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// 用于在项目启动后执行一些异步或者后台持续运行的任务(具体取决于 `MyThreadMethod` 类的实现逻辑)。
|
|
|
|
|
// 声明一个MyThreadMethod类型的变量,用于存储一个自定义的线程对象,这个线程大概率执行一些与业务相关的后台任务,具体任务由MyThreadMethod类的实现决定,
|
|
|
|
|
// 初始化为null,会在合适的时机(项目启动时的上下文初始化阶段)进行实例化并启动。
|
|
|
|
|
private MyThreadMethod myThreadMethod;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 当 Servlet 上下文销毁时(例如服务器关闭),
|
|
|
|
|
*
|
|
|
|
|
* 会调用该方法,用于执行一些清理或者资源释放相关的操作,
|
|
|
|
|
* 当前代码中主要是通过日志记录器记录服务器停止的相关信息,方便后续查看服务器的关闭情况以及是否有异常等问题。
|
|
|
|
|
* 此方法是ServletContextListener接口中定义的,在Web应用的Servlet上下文被销毁时(通常意味着项目停止)会被调用,
|
|
|
|
|
* 在这里主要用于记录服务器停止的相关日志信息,方便后续查看项目的关闭情况以及进行相关的日志分析等操作。
|
|
|
|
|
*
|
|
|
|
|
* @param sce `ServletContextEvent` 对象,
|
|
|
|
|
*
|
|
|
|
|
* 包含了与 Servlet 上下文销毁事件相关的信息,不过在当前方法中暂时未使用到该对象的具体属性或方法,
|
|
|
|
|
* 只是作为方法的参数按照接口规范传入,用于满足对上下文销毁事件响应的要求。
|
|
|
|
|
* @param sce ServletContextEvent对象,包含了与Servlet上下文销毁相关的事件信息,不过在此方法中目前只是利用它来触发日志记录,未对其事件相关内容做更多处理。
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public void contextDestroyed(ServletContextEvent sce) {
|
|
|
|
|
logger.info("----------服务器停止----------");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 当 Servlet 上下文初始化时(也就是项目启动时),
|
|
|
|
|
* 会调用该方法,用于执行一系列的初始化操作,主要包括以下几个部分:
|
|
|
|
|
* 1. 获取 Spring 应用上下文,
|
|
|
|
|
*
|
|
|
|
|
* 以便从上下文中获取相关的 Bean(如 `DictionaryService`)来进行后续的业务操作。
|
|
|
|
|
* 2. 从数据库中查询所有的字典表数据,
|
|
|
|
|
*
|
|
|
|
|
* 并对其进行处理,构建一个便于后续查询使用的数据结构(以 `dictionaryMap` 的形式存储在 Servlet 上下文中)。
|
|
|
|
|
* 3. 根据情况实例化并启动 `MyThreadMethod` 线程,
|
|
|
|
|
*
|
|
|
|
|
* 用于执行特定的业务逻辑任务,使得该线程在项目启动后就开始运行。
|
|
|
|
|
*
|
|
|
|
|
* @param sce `ServletContextEvent` 对象,
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* 包含了与 Servlet 上下文初始化事件相关的信息,通过该对象可以获取到 Servlet 上下文对象,
|
|
|
|
|
* 进而用于获取 Spring 应用上下文以及设置共享的属性等操作,
|
|
|
|
|
* 此方法是ServletContextListener接口中定义的,在Web应用的Servlet上下文初始化时(也就是项目启动时)会被调用,
|
|
|
|
|
* 主要承担了字典表数据初始化以及启动自定义线程的重要任务,通过一系列操作将字典表数据整理并存储到Servlet上下文的属性中,方便后续在整个项目中使用,
|
|
|
|
|
* 同时启动特定线程来执行可能的后台持续任务等操作,并且在各个关键步骤记录相应的日志信息,便于了解初始化的执行情况。
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* 是整个初始化流程中与 Servlet 容器交互的关键参数。
|
|
|
|
|
* @param sce ServletContextEvent对象,包含了与Servlet上下文初始化相关的事件信息,通过它可以获取到Servlet上下文对象,进而用于获取Spring应用上下文以及设置上下文属性等操作。
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public void contextInitialized(ServletContextEvent sce) {
|
|
|
|
|
// 通过 `WebApplicationContextUtils` 工具类,
|
|
|
|
|
//
|
|
|
|
|
// 基于传入的 `ServletContext`(从 `ServletContextEvent` 中获取)获取 Spring 的应用上下文对象,
|
|
|
|
|
// 应用上下文对象包含了 Spring 容器管理的所有 Bean 以及相关的配置信息,
|
|
|
|
|
//
|
|
|
|
|
// 后续可以通过它获取到需要的业务逻辑组件(如 `DictionaryService`)来执行具体的操作。
|
|
|
|
|
// 通过WebApplicationContextUtils工具类的getWebApplicationContext方法,传入从ServletContextEvent对象中获取的Servlet上下文对象,
|
|
|
|
|
// 获取整个Web应用的Spring应用上下文(ApplicationContext),后续可以基于这个上下文来获取Spring容器管理的各种Bean实例,比如获取字典服务相关的Bean。
|
|
|
|
|
ApplicationContext appContext = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
|
|
|
|
|
|
|
|
|
|
logger.info("----------字典表初始化开始----------");
|
|
|
|
|
// 从Spring应用上下文中获取名为"dictionaryService"的Bean实例,并强制转换为DictionaryService类型,
|
|
|
|
|
// DictionaryService应该是一个用于处理字典表相关业务逻辑的服务层接口,通过它可以调用如查询字典表数据等方法来进行字典表初始化操作。
|
|
|
|
|
DictionaryService dictionaryService = (DictionaryService)appContext.getBean("dictionaryService");
|
|
|
|
|
// 调用dictionaryService的selectList方法,传入一个默认的EntityWrapper<DictionaryEntity>对象(可能用于添加一些通用的查询条件等,具体取决于业务实现),
|
|
|
|
|
|
|
|
|
|
// 从 Spring 应用上下文中获取 `DictionaryService`
|
|
|
|
|
// 类型的 Bean,用于调用字典表相关的业务逻辑方法,
|
|
|
|
|
// 这里通过强制类型转换将获取到的 `Object` 类型的
|
|
|
|
|
//
|
|
|
|
|
// Bean 转换为 `DictionaryService` 类型,以便后续进行数据库查询等操作,
|
|
|
|
|
// 因为 `DictionaryService` 应该是实现了对字典表数据进行增删改查等操作的服务层接口,
|
|
|
|
|
//
|
|
|
|
|
// 在项目中负责与数据库交互获取字典表数据。
|
|
|
|
|
DictionaryService dictionaryService = (DictionaryService) appContext.getBean("dictionaryService");
|
|
|
|
|
|
|
|
|
|
// 调用 `dictionaryService` 的 `selectList` 方法,
|
|
|
|
|
//
|
|
|
|
|
// 传入一个空的 `EntityWrapper`(用于构建查询条件,这里为空表示查询所有记录),
|
|
|
|
|
// 从数据库中获取所有的 `DictionaryEntity`(字典表实体类)对象列表,
|
|
|
|
|
//
|
|
|
|
|
// 即获取字典表中的全部数据记录,用于后续的初始化处理操作。
|
|
|
|
|
// 获取字典表中的所有字典实体数据,返回一个List<DictionaryEntity>类型的列表,列表中的每个DictionaryEntity对象代表一条字典表记录,包含了如字典编码、索引等相关信息。
|
|
|
|
|
List<DictionaryEntity> dictionaryEntities = dictionaryService.selectList(new EntityWrapper<DictionaryEntity>());
|
|
|
|
|
// 创建一个HashMap对象,用于存储整理后的字典表数据,其结构是外层的键为字典编码(String类型),值为内层的一个Map<Integer, String>,
|
|
|
|
|
// 内层的Map中,键为代码索引(Integer类型),值为对应的索引名称(String类型),这样的结构方便后续根据字典编码以及索引快速查找对应的名称等信息。
|
|
|
|
|
Map<String, Map<Integer,String>> map = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
// 遍历从字典表中查询到的所有字典实体数据列表,对每条记录进行处理,将其按照特定的结构整理到前面创建的map对象中。
|
|
|
|
|
for(DictionaryEntity d :dictionaryEntities){
|
|
|
|
|
|
|
|
|
|
// 创建一个 `HashMap` 类型的对象,用于存储字典表数据按照字典代码
|
|
|
|
|
//
|
|
|
|
|
// (`dic_code`)分组后的信息,每个 `dic_code` 对应一个内部的 `Map`,
|
|
|
|
|
// 内部 `Map` 的键是 `code_index`(编码索引),值是 `index_name`(索引名称),
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// 方便后续根据字典代码快速查找对应的索引信息等操作,
|
|
|
|
|
// 这个数据结构会被存储到 Servlet 上下文中,供整个项目中其他地方方便地获取和使用字典表相关信息。
|
|
|
|
|
Map<String, Map<Integer, String>> map = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
// 遍历从数据库中查询出来的字典表数据列表,
|
|
|
|
|
//
|
|
|
|
|
// 对每个 `DictionaryEntity` 对象进行处理,构建上述的分组数据结构。
|
|
|
|
|
for (DictionaryEntity d : dictionaryEntities) {
|
|
|
|
|
// 根据当前字典数据对象的 `dic_code` 获取对应的内部 `Map`,
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// 如果不存在则创建一个新的空 `Map`。
|
|
|
|
|
// 根据当前字典实体的字典编码(d.getDicCode())从map中获取对应的内层Map(即代码索引和索引名称的映射关系),如果获取到的是null或者为空,说明还没有该字典编码对应的映射关系,
|
|
|
|
|
// 则创建一个新的HashMap作为内层Map,用于存储该字典编码下的索引和名称对应关系。
|
|
|
|
|
Map<Integer, String> m = map.get(d.getDicCode());
|
|
|
|
|
if (m == null || m.isEmpty()) {
|
|
|
|
|
|
|
|
|
|
if(m ==null || m.isEmpty()){
|
|
|
|
|
m = new HashMap<>();
|
|
|
|
|
}
|
|
|
|
|
// 将当前字典数据对象的 `code_index` 和
|
|
|
|
|
//
|
|
|
|
|
// `index_name` 放入对应的内部 `Map` 中,建立索引关系。
|
|
|
|
|
m.put(d.getCodeIndex(), d.getIndexName());
|
|
|
|
|
// 将包含当前字典数据对象索引信息的内部 `Map`
|
|
|
|
|
//
|
|
|
|
|
// 重新放入外层的 `map` 中,以 `dic_code` 为键进行关联,完成分组存储。
|
|
|
|
|
map.put(d.getDicCode(), m);
|
|
|
|
|
// 将当前字典实体的代码索引(d.getCodeIndex())作为键,索引名称(d.getIndexName())作为值,放入内层的Map(m)中,以此构建字典编码下具体的索引和名称对应关系。
|
|
|
|
|
m.put(d.getCodeIndex(),d.getIndexName());
|
|
|
|
|
// 将整理好的内层Map(m)重新放回外层的map中,以字典编码(d.getDicCode())作为键,完成当前字典实体数据在整体数据结构中的整理和存储。
|
|
|
|
|
map.put(d.getDicCode(),m);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 将构建好的包含字典表数据分组信息的 `map`
|
|
|
|
|
//
|
|
|
|
|
// 对象存入 `ServletContext` 中,设置一个名为 `dictionaryMap` 的属性,
|
|
|
|
|
// 这样在整个项目的其他地方(如不同的 Servlet、JSP
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// 页面或者其他组件)可以通过该属性名获取到最新的字典表数据分组信息,实现数据共享,
|
|
|
|
|
// 方便在后续的业务逻辑中根据字典代码快速查找对应的索引名称等操作,
|
|
|
|
|
//
|
|
|
|
|
// 提高了数据的访问效率和复用性。
|
|
|
|
|
// 将整理好的包含字典表数据的map对象存储到Servlet上下文的属性中,属性名为"dictionaryMap",方便在整个Web应用的其他地方可以通过获取Servlet上下文属性来获取这些字典数据,
|
|
|
|
|
// 用于诸如数据展示、业务逻辑中根据字典进行数据转换等操作。
|
|
|
|
|
sce.getServletContext().setAttribute("dictionaryMap", map);
|
|
|
|
|
|
|
|
|
|
logger.info("----------字典表初始化完成----------");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger.info("----------线程执行开始----------");
|
|
|
|
|
// 判断myThreadMethod是否为null,如果是null,说明还没有实例化该线程对象,
|
|
|
|
|
// 则创建一个MyThreadMethod类的实例,用于后续启动一个自定义的线程来执行相关的后台任务(具体任务由MyThreadMethod类的实现决定)。
|
|
|
|
|
|
|
|
|
|
// 判断 `myThreadMethod` 线程对象是否为空,
|
|
|
|
|
//
|
|
|
|
|
// 如果为空则进行实例化操作,这样可以确保线程对象只被创建一次,
|
|
|
|
|
// 避免多次重复创建线程导致的资源浪费或者逻辑错误等问题,
|
|
|
|
|
//
|
|
|
|
|
// 在项目启动的初始化阶段启动该线程,使其开始执行特定的业务逻辑任务(具体由 `MyThreadMethod` 类的 `run` 方法定义)。
|
|
|
|
|
if (myThreadMethod == null) {
|
|
|
|
|
myThreadMethod = new MyThreadMethod();
|
|
|
|
|
myThreadMethod.start(); // servlet
|
|
|
|
|
|
|
|
|
|
// 上下文初始化时启动线程 myThreadMethod
|
|
|
|
|
// 启动前面实例化的myThreadMethod线程,在Servlet上下文初始化(项目启动)时启动这个线程,让其开始执行相应的任务,
|
|
|
|
|
// 比如可能是定时更新字典数据、执行一些周期性的业务逻辑等操作,具体取决于MyThreadMethod类中run方法的实现内容。
|
|
|
|
|
myThreadMethod.start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logger.info("----------线程执行结束----------");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|