对于电商网站的商品详细页来说,至少几百万个商品,每个商品又有大量的信息,这样的情况同样也适用于使用网页静态化来解决,网页静态化技术和缓存技术的共同点都是为了减轻数据库的访问压力,但是具体的应用场景不同,缓存比较适合小规模的数据,而网页静态化比较适合大规模且相对变化不太频繁的数据。另外网页静态化还有利于SEO

1. 什么是Freemarker

FreeMarker 是一个用 Java 语言编写的模板引擎,它基于模板来生成文本输出。FreeMarker与 Web 容器无关,即在 Web 运行时,它并不知道 Servlet 或 HTTP,它不仅可以用作表现层的实现技术,而且还可以用于生成 XML,JSP 或 Java 等

Freemarker生成静态网页,或者是java代码三要素

  • 模板 : Jsp就是一种模板语言,html+jstl指令组成的 Ftl也是一种模板语言:html+ftl指令组成的
  • 数据
  • freemarker API

2. 环境准备

  • 在Maven项目pom文件添加依赖
<dependencies>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.23</version>
        </dependency>
    </dependencies>

3. 入门案例

  • 创建ftl后缀的html页面 hello.ftl
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Freemarker入门案例</title>
</head>
<body>
    <#-- ${name} 是插值表达式,用来获取传递过来的数据-->
    <h1>欢迎${name}学习 Freemarker</h1>
</body>
</html>
  • 生成模板
package com.pyg;

import freemarker.template.Configuration;
import freemarker.template.Template;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

/**
 * @ Description
 * @ auther          宁宁小可爱
 * @ create          2020-02-04 16:22
 */

public class MyHtmlTest {
    /*
    * 使用hello.ftl模板获取简单数据
    * 三要素:
    * 模板: hello.ftl
    * 数据: 使用map封装
    * API: 引入坐标依赖
    * 模板指令: ${}插值表达式  {}中填写map的key即可获取值
    * */

    @Test
    public void test() throws Exception{
        // 创建freemarker核心配置对象 注意包是freemarker的
        Configuration cf = new Configuration(Configuration.getVersion());
        // 设置编码
        cf.setDefaultEncoding("UTF-8");
        // 设置模板文件位置
        cf.setDirectoryForTemplateLoading(new File("模板文件夹路径"));
        // 根据模板文件位置获取文件下所有的模板
        Template template = cf.getTemplate("hello.ftl");

        // 准备数据 :freemarker数据必须使用map对象进行封装
        Map maps = new HashMap();
        maps.put("name","宁宁小可爱");
        // 创建输出流对象 把生成的html通过流的方式写入磁盘
        Writer out = new FileWriter("生成的模板文件夹路径\\模板名字.html");

        // 生成html文件
        template.process(maps,out);
        // 关闭流对象
        out.close();

    }
}
  • 结果

freemarker 加载静态模板 freemarker调用静态方法_freemarker

4. FTL指令-assign指令

  • 定义assign.ftl模板文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>assign定义常量</title>
</head>
<body>
<#-- 定义简单的常量值-->
    <#assign name="张三">
    <h1>获取到assign定义的常量值 ${name}</h1>
<#-- 定义对象-->
    <#assign user={'id':1,'username':'李四','age':12}>
    <h1>获取到assign定义的对象  ${user.username}</h1>
</body>
</html>
  • 生成模板文件
package com.pyg;

import freemarker.template.Configuration;
import freemarker.template.Template;
import org.junit.Test;

import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

/**
 * @ Description
 * @ auther          宁宁小可爱
 * @ create          2020-02-04 16:22
 */

public class MyHtmlTest1 {
    /*
    * 使用assign指令定义常量
    * 三要素:
    * 模板: assign.ftl
    * 数据: 使用map封装
    * API: 引入坐标依赖
    * 模板指令: ${}插值表达式  {}中填写map的key即可获取值
    * */

    @Test
    public void test() throws Exception{
        // 创建freemarker核心配置对象 注意包是freemarker的
        Configuration cf = new Configuration(Configuration.getVersion());
        // 设置编码
        cf.setDefaultEncoding("UTF-8");
        // 设置模板文件位置
        cf.setDirectoryForTemplateLoading(new File("模板文件夹路径"));
        // 根据模板文件位置获取文件下所有的模板
        Template template = cf.getTemplate("assign.ftl");

        // 创建输出流对象 把生成的html通过流的方式写入磁盘
        Writer out = new FileWriter("生成模板文件夹\\文件名.html");

        // 生成html文件
        template.process(null,out);
        // 关闭流对象
        out.close();

    }
}
  • 结果展示

freemarker 加载静态模板 freemarker调用静态方法_freemarker 加载静态模板_02

5. FTL指令-include指令

  • 此指令用于模板文件的嵌套
  • 创建head.ftl 用于嵌入使用
<head>
    <meta charset="UTF-8">
    <title>include标签引入进来的标题,此文件为head.ftl</title>
</head>
  • 在 include.ftl中引入 head.ftl
<!DOCTYPE html>
<html lang="en">

<#-- 同目录直接写名字即可 -->
<#include 'head.ftl'>
<body>
<h1>测试include指令</h1>
</body>
</html>
  • 生成模板文件,和上面assign一样 ,只需要改文件名即可
  • 结果展示

freemarker 加载静态模板 freemarker调用静态方法_java_03

6. FTL指令-if-else指令

  • 创建ifElse.ftl模板文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>if-else指令</title>
</head>
<body>
<#if flag=true>
    <h1>结果为true</h1>
    <#else >
    <h1>结果为false</h1>
</#if>
</body>
</html>
  • 生成模板文件代码
package com.pyg;

import freemarker.template.Configuration;
import freemarker.template.Template;
import org.junit.Test;

import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

/**
 * @ Description
 * @ auther          宁宁小可爱
 * @ create          2020-02-04 16:22
 */

public class ifElse {
    /*
    * 使用ifElse.ftl模板获取简单数据
    * 三要素:
    * 模板: ifElse.ftl
    * 数据: 使用map封装
    * API: 引入坐标依赖
    * 模板指令: ${}插值表达式  {}中填写map的key即可获取值
    * */

    @Test
    public void test() throws Exception{
        // 创建freemarker核心配置对象 注意包是freemarker的
        Configuration cf = new Configuration(Configuration.getVersion());
        // 设置编码
        cf.setDefaultEncoding("UTF-8");
        // 设置模板文件位置
        cf.setDirectoryForTemplateLoading(new File("同上"));
        // 根据模板文件位置获取文件下所有的模板
        Template template = cf.getTemplate("ifElse.ftl");

        // 准备数据 :freemarker数据必须使用map对象进行封装
        Map maps = new HashMap();
        maps.put("flag",true);
        // 创建输出流对象 把生成的html通过流的方式写入磁盘
        Writer out = new FileWriter("同上");

        // 生成html文件
        template.process(maps,out);
        // 关闭流对象
        out.close();

    }
}
  • 结果展示

freemarker 加载静态模板 freemarker调用静态方法_数据_04

7. FTL指令-list指令

  • 创建Person类
package com.pyg;

/**
 * @ Description
 * @ auther          宁宁小可爱
 * @ create          2020-02-04 17:32
 */
public class Person {
    private int id;
    private String name;
    private String address;
	// 省略下面get set方法 和构造函数
}
  • 创建list.ftl模板
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>list指令</title>
</head>
<body>

<table>
    <tr>
        <th>编号</th>
        <th>角标</th>
        <th>姓名</th>
        <th>地址</th>
    </tr>
    <#list list as p>
        <tr>
            <td>${p.id}</td>
            <td>${p_index}</td>
            <td>${p.name}</td>
            <td>${p.address}</td>
        </tr>
    </#list>
</table>
</body>
</html>
  • 后台代码生成模板
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ Description
 * @ auther          宁宁小可爱
 * @ create          2020-02-04 19:52
 */
public class list {

    @Test
    public void test() throws Exception{
        Map maps = new HashMap();

        // 创建fm的配置
        Configuration config = new Configuration(Configuration.getVersion());
        // 指定默认编码格式
        config.setDefaultEncoding("UTF-8");
        // 设置模板的包路径
        config.setDirectoryForTemplateLoading(new File("模板文件夹路径"));
        // 获得包的模板
        Template template = config.getTemplate("list.ftl");
        // 指定文件输出的路径
        String path = "输出文件的路径\\文件名.html";

        Person person = new Person(1,"宁宁","中国");
        Person person1 = new Person(2,"宁宁小可爱","中国");
        Person person2 = new Person(3,"宁宁小宝贝","中国");
        List list = new ArrayList();
        list.add(person);
        list.add(person1);
        list.add(person2);

        maps.put("list",list);

        // 定义输出流,注意的必须指定编码
        Writer out = new FileWriter(path);
        // 生成html文件
        template.process(maps,out);
        // 关闭流对象
        out.close();
    }

}
  • 结果展示

freemarker 加载静态模板 freemarker调用静态方法_数据_05

8. 内建函数

内建函数语法格式: 变量+?+函数名称

获取集合大小:
我们使用size函数来实现,代码如下: ${goodsList?size}  条记录

转换JSON字符串为对象
 <#assign text="{'bank':'工商银行','account':'10101920201920212'}" />
 <#assign data=text?eval />
	开户行:${data.bank}  账号:${data.account}
	
日期格式化
map.put("today", new Date());

当前日期:${today?date} <br>
当前时间:${today?time} <br>   
当前日期+时间:${today?datetime} <br>        
日期格式化:  ${today?string("yyyy-MM-dd")}

数字转换为字符串
map.put("point", 102920122);
累计积分:${point} 带分隔符,102,920,122
累计积分:${point?c} 不带分隔符 102920122

空值处理运算符
<#if aaa??>
  aaa变量存在
<#else>
  aaa变量不存在
</#if>


缺失变量默认值:"!" ,我们除了可以判断是否为空值,也可以使用!对null值做转换处理
 ${aaa!'默认值'}

9. 运算符

算数运算符
FreeMarker表达式中完全支持算术运算,FreeMarker支持的算术运算符包括:+, - , * , / , %

逻辑运算符
逻辑运算符有如下几个: 
逻辑与:&& 
逻辑或:|| 
逻辑非:! 
逻辑运算符只能作用于布尔值,否则将产生错误 

比较运算符
1  =或者==:判断两个值是否相等. 
2  !=:判断两个值是否不等. 
3  >或者gt:判断左边值是否大于右边值 
4  >=或者gte:判断左边值是否大于等于右边值 
5  <或者lt:判断左边值是否小于右边值 
6  <=或者lte:判断左边值是否小于等于右边值