基于java.util.prefs.Preferences的Winreg类在JSP中无法读取已存储值的问题求助
首先,我来帮你拆解这个问题的核心原因,再给出针对性的解决办法:
问题根源:运行上下文的用户身份不一致
你在本地用Java主函数测试时,程序是以当前登录Windows的个人账户运行的,调用Preferences.userNodeForPackage(Winreg.class)会把数据存在这个用户专属的注册表路径:HKEY_CURRENT_USER\Software\JavaSoft\Prefs\oneconect
而Tomcat 6作为服务器服务运行时,默认是用**Windows系统服务账户(比如Local System)**启动的,这个账户的注册表上下文和你本地登录的用户完全独立。Tomcat调用同一个userNodeForPackage方法时,会去读取服务账户专属的注册表节点,自然找不到你之前用本地用户存储的filepath值,所以只能返回你传入的默认值null。
具体解决办法
这里给你三个可落地的方案,你可以根据实际场景选择:
方案1:改用系统级偏好节点(推荐无用户隔离需求的场景)
把Winreg构造函数中的userNodeForPackage替换为systemNodeForPackage,这样数据会存在系统级注册表路径,所有用户(包括Tomcat的服务账户)都能访问(注意:写入系统节点需要管理员权限):
// 替换构造函数内的这一行代码 prefs = Preferences.systemNodeForPackage(oneconect.Winreg.class);
对应的注册表路径会变为:HKEY_LOCAL_MACHINE\Software\JavaSoft\Prefs\oneconect
这样不管是本地测试还是Tomcat运行,都会访问同一个节点,就能正常读取到之前存储的值了。
方案2:让Tomcat以你本地测试的用户身份运行
修改Tomcat的服务配置,让它使用你本地登录的Windows用户身份启动:
- 打开Windows服务管理器,找到Tomcat 6对应的服务
- 右键选择「属性」→「登录」选项卡
- 选择「此账户」,输入你本地登录的用户名和密码,保存后重启Tomcat
这样Tomcat的运行上下文和你本地测试时完全一致,就能读取到同一个用户节点里的数据了。
方案3:统一在Tomcat上下文内完成存值和取值
如果必须使用用户级节点,那你需要在Tomcat的运行上下文中完成存值操作(比如写一个专门的JSP接口来存储数据),而不是用本地主函数存值。这样存和读的上下文保持一致,就能正常获取到数据了。
额外的代码优化建议
- 你的
getValue方法里的prefs.flush()是多余的:flush()是用来确保写入的数据持久化到磁盘,在读取操作时调用毫无意义,还会增加不必要的性能开销,建议删除这一行。 - 尽量避免传入
null作为默认值,可以复用类中定义的defaultValue = "NA",这样读取失败时返回的结果更友好。
你提供的原始代码(已格式化为标准Markdown)
Winreg.java 类代码
//File Winreg.java package oneconect; import java.util.prefs.*; public class Winreg { Preferences prefs; String defaultValue = "NA"; String InstalledDate = "", version = ""; //构造函数 public Winreg() { try { prefs = Preferences.userNodeForPackage(oneconect.Winreg.class); } catch (Exception E) { System.out.println(E); } } //设置值方法 public void setValue(String vKey, String vValue) { try { prefs.put(vKey, vValue); } catch (Exception E) { E.printStackTrace(); } } //获取值方法 public String getValue(String vKey, String defaultValue) { try { String vGetValues = prefs.get(vKey, defaultValue); prefs.flush(); // 此处在读取时无必要,建议删除 return vGetValues; } catch (Exception E) { E.printStackTrace(); return defaultValue; } } }
本地测试主函数代码
public static void main(String[] args) throws IOException { // TODO Auto-generated method stub try { Winreg iWin = new Winreg(); iWin.setValue("filepath", "Program file") ; System.out.println( iWin.getValue("filepath", null) ); /// 输出 Program file } catch (Exception exp) { System.out.print(exp.toString()); } }
问题JSP代码
<%@page import="oneconect.Winreg"%> <%@page import="java.util.prefs.*"%> <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>..:: Test a</title> </head> <body> <% Winreg iWin = new Winreg(); out.println( iWin.getValue("filepath", null) ); %> </body> </html>
备注:内容来源于stack exchange,提问作者VOIP INDOCHINA

