Java Web:JSON 作为配置文件,简单读写的方法

来源:互联网 发布:数据恢复apk下载 编辑:程序博客网 时间:2024/06/11 20:45

本方法依赖于 JRE 自带的 JavaScript 引擎 Rhino,无须其他第三方 JAR 包。更多这方面的资料,参见《学习使用 Java 自带的 JS 引擎》和《使用自带的 Rhino 作为 Java 的 JSON 解析包》。

具体流程参见源码:http://code.taobao.org/p/bigfoot_v2/src/java/com/ajaxjs/framework/javascript/JSON_Saver.java。

读取配置文件

先大概说一说思路。首先配置文件以 *.json 格式保存在服务端磁盘上。要读取改配置文件的话,通过 java.io.File 包读取磁盘内容,然后形成接口,作为响应内容返回到客户。既然 Web 浏览器天然支持 JSON,这读取一过程我们借助 <script src="xxx.json"></script> 即可。得到 JSON 数据后,再通过 JavaScript 绑定到 HTML 表单上。

读取 JSON 文件内容很简单,我的代码如下:

String filePath = new RequestHelper(request).Mappath("/META-INF/site_config.js");out.println(Fso.readFile(filePath));

RequestHelper.Mappath 和 Fso.readFile 都是我封装的函数,分别是把虚拟的相对路径还原为磁盘的绝对路径;Fso.readFile 顾名思义是读取文件内容。你可以将此写成 JSP 或 Servlet,让浏览器通过 <script src="xxx.jsp"></script> 访问得到即可。另外这里我还加入了格式化函数(Formatter),让输出的 JSON 带有缩进,更方便调试和阅读。

<script type="text/framework/javascript" src="?getConfig"></script>
如上例,我是设置当前 JSP 得到 JSON 内容的,效果如下图。

注意我们把 JSON 显示到表单是通过下面简单的函数的:

// 数据绑定// v1.00function databing(data){for(var i in data){var el = document.querySelector('*[name="bf_Config.site.{0}"]'.format(i));el.value = data[i];}}databing(bf_Config.site);
这里表单各个输入控件的 name 属性是有讲究的,命名方式都是以 JSON 的中 JSON Path 完整路径为依据,如这里的 bf_Config.site.{0}。一个控件项对应一个 JSON 节点。

表单代码如下:

<form class="form-horizontal" method="post" action="?"><input type="hidden" name="jsonFile" value="/META-INF/site_config.js" /><input type="hidden" name="topVarName" value="bf_Config" /><div class="control-group"><label class="control-label">网站标题前缀</label><div class="controls"><input type="text" name="bf_Config.site.titlePrefix" class="ui-wizard-content"placeholder="请输入旧密码" errmsg="旧密码为必填项" requiredfield /></div></div><div class="control-group"><label class="control-label">搜索关键字</label><div class="controls"><textarea name="bf_Config.site.keywords" rows="10"></textarea><span class="requiredfield">*</span></div></div><div class="control-group"><label class="control-label">网站描述</label><div class="controls"><textarea name="bf_Config.site.description" rows="10"></textarea><span class="requiredfield">*</span></div></div><div class="control-group"><label class="control-label">底部版权<br />声明文字</label><div class="controls"><textarea name="bf_Config.site.footCopyright" rows="10"></textarea><span class="requiredfield">*</span></div></div><div class="form-actions"><button class="btn btn-success submitBtn">保存</button></div></form>

生成表单界面如下:

其中要注意两处隐藏域:

<input type="hidden" name="jsonFile" value="/META-INF/site_config.js" /><input type="hidden" name="topVarName" value="bf_Config" />
一个说明是哪个 JSON 文件要被保存的,一个是 JSON 的顶级节点名。

保存配置内容

点击“保存”按钮之后,表单提交如下数据到后台。

具体流程参见源码:http://code.taobao.org/p/bigfoot_v2/src/java/com/ajaxjs/framework/javascript/JSON_Saver.java

保存配置文件,一个是修改当前内存的配置信息,其次是将配置内存保存在服务端的磁盘上,所以说这里是两个主要的操作,因此也需要两个 JavaScript 运行时。一个是 BaseApplication.jsRuntime 静态类型的,常驻内存的,另外一个是用于当前请求的实例化的这么一个 JS 运行时,用于得到 JSON 序列化后的字符串。它们分别作用各不同。

以上逻辑都安排在 save(HttpServletRequest request) 方法:

private void save(HttpServletRequest request) throws Exception {Map<String, String> hash = RequestSender.getClient_Data(request);String jsonFileFullPath = load(request, hash);// 可以json.str() 的 变量名String topVarName = hash.get("topVarName");Util.isEmptyString(topVarName, "没有  topVarName 参数!");hash.remove("topVarName");        saveRAM(hash);String JSON_as_String = null;try {JSON_as_String = (String)eval("JSON.stringify(" + topVarName + ");");} catch (ScriptException e) {e.printStackTrace();throw new Exception("更新配置失败,不能序列化配置!");}if(JSON_as_String != null){ // 持久化配置文件String fileBody = topVarName + " = " + JSON_as_String + ";";//System.out.println(fileBody);//System.out.println("::::::::::::::::::2:"+jsonFileFullPath);try {Fso.writeFile(jsonFileFullPath, fileBody);} catch (IOException e) {e.printStackTrace();throw new Exception("更新配置失败,不能保存配置!");}}}

首先,我们需要把这些数据变为一个 Map:Map<String, String> hash = RequestSender.getClient_Data(request);,加载到内存中,然后对其修改(实际是覆盖过程,同时对两个 js runtime 皆有效),最后保存到文件中(Fso.write)。

/** * 写入内存,覆盖 * @param hash */private void save(Map<String, String> hash){String jsCode = "";for(String key : hash.keySet()){jsCode = key + " = '" + hash.get(key) + "';"; // 全部保存为 String。TODO 支持其他类型//System.out.println(jsCode);try{js.eval(jsCode); // 两个 js runtimeeval(jsCode);}catch(ScriptException e) {System.err.println("写入内存,覆盖失败!");e.printStackTrace();}}}

最后保存完毕,输出 JSON 结果:new ResponseHelper(response).outputJSON(request); 提示用户成功。应该说整个过程并不复杂,操作也足够直观。如果要说有什么地方没考虑到的,就是安全性了。实际使用中还需要注意权限,因为这是直接对服务端的文件进行写操作!

另外有一点可以优化的地方,那就是合并两个 js runtime 为一个,不知是否可行呢?

1 0
原创粉丝点击