一、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,示例如下:

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

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

2.1.3 compress 压缩代码移除空白行

<#compress>1 2  3   4    5test onlyI said, test only
</#compress>1 2  3   4    5test onlyI 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 ["老王","老李","老张"]asp>${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. Spring Boot (四)模板引擎Thymeleaf集成

    一.Thymeleaf介绍 Thymeleaf是一种Java XML / XHTML / HTML5模板引擎,可以在Web和非Web环境中使用.它更适合在基于MVC的Web应用程序的视图层提供XHTM ...

  2. Spring Boot 模板引擎FreeMarker集成

    Spring Boot 模板引擎FreeMarker集成 一.FreeMaker介绍 FreeMarker是一款免费的Java模板引擎,是一种基于模板和数据生成文本(HMLT.电子邮件.配置文件.源代 ...

  3. Spring Boot 最佳实践

    转载自  Spring Boot 最佳实践 Spring Boot是用于开发微服务的最流行的Java框架.在本文中,我将与您分享自2016年以来我在专业开发中使用Spring Boot所采用的最佳实践 ...

  4. Spring Boot 最佳实践(四)模板引擎Thymeleaf集成

    ## 一.Thymeleaf介绍 Thymeleaf是一种Java XML / XHTML / HTML5模板引擎,可以在Web和非Web环境中使用.它更适合在基于MVC的Web应用程序的视图层提供X ...

  5. Spring Boot 最佳实践(二)集成Jsp与生产环境部署

    一.简介 提起Java不得不说的一个开发场景就是Web开发,也是Java最热门的开发场景之一,说到Web开发绕不开的一个技术就是JSP,因为目前市面上仍有很多的公司在使用JSP,所以本文就来介绍一下S ...

  6. Spring boot(五)模板引擎 Thymeleaf

    Thymeleaf 是一款用于渲染 XML/XHTML/HTML 5 内容的模板引擎.类似 JSP.Velocity.FreeMaker 等,它也可以轻易的与 Spring MVC 等 Web 框架进 ...

  7. Spring Boot怎么样引入Thymeleaf模板引擎

    一.前言: 市场上的模板引擎有很多如下: JSP.Velocity.Freemarker.Thymeleaf 而SpringBoot推荐的Thymeleaf,其语法更简单,功能更强大 二.引入thym ...

  8. Spring Boot 最佳实践(五)Spring Data JPA 操作 MySQL 8

    ## 一.Spring Data JPA 介绍 JPA(Java Persistence API)Java持久化API,是 Java 持久化的标准规范,Hibernate是持久化规范的技术实现,而Sp ...

  9. Spring Boot 最佳实践(一)快速入门

    一.关于Spring Boot 在开始了解Spring Boot之前,我们需要先了解一下Spring,因为Spring Boot的诞生和Spring是息息相关的,Spring Boot是Spring发 ...

最新文章

  1. 为指针分配的内存太小
  2. Shell until循环
  3. android 如何使用服务器进行版本更新
  4. python如何实时捕捉cmd显示_如何从Python脚本中捕获Python解释器和/或CMD.EXE的输出? -问答-阿里云开发者社区-阿里云...
  5. cpython教程_python高性能扩展工具-cython教程1快速入门
  6. tomcat启动报错APR问题
  7. FCC新主席发推特称赞亚马逊,但被质疑违反了联邦道德准则
  8. 95-130-348-源码-source-kafka相关-Handover
  9. ofo 回应甩卖办公桌;华为与袁隆平合作;罗永浩 1 亿股权遭冻结 | 极客头条
  10. UITableView单元格选择颜色?
  11. linux shutdown 命令
  12. 微型计算机原理及应用 阶段作业,微机原理及应用第三次作业
  13. asp.net 旅游网站 源码+配置文档
  14. 20 分钟教你量化自己的资产
  15. ftp服务器软件 性能对比,常用ftp服务器软件介绍
  16. wordpress后台打开速度非常慢怎么办
  17. Flink HA配置
  18. 【Day1】一小时入门 python 基础,从安装到入门
  19. STM32开发实例 基于STM32单片机的炼钢厂环境检测
  20. 单元电路设计之继电器学习

热门文章

  1. uint8 转换为 float
  2. go之树型结构深度理解补充
  3. c#统计字符串中数字字符的个数【C#】
  4. ubuntu进行apt-get时候出现Package ssh is not available, but is referred to by another package 错误...
  5. 【Spark】Spark-空RDD判断与处理
  6. lightbox自定义图片大小的实现
  7. 转换和编辑的sony的MTS硬盘摄像机格式文件。
  8. [转载] JVM中对象的回收过程
  9. python实现接口_Python | 使用类实现接口
  10. duration java_Java Duration类| plusDays()方法与示例