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
相关产品推荐
相关产品推荐

