一、FreeMarker简介

1、动态网页和静态网页差异

在进入主题之前我先介绍一下什么是动态网页,动态网页是指跟静态网页相对应的一种网页编程技术。静态网页,随着HTML代码的生成,页面的内容和显示效 果就不会再发生变化(除非你修改页面代码)。而动态网页则不然,页面代码虽然没有发生变化,但是显示的内容却是可以随着时间、环境或者数据库操作的结果而 发生相应的变化。简而言之,动态网页是基本的HTML语法规范与java、VB、VC等高级程序设计语言、数据库编程等多种技术的融合,以实现对网站内容 和风格的高效、动态和交互式的管理。

通过前面的介绍我们可以得出动态网页和静态网页的优缺点(这里我们只考虑网站性能方面的相关问题,信息安全等多方面问题不做赘述):

1)静态网页:

  a、静态网页的内容稳定,页面加载速度快。

  b、静态网页的没有数据库支持,在网站制作和维护方面的工作量较大。

  c、静态网页的交互性差,有很大的局限性。

2)动态网页:

  a、交互性好。

  b、动态网页的信息都需要从数据库中读取,每打开一个一面就需要去获取一次数据库,如果访问人数很多,也就会对服务器增加很大的荷载,从而影响这个网站的运行速度。

   通过上面的比较我们不难看出,要提升网站的性能,我们只要把动态网页做成静态网页就会在运行速度方面有显著的提升,但是问题出来了,如果将所有页面都做 成静态页面显然是不切实际的。有什么办法能让我们的网站即能有动态网页的交互性,又有静态网页的加载速度呢?FreeMarker便能实现这样的需求:实 现动态网页静态化。

2、FreeMarker原理

  FreeMarker是一个基 于Java的开发包和类库的一种将模板和数据进行整合并输出文本的通用工具,FreeMarker实现页面静态化的原理是:将页面中所需要的样式写入到 FreeMarker模板文件中,然后将页面所需要的数据进行动态绑定并放入到Map中,然后通过FreeMarker的模板解析类process()方 法完成静态页面的生成。其工作原理如图2-1所示。

模板 + 数据模型 = 输出

二、 示例演示FreeMarker

先看一下Demo项目的整体结构:

上面我们已经说了, 模板 + 数据模型 = 输出, 那么我们就一个个看模板和数据模型是什么样子的, 以及最后的输出是什么样子的.

注: 这里将省略freemarker的语法, 因为很多都是类似EL表达式的, 这里只提供几种情况的讲解, 其中包括: list, map, list和map混合
FMDemo.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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: 模板文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!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中的消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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配置文件:

1
2
3
4
5
6
7
8
9
10
11
<!-- 配置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:

1
2
3
4
5
6
7
8
9
10
11
<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 进行判断:

1
2
3
4
5
6
7
8
9
10
11
12
13
<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的静态化页面, 查看访问后的页面:

关于Freemarker简单的讲解差不多就是这样, 还没有其他高深的理解, 相信技术都是慢慢积累的, 先入门再深入. 本博客会永久更新, 我相信我会一直坚持下来的.

来源:http://www.cnblogs.com/wang-meng/p/5840281.html