1️⃣ 什么是FreeMarker?

FreeMarker 是一款模板引擎:即一种基于模板、用来生成输出文本(任何来自于 HTML格式的文本用来自动生成源代码、电子邮件、配置文件、源代码等)的通用工具 (可用于进行页面静态化的模板) 。它是为 Java 程序员提供的一个开发包,或者说是一个类库。它不是面向最终用户的,而是为程序员提供的一款可以嵌入他们所开发产品的应用程序。

FreeMarker 实际上是被设计用来生成 HTML 页面,尤其是通过实现了基于 MVC(Model View Controller,模型-视图-控制器)模式的 Java Servlet 应用程序。使用 MVC 模式的动态页面 的设计构思使得你可以将前端设计师(编写 HTML 页面的人员)从程序员中分离出来。那么,所有人各司其职,发挥其最擅长的一面。网页设计师可以改写页面的显示效果而不受程序员编译代码的影响,因为应用程序的逻辑(这里是 Java 程序)和页面设计(这里是 FreeMarker 模 板)已经被分开了。页面模板代码不会受到复杂程序代码的影响。这种分离的思想即便对一个程序员和页面设计师是同一个人的项目来说也都是非常有用的,因为分离使得代码保持简洁而且易于维护。

在这里插入图片描述

1️⃣ 模板入门

2️⃣ 模板+数据模型=输出

freemarker并不关心数据的来源,只是根据模板的内容,将数据模型在模板中显示并输出文件(通常为html,也可以生成其它格式的文本文件):

1、数据模型:数据模型在java中可以是基本类型也可以List、Map、Pojo等复杂类型。
2、来自官方的例子:https://freemarker.apache.org/docs/dgui_quickstart_basics.html

数据模型:

在这里插入图片描述

模板:

在这里插入图片描述

输出:

在这里插入图片描述

2️⃣ FreeMarker快速入门

freemarker作为springmvc一种视图格式,默认情况下SpringMVC支持freemarker视图格式。 需要创建Spring Boot+Freemarker工程用于测试模板。

3️⃣ 创建测试工程

创建一个freemarker 的测试工程专门用于freemarker的功能测试与模板的测试。

测试环境搭建目录:

导入依赖:

<dependency>
  <groupId>org.freemarker</groupId>
  <artifactId>freemarker</artifactId>
  <version>2.3.23</version>
</dependency>

如果是springboot项目可以直接使用下面这个依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

3️⃣ 配置文件

配置application.yml。

application.yml内容如下:

server:
  port: 8088 #服务端口

spring:
  main:
    allow-bean-definition-overriding: true
  application:
    name: freemarker-demo #指定服务名
  freemarker:
    cache: false  #关闭模板缓存,方便测试
    settings:
      template_update_delay: 0 #检查模板更新延迟时间,设置为0表示立即检查,如果时间大于0会有缓存不方便进行模板测试
    suffix: .ftl
    template-loader-path: classpath:/templates/

3️⃣ 创建模型类

在freemarker的测试工程下创建模型类型用于测试:

Student.java内容如下:

@Data
@ToString
public class Student {
    private String name;//姓名
    private int age;//年龄
    private Date birthday;//生日
    private Float wallet;//钱包
    private List<Student> friends;//朋友列表
    private Student bestFriend;//最好的朋友
}

3️⃣ 创建模板

src/main/resources下创建templates,此目录为freemarker的默认模板存放目录。

templates下创建模板文件test1.ftl,模板中的${name}最终会被freemarker替换成具体的数据。

test1.ftl内容如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
Hello,${name}!
</body>
</html>

3️⃣ 创建controller

创建Controller类,向Map中添加name,最后返回模板文件。

FreemarkerController.java内容如下:

@RequestMapping("/freemarker")
@Controller     //这里不要使用@RestController,要输出html网页,RestController输出时json数据
public class FreemarkerController {

    //测试1
    @RequestMapping("/test1")
    public String test1(Map<String, Object> map) {
        //map就是freemarker模板所使用的数据
        map.put("name", "黄汉升");

        //返回freemarker模板的位置,基于resources/templates路径的
        return "test1";
    }
}

3️⃣ 创建启动类

FreemarkerTestApplication.java:

@SpringBootApplication
public class FreemarkerDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(FreemarkerDemoApplication.class, args);
    }
}

测试结果:

在这里插入图片描述
以上便是freemarker的环境搭建ヾ(◍°∇°◍)ノ゙

1️⃣ FreeMarker基础

2️⃣ 基础语法种类

1、注释,即<#‐‐‐‐>,介于其之间的内容会被freemarker忽略 。
2、插值(Interpolation):即 ${..}部分,freemarker会用真实的值代替${..}
3、FTL指令:和HTML标记类似,名字前加#予以区分,Freemarker会解析标签中的表达式或逻辑。
4、文本,仅文本信息,这些不是freemarker的注释、插值、FTL指令的内容会被freemarker忽略解析,直接输出内容。

下边方法形参map即为freemarker静态化所需要的数据模型,在map中填充数据

FreemarkerController.java:

@RequestMapping("/test2")
public String test2(Map<String, Object> map) {
    //向数据模型放数据
    map.put("name","黄汉升");
    Student stu1 = new Student();
    stu1.setName("赵子龙");
    stu1.setAge(21);
    stu1.setWallet(1314.2f);
    stu1.setBirthday(new Date());
    Student stu2 = new Student();
    stu2.setName("关云长");
    stu2.setWallet(520.0f);
    stu2.setAge(20);
    stu2.setBirthday(new Date());
    List<Student> friends = new ArrayList<>();
    friends.add(stu1);
    stu2.setFriends(friends);
    stu2.setBestFriend(stu1);
    List<Student> stus = new ArrayList<>();
    stus.add(stu1); stus.add(stu2);
    //向数据模型放数据
    map.put("stus",stus);
    //准备map数据
    HashMap<String,Student> stuMap = new HashMap<>();
    stuMap.put("stu1",stu1);
    stuMap.put("stu2",stu2);
    //向数据模型放数据
    map.put("stu1",stu1);
    //向数据模型放数据
    map.put("stuMap",stuMap);
    //返回模板文件名称
    return "test2";
}

2️⃣ 复杂对象取值(嵌套对象)

创建一个订单Order和价格Price实体类,其中Order中嵌套了Price实体类

@Data
public class Order {
    private Long orderId;
    private String orderName;
    private Price price;
}

@Data
public class Price {
    private double price;
    private Date date;
}

创建接口:

@RequestMapping("/test11")
public String test11(Map<String, Object> map) {
    Price price = new Price();
    price.setPrice(123.45);
    price.setDate(new Date());
    Order order = new Order();
    order.setOrderId(123456789L);
    order.setOrderName("测试订单");
    order.setPrice(price);
    map.put("order", order);
    return "test11";
}

ftl文件,使用两种方式访问,建议使用第二种:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
<#--方式1-->
订单id:${order.orderId} <br>
订单名称:${order.orderName} <br>
订单价格:${order.price.price} <br>
订单日期:${order.price.date?string("yyyy年MM月")} <br>

<br>
<br>
<br>


<#--方式2-->
订单id:${order.getOrderId()} <br>
订单名称:${order.getOrderName()} <br>
订单价格:${order.getPrice().getPrice()} <br>
订单日期:${order.getPrice().getDate()?string("yyyy年MM月")} <br>
</body>
</html>

测试结果:

在这里插入图片描述

2️⃣ list指令

test1.ftl模板中使用list指令遍历数据模型中的数据:

test2.ftl:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
Hello,${name}!
<table>
    <tr>
        <td>序号</td>
        <td>姓名</td>
        <td>年龄</td>
        <td>钱包</td>
    </tr>
    <#list stus as stu>
        <tr>
            <td>${stu_index + 1}</td> <#--说明: _index:得到循环的下标,使用方法是在stu后边加"_index",它的值是从0开始-->
            <td <#if stu.name =='张翼德'>style="background:red;"</#if>>${stu.name}</td>
            <td>${stu.age}</td>
            <td>${stu.wallet}</td>
        </tr>
    </#list>
</table>
</body>
</html>

测试结果:
在这里插入图片描述

2️⃣ 遍历map数据

test1.ftl模板中使用map指令遍历数据模型中的stuMap,

test3.ftl:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
遍历数据模型中的stuMap(map数据),第一种方法:在中括号中填写map的key,第二种方法:在map后边直接加"点(.) key"
<br/>
输出stu1的学生信息:<br/>
姓名:${stuMap['stu1'].name}<br/>
年龄:${stuMap['stu1'].age}<br/>
输出stu1的学生信息:<br/>
姓名:${stu1.name}<br/>
年龄:${stu1.age}<br/>
遍历map中的key.stuMap?keys就是列表(是一个list)<br/>
遍历输出两个学生信息:<br/>
<table>
    <tr>
        <td>序号</td>
        <td>姓名</td>
        <td>年龄</td>
        <td>钱包</td>
    </tr>
    <#list stuMap?keys as k>
        <tr>
            <td>${k_index + 1}</td>
            <td>${stuMap[k].name}</td>
            <td>${stuMap[k].age}</td>
            <td>${stuMap[k].wallet}</td>
        </tr>
    </#list>
</table>

</body>
</html>

测试结果:

在这里插入图片描述

2️⃣ if指令

在test1.ftl模板中使用if 指令即判断指令,是常用的FTL指令,freemarker在解析时遇到if会进行判断,条件为真则输出if中间的内容,否则跳过内容不再输出。

test4.ftl

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
<table>
    <tr>
        <td>序号</td>
        <td>姓名</td>
        <td>年龄</td>
        <td>钱包</td>
    </tr>
    <#list stus as stu>
        <tr>
            <td>${stu_index + 1}</td>   <#--说明: _index:得到循环的下标,使用方法是在stu后边加"_index",它的值是从0开始-->
            <td <#if stu.name =='赵子龙'>style="background:red;"</#if>>${stu.name}</td>
            <td <#if stu.age gt 20>style="background:yellow;"</#if>>${stu.age}</td>
            <td <#if (stu.wallet > 999)>style="background:blue;"</#if>>${stu.wallet}</td>
        </tr>
    </#list>
</table>

</body>
</html>

测试结果:

在这里插入图片描述
对于在if里运用的运算符,参考如下:

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

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

3、 比较运算符 :
表达式中支持的比较运算符有如下几个:
1、 =或者==:判断两个值是否相等.
2、 !=:判断两个值是否不等.
3、 或者gt:判断左边值是否大于右边值
4、 >=或者gte:判断左边值是否大于等于右边值
5 、<或者lt:判断左边值是否小于右 边值
6 、<=或者lte:判断左边值是否小于等于右边值

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

2️⃣ 空值处理

1、判断某变量是否存在使用 “??” 用法为:variable??,如果该变量存在,返回true,否则返回false

例如先把FreemarkerController中的:

//向数据模型放数据
//map.put("stus",stus);

注释掉,运行访问会出现什么情况呢?

在这里插入图片描述

是的,报错了,因为没有数据的原因出现了这个错误,而现在就是对空值应该怎么处理呢?
可以写入 <#if stus??></#if>

test5.ftl:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
Hello,${name}!
<table>
    <tr>
        <td>序号</td>
        <td>姓名</td>
        <td>年龄</td>
        <td>钱包</td>
    </tr>
    <#if stus??>
        <#list stus as stu>
            <tr>
                <td>${stu_index + 1}</td>   <#--说明: _index:得到循环的下标,使用方法是在stu后边加"_index",它的值是从0开始-->
                <td <#if stu.name =='小懒猪'>style="background:red;"</#if>>${stu.name}</td>
                <td <#if stu.age gt 20>style="background:yellow;"</#if>>${stu.age}</td>
                <td <#if (stu.mondy > 999)>style="background:blue;"</#if>>${stu.mondy}</td>
            </tr>
        </#list>
    </#if>
</table>
</body>
</html>

运行结果:

在这里插入图片描述

2、缺失变量默认值使用 “!” 使用!要以指定一个默认值,当变量为空时显示默认值。 例: ${name!’’}表示如果name为空显示空字符串。 如果是嵌套对象则建议使用()括起来。
例: ${(stu1.name)!’’}表示,如果stu1或name为空默认显示空字符串。

都先注释掉:

// stuMap.put(“stu1”,stu1);
// map.put(“stu1”,stu1);
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
输出stu1的学生信息:<br/>
姓名:${(stuMap['stu1'].name)!''}<br/>
年龄:${(stuMap['stu1'].age)!''}<br/>
输出stu1的学生信息:<br/>
姓名:${(stu1.name)!''}<br/>
年龄:${(stu1.age)!''}<br/>
</body>
</html>

运行结果:

在这里插入图片描述

2️⃣ 内建函数

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

1、和到某个集合的大小

${集合名?size}

例:学生个数:${stus?size}

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
学生个数:${stus?size}
</body>
</html>

运行结果:

在这里插入图片描述

2、日期格式化

显示年月日: ${today?date}
显示时分秒:${today?time}
显示日期+时间:${today?datetime} <br>
自定义格式化: ${today?string("yyyy年MM月")}

例如:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
学生个数:${stus?size}
<table>
    <tr>
        <td>序号</td>
        <td>姓名</td>
        <td>年龄</td>
        <td>钱包</td>
        <td>出生日期date</td>
        <td>出生日期time</td>
        <td>出生日期datetime</td>
        <td>出生日期(自定义)</td>

    </tr>
    <#list stus as stu>
        <tr>
            <td>${stu_index + 1}</td>   <#--说明: _index:得到循环的下标,使用方法是在stu后边加"_index",它的值是从0开始-->
            <td <#if stu.name =='赵子龙'>style="background:red;"</#if>>${stu.name}</td>
            <td <#if stu.age gt 20>style="background:yellow;"</#if>>${stu.age}</td>
            <td <#if (stu.wallet > 999)>style="background:blue;"</#if>>${stu.wallet}</td>
            <td>${stu.birthday?date}</td>
            <td>${stu.birthday?time}</td>
            <td>${stu.birthday?datetime}</td>
            <td>${stu.birthday?string("yyyy年MM月")}</td>
        </tr>
    </#list>
</table>
</body>
</html>

运行结果:

在这里插入图片描述

3、内建函数c

map.put("point", 102920122); 

运行结果:

在这里插入图片描述

point是数字型,使用 ${point} 会显示这个数字的值,不并每三位使用逗号分隔。
如果不想显示为每三位分隔的数字,可以使用c函数将数字型转成字符串输出

${point?c} 

运行结果:

在这里插入图片描述

4、将json字符串转成对象一个例子:

其中用到了assign标签,assign的作用是定义一个变量。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
${point?c} <br>

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

运行结果:

在这里插入图片描述

以上便是有关FreeMarker比较常用的基础指令,若想深入了解FreeMarker,
可以查看这本书FreeMarker_Manual_zh_CNhttps://github.com/huang-hanson/Java-CSDN/blob/master/freemarker-demo/doc/FreeMarker_Manual_zh_CN.pdf

也可以查看官网文档
英文文档:https://freemarker.apache.org/docs/index.html
中文文档:http://freemarker.foofun.cn/index.html

本文代码地址:https://github.com/huang-hanson/Java-CSDN/tree/master/freemarker-demo

好文推荐《【Thymeleaf】spring boot模板引擎thymeleaf用法详解》

至此便是本文章关于FreeMarker简单的基础入门<(▰˘◡˘▰)

在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐