freemarker基本语法

# 简介

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

在Java Web领域,FreeMarker是应用广泛的模板引擎,主要用于MVC中的view层,生成html展示数据给客户端,可以完全替代JSP。

# 模板组成部分

FreeMarker模板文件主要由如下4个部分组成:

  • 文本:直接输出的部分
  • 注释:使用<#-- ... -->格式做注释,里面内容不会输出
  • 插值:即${...}或#{...}格式的部分,类似于占位符,将使用数据模型中的部分替代输出
  • FTL指令:即FreeMarker指令,全称是:FreeMarker Template Language,和HTML标记类似,但名字前加#予以区分,不会输出

下面是一个FreeMarker模板的例子,包含了以上所说的4个部分:

<html>
<head>
<title>Welcome to FreeMarker 中文官网</title><br> 
</head> 
<body>
<#-- 注释部分 --> 
<#-- 下面使用插值 --> 
<h1>Welcome ${user} !</h1><br> 
<p>We have these animals:<br> 
<u1>
<#-- 使用FTL指令 --> 
<#list animals as being><br> 
  <li>${being.name} for ${being.price} Euros<br> 
<#list>
<u1>
</body> 
</html> 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 使用步骤

  • 第一步:创建一个Configuration对象,直接new一个对象。构造方法的参数就是FreeMarker对于的版本号。
  • 第二步:设置模板文件所在的路径。
  • 第三步:设置模板文件使用的字符集。一般就是utf-8.
  • 第四步:加载一个模板,创建一个模板对象。
  • 第五步:创建一个模板使用的数据集,可以是pojo也可以是map。一般是Map。
  • 第六步:创建一个Writer对象,一般创建一FileWriter对象,指定生成的文件名。
  • 第七步:调用模板对象的process方法输出文件。
  • 第八步:关闭流。
// 第一步:创建一个Configuration对象,直接new一个对象。构造方法的参数就是FreeMarker对于的版本号。
Configuration configuration = new Configuration(Configuration.getVersion());

// 第二步:设置模板文件所在的路径。
configuration.setDirectoryForTemplateLoading(new File("/WEB-INF/ftl"));

// 第三步:设置模板文件使用的字符集。一般就是utf-8.
configuration.setDefaultEncoding("utf-8");

// 第四步:加载一个模板,创建一个模板对象。
Template template = configuration.getTemplate("hello.ftl");

// 第五步:创建一个模板使用的数据集,可以是pojo也可以是map。一般是Map。
Map dataModel = new HashMap<>();
dataModel.put("hello", "this is my first FreeMarker test.");//向数据集中添加数据

// 第六步:创建一个Writer对象,一般创建一FileWriter对象,指定生成的文件名。
Writer out = new FileWriter(new File("/hello.html"));

// 第七步:调用模板对象的process方法输出文件。
template.process(dataModel, out);

// 第八步:关闭流。
out.close();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# Helloword示范

第一步:引入jar包

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-freemarker</artifactId>
  <version>1.4.1.RELEASE</version>
</dependency>
1
2
3
4
5
spring.freemarker.template-loader-path=classpath:/templates/
spring.freemarker.charset=utf-8
spring.freemarker.suffix=.ftl

spring.mvc.view.prefix=/
spring.mvc.view.suffix=.html
1
2
3
4
5
6

第二步:编写模板文件hello.ftl

<#ftl attributes={"content_type":"text/html; charset=UTF-8"}>
<?xml version="1.0" encoding="utf-8"?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
${hello}!
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11

第三步:编写数据模型

public class TestFreeMarker {
  public static void main(String[] args) throws Exception {
    Configuration cfg = new Configuration();
    cfg.setDirectoryForTemplateLoading(new File("E:/ftl"));
    Template template = cfg.getTemplate("hello.ftl");
    Map map = new HashMap();
    map.put("hello", "Hello FreeMarker!"); 

    StringWriter stringWriter = new StringWriter();
    template.process(map, stringWriter);
    String resultStr = stringWriter.toString();
    System.out.println(resultStr);
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

结果:

<?xml version="1.0" encoding="utf-8"?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Hello World</title>
</head>
<body>
Hello FreeMarker!
</body>
</html>
1
2
3
4
5
6
7
8
9
10

# 文件流处理方式

采用的apche的,其实我们也可以用普通的流来实现,但性能不知道有没有区别。

//将模板和数据模型结合生成html文本
String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
//将html内容存到输入流中
InputStream inputStream = IOUtils.toInputStream(content);
//创建文件test1.html
FileOutputStream outputStream = new FileOutputStream(new File("D:/test1.html"));
//将输入流中的html文本内容输送到输出流创建的文件中
IOUtils.copy(inputStream, outputStream);
1
2
3
4
5
6
7
8

普通输出流

//html文本
String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
//输出流
File f = new File("d:/test1.html");
FileWriter fw = new FileWriter(f, false);
BufferedWriter bw = new BufferedWriter(fw);
PrintWriter pw = new PrintWriter(bw);
pw.println(content);
pw.flush();
1
2
3
4
5
6
7
8
9

# 配置模板方式

/**  
* 根据模板生成html  
*/  
@GetMapping("creatHtmlByFile/{name}")  
public ResponseResult creatHtmlByFile(@PathVariable("name") String name) {  
  TemplateEngine engine = TemplateUtil.createEngine(new
                                                    TemplateConfig("templates", TemplateConfig.ResourceMode.CLASSPATH));  
  Template template = engine.getTemplate("test.ftl");  
  //Dict本质上为Map,此处可用Map  
  String content = template.render(Dict.create().set("name", name));  
  FileWriter writer = new
    FileWriter("static/test.html");//生成文件到target的static目录中  
  writer.write(content);  
  return new ResponseResult(CommonCode.SUCCESS, content);  
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**  
* 根据字符串生成html  
*/  
@GetMapping("creatHtmlByString/{name}")  
public ResponseResult creatHtmlByString(\@PathVariable("name") String name)
  throws URISyntaxException {  
  //自动根据用户引入的模板引擎库的jar来自动选择使用的引擎  
  //TemplateConfig为模板引擎的选项,可选内容有字符编码、模板路径、模板加载方式等,默认通过模板字符串渲染  
  TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig());  
  //假设我们引入的是Beetl引擎,则:  
  String html = "<!DOCTYPE html>\n" +  
    "<html lang=\"en\">\n" +  
    "<head>\n" +  
    " <meta charset=\"UTF-8\">\n" +  
    " <title>freemarker测试</title>\n" +  
    "</head>\n" +  
    "<body>\n" +  
    "<div>\n" +  
    " hello ${name}\n" +  
    "</div>\n" +  
    "</body>\n" +  
    "</html>";  
  Template template = engine.getTemplate(html);  
  //Dict本质上为Map,此处可用Map  
  HashMap<String, Object> map = new HashMap<>();  
  map.put("name", name);  
  String content = template.render(map);  
  FileWriter writer = new
    FileWriter("static/test.html");//生成文件到target的static目录中  
  writer.write(content);  
  return new ResponseResult(CommonCode.SUCCESS, content);  
}
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

可以通过用户输入字符串或者从文件中提取字符串从而创建一个静态化页面

//定义配置类
Configuration configuration = new Configuration(Configuration.getVersion());

//字符串内容,这里测试时使用简单的字符串作为模板内容,但此时这模板仍没有数据,若想要和数据结合,必须将此字符串变成模板类型
String templateString="" +
  "<html>\n" +
  " <head></head>\n" +
  " <body>\n" +
  " 名称:${name}\n" +
  " </body>\n" +
  "</html>";
//使用FreeMarker模板加载器将templateString字符串变成模板
StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
stringTemplateLoader.putTemplate("template", templateString);
//在配置中设置模板加载器并生成模板
configuration.setTemplateLoader(stringTemplateLoader);
//获取模板
Template template = configuration.getTemplate("template", "utf-8");

//-------------------------下面和test方法的步骤一样了,就是生成html文件了-------------------------
Map map = getMap();
//静态化
String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
//将html内容存到输入流中
InputStream inputStream = IOUtils.toInputStream(content);
//创建文件test1.html
FileOutputStream outputStream = new FileOutputStream(new File("D:/test1.html"));
//将输入流中的html文本内容输送到输出流创建的文件中
IOUtils.copy(inputStream, outputStream);

//关闭流
inputStream.close();
outputStream.close();
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

# 工作原理

FreeMarker的原理就是:模板+数据模型=输出,模板只负责数据在页面中的表现,不涉及任何的逻辑代码,而所有的逻辑都是由数据模型来处理的。用户最终看到的输出是模板和数据模型合并后创建的。其原理如下图所示:

img

image-20201215142436528

# 语法

# 数据访问

# 访问map中的key

${key}
1

# 访问pojo中的属性

//Student对象。学号、姓名、年龄
${student.id}
1
2

# 取集合中的数据

<#list studentList as student>
${student.id}/${studnet.name}
</#list>
1
2
3

# 指令

# assign指令

此指令用于在页面上定义一个变量

定义简单类型

<#assign linkman=“samy先生”> 联系人:${linkman}
1

定义对象类型

<#assign info={“mobile”:“13301231212”,‘address’:‘北京市昌平区’} > 电话:${info.mobile} 地址:${info.address}
1

# include指令

此指令用于模板文件的嵌套

创建模板文件head.ftl

<h1>samyzh</h1>
1

我们修改test.ftl,在模板文件中使用include指令引入刚才我们建立的模板

<#include “head.ftl”>
1

# if指令

在模板文件上添加

<#if success=true> 你已通过实名认证 <#else> 你未通过实名认证 </#if>
1

在代码中对str变量赋值

*map.put(“success”, true)*;
1

在freemarker的判断中,可以使用= 也可以使用==

<#if condition>  
....  
<#elseif condition2>  
...  
<#elseif condition3>  
...  
<#else>  
...  
</#if>
  
 <#if student_index % 2 == 0>
<#else>
</#if>
1
2
3
4
5
6
7
8
9
10
11
12
13

# list指令

1)代码中对变量goodsList赋值

List goodsList=new ArrayList(); 
Map goods1=new HashMap(); 
goods1.put(“name”, “苹果”); 
goods1.put(“price”, 5.8); 
Map goods2=new HashMap();
goods2.put(“name”, “香蕉”); 
goods2.put(“price”, 2.5); 
Map goods3=new HashMap(); 
goods3.put(“name”, “橘子”); 
goods3.put(“price”, 3.2); 
goodsList.add(goods1); 
goodsList.add(goods2); 
goodsList.add(goods3); 
map.put(“goodsList”, goodsList);
1
2
3
4
5
6
7
8
9
10
11
12
13
14

(2)在模板文件上添加

----商品价格表----<br> 
<#list goodsList as goods> ${goods_index+1} 商品名称: ${goods.name} 价格:${goods.price}<br> </#list>

<#list studentList as student>
  ${student.id}/${studnet.name}
</#list>
1
2
3
4
5
6

其他list数组相关

如果想在循环中得到索引,使用循环变量+_index就可以得到。

<#list sequence as item>  
...  
</#list>  
除此之外,迭代集合对象时,还包括两个特殊的循环变量:  
a、item_index:当前变量的索引值。  
b、item_has_next:是否存在下一个对象  
也可以使用<#break>指令跳出迭代  
<#list ["星期一","星期二","星期三","星期四","星期五"] as x>  
${x_index +1}.${x} <#if x_has_next>,</#if>  
<#if x = "星期四"><#break></#if>  
</#list>
  
  //取循环中的下标
  <#list studentList as student>
  ${student_index}
</#list>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# if/list示范

<#if users??>判断是否为null,不为null执行下面的代码 <#list users as o>是循环users ${o_index}是每个下标,从0开始

<body>
  <#if users??>
    <table border="1px">
      <tr>
        <td>编号</td>
        <td>姓名</td>
        <td>年龄</td>
        <td>性别</td>
      </tr>
      <#list users as o>
        <tr>
          <td>${o_index}</td>
          <td>${o.name}</td>
          <td>${o.age}</td>
          <td>${o.sex}</td>
        </tr>
        </#list>
    </table>
    </#if>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 内建函数

# 获取集合大小

${集合名?size}

共 ${goodsList?size} 条记录
1

# 转换JSON字符串为对象

<#assign text="{‘bank’:‘工商银行’,‘account’:‘10101920201920212’}" /> <#assign data=text?eval /> 开户行:${data.bank} 账号:${data.account}
1

# 日期格式化

代码中对变量赋值

dataModel.put(“today”, new Date());
1

在模板文件中加入

当前日期:${today?date} <br>
当前时间:${today?time} <br>
当前日期+时间:${today?*datetime*} <br>
日期格式化: ${today?string(“yyyy年MM月”)}
1
2
3
4

运行效果如下: 在这里插入图片描述

# 数字转换为字符串

代码中对变量赋值:

map.put(“point”, 102920122);
1

修改模板:

累计积分:${point} //102,920,122
1

会发现数字会以每三位一个分隔符显示,有些时候我们不需要这个分隔符,就需要将数字转换为字符串,使用内建函数c

累计积分:${point?c} //102920122
1

其他相关

?html:html字符转义  
?cap_first: 字符串的第一个字母变为大写形式  
?lower_case :字符串的小写形式  
?upper_case :字符串的大写形式  
?trim:去掉字符串首尾的空格  
?substring:截字符串  
?lenth: 取长度  
?size: 序列中元素的个数  
?int : 数字的整数部分(比如- 1.9?int 就是- 1)
?replace:字符串替换
1
2
3
4
5
6
7
8
9
10

# 运算符

# 空值处理运算符

# 判断某变量是否存在:“??”

用法为:variable??,如果该变量存在,返回true,否则返回false

<#if *aaa*??> *aaa*变量存在 <#else> *aaa*变量不存在 </#if>
1
# 缺失变量默认值:“!”

除了可以判断是否为空值,也可以使用!对null值做转换处理;在模板文件中加入

${*aaa*!’-’}
1

在代码中不对aaa赋值,也不会报错了 ,当aaa为null则返回!后边的内容-

如果是嵌套对象则建议使用()括起来。

例:${(stu.bestFriend.name)!’’}表示,如果stu或bestFriend或name为空默认显示空字符串。

# 算数运算符

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

# 逻辑运算符

逻辑运算符有如下几个:

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

# 比较运算符

表达式中支持的比较运算符有如下几个:

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

注意: =和!=可以用于字符串,数值和日期来比较是否相等,但=和!=两边必须是相同类型的值,否则会产生错误,而且FreeMarker是精确比较,“x”,"x ","X"是不等的.其它的运行符可以作用于数字和日期,但不能作用于字符串,大部分的时候,使用gt等字母运算符代替>会有更好的效果,因为 FreeMarker会把>解释成FTL标签的结束字符,当然,也可以使用括号来避免这种情况,如:<#if (x>y)>

# 常用示例

/**
         * freemark入门案例
         * freemark三要素:
         * 1.freemark API
         * 2.数据
         * 3.模板文件:ftl文件
         * @throws Exception 
         */
@Test
public void test1() throws Exception{
  //创建freemarker核心配置对象,指定freemarker
  Configuration cf = new Configuration(Configuration.getVersion());
  //指定服务器模板文件所在路径
  cf.setDirectoryForTemplateLoading(new File("F:\\template"));
  //指定模板文件编码
  cf.setDefaultEncoding("utf-8");
  //从模板文件路径下面获取模板文件对象
  Template template = cf.getTemplate("hello.ftl");

  //创建map对象,封装模板数据
  Map<String,Object> maps = new HashMap<String,Object>();
  maps.put("hello", "freemarker入门案例");
  //创建一个输出对象,把数据输出daoHtml页面
  Writer out = new FileWriter(new File("F:\\template\\out\\quickstart.html"));
  //生成Html页面
  template.process(maps, out);

  //关闭资源
  out.close();
}

/**
         * freemarker模板语法处理特殊数据格式   
         * 例如:$0.2,20%
         * 模板语法:$0.2:${price?string.currency}
         * 20%:${price?string.percent}
         * @throws Exception 
         */
@Test
public void test2() throws Exception{
  //创建freemark核心配置对象,指定freemark版本
  Configuration cf = new Configuration(Configuration.getVersion());
  //指定模板文件所在路径
  cf.setDirectoryForTemplateLoading(new File("F:\\template"));
  //设置模板编码
  cf.setDefaultEncoding("utf-8");
  //从模板文件路径下面取模板文件对象
  Template template = cf.getTemplate("num.ftl");
  //创建map对象,封装模板数据
  Map<String,Object> maps = new HashMap<>();
  maps.put("price", 0.2);
  //创建输出对象,把数据输出到Html页面
  Writer out = new FileWriter(new File("F:\\template\\out\\price.html"));
  //生成Html页面
  template.process(maps, out);

  //关闭资源
  out.close();
}

/**
         * 使用模板语法处理null值
         * 模板文件处理语法:
         * 1.?
         * 语法:${username?default("张三")}
         * 2.!
         * 语法:
         * ${username!}
         * ${username!"默认值"}
         * 3.if
         * 语法:
         * <#if username??>
         * ${username}
         * </#if>
         * @throws Exception 
         */
@Test
public void test3() throws Exception{
  //创建freemark核心配置对象,指定freemarker版本
  Configuration cf = new Configuration(Configuration.getVersion());
  //指定模板文件所在路径
  cf.setDirectoryForTemplateLoading(new File("F:\\template"));
  //设置模板编码
  cf.setDefaultEncoding("utf-8");
  //从模板文件路径下获取模板文件对象
  Template template = cf.getTemplate("null.ftl");
  //创建map对象,封装模板数据
  Map<String,Object> maps = new HashMap<>();
  maps.put("username", null);
  //创建输出对象,把数据输出到html页面
  Writer out = new FileWriter(new File("F:\\template\\out\\username.html"));
  //生成html页面
  template.process(maps, out);
  //关闭资源
  out.close();
}

/**
         * 使用模板语法处理pojo数据
         * el表达式获取数据:
         * model.addAttribute("p",person);
         * ${p.username}
         * ${p.address}
         * 模板语法获取pojo数据
         * model.addAttribute("p",person);
         * ${p.username}
         * ${p.address}
         * @throws Exception 
         */
@Test
public void test4() throws Exception{
  //创建freemark核心配置对象,指定freemarker版本
  Configuration cf = new Configuration(Configuration.getVersion());
  //指定模板文件所在路径
  cf.setDirectoryForTemplateLoading(new File("F:\\template"));
  //设置模板编码
  cf.setDefaultEncoding("utf-8");
  //从模板文件路径下获取模板文件对象
  Template template = cf.getTemplate("person.ftl");
  //创建map对象,封装模板数据
  Map<String,Object> maps = new HashMap<>();
  //创建person对象
  Person person = new Person();
  person.setUsername("张三");
  person.setAge(22);
  maps.put("p", person);
  //创建输出对象,把数据输出到html页面
  Writer out = new FileWriter(new File("F:\\template\\out\\person.html"));
  //生成html页面
  template.process(maps, out);
  //关闭资源
  out.close();
}

/**
         * 使用模板语法处理集合数据
         * el表达式获取数据:
         * model.addAttribute("pList",pList);
         * <c:foreach item="pList" var="p">
         *      ${p.username}
         *      ${p.age}
         * </c:foreach>
         * 模板语法获取list数据
         * model.addAttribute("pList",pList);
         * <#list pList as p>
         *      ${p.username}
         *      ${p.age}
         * </#list>
         * 角标语法:${别名_index}
         * @throws Exception 
         */
@Test
public void test5() throws Exception{
  //创建freemark核心配置对象,指定freemarker版本
  Configuration cf = new Configuration(Configuration.getVersion());
  //指定模板文件所在路径
  cf.setDirectoryForTemplateLoading(new File("F:\\template"));
  //设置模板编码
  cf.setDefaultEncoding("utf-8");
  //从模板文件路径下获取模板文件对象
  Template template = cf.getTemplate("list.ftl");
  //创建map对象,封装模板数据
  Map<String,Object> maps = new HashMap<>();
  //创建list集合
  List<Person> pList = new ArrayList<>();
  //创建person对象
  Person person1 = new Person();
  person1.setUsername("张三");
  person1.setAge(22);
  //创建person对象
  Person person2 = new Person();
  person2.setUsername("李四");
  person2.setAge(24);
  pList.add(person1);
  pList.add(person2);
  maps.put("pList", pList);
  //创建输出对象,把数据输出到html页面
  Writer out = new FileWriter(new File("F:\\template\\out\\list.html"));
  //生成html页面
  template.process(maps, out);
  //关闭资源
  out.close();
}

/**
         * 使用模板语法处理时间类型数据
         * 获取数据日期:${today?date}
         * 获取数据时间:${today?time}
         * 获取数据日期时间:${today?datetime}
         * 获取数据日期时间格式化:${today?string('yyyy-MM-dd')}
         * @throws Exception 
         */
@Test
public void test6() throws Exception{
  //创建freemark核心配置对象,指定freemarker版本
  Configuration cf = new Configuration(Configuration.getVersion());
  //指定模板文件所在路径
  cf.setDirectoryForTemplateLoading(new File("F:\\template"));
  //设置模板编码
  cf.setDefaultEncoding("utf-8");
  //从模板文件路径下获取模板文件对象
  Template template = cf.getTemplate("date.ftl");
  //创建map对象,封装模板数据
  Map<String,Object> maps = new HashMap<>();

  maps.put("today", new Date());
  //创建输出对象,把数据输出到html页面
  Writer out = new FileWriter(new File("F:\\template\\out\\date.html"));
  //生成html页面
  template.process(maps, out);
  //关闭资源
  out.close();
}
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213

# 页面静态化

1.工具类

import freemarker.template.Configuration;
import freemarker.template.Template;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.Map;

@Component
public class CreateHtmlUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(CreateHtmlUtil.class);

    @Value("${htmlPath}")
    private String htmlPath;
    @Value("${ftlPath}")
    private String ftlPath;


    /**
     * 通过freemarker生成静态HTML页面
     */
    public  void createHtml(String templateName,String targetFileName,Map<String, Object> map) throws Exception{
        LOGGER.info("生成路径: {}, 模板路径:{}", htmlPath, ftlPath);
        //创建fm的配置
        Configuration config = new Configuration();
        //指定默认编码格式
        config.setDefaultEncoding("UTF-8");
        Template template = null;
        //设置模版文件的路径
        try {
            config.setDirectoryForTemplateLoading(new File(ftlPath));
            //获得模版包
            template = config.getTemplate(templateName);
        } catch (Exception e) {
            LOGGER.info("设置模板包异常:{}" + e.getMessage());
        }

        //定义输出流,注意必须指定编码

        try (FileOutputStream fileInputStream = new FileOutputStream(new File(htmlPath+"/"+targetFileName));
             OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileInputStream, "UTF-8");
             Writer writer = new BufferedWriter(outputStreamWriter)) {
            template.process(map, writer);
            LOGGER.info("写入html");
        } catch (Exception e) {
            LOGGER.info("生成异常: {}", e.getMessage());
        }
    }

}
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

2.添加填充数据据

    private void generateHtml (Integer CategoryNo, int count, Map<String, Object> pageMap) {
        try {
            String htmlFileName = getHtmlFileName(CategoryNo, count + 1);
            LOGGER.info("html 文件名: {}" , htmlFileName);
            createHtmlUtil.createHtml(NEWS_TEMPLATE, htmlFileName, pageMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
1
2
3
4
5
6
7
8
9

3.静态页面

<input type="hidden" id="total" value="${total}"/>
<#if newsPageDatas??>
    <#list newsPageDatas as key>
        <div class="new-item-box clearfix clear">
            <div class="image fl">
                <img src="<#if key.titleUrl??>${key.titleUrl}<#else >../images/news-1.png</#if>" alt="">
            </div>
            <div class="item-content-box">
                <div class="item-content">
                    ${key.title!''}
                </div>
                <div class="item-time-arrow clearfix">
                    <div class="item-time">
                        <div class="item-time-day">
                            <#if key.publishDate??>
                                ${key.publishDate?string("dd")!}
                            </#if>
                        </div>
                        <div class="item-time-year">
                            <#if key.publishDate??>
                                ${key.publishDate?string("yyyy.MM")!}
                            </#if>
                        </div>
                    </div>
                </div>
            </div>
            <div class="arrow">
                <a href="../page/news_details_${key.id}.html">
                    <img src="../images/jiantou.png" alt="">
                </a >
            </div>
        </div>
    </#list>
</#if>
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

作者:咪雅先森 链接:https://www.jianshu.com/p/fb591f12203a 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

# 相关链接

  • https://freemarker.apache.org/
  • http://freemarker.foofun.cn/
  • http://www.freemarker.net/
上次更新: 2022/04/15, 05:41:32
×