zoukankan      html  css  js  c++  java
  • Spring Boot (三)模板引擎FreeMarker集成

    一、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

  • 相关阅读:
    运放之典型应用
    关于set_clock_uncertainty的两点注意事项
    ARINC 429 接口简介
    关于set_input/output_delay中的clock_fall和add_delay选项
    卡诺图
    关于乒乓操作的一些小技巧
    程序Title样本参考
    【游戏】精忠报国岳飞传之基本说明一
    运放虚短虚断的简单推导
    我的小型网站搜索分词中遇到的问题
  • 原文地址:https://www.cnblogs.com/vipstone/p/9559052.html
Copyright © 2011-2022 走看看