Freemarker快速入门

发布于 2019-09-10 09:05:24

1. 创建测试工程

1.1创建springboot工程test-freemarker用于freemarker的功能测试与模板的测试。

pom.xml如下:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>

1.2 配置文件

配置application.yml,内容如下:

server:
  port: 8088 #服务端口

spring:
  application:
    name: test-freemarker #指定服务名
  freemarker:
    cache: false  #关闭模板缓存,方便测试
    settings:
      template_update_delay: 0 #检查模板更新延迟时间,设置为0表示立即检查,如果时间大于0会有缓存不方便进行模板测试

1.3 创建模型类

在test-freemarker的测试工程下创建模型类型用于测试

@Data
@ToString
public class Student {
    private String name;//姓名
    private int age;//年龄
    private Date birthday;//生日
    private Float mondy;//钱包
    private List<Student> friends;//朋友列表
    private Student bestFriend;//最好的朋友
}

image.png

@Data 就代表写了get/set方法,这里需要安装一个插件lombok

1.4 创建模板

在 src/main/resources下创建templates,此目录为freemarker的默认模板存放目录。 在templates下创建模板文件test1.ftl,模板中的${name}最终会被freemarker替换成具体的数据。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
Hello ${name}!
</body>
</html>

1.5 创建controller

@Controller
@RequestMapping("freemarker")
public class FreemarkerController {

    @Autowired
    RestTemplate restTemplate;

    @RequestMapping("/test1")
    public String freemarker(Map<String,Object> map){
        map.put("name","申来来");
        return "test1";
    }
}

1.6 创建启动类,请求:http://localhost:8088/freemarker/test1

屏幕显示:Hello 申来来!

2. FreeMarker基础

2.1 List指令

2.1.1 controller

@Controller
@RequestMapping("freemarker")
public class FreemarkerController {

    @Autowired
    RestTemplate restTemplate;


    @RequestMapping("/test1")
    public String freemarker(Map<String,Object> map){
        map.put("name","申来来");


        Student stu1  =  new Student();
        stu1.setName("小明");
        stu1.setAge(18);
        stu1.setMondy(1000.86f);
        stu1.setBirthday(new Date());
        Student stu2  = new  Student();
        stu2.setName("小红");
        stu2.setMondy(200.1f);
        stu2.setAge(19); //        
        stu2.setBirthday(new Date());
        List<Student> friends = new ArrayList<>();    // 好朋友集合
        friends.add(stu1);
        stu2.setFriends(friends);
        stu2.setBestFriend(stu1);
        List<Student> stus = new ArrayList<>();     // 学生集合
        stus.add(stu1);
        stus.add(stu2);
        //向数据模型放数据
        map.put("stus",stus);   // 学生集合
        //准备map数据        
        HashMap<String,Student> stuMap  =  new  HashMap<>();
        stuMap.put("stu1",stu1);   // 学生对象
        stuMap.put("stu2",stu2);   // 学生对象
        //向数据模型放数据
        map.put("stu1",stu1);
        //向数据模型放数据
        map.put("stuMap",stuMap);
        map.put("point",102920122);
        //返回模板文件名称
        return "test1";
    }
}

在test1.ftl模板中使用list指令遍历数据模型中的数据:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
Hello ${name}!

<table>
    <tr>
        <td>序号</td>
        <td>姓名</td>
        <td>年龄</td>
        <td>钱包</td>
    </tr>
    <#list stus as stu>
      <tr>
        <td>${stu_index + 1}</td>     <#--说明: _index:得到循环的下标,使用方法是在stu后边加"_index",它的值是从0开始-->
        <td>${stu.name}</td>
        <td>${stu.age}</td>
        <td>${stu.mondy}</td>
      </tr>
    </#list>
</table>

</body>
</html>

2.1.2

输出: Hello 申来来! 序号 姓名 年龄 钱包 1 小明 18 1,000.86 2 小红 19 200.1

2.2 遍历Map数据

    <#--遍历Map   使用map指令遍历数据模型中的stuMap-->
    输出stu1的学生信息:>br>
    姓名:${stuMap['stu1'].name} <br/>
    年龄:${stuMap['stu1'].age} <br/>

    遍历输出两个学生信息:<br/>
    <table>
        <tr>
            <td>序号</td>
            <td>姓名</td>
            <td>年龄</td>
            <td>钱包</td>
        </tr>
        <#list stuMap?keys as k>
            <tr>
                <td>${k_index +1}</td>
                <td>${stuMap[k].name}</td>
                <td>${stuMap[k].age}</td>
                <td>${stuMap[k].mondy}</td>
            </tr>
        </#list>
    </table>

输出stu1的学生信息: 姓名:小明 年龄:18
遍历输出两个学生信息:
序号 姓名 年龄 钱包
1 小红 19 200.1
2 小明 18 1,000.86

2.3 if指令

if 指令即判断指令,是常用的FTL指令,freemarker在解析时遇到if会进行判断,条件为真则输出if中间的内容,否 则跳过内容不再输出。

2.3.1、数据模型: 使用list指令中测试数据模型。

2.3.2、模板:

    <#--if 指令即判断指令,是常用的FTL指令,freemarker在解析时遇到if会进行判断,条件为真则输出if中间的内容,否 则跳过内容不再输出-->
        <table>
            <tr>
                <td>姓名</td>
                <td>年龄</td>
                <td>钱包</td>
            </tr>
            <#list stus as stu>
                <tr>
                    <td <#if stu.name == '小明'>style="background: red;" </#if>>${stu.name}</td>
                    <td>${stu.age}</td>
                    <td>${stu.mondy}</td>
                </tr>
            </#list>
        </table>

通过阅读上边的代码,实现的功能是:如果姓名为“小明”则背景色显示为红色。

2.3.3 3、输出: 通过测试发现 姓名为小明的背景色为红色。

2.4 其它指令

2.4.1 运算符

1、算数运算符 FreeMarker表达式中完全支持算术运算,FreeMarker支持的算术运算符包括:+, - , * , / , % 2、逻辑 运算符 逻辑运算符有如下几个: 逻辑与:&& 逻辑或:|| 逻辑非:! 逻辑运算符只能作用于布尔值,否则将产生错误 3、 比较运算符 表达式中支持的比较运算符有如下几个: 1 =或者==:判断两个值是否相等. 2 !=:判断两个值是否不等. 3 > 或者gt:判断左边值是否大于右边值 4 >=或者gte:判断左边值是否大于等于右边值 5 <或者lt:判断左边值是否小于右 边值 6 <=或者lte:判断左边值是否小于等于右边值

注意: =和!=可以用于字符串,数值和日期来比较是否相等,但=和!=两边必须是相同类型的值,否则会产生错误,而且 FreeMarker是精确比较,"x","x ","X"是不等的.其它的运行符可以作用于数字和日期,但不能作用于字符串,大部分的时 候,使用gt等字母运算符代替>会有更好的效果,因为 FreeMarker会把>解释成FTL标签的结束字符,当然,也可以使用括 号来避免这种情况,如:<#if (x>y)>

2.4.2 空值处理

1、判断某变量是否存在使用 “??” 用法为:variable??,如果该变量存在,返回true,否则返回false 例:为防止stus为空报错可以加上判断如下:

    <#--、判断某变量是否存在使用 “??” 用法为:variable??,如果该变量存在,返回true,否则返回false
例:为防止stus为空报错可以加上判断如下-->
        <#if stus??>
            <#list stus as stu>
                .....
            </#list>

        </#if>

2、缺失变量默认值使用 “!” 使用!要以指定一个默认值,当变量为空时显示默认值。 例: ${name!''}表示如果name为空显示空字符串。 如果是嵌套对象则建议使用()括起来。例: ${(stu.bestFriend.name)!''}表示,如果stu或bestFriend或name为空默认显示空字符串。

<#--2、缺失变量默认值使用 “!” 使用!要以指定一个默认值,当变量为空时显示默认值。 例: ${name!''}表示如果name为空显示空字符串。
 
如果是嵌套对象则建议使用()括起来
例: ${(stu.bestFriend.name)!''}表示,如果stu或bestFriend或name为空默认显示空字符串-->
${(stu.bestFriend.name)!'空字符串'}

2.5 内建函数

内建函数语法格式: 变量+?+函数名称

2.5.1、和到某个集合的大小 ${集合名?size}

2.5.2、日期格式化

显示年月日: ${today?date} 
显示时分秒:${today?time} 
显示日期+时间:${today?datetime} <br> 
自定义格式化: ${today?string("yyyy年MM月")}
<#--日期的格式化-->
显示年月日: ${stuMap['stu1'].birthday?string("yyyy年MM月")} 

2.5.3、内建函数c map.put("point", 102920122); point是数字型,使用${point}会显示这个数字的值,不并每三位使用逗号分隔。 如果不想显示为每三位分隔的数字,可以使用c函数将数字型转成字符串输出 ${point?c}

2.5.4、将json字符串转成对象 一个例子: 其中用到了 assign标签,assign的作用是定义一个变量。

<#assign text="{'bank':'工商银行','account':'10101920201920212'}" /> 

<#assign data=text?eval /> 开户行:${data.bank} 账号:${data.account}

2.5.5 完整的模板

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
Hello ${name}!

<table>
    <tr>
        <td>序号</td>
        <td>姓名</td>
        <td>年龄</td>
        <td>钱包</td>
    </tr>
    <#list stus as stu>
      <tr>
        <td>${stu_index + 1}</td>     <#--说明: _index:得到循环的下标,使用方法是在stu后边加"_index",它的值是从0开始-->
        <td>${stu.name}</td>
        <td>${stu.age}</td>
        <td>${stu.mondy}</td>
      </tr>
    </#list>
</table>


    <#--遍历Map   使用map指令遍历数据模型中的stuMap-->
    输出stu1的学生信息:>br>
    姓名:${stuMap['stu1'].name} <br/>
    年龄:${stuMap['stu1'].age} <br/>

    便利出两个学生的信息:<br/>
    <table>
        <tr>
            <td>序号</td>
            <td>姓名</td>
            <td>年龄</td>
            <td>钱包</td>
        </tr>
        <#list stuMap?keys as k>
            <tr>
                <td>${k_index +1}</td>
                <td>${stuMap[k].name}</td>
                <td>${stuMap[k].age}</td>
                <td>${stuMap[k].mondy}</td>
            </tr>
        </#list>
    </table>


    <#--if 指令即判断指令,是常用的FTL指令,freemarker在解析时遇到if会进行判断,条件为真则输出if中间的内容,否 则跳过内容不再输出-->
        <table>
            <tr>
                <td>姓名</td>
                <td>年龄</td>
                <td>钱包</td>
            </tr>
            <#list stus as stu>
                <tr>
                    <td <#if stu.name == '小明'>style="background: red;" </#if>>${stu.name}</td>
                    <td>${stu.age}</td>
                    <td>${stu.mondy}</td>
                </tr>
            </#list>
        </table>

    <#--、判断某变量是否存在使用 “??” 用法为:variable??,如果该变量存在,返回true,否则返回false
例:为防止stus为空报错可以加上判断如下-->
        <#if stus??>
            <#list stus as stu>
                .....
            </#list>

        </#if>


<#--2、缺失变量默认值使用 “!” 使用!要以指定一个默认值,当变量为空时显示默认值。 例: ${name!''}表示如果name为空显示空字符串。
 
如果是嵌套对象则建议使用()括起来
例: ${(stu.bestFriend.name)!''}表示,如果stu或bestFriend或name为空默认显示空字符串-->
${(stu.bestFriend.name)!'空字符串'}


<#--stus集合的大小-->
    stus集合的大小
    ${stus?size}


<#--日期的格式化-->
显示年月日: ${stuMap['stu1'].birthday?string("yyyy年MM月")} 
<#--显示时分秒:${today?time}   
显示日期+时间:${today?datetime} <br>        
自定义格式化:${today?string("yyyy年MM月")}-->


<#--
内建函数c  map.put("point",102920122);point是数字型,使用${point}会显示这个数字的值,不并每三位使用逗号分隔。
如果不想显示为每三位分隔的数字,可以使用c函数将数字型转成字符串输出${point?c}
-->
<#--point:${point?c}-->


<#--
将json字符串转成对象一个例子:其中用到了assign标签,assign的作用是定义一个变量
-->

<#assign text="{'bank':'工商银行','account':'10101920201920212'}"/>   <#--什么一个变量-->
<#assign data=text?eval/>开户行:${data.bank}账号:${data.account}

</body>
</html>

2.6 静态化测试

1、使用模板文件静态化 定义模板文件,使用freemarker静态化程序生成html文件。 2、使用模板字符串静态化 定义模板字符串,使用freemarker静态化程序生成html文件。

2.6.1 使用模板文件静态化 在test下创建测试类,并且将main下的resource/templates拷贝到test下,本次测试使用之前我们在main下创建 的模板文件。

image.png

2.6.2 新建测试类:FreemarkerTest 内容如下:

package com.xuecheng.test.freemarker;

import com.xuecheng.test.freemarker.model.Student;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.apache.commons.io.IOUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

@SpringBootTest
@RunWith(SpringRunner.class)
public class FreemarkerTest {

    // 测试静态化 基于ftl模板文件生成html
    @Test
    public  void testGenerateHtml() throws IOException, TemplateException {
        // 定义配置类
        //创建配置类
        Configuration configuration = new Configuration(Configuration.getVersion());
        //设置模板路径
         String classpath = this.getClass().getResource("/").getPath();
         configuration.setDirectoryForTemplateLoading(new File(classpath+"/templates/"));
        //设置字符集
        configuration.setDefaultEncoding("utf-8");
        //加载模板
        Template template = configuration.getTemplate("test1.ftl");
        // 定义数据模型
        Map map = getMap();
     //   map.put("name","申来来");
        // 静态化
        String context = FreeMarkerTemplateUtils.processTemplateIntoString(template,map);
        //System.out.println(context);
        InputStream inputStream = IOUtils.toInputStream(context);
        FileOutputStream outputStream = new FileOutputStream(new File("d:/test1.html"));
        // 输出文件
        IOUtils.copy(inputStream,outputStream);
        inputStream.close();
        outputStream.close();

    }


    //基于模板字符串生成静态化文件
    @Test
    public void testGenerateHtmlByString() throws IOException, TemplateException {
        //创建配置类
        Configuration configuration=new Configuration(Configuration.getVersion());
        //获取模板内容
        //模板内容,这里测试时使用简单的字符串作为模板
        String templateString="" +
                "<html>\n" +
                "    <head></head>\n" +
                "    <body>\n" +
                "    名称:${name}\n" +
                "    </body>\n" +
                "</html>";

        //加载模板
        //模板加载器
        StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
        stringTemplateLoader.putTemplate("template",templateString);
        configuration.setTemplateLoader(stringTemplateLoader);
        Template template = configuration.getTemplate("template","utf-8");

        //数据模型
        Map map = getMap();
        //静态化
        String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
        //静态化内容
        System.out.println(content);
        InputStream inputStream = IOUtils.toInputStream(content);
        //输出文件
        FileOutputStream fileOutputStream = new FileOutputStream(new File("d:/test1.html"));
        IOUtils.copy(inputStream, fileOutputStream);
    }

    //数据模型
    //数据模型
    private Map getMap(){
        Map<String, Object> map = new HashMap<>();
        //向数据模型放数据
        map.put("name","申来来");
        Student stu1 = new Student();
        stu1.setName("小明");
        stu1.setAge(18);
        stu1.setMondy(1000.86f);
        stu1.setBirthday(new Date());
        Student stu2 = new Student();
        stu2.setName("小红");
        stu2.setMondy(200.1f);
        stu2.setAge(19);
//        stu2.setBirthday(new Date());
        List<Student> friends = new ArrayList<>();
        friends.add(stu1);
        stu2.setFriends(friends);
        stu2.setBestFriend(stu1);
        List<Student> stus = new ArrayList<>();
        stus.add(stu1);
        stus.add(stu2);
        //向数据模型放数据
        map.put("stus",stus);
        //准备map数据
        HashMap<String,Student> stuMap = new HashMap<>();
        stuMap.put("stu1",stu1);
        stuMap.put("stu2",stu2);
        //向数据模型放数据
        map.put("stu1",stu1);
        //向数据模型放数据
        map.put("stuMap",stuMap);
        return map;
    }


}

执行testGenerateHtml()方法,得到的文本内容是:

image.png

执行testGenerateHtmlByString()方法,得到的文本内容是:

image.png

0 条评论

发布
问题