[SpringBoot] Spring Boot(3)模板引擎FreeMarker集成

1 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返回给用户,如下图:

 

2 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 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} 

  输出:

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

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

3 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;
  }
} 

  关键代码解读:

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

3.2.5 运行

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

 4  参考资料

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

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

备注:

  原文链接:https://blog.csdn.net/sufu1065/article/details/82218392

posted @ 2020-05-11 15:34  wxxujian  阅读(857)  评论(0)    收藏  举报