1、FreeMarker簡介javascript
一、動態網頁和靜態網頁差別html
在進入主題以前我先介紹一下什麼是動態網頁,動態網頁是指跟靜態網頁相對應的一種網頁編程技術。靜態網頁,隨着HTML代碼的生成,頁面的內容和顯示效 果就不會再發生變化(除非你修改頁面代碼)。而動態網頁則否則,頁面代碼雖然沒有發生變化,可是顯示的內容倒是能夠隨着時間、環境或者數據庫操做的結果而 發生相應的變化。簡而言之,動態網頁是基本的HTML語法規範與java、VB、VC等高級程序設計語言、數據庫編程等多種技術的融合,以實現對網站內容 和風格的高效、動態和交互式的管理。java
經過前面的介紹咱們能夠得出動態網頁和靜態網頁的優缺點(這裏咱們只考慮網站性能方面的相關問題,信息安全等多方面問題不作贅述):web
1)靜態網頁:spring
a、靜態網頁的內容穩定,頁面加載速度快。數據庫
b、靜態網頁的沒有數據庫支持,在網站製做和維護方面的工做量較大。編程
c、靜態網頁的交互性差,有很大的侷限性。安全
2)動態網頁:服務器
a、交互性好。app
b、動態網頁的信息都須要從數據庫中讀取,每打開一個一面就須要去獲取一次數據庫,若是訪問人數不少,也就會對服務器增長很大的荷載,從而影響這個網站的運行速度。
經過上面的比較咱們不難看出,要提高網站的性能,咱們只要把動態網頁作成靜態網頁就會在運行速度方面有顯著的提高,可是問題出來了,若是將全部頁面都作 成靜態頁面顯然是不切實際的。有什麼辦法能讓咱們的網站即能有動態網頁的交互性,又有靜態網頁的加載速度呢?FreeMarker便能實現這樣的需求:實 現動態網頁靜態化。
二、FreeMarker原理
FreeMarker是一個基 於Java的開發包和類庫的一種將模板和數據進行整合並輸出文本的通用工具,FreeMarker實現頁面靜態化的原理是:將頁面中所須要的樣式寫入到 FreeMarker模板文件中,而後將頁面所須要的數據進行動態綁定並放入到Map中,而後經過FreeMarker的模板解析類process()方 法完成靜態頁面的生成。其工做原理如圖2-1所示。
模板 + 數據模型 = 輸出
二, 示例演示FreeMarker
先看一下Demo項目的總體結構:
上面咱們已經說了, 模板 + 數據模型 = 輸出, 那麼咱們就一個個看模板和數據模型是什麼樣子的, 以及最後的輸出是什麼樣子的.
注: 這裏將省略freemarker的語法, 由於不少都是相似EL表達式的, 這裏只提供幾種狀況的講解, 其中包括: list, map, list和map混合
FMDemo.java:
1 public class FMDemo { 2 3 //Freemarker 4 public static void main(String[] args) throws Exception { 5 6 Configuration conf = new Configuration(); 7 //模板+數據模型 = 輸出 8 //ftl: freemarker template 9 //第一步: 讀取html模板 10 String dir = "C:\\workspace\\freemarker\\ftl\\"; 11 conf.setDirectoryForTemplateLoading(new File(dir)); 12 Template template = conf.getTemplate("freemarker.html"); 13 14 //第二步: 加載數據模型 15 Map root = new HashMap(); 16 root.put("world", "世界你好"); 17 18 //List集合 19 List<String> persons = new ArrayList<String>(); 20 persons.add("范冰冰"); 21 persons.add("李冰冰"); 22 persons.add("何炅"); 23 root.put("persons", persons); 24 25 //Map集合 26 Map map = new HashMap(); 27 map.put("fbb", "范冰冰"); 28 map.put("lbb", "李冰冰"); 29 root.put("map", map); 30 31 //list和map混合 32 List<Map> maps = new ArrayList<Map>(); 33 Map pms1 = new HashMap(); 34 pms1.put("id1", "范冰冰"); 35 pms1.put("id2", "李冰冰"); 36 Map pms2 = new HashMap(); 37 pms2.put("id1", "曾志偉"); 38 pms2.put("id2", "何炅"); 39 maps.add(pms1); 40 maps.add(pms2); 41 root.put("maps", maps); 42 43 Writer out = new FileWriter(new File(dir + "hello.html")); 44 template.process(root, out); 45 System.out.println("生成完成"); 46 } 47 }
freemarker.html: 模板文件
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Insert title here</title> 6 </head> 7 <body> 8 ${world} 9 <br/> 10 11 <#list persons as person> 12 <#if person_index == 2> 13 ${person}---紅色 14 <#else> 15 ${person}---綠色 16 </#if> 17 </#list><br/> 18 19 <#list map?keys as key> 20 ${map[key]} 21 </#list> 22 ${map.fbb}/${map.lbb}<br/> 23 24 <#list maps as map> 25 <#list map?keys as key> 26 ${map[key]} 27 </#list> 28 </#list> 29 <#list maps as map> 30 ${map.id1}///${map.id2} 31 </#list> 32 </body> 33 </html>
執行FMDemo.java中的Main方法, 這會生成:
hello.html:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Insert title here</title> 6 </head> 7 <body> 8 世界你好 9 <br/> 10 11 范冰冰---綠色 12 李冰冰---綠色 13 何炅---紅色 14 <br/> 15 16 李冰冰 17 范冰冰 18 范冰冰/李冰冰<br/> 19 20 李冰冰 21 范冰冰 22 何炅 23 曾志偉 24 范冰冰///李冰冰 25 曾志偉///何炅 26 </body> 27 </html>
三, 靜態化頁面在項目中的使用
這裏就來講下靜態化頁面在項目中的使用狀況, 如今只是給商品詳情頁作了靜態化處理.
前面關於ActiveMQ的文章已經說過, 當一個商品上架的時候, 經過發送消息來通知babasport-cms 來將對應的頁面靜態化.
在這裏咱們只寫接收消息的方法, 首先來看看babasport-cms的結構圖:
CustomMessageListener.java:接收MQ中的消息
1 public class CustomMessageListener implements MessageListener{ 2 @Autowired 3 private StaticPageService staticPageService; 4 @Autowired 5 private CMSService cmsService; 6 7 @Override 8 public void onMessage(Message message) { 9 //先將接收到的消息強轉爲ActiveMQ類型的消息 10 //由於在消息發送方那邊傳遞的是Text類型的消息對象, 因此須要轉成ActiveMQTextMessage 11 ActiveMQTextMessage amtm = (ActiveMQTextMessage)message; 12 try { 13 String id = amtm.getText(); 14 System.out.println("CMS接收到的ID:"+id); 15 Map<String, Object> root = new HashMap<String, Object>(); 16 17 Product product = cmsService.selectProductById(Long.parseLong(id)); 18 List<Sku> skus = cmsService.selectSkuListByProductIdWithStock(Long.parseLong(id)); 19 //去掉重複的顏色 20 Set<Color> colors = new HashSet<Color>(); 21 for (Sku sku : skus) { 22 colors.add(sku.getColor()); 23 } 24 root.put("colors", colors); 25 root.put("product", product); 26 root.put("skus", skus); 27 28 staticPageService.index(root, id); 29 } catch (JMSException e) { 30 // TODO Auto-generated catch block 31 e.printStackTrace(); 32 } 33 } 34 }
StaticPageServiceImpl.java:
1 public class StaticPageServiceImpl implements StaticPageService, ServletContextAware{ 2 //SpringMvc 管理 conf 3 private Configuration conf; 4 public void setFreeMarkerConfig(FreeMarkerConfig freeMarkerConfig) { 5 this.conf = freeMarkerConfig.getConfiguration(); 6 } 7 8 //靜態化頁面的方法 9 public void index(Map<String, Object> root, String id){ 10 //輸出目錄: 經過getPath方法獲取的是絕對路徑 11 String path = getPath("/html/product/" + id +".html"); 12 File f = new File(path); 13 File parentFile = f.getParentFile(); 14 if(!parentFile.exists()){ 15 parentFile.mkdirs(); 16 } 17 18 //spring中已經設置了模板路徑:<property name="templateLoaderPath" value="/WEB-INF/ftl/" /> 19 Writer out = null; 20 21 try { 22 //讀 23 Template template = conf.getTemplate("product.html"); 24 25 //設置輸出的位置 26 //寫 27 out = new OutputStreamWriter(new FileOutputStream(f), "UTF-8"); 28 template.process(root, out); 29 } catch (Exception e) { 30 // TODO Auto-generated catch block 31 e.printStackTrace(); 32 }finally { 33 if (out != null) 34 { 35 try { 36 out.close(); 37 } catch (IOException e) { 38 // TODO Auto-generated catch block 39 e.printStackTrace(); 40 } 41 } 42 43 } 44 45 } 46 47 //獲取webapp下的html文件夾所在的位置 48 //將相對路徑轉換爲絕對路徑 49 public String getPath(String path){ 50 return servletContext.getRealPath(path); 51 } 52 53 private ServletContext servletContext; 54 @Override 55 public void setServletContext(ServletContext servletContext) { 56 this.servletContext = servletContext; 57 } 58 }
使用Spring管理Freemarker配置文件:
1 <!-- 配置freemarker 實現類 --> 2 <bean class="cn.itcast.core.service.StaticPageServiceImpl"> 3 <property name="freeMarkerConfig"> 4 <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> 5 <!-- 設置模板所在目錄或文件夾的位置, 相對路徑 --> 6 <property name="templateLoaderPath" value="/WEB-INF/ftl/" /> 7 <!-- 設置默認編碼集 --> 8 <property name="defaultEncoding" value="UTF-8"></property> 9 </bean> 10 </property> 11 </bean>
模板頁面: product.html 中的改動:
引入其餘頁面:
<!-- header start -->
<#include "commons/header.html" />
循環遍歷colors:
1 <div class="dd" id="colors"> 2 <#list colors as color> 3 <div class="item" onclick="colorToRed(this,'${color.id}')"> 4 <b></b> 5 <a href="javascript:;" title="${color.name }" > 6 <img data-img="1" 7 src="/images/53f44cc2N0b714cb2_002.jpg" 8 alt="灰色三件套" height="25" width="25"><i>${color.name }</i></a> 9 </div> 10 </#list> 11 </div>
循環遍歷imgUrls, 而且使用if..else 進行判斷:
1 <div class="spec-items"> 2 <ul class="lh"> 3 <#list product.imgUrls as pic> 4 <#if pic_index == 0> 5 <li><img data-img="1" class="img-hover" 6 alt="${product.name}" src="${pic}" width="50" height="50"></li> 7 <#else> 8 <li><img data-img="1" alt="${product.name}" src="${pic}" 9 width="50" height="50" ></li> 10 </#if> 11 </#list> 12 </ul> 13 </div>
其餘的照常使用EL表達式, 而後生成 id.html的靜態化頁面, 查看訪問後的頁面:關於Freemarker簡單的講解差很少就是這樣, 尚未其餘高深的理解, 相信技術都是慢慢積累的, 先入門再深刻. 本博客會永久更新, 我相信我會一直堅持下來的.