You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Struts2开发中如何将单例类数据传递至JSP并实现Session读写

解决方案

首先先修正你现有代码里的两个致命问题,否则逻辑根本跑不通:

  • 单例类构造方法名和类名不匹配:你定义的类是TestSingleton,构造方法写成了ServerSingleton(),Java中构造方法必须和类名完全一致,这个方法不会被当作构造方法执行。
  • 单例没有做初始化:现有getINSTANCE()直接返回空的INSTANCE对象,调用就会抛空指针;另外DAO层查询结果集没有调用rs.next()就直接取值,永远拿不到返回结果。

单例实现+Session操作逻辑

不推荐在单例类里硬依赖Web容器对象,耦合度太高。更合理的方式是单例只负责缓存全局共享的数据库配置值,Session操作放到请求链路的Action或者拦截器层完成。如果确实需要在单例内操作Session,通过Struts2提供的ServletActionContext获取HttpSession对象即可。

修正后的单例代码

import org.apache.struts2.ServletActionContext;
import javax.servlet.http.HttpSession;

public class TestSingleton {
    private static volatile TestSingleton INSTANCE;
    private String name;

    private TestSingleton() {
        try {
            // 单例第一次初始化时只查一次库,全局复用
            this.name = new TestDAO().getServerName();
        } catch (DAOException e) {
            e.printStackTrace();
            this.name = "defaultServer";
        }
    }

    // 双重检查锁保证线程安全
    public static TestSingleton getInstance() {
        if (INSTANCE == null) {
            synchronized (TestSingleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new TestSingleton();
                }
            }
        }
        return INSTANCE;
    }

    // 写入Session的方法
    public void saveToSession() {
        HttpSession session = ServletActionContext.getRequest().getSession();
        session.setAttribute("serverName", this.name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

修正后的DAO层代码

补上结果集游标移动和资源关闭逻辑:

public class TestDAO {
    public String getServerName() throws DAOException {
        String findStatement = "SELECT name FROM classTest where value='1234'";
        PreparedStatement ps = null;
        ResultSet rs = null;
        Connection conn = null;
        try {
            conn = DBAccessManager.getConnection();
            ps = conn.prepareStatement(findStatement);
            rs = ps.executeQuery();
            String name = null;
            if (rs.next()) {
                name = rs.getString("name");
            }
            return name;
        } catch (SQLException e) {
            throw new DAOException("查询服务名失败", e);
        } finally {
            // 按顺序关闭资源
            DBAccessManager.close(rs, ps, conn);
        }
    }
}

触发Session写入

不需要在每个JSP页面都触发写入,只需要在用户第一次进入系统的节点(比如登录校验拦截器、首页入口Action)调用一次写入方法即可,后续所有请求都可以直接从Session取值:

// 拦截器或Action中登录/入口逻辑处添加
TestSingleton.getInstance().saveToSession();

JSP页面读取Session值

两种常用方式,优先选EL表达式,代码更简洁:

  • EL表达式读取(推荐)
当前服务名称:${serverName}
  • Struts2标签读取
<%@ taglib prefix="s" uri="/struts-tags" %>
当前服务名称:<s:property value="#session.serverName"/>

注意事项

  • 单例是JVM全局共享对象,所有访问用户拿到的name值是同一份,适合存全局系统配置。如果这个值是用户维度的独立数据,不要用单例缓存,直接查库后存入当前用户Session即可。
  • 如果后续数据库里的配置值更新了,可以提供一个刷新方法,调用setName()更新单例里的缓存值,再重新写入Session即可,不需要重启应用。

内容的提问来源于stack exchange,提问作者WCM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 10:03:15