一、FreeMaker介绍

FreeMarker是一款免费的Java模板引擎,是一种基于模板和数据生成文本(HMLT、电子邮件、配置文件、源代码等)的工具,它不是面向最终用户的,而是一款程序员使用的组件。

FreeMarker最初设计是用来在MVC模式的Web开发中生成HTML页面的,所以没有绑定Servlet或任意Web相关的东西上,所以它可以运行在非Web应用环境中。

发展史

FreeMarker第一版在1999年未就发布了,2002年初使用JavaCC(Java Compiler Compiler是一个用Java开发的语法分析生成器)重写了FreeMarker的核心代码,2015年FreeMarker代码迁移到了Apache下。

GitHub地址:https://github.com/apache/freemarker

工作原理

FreeMarker模板存储在服务器上,当有用户访问的时候,FreeMarker会查询出相应的数据,替换模板中的标签,生成最终的HTML返回给用户,如下图:

二、FreeMarker基础使用

基础使用分为3部分,这3部分组成了FreeMarker:

  • 指令
  • 表达式

指令是FreeMarker用来识别转换的特殊标签,表达式是标签里具体的语法实现,其他部分是一些不好分类的模板。

2.1 指令

使用FTL(freemarker template language)标签来调用指令。

指令速览:

  • assign
  • attempt, recover
  • compress
  • escape, noescape
  • flush
  • ftl
  • function, return
  • global
  • if, else, elseif
  • import
  • include
  • list, else, items, sep, break
  • local
  • macro, nested, return
  • noparse
  • nt
  • setting
  • stop
  • switch, case, default, break
  • t, lt, rt
  • visit, recurse, fallback
  • 用户自定义标签

下来我们分别来看每个指令对应具体使用。

2.1.1 assign 代码声明

assign 分为变量和代码片段声明两种。

2.1.1.1 变量声明

可以是单变量声明,或多变量声明,下面是多变量声明的示例:

<#assign name="adam" age=18 "sex"="man">
${name} - ${age} - ${"sex"}

单个变量的话,只写一个就可以了。

2.1.1.2 代码片段声明
<#assign code>
<#list ["java","golang"] as c>
${c}
</#list>
</#assign>
${code}

其中 ${code} 是用来执行方法的,如果不调用话,代码片段不会执行。

2.1.2 attempt, recover 异常指令

attempt(尝试), recover(恢复)指令类似于程序的try catch,示例如下:

<#attempt>
i am ${name}
<#recover>
error name
</#attempt>

如果有变量“name”就会正常显示,显示“i am xxx”,如果没有变量就会显示“error name”。

2.1.3 compress 压缩代码移除空白行

<#compress>
1 2 3 4 5 test only I said, test only
</#compress> 1 2 3 4 5 test only I said, test only

效果如下:

对空白不敏感的格式,移除空白行还是挺有用的功能。

2.1.4 escape, noescape 转义,不转义

2.1.4.1 escape使用
<#escape x as x?html>
${firstName}
${lastName}
</#escape>

上面的代码,类似于:

${firstName?html}
${lastName?html}

Java代码:

@RequestMapping("/")
public ModelAndView index() {
ModelAndView modelAndView = new ModelAndView("/index");
modelAndView.addObject("firstName", "<span style='color:red'>firstName</span>");
modelAndView.addObject("lastName", "lastName");
return modelAndView;
}

最终的效果是:

2.1.4.2 “?html”语法解析

单问号后面跟的是操作函数,类似于Java中的方法名,html属于内建函数的一个,表示字符串会按照HTML标记输出,字符替换规则如下:

  • < 替换为 &lt;
  • > 替换为 &gt;
  • & 替换为 &amp;
  • " 替换为 &quot;
2.1.4.3 noescape使用

HTML代码:

<#escape x as x?html>
<#noescape>
${firstName}
</#noescape>
${lastName}
</#escape>

Java代码:

@RequestMapping("/")
public ModelAndView index() {
ModelAndView modelAndView = new ModelAndView("/index");
modelAndView.addObject("firstName", "<span style='color:red'>firstName</span>");
modelAndView.addObject("lastName", "lastName");
return modelAndView;
}

最终效果:

2.1.5 function, return 方法声明

代码格式:

<#function name param1 param2 ... paramN>
...
<#return returnValue>
...
</#function>
  • name 为方法名称
  • param1, param2,paramN 方法传递过来的参数,可以有无限个参数,或者没有任何参数
  • return 方法返回的值,可以出现在function的任何位置和出现任意次数

示例代码如下:

<#function sum x y z>
<#return x+y+z>
</#function> ${sum(5,5,5)}

注意:function如果没有return是没有意义的,相当于返回null,而function之中信息是不会打印到页面的,示例如下:

<#function wantToPrint>
这里的信息是显示不了的
</#function> <#if wantToPrint()??>
Message:${wantToPrint()}
</#if>

“??”用于判断值是否是null,如果为null是不执行的。如果不判null直接使用${}打印,会报模板错误,效果如下:

2.1.6 global 全局代码声明

语法如下:

<#global name=value>

<#global name1=value1 name2=value2 ... nameN=valueN>

<#global name>
capture this
</#global>

global使用和assign用法类似,只不过global声明是全局的,所有的命名空间都是可见的。

2.1.7 if elseif else 条件判断

语法如下:

<#if condition>
...
<#elseif condition2>
...
<#elseif condition3>
...
...
<#else>
...
</#if>

示例如下:

<#assign x=1 >
<#if x==1>
x is 1
<#elseif x==2>
x is 2
<#else>
x is not 1
</#if>

2.1.8 import 引入模板

语法: <#import path as hash>

示例如下

footer.ftl 代码如下:

<html>
<head>
<title>王磊的博客</title>
</head>
<body>
this is footer.ftl
<#assign copy="来自 王磊的博客">
</body>
</html>

index.ftl 代码如下:

<html>
<head>
<title>王磊的博客</title>
</head>
<body>
<#import "footer.ftl" as footer>
${footer.copy}
</body>
</html>

最终输出内容:

来自 王磊的博客

2.1.9 include 嵌入模板

语法: <#include path>

示例如下

footer.ftl 代码如下:

<html>
<head>
<title>王磊的博客</title>
</head>
<body>
this is footer.ftl
<#assign copy="来自 王磊的博客">
</body>
</html>

index.ftl 代码如下:

<html>
<head>
<title>王磊的博客</title>
</head>
<body>
<#include "footer.ftl">
</body>
</html>

最终内容如下:

this is footer.ftl

2.1.10 list, else, items, sep, break 循环

2.1.10.1 正常循环

输出1-3的数字,如果等于2跳出循环,代码如下:

<#list 1..3 as n>
${n}
<#if n==2>
<#break>
</#if>
</#list>

注意:“1..3”等于[1,2,3]。

结果: 1 2

2.1.10.2 使用items输出

示例如下:

<#list 1..3>
<ul>
<#items as n>
<li>${n}</li>
</#items>
</ul>
</#list>
2.1.10.3 sep 使用

跳过最后一项

<#list 1..3 as n>
${n}
<#sep>,</#sep>
</#list>

最终结果:1 , 2 , 3

2.1.10.4 数组最后一项

代码如下:

<#list 1..3 as n>
${n}
<#if !n_has_next>
最后一项
</#if>
</#list>

使用“变量_has_next”判断是否还有下一个选项,来找到最后一项,最终的结果:1 2 3 最后一项

2.1.11 macro 宏

宏:是一个变量名的代码片段,例如:

<#macro sayhi name>
Hello, ${name}
</#macro> <@sayhi "Adam" />

相当于声明了一个名称为“sayhi”有一个参数“name”的宏,使用自定义标签“@”调用宏。

输出的结果: Hello, Adam

2.1.12 switch, case, defalut, break 多条件判断

示例代码如下:

<#assign animal="dog" >
<#switch animal>
<#case "pig">
This is pig
<#break>
<#case "dog">
This is dog
<#break>
<#default>
This is Aaimal
</#switch>

2.1.13 扩展知识

指令自动忽略空格特性

FreeMarker会忽略FTL标签中的空白标记,所以可以直接写:

<#list ["老王","老李","老张"]
as
p>
${p}
</#list>

即使是这个格式也是没有任何问题的,FreeMarker会正常解析。

2.2 表达式

2.2.1 字符串拼接

字符拼接代码:

<#assign name="ABCDEFG">
${"Hello, ${name}"}

结果:Hello, ABCDEFG

2.2.2 算术运算

2.2.2.1 算术符

算术符有五种:

  • +
  • -
  • *
  • /
  • % 求余(求模)

示例代码:

${100 - 10 * 20}

输出:

-100
2.2.2.2 数值转换
${1.999?int}

输出:

1

注意:数值转换不会进行四舍五入,会舍弃小数点之后的。

2.2.3 内建函数(重点)

内建函数:相当于我们Java类里面的内置方法,非常常用,常用的内建函数有:时间内建函数、字符内建函数、数字内建函数等。

2.2.3.1 单个问号和两个问号的使用和区别

单问号:在FreeMarker中用单个问号,来调用内建函数,比如: ${"admin"?length} 查看字符串“admin”的字符长度,其中length就是字符串的内建函数。

双引号:表示用于判断值是否为null,比如:

<#if admin??>
Admin is not null
</#if>
2.2.3.2 字符串内建函数
2.2.3.2.1 是否包含判断

使用contains判断,代码示例:

<#if "admin"?contains("min")>
min
<#else >
not min
</#if>

输出:

min
2.2.3.2.2 大小写转换

示例代码:

<#assign name="Adam">
${name?uncap_first}
${name?upper_case}
${name?cap_first}
${name?lower_case}

输出:

adam ADAM Adam adam

更多的字符串内建函数:https://freemarker.apache.org/docs/ref_builtins_string.html

2.2.3.3 数字内建函数

示例代码:

${1.23569?string.percent}
${1.23569?string["0.##"]}
${1.23569?string["0.###"]}

输出:

124% 1.24 1.236

注意:

  • 使用string.percent计算百分比,会自动四舍五入。
  • 使用“?string["0.##"]”可以自定义取小数点后几位,会自动四舍五入。
2.2.3.4 时间内建函数
2.2.3.4.1 时间戳转换为任何时间格式

代码:

<#assign timestamp=1534414202000>
${timestamp?number_to_datetime?string["yyyy/MM/dd HH:mm"]}

输出:

2018/08/16 18:10
2.2.3.4.2 时间格式化

示例代码:

<#assign nowTime = .now>
${nowTime} <br />
${nowTime?string["yyyy/MM/dd HH:mm"]} <br />

输出:

2018-8-16 18:33:50
2018/08/16 18:33

更多内建方法:https://freemarker.apache.org/docs/ref_builtins.html

三、Spring Boot 集成

3.1 集成环境

  • Spring Boot 2.0.4
  • FreeMaker 2.3.28
  • JDK 8
  • Windows 10
  • IDEA 2018.2.1

3.2 集成步骤

3.2.1 pom.xml 添加FreeMaker依赖

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

3.2.2 application.properties 配置模板

主要配置,如下:

## Freemarker 配置
spring.freemarker.template-loader-path=classpath:/templates/
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.check-template-location=true
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes=false
spring.freemarker.request-context-attribute=request
spring.freemarker.suffix=.ftl
配置项 类型 默认值 建议值 说明
spring.freemarker.template-loader-path String classpath:/templates/ 默认 模版存放路径
spring.freemarker.cache bool true 默认 是否开启缓存,生成环境建议开启
spring.freemarker.charset String - UTF-8 编码
spring.freemarker.content-type String text/html text/html content-type类型
spring.freemarker.suffix String .ftl .ftl 模板后缀
spring.freemarker.expose-request-attributes bool false false 设定所有request的属性在merge到模板的时候,是否要都添加到model中
spring.freemarker.expose-session-attributes bool false false 设定所有HttpSession的属性在merge到模板的时候,是否要都添加到model中.
spring.freemarker.request-context-attribute String - request RequestContext属性的名称

更多配置:

# FREEMARKER (FreeMarkerProperties)
spring.freemarker.allow-request-override=false # Whether HttpServletRequest attributes are allowed to override (hide) controller generated model attributes of the same name.
spring.freemarker.allow-session-override=false # Whether HttpSession attributes are allowed to override (hide) controller generated model attributes of the same name.
spring.freemarker.cache=false # Whether to enable template caching.
spring.freemarker.charset=UTF-8 # Template encoding.
spring.freemarker.check-template-location=true # Whether to check that the templates location exists.
spring.freemarker.content-type=text/html # Content-Type value.
spring.freemarker.enabled=true # Whether to enable MVC view resolution for this technology.
spring.freemarker.expose-request-attributes=false # Whether all request attributes should be added to the model prior to merging with the template.
spring.freemarker.expose-session-attributes=false # Whether all HttpSession attributes should be added to the model prior to merging with the template.
spring.freemarker.expose-spring-macro-helpers=true # Whether to expose a RequestContext for use by Spring's macro library, under the name "springMacroRequestContext".
spring.freemarker.prefer-file-system-access=true # Whether to prefer file system access for template loading. File system access enables hot detection of template changes.
spring.freemarker.prefix= # Prefix that gets prepended to view names when building a URL.
spring.freemarker.request-context-attribute= # Name of the RequestContext attribute for all views.
spring.freemarker.settings.*= # Well-known FreeMarker keys which are passed to FreeMarker's Configuration.
spring.freemarker.suffix=.ftl # Suffix that gets appended to view names when building a URL.
spring.freemarker.template-loader-path=classpath:/templates/ # Comma-separated list of template paths.
spring.freemarker.view-names= # White list of view names that can be resolved.

3.2.3 编写HTML代码

<html>
<head>
<title>王磊的博客</title>
</head>
<body>
<div>
Hello,${name}
</div>
</body>
</html>

3.2.4 编写Java代码

新建index.java文件,Application.java(入口文件)代码不便,index.java代码如下:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView; @Controller
@RequestMapping("/")
public class Index {
@RequestMapping("/")
public ModelAndView index() {
ModelAndView modelAndView = new ModelAndView("/index");
modelAndView.addObject("name", "老王");
return modelAndView;
}
}

关键代码解读:

  1. @Controller注解:标识自己为控制器,只需要配置@RequestMapping之后,就可以把用户URL映射到控制器;
  2. 使用ModelAndView对象,指定视图名&添加视图对象。

3.2.5 运行

执行上面4个步骤之后,就可以运行这个Java项目了,如果是IDEA使用默认快捷键“Shift + F10”启动调试,在页面访问:http://localhost:8080/ 就可看到如下效果:

四、参考资料

FreeMarker官方文档:https://freemarker.apache.org/

FreeMarker翻译的中文网站:http://freemarker.foofun.cn/toc.html

Spring Boot (三)模板引擎FreeMarker集成的更多相关文章

  1. SpringBoot系列:Spring Boot使用模板引擎FreeMarker

    一.Java模板引擎 模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档. 在jav ...

  2. Spring Boot整合模板引擎freemarker

    jsp本质是servlet,渲染都在服务器,freemarker模板引擎也是在服务器端渲染. 项目结构 引入依赖pom.xml <!-- 引入 freemarker 模板依赖 --> &l ...

  3. spring boot: freemarket模板引擎

    spring boot: freemarket模板引擎 freemarket模板引擎,可以和thymeleaf模板引擎共存 pom.xml引入 <!-- Freemarket --> &l ...

  4. spring boot: thymeleaf模板引擎使用

    spring boot: thymeleaf模板引擎使用 在pom.xml加入thymeleaf模板依赖 <!-- 添加thymeleaf的依赖 --> <dependency> ...

  5. SpringBoot系列:Spring Boot使用模板引擎Thymeleaf

    一.Java模板引擎 模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档. 在jav ...

  6. SpringBoot系列:Spring Boot使用模板引擎JSP

    一.Java模板引擎 模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档. 在jav ...

  7. Spring boot 梳理 - 模版引擎 -freemarker

    开发环境中关闭缓存 spring: thymeleaf: cache: false freemarker: cache: false Spring boot 集成 freemarker <dep ...

  8. Spring Boot Thymeleaf 模板引擎的使用

    Spring Boot 中可以支持很多模板引擎,Thymeleaf 是 Spring Boot 官方推荐使用的模板引擎,虽然在社区 Thymeleaf 的性能被许多人所吐糟,但这仍然不影响大量的开发人 ...

  9. Spring Boot整合模板引擎thymeleaf

    项目结构 引入依赖pom.xml <!-- 引入 thymeleaf 模板依赖 --> <dependency> <groupId>org.springframew ...

随机推荐

  1. JavaWeb三大组件之Filter

    对请求或者响应进行拦截,并做额外的逻辑处理 filter能在一个请求访问目标资源之前对其进行拦截然后做某些逻辑处理,例如权限检查,也可以在一个输出响应到达客户端之前对其进行拦截并做一些额外的操作(例如 ...

  2. 20155205 郝博雅 Exp6 信息搜集与漏洞扫描

    20155205 郝博雅 Exp6 信息搜集与漏洞扫描 一.实践内容 (1)各种搜索技巧的应用 (2)DNS IP注册信息的查询 (3)基本的扫描技术:主机发现.端口扫描.OS及服务版本探测.具体服务 ...

  3. 解决 Files 的值"<<<<<<< HEAD"无效。路径中具有非法字符

    通常我们使用版本控制后会出现诸如此类的问题,此时从vs工具找错误和调试是无法找到问题的,也不影响项目的运行,但是有错误就是得解决.原因是版本控制导致文件的路径出现问题. 解决 Files 的值&quo ...

  4. C pointer again …

    记录一个比较基础的东东…… C 语言的指针,一直让人又爱又恨,爱它的人觉得它既灵活又强大,恨它的人觉得它太过于灵活太过于强大以至于容易将人绕晕.最早接触 C 语言,还是在刚进入大学的时候,算起来有好些 ...

  5. lucene之Field属性的解释

    Field类 数据类型 Tokenized是否分词 Indexed 是否索引 Stored 是否存储 说明 StringField(FieldName, FieldValue,Store.YES)) ...

  6. _ZNote_Qt_添加图标方法

    简单来说就两步: 将icns图标添加入资源文件,例如picture.icns .pro文件中添加 (图标) ICON = picture.icns 程序中添加(程序窗口上显示) setWindowIc ...

  7. Leetcode(一)两数之和

    1.两数之和 题目要求: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重 ...

  8. 基本数据类型的包装类(Interger)

    基本数据类型 vs包装类 byte Byte short Short char Character int Integer long Long float Float double Double bo ...

  9. HTML 列表中的dl,dt,dd,ul,li,ol区别及应用

      无序列表 无序列表是一个项目的列表,此列项目使用粗体圆点(典型的小黑圆圈)进行标记. 无序列表始于 <ul> 标签.每个列表项始于 <li>. 有序列表 同样,有序列表也是 ...

  10. shell指令(一)

    ubuntu桌面窗口下进入shell窗口:Ctrl + Alt + F2~F6:  退出shell窗口:Ctrl + Alt + F7:从UI中进入UI命令窗口,Ctrl + Alt +T shell ...