Java Web:JSON 作為配置檔案,簡單讀寫的方法
讀取配置檔案
先大概說一說思路。首先配置檔案以 *.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.00
function 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 的頂級節點名。儲存配置內容
點選“儲存”按鈕之後,表單提交如下資料到後臺。
儲存配置檔案,一個是修改當前記憶體的配置資訊,其次是將配置記憶體儲存在服務端的磁碟上,所以說這裡是兩個主要的操作,因此也需要兩個 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 runtime
eval(jsCode);
}catch(ScriptException e) {
System.err.println("寫入記憶體,覆蓋失敗!");
e.printStackTrace();
}
}
}
最後儲存完畢,輸出 JSON 結果:new ResponseHelper(response).outputJSON(request); 提示使用者成功。應該說整個過程並不複雜,操作也足夠直觀。如果要說有什麼地方沒考慮到的,就是安全性了。實際使用中還需要注意許可權,因為這是直接對服務端的檔案進行寫操作!
另外有一點可以優化的地方,那就是合併兩個 js runtime 為一個,不知是否可行呢?