页面静态化技术Freemarker技术的介绍及使用实例.

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java3y

JSP面试题都在这里

下面是我整理下来的JSP知识点: ? 图上的知识点都可以在我其他的文章内找到相应内容。 JSP常见面试题 jsp静态包含和动态包含的区别 jsp静态包含和动态包...

42610
来自专栏JackieZheng

Spring实战——缓存

缓存 提到缓存,你能想到什么?一级缓存,二级缓存,web缓存,redis…… 你所能想到的各种包罗万象存在的打着缓存旗号存在的各种技术或者实现,无非都是宣扬缓...

22010
来自专栏JackieZheng

Spring实战——缓存

缓存 提到缓存,你能想到什么?一级缓存,二级缓存,web缓存,redis…… 你所能想到的各种包罗万象存在的打着缓存旗号存在的各种技术或者实现,无非都是宣扬缓...

19610
来自专栏测试开发架构之路

【总结】梳理下接口功能测试

1473
来自专栏Java帮帮-微信公众号-技术文章全总结

Java并发学习2【面试+工作】

  关键字synchronized的作用是实现进程间的同步。它的工作是对同步的代码加锁,使得每一次,只能有一个线程进入同步块,从而保证线程间的安全性(即同步块每...

1092
来自专栏知识分享

关于原子哥ENC28J60网络通信模块接收数据代码的一点疑惑

---恢复内容开始--- 这几天做STM32的ENC28J60网络通信模块,自己在原子哥的代码上进行修改测试,,发现一个问题,电脑和板子进行通信的时候总隔一段时...

3648
来自专栏Linux驱动

41.Linux应用调试-修改内核来打印用户态的oops

1.在之前第36章里,我们学习了通过驱动的oops定位错误代码行 第36章的oops代码如下所示: Unable to handle kernel paging...

3015
来自专栏JackieZheng

Spring实战——缓存

缓存 提到缓存,你能想到什么?一级缓存,二级缓存,web缓存,redis…… 你所能想到的各种包罗万象存在的打着缓存旗号存在的各种技术或者实现,无非都是宣扬缓...

21010
来自专栏人工智能LeadAI

ElasticSearch优化系列二:机器设置(内存)

预留一半内存给Lucence使用 一个常见的问题是配置堆太大。你有一个64 GB的机器,觉得JVM内存越大越好,想给Elasticsearch所有64 GB的内...

4624
来自专栏开发与安全

linux系统编程之进程(三):exec系列函数和system函数

一、exec替换进程映象 在进程的创建上Unix采用了一个独特的方法,它将进程创建与加载一个新进程映象分离。这样的好处是有更多的余地对两种操作进行管理。当我们创...

2776

扫码关注云+社区

领取腾讯云代金券