FreeMarker 模板引擎入门:从基础到实践的全面指南
最编程
2024-10-17 10:23:41
...
前言
什么是FreeMarker
FreeMarker是一个基于模板生成文本输出的通用工具,它使用纯Java编写,能够生成HTML、XML、JSON、RTF、Java源代码等多种格式的文本。FreeMarker模板引擎允许将数据模型与模板文件结合,生成动态的文本输出,广泛应用于Web开发、邮件生成、报告生成等场景。以下是对FreeMarker使用的详细解析。
FreeMarker的基本概念
-
模板文件(*.ftl):FreeMarker的模板文件通常以
.ftl
为后缀,其中包含了用于生成文本的标记和指令。 - 数据模型:数据模型是一个包含要插入模板中数据的对象,通常是一个Map或JavaBean。
- 输出:通过模板和数据模型的结合,FreeMarker生成最终的文本输出。
FreeMarker模板的基本组成部分
- 文本:模板中直接输出的内容部分。
-
注释:不会输出的内容,格式为
<#-- 注释内容 -->
。 -
取值(插值):代替输出数据模型的部分,格式为
${数据模型}
或#{数据模型}
。 - ftl指令:FreeMarker指令,类似于HTML标记,包括内建指令和自定义指令。
FreeMarker的基础语法
-
字符输出
-
${emp.name?if_exists}
:变量存在时输出,否则不输出。 -
${emp.name!}
:变量存在时输出,否则输出空字符串。 -
${emp.name?default("xxx")}
:变量不存在时取默认值xxx。 - 常用内部函数,如
${"123<br>456"?html}
对字符串进行HTML编码,${"str"?cap_first}
使字符串第一个字母大写等。
-
-
日期输出
-
${emp.date?string('yyyy-MM-dd')}
:格式化日期输出。
-
-
数字输出
-
${emp.name?string.number}
:以数字形式输出。 -
${emp.name?string.currency}
:以货币形式输出。 -
${emp.name?string.percent}
:以百分比形式输出。 - 数字格式化插值可采用
#{expr;format}
形式,其中格式可以是mX(小数部分最小X位)、MX(小数部分最大X位)等。
-
-
声明变量
-
<#assign foo=false/>
:声明变量,并插入布尔值进行显示。 -
${foo?string("yes","no")}
:当变量为真时输出“yes”,否则输出“no”。
-
-
表达式中的运算符
- 比较运算符:=或==(判断两个值是否相等)、!=(判断两个值是否不等)、>或gt(大于)、<或lt(小于)、>=或lte(大于等于)、<=或gte(小于等于)。
- 算术运算符:+、-、*、/、%。
- 逻辑运算符:&&(逻辑与)、||(逻辑或)、!(逻辑非)。
FreeMarker的控制语句
if逻辑判断
<#if condition>
...
<#elseif condition2>
...
<#elseif condition3>
...
<#else>
...
</#if>
switch语句
<#switch value>
<#case refValue1>
...
<#break>
<#case refValue2>
...
<#break>
<#case refValueN>
...
<#break>
<#default>
...
</#switch>
集合与循环
<#list empList as emp>
${emp.name!}
</#list>
或者通过索引遍历集合:
<#list 0..(empList!?size-1) as i>
${empList[i].name!}
</#list>
FreeMarker的高级功能
-
宏定义
宏是一种可以在模板中定义并重复使用的代码块。通过宏定义,可以简化模板的编写,提高代码的可读性和可维护性。
-
自定义指令
自定义指令是FreeMarker提供的一种扩展机制,允许用户根据自己的需求定义新的指令。自定义指令可以包含复杂的逻辑和操作,以满足特定的模板需求。
-
国际化与本地化
FreeMarker支持国际化与本地化功能,允许根据用户的语言和地区设置生成不同语言的文本输出。这通常通过加载不同的语言资源文件来实现。
FreeMarker的使用步骤
- 导入FreeMarker库:将FreeMarker的jar包添加到项目中。
-
创建FreeMarker配置对象:使用
Configuration
类来创建FreeMarker的配置对象,并设置模板文件的路径、编码格式等。 -
获取模板文件:使用
Configuration
对象的getTemplate
方法来获取模板文件的对象。 - 创建数据模型:创建一个数据模型对象,用于存储模板中所需的数据。
-
渲染模板:使用模板对象的
process
方法将数据模型与模板文件进行渲染,并将结果输出到指定的位置。
注意事项
- 模板文件的路径和文件名:确保模板文件的路径和文件名正确无误。
- 数据模型中的变量:确保在数据模型中定义了所有在模板中使用的变量。
- 表达式的语法和用法:检查表达式的语法和用法是否正确。
- 控制语句的语法和用法:检查控制语句的语法和用法是否正确。
FreeMarker基本使用案例
FreeMarker在我看来是用来代替JSP进行取值的一种方式,因为FreeMarker不需要再页面中书写额外配置和java代码就可以取到后台存储在各个作用域中的数据,代码十分类似HTML,接下来,我将演示如何使用FreeMarker进行取值等基本操作。
注意:接下来演示的项目是在整合了SSM框架的基础上进行的。
第一步:导入相关依赖
pom.xml
<!--freemarker-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
第二步:添加FreeMarker配置到SpringMVC配置文件中
spring-mvc.xml
<!-- 针对FREEMAKER的视图配置 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="true" />
<property name="prefix" value="/ftl/" />
<property name="suffix" value=".ftl" />
<property name="contentType" value="text/html;charset=UTF-8"></property>
<property name="allowSessionOverride" value="true"/>
<property name="requestContextAttribute" value="request" />
<property name="exposeSpringMacroHelpers" value="true" />
<property name="exposeRequestAttributes" value="true" />
<property name="exposeSessionAttributes" value="true" />
</bean>
<bean id="freemarkerConfig"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/" />
<property name="freemarkerSettings">
<props>
<prop key="template_update_delay">0</prop>
<prop key="default_encoding">UTF-8</prop>
<prop key="number_format">0.##########</prop>
<prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
<prop key="classic_compatible">true</prop>
<prop key="template_exception_handler">ignore</prop>
</props>
</property>
</bean>
使用FreeMarker视图解析器代替jsp视图解析器
第三步:创建Controller层控制器
FreeController
存储User对象的前提是我已经创建了User实体类
@Controller
public class FreeController {
@RequestMapping("/free")
public String freeTest(Model model){
User user =new User();
user.setUser_name("数码暴龙战士");
user.setBirthday(new Date());
model.addAttribute("user",user);
List<User> list =new ArrayList<>();
User u1 =new User();
u1.setUser_name("独孤求败");
User u2 =new User();
u2.setUser_name("步惊云");
User u3 =new User();
u3.setUser_name("聂风");
list.add(u1);
list.add(u2);
list.add(u3);
model.addAttribute("list",list);
return "free";
}
}
第四步:书写FreeMarker页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<#assign username="张三">
${username}
<hr/>
${user.user_name}
<hr/>
${user.password!"密码不存在"}
<hr/>
${user.birthday?string('yyyy-MM-dd HH:mm:ss zzzz')}
<hr/>
${user.birthday?date}
<hr/>
<#--判断对象属性值是否为空-->
<#if user.password?exists>
有密码
<#else >
无数据
</#if>
<hr/>
<#--判断对象属性值是否为空-->
<#if user.password??>
有密码
<#else >
无数据
</#if>
<hr/>
<#include "/up.html"/>
<hr/>
<#assign arrList=['a','b','c','d']/>
<#if arrList?size=0>
arrList数组为空
<#else >
数组不为空
</#if>
<hr/>
<br/>
<#list list as user>
${user_index},${user.user_name}<br/>
</#list>
</body>
</html>
代码分析
<#assign username="张三"> 页面设置变量username,并赋值张三 ${username} 页面取变量username的值${user.user_name} 获取controller中存储在request域中的user对象的user_name属性值
${user.password!"密码不存在"} 因为password未存值,使用!判断,值是否为空,为空输出!后面的字符串
${user.birthday?string('yyyy-MM-dd HH:mm:ss zzzz')} 使用?string(日期格式),进行Date类型的格式化显示,zzzz表示中国标准时间
${user.birthday?date} 使用默认的格式解析日期(这里是年月日,不包括时分秒)
<#--判断对象属性值是否为空--> <#if user.password?exists> 有密码 <#else > 无数据 </#if> 注意<#else>的位置,写在<#if>标签中间
<#--判断对象属性值是否为空--> <#if user.password??> 有密码 <#else > 无数据 </#if> 两种判断方式,?exists等价于??
<#include "/up.html"/> 引入另一个html页面的内容,包括html,css和js
<#assign arrList=['a','b','c','d']/> <#if arrList?size=0> arrList数组为空 <#else > 数组不为空 </#if> 定义数组/集合,根据集合或数组的长度进行判断
<#list list as user> ${user_index},${user.user_name}<br/> </#list> 获取后台存入request域中的list集合,并变量输出;_index为固定写法,表示取索引下标,从0开始。
演示效果
下一篇: 基于春笋+微信小程序的农产品销售平台
推荐阅读
-
FreeMarker 模板引擎入门:从基础到实践的全面指南
-
【2022新手指南】Java编程进阶之路 - 六、技术架构篇 ### MySQL索引底层解析与优化实战 - 你会讲解MySQL索引的数据结构吗?性能调优技巧知多少? - Redis深度揭秘:你知道多少?从基础到哨兵、主从复制全梳理 - Redis持久化及哨兵模式详解,还有集群搭建和Leader选举黑箱打开 - Zookeeper是个啥?特性和应用场景大公开 - ZooKeeper集群搭建攻略及 Leader选举、读写一致性、共享锁实现细节 - 探究ZooKeeper中的Leader选举机制及其在分布式环境中的作用 - Zab协议深入剖析:原理、功能与在Zookeeper中的核心地位 - RabbitMQ全方位解读:工作模式、消费限流、可靠投递与配置策略 - 设计者视角:RabbitMQ过期时间、死信队列与延时队列实践指南 - RocketMQ特性和应用场景揭示:理解其精髓与差异化优势 - Kafka详细介绍:特性及广泛应用于实时数据处理的场景解析 - ElasticSearch实力揭秘:特性概述与作为搜索引擎的广泛应用 - MongoDB认知升级:非关系型数据库的优势阐述,安装与使用实战教学 - BIO/NIO/AIO网络模型对比:掌握它们的区别与在网络编程中的实际应用 - Netty带你飞:理解其超快速度背后的秘密,包括线程模型分析 - 网络通信黑科技:Netty编解码原理与常用编解码器的应用,Protostuff实战演示 - 解密Netty粘包与拆包现象,怎样有效应对这一常见问题 - 自定义Netty心跳检测机制,轻松调整检测间隔时间的艺术 - Dubbo轻骑兵介绍:核心特性概览,服务降级实战与其实现益处 - Dubbo三大神器解读:本地存根与本地伪装的实战运用与优势呈现 ----------------------- 七、结语与回顾
-
C#新手指南 - 学习C#基础 - 一步步掌握C#:从入门到实践 - 理解并运用C#处理程序异常的技巧