FreeMarker簡介
FreeMarker原理
FreeMarker是一個基 於Java的開發包和類庫的一種將模板和數據進行整合並輸出文本的通用工具,FreeMarker實現頁面靜態化的原理是:將頁面中所需要的樣式寫入到 FreeMarker模板文件中,然後將頁面所需要的數據進行動態綁定並放入到Map中,然後通過FreeMarker的模板解析類process()方 法完成靜態頁面的生成。其工作原理如圖所示。
模板 + 數據模型 = 輸出
示例演示FreeMarker
先看一下Demo項目的整體結構:
上面我們已經說了, 模板 + 數據模型 = 輸出, 那麼我們就一個個看模板和數據模型是什麼樣子的, 以及最後的輸出是什麼樣子的.
注: 這裏將省略freemarker的語法, 因爲很多都是類似EL表達式的, 這裏只提供幾種情況的講解, 其中包括: list, map, list和map混合
FMDemo.java:
public class FMDemo {
//Freemarker
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
//模板+數據模型 = 輸出
//ftl: freemarker template
//第一步: 讀取html模板
String dir = "C:\\workspace\\freemarker\\ftl\\";
conf.setDirectoryForTemplateLoading(new File(dir));
Template template = conf.getTemplate("freemarker.html");
//第二步: 加載數據模型
Map root = new HashMap();
root.put("world", "世界你好");
//List集合
List<String> persons = new ArrayList<String>();
persons.add("范冰冰");
persons.add("李冰冰");
persons.add("何炅");
root.put("persons", persons);
//Map集合
Map map = new HashMap();
map.put("fbb", "范冰冰");
map.put("lbb", "李冰冰");
root.put("map", map);
//list和map混合
List<Map> maps = new ArrayList<Map>();
Map pms1 = new HashMap();
pms1.put("id1", "范冰冰");
pms1.put("id2", "李冰冰");
Map pms2 = new HashMap();
pms2.put("id1", "曾志偉");
pms2.put("id2", "何炅");
maps.add(pms1);
maps.add(pms2);
root.put("maps", maps);
Writer out = new FileWriter(new File(dir + "hello.html"));
template.process(root, out);
System.out.println("生成完成");
}
}
freemarker.html: 模板文件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
${world}
<br/>
<#list persons as person>
<#if person_index == 2>
${person}---紅色
<#else>
${person}---綠色
</#if>
</#list><br/>
<#list map?keys as key>
${map[key]}
</#list>
${map.fbb}/${map.lbb}<br/>
<#list maps as map>
<#list map?keys as key>
${map[key]}
</#list>
</#list>
<#list maps as map>
${map.id1}///${map.id2}
</#list>
</body>
</html>
執行FMDemo.java中的Main方法, 這會生成:
hello.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
世界你好
<br/>
范冰冰---綠色
李冰冰---綠色
何炅---紅色
<br/>
李冰冰
范冰冰
范冰冰/李冰冰<br/>
李冰冰
范冰冰
何炅
曾志偉
范冰冰///李冰冰
曾志偉///何炅
</body>
</html>
靜態化頁面在項目中的使用
這裏就來說下靜態化頁面在項目中的使用情況, 現在只是給商品詳情頁做了靜態化處理.
前面關於ActiveMQ的文章已經說過, 當一個商品上架的時候, 通過發送消息來通知babasport-cms 來將對應的頁面靜態化.
在這裏我們只寫接收消息的方法, 首先來看看babasport-cms的結構圖:
CustomMessageListener.java:接收MQ中的消息
public class CustomMessageListener implements MessageListener{
@Autowired
private StaticPageService staticPageService;
@Autowired
private CMSService cmsService;
@Override
public void onMessage(Message message) {
//先將接收到的消息強轉爲ActiveMQ類型的消息
//因爲在消息發送方那邊傳遞的是Text類型的消息對象, 所以需要轉成ActiveMQTextMessage
ActiveMQTextMessage amtm = (ActiveMQTextMessage)message;
try {
String id = amtm.getText();
System.out.println("CMS接收到的ID:"+id);
Map<String, Object> root = new HashMap<String, Object>();
Product product = cmsService.selectProductById(Long.parseLong(id));
List<Sku> skus = cmsService.selectSkuListByProductIdWithStock(Long.parseLong(id));
//去掉重複的顏色
Set<Color> colors = new HashSet<Color>();
for (Sku sku : skus) {
colors.add(sku.getColor());
}
root.put("colors", colors);
root.put("product", product);
root.put("skus", skus);
staticPageService.index(root, id);
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
StaticPageServiceImpl.java:
public class StaticPageServiceImpl implements StaticPageService, ServletContextAware{
//SpringMvc 管理 conf
private Configuration conf;
public void setFreeMarkerConfig(FreeMarkerConfig freeMarkerConfig) {
this.conf = freeMarkerConfig.getConfiguration();
}
//靜態化頁面的方法
public void index(Map<String, Object> root, String id){
//輸出目錄: 通過getPath方法獲取的是絕對路徑
String path = getPath("/html/product/" + id +".html");
File f = new File(path);
File parentFile = f.getParentFile();
if(!parentFile.exists()){
parentFile.mkdirs();
}
//spring中已經設置了模板路徑:<property name="templateLoaderPath" value="/WEB-INF/ftl/" />
Writer out = null;
try {
//讀
Template template = conf.getTemplate("product.html");
//設置輸出的位置
//寫
out = new OutputStreamWriter(new FileOutputStream(f), "UTF-8");
template.process(root, out);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if (out != null)
{
try {
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//獲取webapp下的html文件夾所在的位置
//將相對路徑轉換爲絕對路徑
public String getPath(String path){
return servletContext.getRealPath(path);
}
private ServletContext servletContext;
@Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
}
使用Spring管理Freemarker配置文件:
<!-- 配置freemarker 實現類 -->
<bean class="cn.itcast.core.service.StaticPageServiceImpl">
<property name="freeMarkerConfig">
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<!-- 設置模板所在目錄或文件夾的位置, 相對路徑 -->
<property name="templateLoaderPath" value="/WEB-INF/ftl/" />
<!-- 設置默認編碼集 -->
<property name="defaultEncoding" value="UTF-8"></property>
</bean>
</property>
</bean>
模板頁面: product.html 中的改動:
引入其他頁面:
<#include “commons/header.html” />
循環遍歷colors:
<div class="dd" id="colors">
<#list colors as color>
<div class="item" onclick="colorToRed(this,'${color.id}')">
<b></b>
<a href="javascript:;" title="${color.name }" >
<img data-img="1"
src="/images/53f44cc2N0b714cb2_002.jpg"
alt="灰色三件套" height="25" width="25"><i>${color.name }</i></a>
</div>
</#list>
</div>
循環遍歷imgUrls, 並且使用if..else 進行判斷:
<div class="spec-items">
<ul class="lh">
<#list product.imgUrls as pic>
<#if pic_index == 0>
<li><img data-img="1" class="img-hover"
alt="${product.name}" src="${pic}" width="50" height="50"></li>
<#else>
<li><img data-img="1" alt="${product.name}" src="${pic}"
width="50" height="50" ></li>
</#if>
</#list>
</ul>
</div>
其他的照常使用EL表達式, 然後生成 id.html的靜態化頁面, 查看訪問後的頁面: