首页 > 其他分享 >FreeMaker 入门

FreeMaker 入门

时间:2024-08-03 21:17:08浏览次数:18  
标签:文件 入门 FreeMarker 模板 new freemarker 数据模型 FreeMaker

Freemaker 基础

什么是模板引擎?为什么需要它?

模板引擎是一种用于生成动态内容的类库(或框架),通过将预定义的模板与特定数据合并,来生成最终的输出。
使用模板引擎有很多的优点,首先就是提供现成的模板文件语法和解析能力。开发者只要按照特定要求去编写模板文件,比如使用 ${参数} 语法,模板引擎就能自动将参数注入到模板中,得到完整文件,不用再自己编写解析逻辑了。
其次,模板引擎可以将数据和模板分离,让不同的开发人员独立工作。比如后端专心开发业务逻辑提供数据,前端专心写模板等,让系统更易于维护。
此外,模板引擎可能还具有一些安全特性,比如防止跨站脚本攻击等。所以强烈大家掌握至少一种模板引擎的用法。
有很多现成的模板引擎技术,比如 Java 的 Thymeleaf、FreeMarker、Velocity,前端的 Mustache 等。

什么是 FreeMarker?

FreeMarker 是 Apache 的开源模板引擎,优点是入门简单、灵活易扩展。它不用和 Spring 开发框架、Servlet 环境、第三方依赖绑定,任何 Java 项目都可以使用。

推荐 FreeMarker 官方文档,虽然是英文的,但每一节基本都有代码示例。

[!note]
FreeMarker 官方文档:https://freemarker.apache.org/docs/index.html
中文教程:http://freemarker.foofun.cn/toc.html
FreeMarker 教程网:http://www.freemarker.net/

模板引擎的作用

上面已经讲过了模板引擎的作用,这里就再用 FreeMarker 官网的一张图,强化下大家的理解。
如下图,FreeMarker 模板引擎的作用就是接受模板和 Java 对象,对它们进行处理,输出完整的内容。
模板 + 数据模型 = 输出

image.png

下面我们先依次来学习 FreeMarker 的核心概念(模板和数据模型),然后通过一个 Demo 快速入门。

模板

FreeMarker 拥有自己的模板编写规则,一般用 FTL 表示 FreeMarker 模板语言。比如 myweb.html.ftl 就是一个 FreeMarker 的模板文件。

模板文件由 4 个核心部分组成
1)文本:固定的内容,会按原样输出。
2)插值:用 ${...} 语法来占位,尖括号中的内容在经过计算和替换后,才会输出。
3)FTL 指令:有点像 HTML 的标签语法,通过 <#xxx ... > 来实现各种特殊功能。比如 <#list elements as element> 实现循环输出。
4)注释:和 HTML 注释类似,使用 <#-- ... --> 语法,注释中的内容不会输出。

让我们以《鱼皮官网》为例,举一个 FreeMarker 模板文件的例子:

<!DOCTYPE html>
<html>
  <head>
    <title>鱼皮官网</title>
  </head>
  <body>
    <h1>欢迎来到鱼皮官网</h1>
    <ul>
      <#-- 循环渲染导航条 -->
      <#list menuItems as item>
        <li><a href="${item.url}">${item.label}</a></li>
      </#list>
    </ul>
    <#-- 底部版权信息(注释部分,不会被输出)-->
      <footer>
        ${currentYear} 鱼皮官网. All rights reserved.
      </footer>
  </body>
</html>

数据模型

我们把为模板准备的所有数据整体统称为 数据模型
在 FreeMarker 中,数据模型一般是树形结构,可以是复杂的 Java 对象、也可以是 HashMap 等更通用的结构。
比如为上述《鱼皮官网》模板准备的数据模型,结构可能是这样的:

{
  "currentYear": 2023,
  "menuItems": [
    {
      "url": "https://codefather.cn",
      "label": "编程导航",
    },
    {
      "url": "https://laoyujianli.com",
      "label": "老鱼简历",
    }
  ]
}

常用语法

注意,FreeMarker 的语法和特性非常多,本文仅带大家学习常用的、易用的语法。无需记忆,日后需要用到 FreeMarker 时,再去对照官方文档查漏补缺即可。

1、插值

在上面的 Demo 中,已经给大家演示了差值的基本语法( ${xxx} )。但插值还有很多花样可以玩,比如支持传递表达式:

表达式:${100 + money}

不过个人不建议在模板文件中写表达式,为什么不在创建数据模型时就计算好要展示的值呢?

2、分支和判空

和程序开发一样,FreeMarker 模板也支持分支表达式(if ... else),示例代码如下:

<#if user == "鱼皮">
  我是鱼皮
<#else>
  我是猪皮
</#if>

分支语句的一个常用场景就是判空,比如要判断 user 参数是否存在,可以用下面的语法:

<#if user??>
  存在用户
<#else>
  用户不存在
</#if>

3、默认值

FreeMarker 对变量的空值校验是很严格的,如果模板中某个对象为空,FreeMarker 将会报错而导致模板生成中断。
为了防止这个问题,建议给可能为空的参数都设置默认值。使用 表达式!默认值 的语法,示例代码如下:

${user!"用户为空"}

上述代码中,如果 user 对象为空,则会输出 “用户为空” 字符串。

4、循环

在上述 Demo 实战部分,已经给大家演示了循环的用法。即 <#list items as item> 表达式,可以遍历某个序列类型的参数并重复输出多条内容。
示例代码如下:

<#list users as user>
  ${user}
</#list>

其中,users 是整个列表,而 user 是遍历列表每个元素时临时存储的变量,跟 for 循环一样,会依次输出每个 user 的值。

5、宏定义

学过 C 语言和 C++ 的同学应该对 “宏” 这个词并不陌生。可以把 “宏” 理解为一个预定义的模板片段。支持给宏传入变量,来复用模板片段。

其实类似于前端开发中组件复用的思想。

在 FreeMarker 中,使用 macro 指令来定义宏。
让我们来定义一个宏,用于输出特定格式的用户昵称,比如:

<#macro card userName>     
---------    
${userName}
---------
</#macro>

其中,card 是宏的名称,userName 是宏接受的参数。
可以用 @ 语法来使用宏,示例代码如下:

<@card userName="鱼皮"/>
<@card userName="二黑"/>

实际生成的输出结果为:

---------    
鱼皮
---------
---------    
二黑
---------

宏标签中支持嵌套内容,不过还是有些复杂的(再讲下去就成前端课了),大家需要用到时查看官方文档就好。

自定义指令:http://freemarker.foofun.cn/dgui_misc_userdefdir.html

6、内建函数

内建函数是 FreeMarker 为了提高开发者处理参数效率而提供的的语法糖,可以通过 ? 来调用内建函数。
比如将字符串转为大写:

${userName?upper_case}

比如输出序列的长度:

${myList?size}

把内建函数想象成调用 Java 对象的方法,就很好理解了。
内建函数是 FreeMarker 非常强大的一个能力,比如想在循环语法中依次输出元素的下标,就可以使用循环表达式自带的 index 内建函数:

<#list users as user>
  ${user?index}
</#list>

内建函数种类丰富、数量极多,因此不建议大家记忆,需要用到的时候去查阅官方文档即可。

内建函数大全参考:http://freemarker.foofun.cn/ref_builtins.html

7、其他

还有更多特性,比如命名空间,其实就相当于 Java 中的包,用于隔离代码、宏、变量等。
不过没必要细讲,因为掌握上述常用语法后,基本就能够开发大多数模板文件了。更多内容自主查阅官方文档学习即可。

Demo 实战

在了解模板和数据模型后,让我们通过 FreeMarker 对二者进行组合处理。

1、引入依赖

首先创建一个 Maven 项目(这里就用我们的 yuzi-generator-basic 项目),在 pom.xml 中引入 FreeMarker:

<!-- https://freemarker.apache.org/index.html -->
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.32</version>
</dependency>

如果是 Spring Boot 项目的话,可以直接引入 starter 依赖:

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

2、创建配置对象

test/java 目录下新建一个单元测试类 FreeMarkerTest� ,在 Test 方法中创建一个 FreeMarker 的全局配置对象,可以统一指定模板文件所在的路径、模板文件的字符集等。
示例代码如下:

// new 出 Configuration 对象,参数为 FreeMarker 版本号
Configuration configuration = new Configuration(Configuration.VERSION_2_3_32);

// 指定模板文件所在的路径
configuration.setDirectoryForTemplateLoading(new File("src/main/resources/templates"));

// 设置模板文件使用的字符集
configuration.setDefaultEncoding("utf-8");

3、准备模版并加载

我们将上述《鱼皮官网》的模板代码保存为 myweb.html.ftl 文件,存放在上面指定的目录下。
image.png

准备好模板文件后,通过创建 Template 对象来加载该模板。示例代码如下:

// 创建模板对象,加载指定模板
Template template = configuration.getTemplate("myweb.html.ftl");

4、创建数据模型

如果想保证数据的质量和规范性,可以使用对象来保存 “喂” 给模板的数据;反之,如果想更灵活地构造数据模型,推荐使用 HashMap 结构。
比如我们想构造《鱼皮官网》的数据模型,需要制定当前年份和导航菜单项,示例代码如下:

Map<String, Object> dataModel = new HashMap<>();
dataModel.put("currentYear", 2023);
List<Map<String, Object>> menuItems = new ArrayList<>();
Map<String, Object> menuItem1 = new HashMap<>();
menuItem1.put("url", "https://codefather.cn");
menuItem1.put("label", "编程导航");
Map<String, Object> menuItem2 = new HashMap<>();
menuItem2.put("url", "https://laoyujianli.com");
menuItem2.put("label", "老鱼简历");
menuItems.add(menuItem1);
menuItems.add(menuItem2);
dataModel.put("menuItems", menuItems);

5、指定生成的文件

可以直接使用 FileWriter 对象,指定生成的文件路径和名称:

Writer out = new FileWriter("myweb.html");

6、生成文件

一切准备就绪,最后只需要调用 template 对象的 process 方法,就可以处理并生成文件了。
示例代码如下:

template.process(dataModel, out);

// 生成文件后别忘了关闭哦
out.close();

7、完整代码

组合上面的所有代码并执行,发现在项目的根路径下生成了网页文件,至此 Demo 结束,很简单吧~
image.png

FreeMarkerTest.java 文件的完整代码:

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

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * FreeMarker 学习测试
 */
public class FreeMarkerTest {

    @Test
    public void test() throws IOException, TemplateException {
        // new 出 Configuration 对象,参数为 FreeMarker 版本号
        Configuration configuration = new Configuration(Configuration.VERSION_2_3_32);

        // 指定模板文件所在的路径
        configuration.setDirectoryForTemplateLoading(new File("src/main/resources/templates"));

        // 设置模板文件使用的字符集
        configuration.setDefaultEncoding("utf-8");

        // 创建模板对象,加载指定模板
        Template template = configuration.getTemplate("myweb.html.ftl");

        // 创建数据模型
        Map<String, Object> dataModel = new HashMap<>();
        dataModel.put("currentYear", 2023);
        List<Map<String, Object>> menuItems = new ArrayList<>();
        Map<String, Object> menuItem1 = new HashMap<>();
        menuItem1.put("url", "https://codefather.cn");
        menuItem1.put("label", "编程导航");
        Map<String, Object> menuItem2 = new HashMap<>();
        menuItem2.put("url", "https://laoyujianli.com");
        menuItem2.put("label", "老鱼简历");
        menuItems.add(menuItem1);
        menuItems.add(menuItem2);
        dataModel.put("menuItems", menuItems);

        // 生成
        Writer out = new FileWriter("myweb.html");
        template.process(dataModel, out);

        // 生成文件后别忘了关闭哦
        out.close();
    }
}

问题解决示例

给大家分享一个通过查阅官方文档解决具体问题的例子,比如之前生成的网站文件中,我们发现数字中间加了一个逗号分割符,如下图:
image.png

这是因为 FreeMarker 使用 Java 平台的本地化敏感的数字格式信息,如果想把分割符取消掉,怎么办呢?
我们可以通过查阅官方文档看到以下信息:

地址:http://freemarker.foofun.cn/app_faq.html#faq_number_grouping

image.png

按照文档的提示,修改 configuration 配置类的 number_format 设置,即可调整默认生成的数字格式啦。

标签:文件,入门,FreeMarker,模板,new,freemarker,数据模型,FreeMaker
From: https://www.cnblogs.com/licwuu/p/18341113

相关文章

  • SpringSecurity入门
    SpringSecurity1、简介SpringSecurity是Spring家族中的一个安全管理框架。相比与另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富。一般来说中大型的项目都是使用SpringSecurity来做安全框架。小项目有Shiro的比较多,因为相比与SpringSecurity,Shiro......
  • 文件系统 FTP Ubuntu 安装入门介绍
    文件服务系列文件存储服务系统(FileStorageServiceSystem)-00-文件服务器是什么?为什么需要?文件存储服务系统(FileStorageServiceSystem)-01-常见的文件协议介绍文件系统FTPUbuntu安装入门介绍文件存储服务系统(FileStorageServiceSystem)-02-SFTP协议介绍分布式文件服......
  • C++入门基础
    1.C++的第一个程序当然C++有⼀套自己的输入输出,严格说C++版本的helloworld应该是这样写的。 2.命名空间2.1namespace(命名空间)的价值在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名......
  • MySQL 入门知识详解
    MySQL入门知识详解在学习MySQL的过程中,初学者需要掌握一些基本概念、常用操作和设计原则。本文将详细讲解这些知识点,并通过具体示例帮助你更好地理解。1.基本概念数据库数据库是一个用来存储和组织化数据的容器。在MySQL中,一个数据库包含多个表。每个数据库通常代表......
  • python 爬虫入门实战——爬取维基百科“百科全书”词条页面内链
    1.简述本次爬取维基百科“百科全书”词条页面内链,仅发送一次请求,获取一个html页面,同时不包含应对反爬虫的知识,仅包含最基础的网页爬取、数据清洗、存储为csv文件。爬取网址url为“https://zh.wikipedia.org/wiki/百科全书”,爬取内容为该页面所有内链及内链标识(下图蓝......
  • 区块链入门基础课:《Nethereum教程》零基础玩转以太坊开发(三)合约状态
    今天我们要讨论的是如何与智能合约进行交互,获取合约状态。下面的示例将会详细讲解如何与合约进行交互,及一些概念性的解释,有需要的朋友们可以收藏一下。一:概念解释在下面示例之前呢,我先解释下为什么需要调用合约状态,以及合约状态对开发而言有什么作用。实时的了解合约状......
  • ONNXRuntime: 深度学习模型入门学习简介
    目录ONNXRuntime的作用主要功能跨平台支持性能优化易于集成如何使用ONNXRuntimeONNXRuntime的优缺点优点缺点应用领域1.自然语言处理(NLP)2.计算机视觉(CV)3.语音识别和处理4.推荐系统5.医疗健康6.金融科技(FinTech)具体应用案例微软产品与服......
  • Day16_1--JSP了解学习之EL表达式语言入门教程
    JSP(JavaServerPages)是一个用于生成动态网页的技术。EL(ExpressionLanguage)是JSP中的一种表达式语言,用于简化JSP页面中的Java代码,使其更易于书写和阅读。下面是对JSPEL表达式语言的简要介绍。1.什么是EL?EL(表达式语言)是JSP2.0引入的一种语言,它提供了一种简单的方法来访......
  • 使用SpringBoot+Vue3来实现前后端登录注册功能(新手入门,带你一步一步实现)
    目录一.所用技术栈:二.前端创建工程: 1.使用elementplus展开前端页面格式布局:2.基于Vue3的使用来实现登录与注册:(1)定义数据模型:(2):model绑定表单:(3)表单数据校验:①定义表单校验规则:②给表单绑定校验规则:(4)前端注册功能开发: ①创建request.js请求工具:②创建user.js来调用......
  • 【大数据开发语言Scala的入门教程】
    ......