一、Freemarker介绍

FreeMarker是一个模板引擎,一个基于模板生成文本输出的通用工具,使用纯Java编写。

FreeMarker被设计用来生成HTML Web页面,特别是基于MVC模式的应用程序。

虽然FreeMarker具有一些编程的能力,但通常由Java程序准备要显示的数据,由FreeMarker生成页面,通过模板显示准备的数据,简单来讲就是模板加数据模型,然后输出页面。

FreeMarker介绍

FreeMarker不是一个Web应用框架,而适合作为Web应用框架一个组件。

FreeMarker与容器无关,因为它并不知道HTTP或Servlet;FreeMarker同样可以应用于非Web应用程序环境。

以上内容来自:官网

二、freemarker、thymeleaf、jsp比较

1. 现在为何越来越多的项目不使用JSP

尽管JSP已经存在了很长的时间,并且在Java Web服务器中无处不在,但是它却存在一些缺陷。JSP最明显的问题在于它看起来像HTML或XML,而事实上它并不是。大多数的JSP模板都采用HTML的形式,但是由于掺杂上了各种JSP标签库的标签和一些Scriptlet片段,使其变得极其混乱。这些特性虽然能够以很方便的方式为JSP带来动态渲染的强大功能,但是它也摧毁了我们想维持一个格式良好的文档的可能性。JSP缺乏良好格式的一个副作用就是它很少能够与其产生的HTML类似。所以,在Web浏览器或HTML编辑器中查看未经渲染的JSP模板是非常令人困惑的,而且得到的结果看上去也很丑陋。这个结果是不完整的——在视觉上这简直就是一场灾难!因为JSP并不是真正的HTML,很多浏览器和编辑器展现的效果都很难在审美上接近模板最终所渲染出来的效果。

补充:JSP为什么被淘汰了?

2. 前端模板和后端模板
  HTML页面就是个字符串,模板引擎就是给了你模板引擎自定义的语法,用来对这个字符串进行变量 /表达式的替换,最后还是得到HTML的字符串。
  前端(浏览器)渲染就是这个替换操作在浏览器用JS执行,比如react、vue;后端(服务器)渲染就是替换操作在后端执行,比如freemarker、thymeleaf,也可以后端渲染完生成HTML给前端,前端拿到HTML再做一次渲染。
  jsp也算是模板引擎,和 freemarker、thymeleaf就是语法 /性能 /其他功能强弱有无的区别,反正模板引擎做的事基本上都是输入模板 + 变量,输出HTML字符串。

3. freemaker和thymeleaf优缺点

freemaker优缺点:

  • 优点:freemaker和jsp类似,学习成本低,符合以前使用jsp的习惯;
  • 优点:freemaker性能比thymeleaf好;
  • 优点:使用了easyui等UI框架很少对HTML标签和标签属性进行手动处理,都是通过ajax返回json数据,由UI框架的组件直接渲染;
  • 不足:模板页面无法用浏览器打开直接渲染。

thymeleaf优缺点:
- 能够直接在浏览器中打开并正确显示模板页面,而不需要启动整个Web应用,便于前后端联调,SpringBoot官方推荐方案;
- 不足:模板必须符合xml规范,js脚本必须加入/*<![CDATA[*/标识,超级不方便。

具体开发过程中如何选择看具体情况。

4. 实际开发
  实际开发过程中,模板语言通过指定的语法填充数据,然后执行部分是模板引擎。相当于后端获取到要填充的数据之后按照指定格式填充到模板语言指定的位置,然后这样子发给前端去渲染。考虑到前后端分离,freemarker通常由前端来写,并且规定后端开发不能修改这些模板文件;前端和后端商量好借口,freemarker变量也好,JSON数据也好,前端本地开发时自己写模拟数据(保存在指定的文件里)并提交。

三、Freemarker基础语法

模板文件中四种元素:
- 文本:直接输出的部分;
- 注释:即<#--...-->格式不会输出;
- 取值:即${...}部分,将使用数据模型中的部分替代输出;
- FTL指令:FreeMarker指令,和HTML标记类似,名字前加#予以区分,不会输出。

hello.ftl

<#-- 我只是一个注释,不会有任何输出 -->
<h3>${name},上午好,${message}!</h3>

FreemarkerTest.java

@Test
public void test() throws Exception {

    // 创建配置信息对象
    Configuration configuration = new Configuration(Configuration.VERSION_2_3_26);
    // 设置模板文件加载的基础路径
    configuration.setClassForTemplateLoading(freemarkerTest.class,"/templates");
    // 设置默认编码
    configuration.setDefaultEncoding("UTF-8");
    // 加载模板文件,产生模板对象
    Template template = configuration.getTemplate("hello.ftl");
    // 定义数据模型
    Map<String,Object> dataModel = new HashMap<>();
    dataModel.put("name","sina");
    dataModel.put("message","今天天气不错");
    template.process(dataModel,new FileWriter("D:\hello.html"));
}

四、Freemarker FTL指令

1. assign变量指令

说明:此指令用于在页面上定义一个变量,如果在后端定义了变量,FTL页面可不用额外再用assgin定义

  • 定义简单类型:
<#-- 变量指令 (简单类型) -->
<#assign linkman="Z.K"/> 联系人:${linkman}
  • 定义对象类型:
<#-- 变量指令 (对象类型) -->
<#assign info={"mobile":"132...0280","address":"广州市天河区"} />
电话: ${info.mobile}  地址: ${info.address}

运行效果:
assign变量指令

2. include包含指令

说明:此指令用于包含模板文件

  • 创建模板文件/templates/header.ftl
<h1>这是一个Freemarker Demo</h1>
  • 修改/templates/hello.ftl,在模板文件中使用include指令包含header.ftl模板
<#include "header.ftl"/>

运行效果:
 include包含指令

3. if 条件指令

说明:if条件判断,If后变量的值只能为true/false,不然会报错的

  • 在模板文件中添加条件指令代码:
<#-- 条件指令 -->
<#if success>
    你已通过实名认证
<#else>
    你未通过实名认证
</#if>
  • 在后台代码中对success变量赋值:
dataModel.put("success", true);

运行效果:
if 条件指令

4. list迭代指令

  • 在模板文件中添加迭代指令代码:
<#-- list迭代指令 -->
<table border="1" width="300px">
    <tr>
        <th>编号</th>
        <th>姓名</th>
        <th>年龄</th>
    </tr>
    <#list users as user>
        <tr>
            <td>${user_index + 1}</td>
            <td>${user.name}</td>
            <td>${user.age}</td>
        </tr>
    </#list>
</table>
  • 后台代码中对变量users赋值:
List<Map<String, Object>> users = new ArrayList<>();
Map<String,Object> user1 = new HashMap<>();
user1.put("name","AAA");
user1.put("age",20);

Map<String,Object> user2 = new HashMap<>();
user2.put("name","BBB");
user2.put("age",19);

Map<String,Object> user3 = new HashMap<>();
user3.put("name","CCC");
user3.put("age",18);

users.add(user1);
users.add(user2);
users.add(user3);
dataModel.put("users",users);

说明:在循环中得到索引,可以使用 循环变量_index

运行效果:
list迭代指令

五、Freemarker 内建函数

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

1. size函数

说明:获取集合大小

<#-- size函数 -->
共${users?size}条记录。

2. eval函数

说明:将json字符串转换为对象

<#-- eval函数 -->
<#assign text="{'bank':'工商银行','account':'1806759312876'}"/>
<#assign data=text?eval/>
开户行: ${data.bank}  账号: ${data.account}

运行效果:
eval函数

3. 日期格式化函数

说明:将json字符串转换为对象

  • 后台代码中对变量赋值:
dataModel.put("today", new Date());
  • 在模板文件中加入日期格式化函数:
当前日期: ${today?date} <br/>
当前时间: ${today?time} <br/>
当前日期 + 时间: ${today?datetime} <br/>
日期格式化: ${today?string("yyyy年MM月dd日")} <br/>

运行效果如下:
日期格式化函数

4. 数字转换为字符串

  • 后台代码中对变量赋值:
dataModel.put("point",123456789);
  • 模板文件:
累计积分: ${point}

说明:模板文件中数字会以每三位一个分隔符显示,有时不需要这个分隔符,就需要将数字转换为字符串
- 使用内建函数

累计积分: ${point?c}

运行效果:
数字转换为字符串

5. 空值处理

注意:如果在模板中使用了变量但是在代码(模板页面或者后台)中没有对变量赋值,那么运行生成时会抛出异常,但是有时有的变量确实是null,该怎么办?

  • variable??,判断variable变量是否存在,如果该变量存在,返回true否则返回false
<#if aaa??>
    aaa变量存在
<#else>
    aaa变量不存在
</#if>
  • variable!,对null值进行转换处理
变量是否存在: ${aaa!'默认值'}

在代码中即使没有对aaa赋值,也不会报错,当aaa为null则返回!后边的内容“默认值”

六、Freemarker 运算符

1. 算数运算符

FreeMarker支持的算术运算符包括:+、 -、 *、/、%

4+2: ${4+2} 
4-2: ${4-2} 
4*2: ${4*2} 
4/2: ${4/2} 
4%2: ${4%2} 

2. 逻辑运算符

逻辑与:&&
逻辑或:||
逻辑非:!

与: ${(true && false)?c}
或: ${(true || false)?c} 
非: ${(!false)?c} 

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

10和10是否相等: ${(10==10)?c}
10和10是否不等: ${(10==10)?c}

5是否大于3: ${(5>3)?c} 
5是否大于5: ${(5>=3)?c}

5是否小于3: ${(5<3)?c}
5是否小于登于3: ${(5<=3)?c} 

运行效果:
Freemarker 运算符


星河滚烫,你是人间理想