在上篇博客中說到我採用第二種方案實現靜態化,也就是通過擴展FreeMarker的FreeMarkerView類(參考【我的博客】)。上次說到這種方式更加優雅,節省不少的工作量,而且降低了後期的維護成本。這篇博客將指出這種方案的一個缺點,以及解決方案。
該靜態化方案中,FreeMarker渲染頁面的工作發生在Controller層return之後,如下形式:
@RequestMapping(value = "detail")
@NeedNavigation
public String detail(HttpServletRequest request, Model model, Integer id, String createHtml){
……頁面數據處理邏輯略……
//頁面靜態化
if (createHtml != null && "true".equals(createHtml)) {
StaticSupportInfo staticSupportInfo = new StaticSupportInfo();
//設置靜態化文件名
staticSupportInfo.setTargetHtml("detail_" + id + ".html");
//將靜態化信息支持對象放到Attribute中,注意key值不要寫錯
request.setAttribute("staticSupportInfo", staticSupportInfo);
}
return "web/blog/detail";
}
我們向上層容器返回了模板頁的路徑,也就是web/home/index.ftl,然後渲染頁面以及向客戶端返回結果的工作就交給了FreeMarker,然後其他的事就不由我們管了。那麼批量靜態化怎麼辦呢?這是一個問題,因爲我們沒法通過循環向一個方法傳遞不同的參數讓其靜態化這一批頁面,無論我們怎麼循環,上層的FreeMarker都只是處理我們return給它的那一個模板頁。
其實解決辦法很簡單,在一次訪問的內部循環不行,那我們就在外部循環嘛,讓每一次循環都是一次完整的http訪問。代碼如下:
@RequestMapping("static_all")
public void staticAll(HttpServletRequest request, HttpServletResponse response) throws IOException {
……業務邏輯略……
for (Integer id : ids) { //ids獲取的具體業務邏輯略
String urlString = "www.test.com/web/blog/detail.htm?id=" + id + "&createHtml=true";
try {
UrlResource urlResource = new UrlResource(urlString);
EncodedResource encodedResource = new EncodedResource(urlResource,"utf-8");
String result = FileCopyUtils.copyToString(encodedResource.getReader());
} catch (Exception e) {
e.printStackTrace();
continue;
}
}
……response中返回處理結果的邏輯略……
}
注:這裏UrlResource是spring對java接口的封裝,用java的URL和HttpURLConnection也可以。
url中用的是域名,服務器要記得配置host。
如此,我們就解決了批量靜態化的問題,從理論上講,相比於靜態化方案一(參考【我的博客】),這種方式效率較低,因爲每一次循環都是一次完整的http訪問。靜態化功能本來就是提供給公司內部的,因此不用在這個問題上糾結。在效率要求不高的前提下這種方案不失爲一種簡單的解決方案。