• springboot基础(57):整合FreeMarker


    前言

    本章介绍如何整合FreeMarker,简单的快速入门。
    FreeMarker官网 :https://freemarker.apache.org/

    第一节 FreeMarker简介

    FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。

    模板编写为FreeMarker Template Language (FTL)。它是简单的,专用的语言, 不是 像PHP那样成熟的编程语言。 那就意味着要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。在模板中,你可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据。
    在这里插入图片描述
    其实从上面这张图,我们可以看出,FreeMarker就是通过模板+参数,进行标签替换和输出,得到用户视图的过程。

    第二节 FreeMarker入门案例

    1. 导入依赖
         <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-freemarker</artifactId>
            </dependency>
    
    • 1
    • 2
    • 3
    • 4
    1. 添加freemarker相关的配置文件
    spring:
      freemarker:
        #指定HttpServletRequest的属性是否可以覆盖controller的model的同名项
        allow-request-override: false
        #req访问request
        request-context-attribute: req
        #后缀名freemarker默认后缀为.ftl,当然你也可以改成自己习惯的.html
        suffix: .ftl
        #设置响应的内容类型
        content-type: text/html;charset=utf-8
        #是否允许mvc使用freemarker
        enabled: true
        #是否开启template caching
        cache: false
        #设定模板的加载路径,多个以逗号分隔,默认: [“classpath:/templates/”]
        template-loader-path: classpath:/templates/
        #设定Template的编码
        charset: UTF-8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    1. 在resources目录下创建templates文件夹,并在templates目录下新建一个hello.ftl文件
    <html>
    <head>
        <title>${title}title>
    head>
    <body>
    <h1>${context}h1>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    1. 新建HelloController测试,注意不要使用@RestController
    @Controller
    @RequestMapping("/hello")
    public class HelloController {
        @GetMapping("/abc")
        public String abc(Model model){
            System.out.println("=======================");
            model.addAttribute("title","你好");
            model.addAttribute("context","欢迎光临");
            return "hello"; //返回对应hello.ftl的模板
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1. 启动服务运行,并访问localhost:8080/hello/abc,可以发现hello.ftl内容被解析成功,并正确显示,表明案例测试成功。
      在这里插入图片描述

    到这里,FreeMarker基本上运行成功了。

    第三节 数据类型

    FreeMarker包含的数据类型有布尔,日期,数值,字符,sequence,hash。

    1. 布尔、日期、数值、字符

    下面demo包含了字符串,数值,布尔和日期。

            model.addAttribute("str","abc");
            model.addAttribute("num",123);
            model.addAttribute("flag",true);
            model.addAttribute("mydate",new Date());
    
    • 1
    • 2
    • 3
    • 4

    模板内容

    <h2>数据类型h2>
    <h3>字符串 h3>
    ${str}
    <h3>数值 : h3>
    ${num}
    <h3>boolean:h3>
     ?c表示转换成字符串。当flag为boolean类型时,直接使用$ {flag}是不能输出的<br>
    ${flag?c}  转成字符串(?c和?string都是转字符串,是一样的) <br>
    ${flag?string}  转成字符串 <br>
    ${flag?then('yes','no')} 三目运算<br>
    ${flag?string('y','n')} 三目运算
    <h3>日期h3>
    ${mydate?date}  格式:yyyy-MM-dd<br>
    ${mydate?time}  格式:HH:mm:ss<br>
    ${mydate?datetime} 格式:yyyy-MM-dd HH:mm:ss<br>
    ${mydate?string("yyyy年MM月dd日 HH:mm:ss")} 自定义格式<br>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    输出的结果
    在这里插入图片描述

    2. 数值类型

    2.1 普通数字、货币、百分比、

     @GetMapping("/num")
        public String num(Model model){
            System.out.println("=======================");
            model.addAttribute("money",12003.54);
            model.addAttribute("score",100000);
            model.addAttribute("taxRate",0.13599);
            model.addAttribute("taxRate2",0.6439);
            return "num";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    <h1>numh1>
    分数: ${score}<br>
    数值转字符串输出:${score?c}<br>
    数值转货币输出:${money?string.currency}<br>
    
    税率:${taxRate?c}<br>
    税率:${taxRate2?c}<br>
    税率百分比(默认会四舍五入): ${taxRate?string.percent}<br>
    税率保留2位小数(默认会四舍五入): ${taxRate?string["0.##"]}<br>
    税率2保留2位小数(默认会四舍五入): ${taxRate2?string["0.##"]}<br>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    输出结果
    在这里插入图片描述

    2.2 数值格式化处理

    使用#{expression:format}形式格式化数值
    mx: 表示小数部分最少几位,
    Mx: 表示小数部分最多几位
    例如m1M2, 表示最多一位小数,最多两位小数

    <#assign a=3.1415926 b=87  />
    #{a;m1M2}<br>
    #{b;m1M2}<br>
    #{a;m1}<br>
    #{a;M2}<br>
    #{b;m1}<br>
    #{b;M2}<br>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    3. assign 声明

    FreeMarker支持声明变量,也支持数学运算。

    <#assign a=1, b=2  /> 可以声明多个变量,可以使用逗号隔开,也可以使用空格分开
    ${a}   支持声明<br>
    ${a+b} 支持运算<br>
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    4. 条件语法

    4.1 if else 指令

    <#if condition>…
    <#elseif condition2>…
    <#elseif condition3>…
    <#else>…

    condition 布尔表达式
    可以包含0个或者多个elseif,但是else或者elseif必须在if的开始和结束标签之间
    示例

    <#assign score=58  />
    <#if score gt 80 >
        ${score} 是 优秀
    <#elseif score gt 60 >
        ${score} 是 及格
    <#else >
        ${score} 是 不及格
    #if>
    <br>
    <#if score=58>考了58#if>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    FreeMarker标签中,
    gt: 大于
    lt: 小于
    等于直接用 “=”
    或者也可以使用小括号,将表达式括起来,再使用>和< ,如下示例

    <#assign score=58  />
    <#if (score > 80) >
        ${score} 是 优秀
    <#elseif (score > 60) >
        ${score} 是 及格
    <#else >
        ${score} 是 不及格
    #if>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4.2 switch

    <#switch value>
    <#case refValue>…<#break>
    <#case refValue>…<#break>
    <#default>…

    switch规则很简单

    <#assign month=8  />
    ${month}月 是
    <#switch month>
        <#case 1>
        <#case 2>
        <#case 3>
        春天
            <#break >
        <#case 4>
        <#case 5>
        <#case 6>
            夏天
            <#break >
        <#case 7>
        <#case 8>
        <#case 9>
            秋天
            <#break >
        <#case 10>
        <#case 11>
        <#case 12>
            冬天
            <#break >
        <#default >
             错了
    #switch>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    输出结果
    在这里插入图片描述

    4.3 import

    import指令,从其它文件中导入,然后在当前文件中使用。
    格式

    <#import "params.ftl" as params>  将params.ftl文件导入进来,封装到params对象中
    
    • 1

    示例
    params.ftl文件

    <#assign a=1 b=2>
    
    • 1

    另一个文件中导入它

    <#import "params.ftl" as params>
    ${params.a+params.b}  从其它文件引入变量进行计算
    
    • 1
    • 2

    运行结果
    在这里插入图片描述

    5. 字符串处理

    类似java里的string处理

     @GetMapping("/str")
        public String str(Model model){
            System.out.println("=======================");
            model.addAttribute("str","hello hello world");
            return "str";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    <html>
    <head>
        <title>stringtitle>
    head>
    <body>
    <h1>Stringh1>
    原始字符串:${str}<br>
    ${str?length} 字符串长度<br>
    ${str?substring(2)} 从下标2(含)开始到结尾<br>
    ${str?substring(2,4)} 从下标2(含)开始到下标4(不含)<br>
    ${str?uncap_first} > 首字母小写<br>
    ${str?cap_first}  首字母大写<br>
    ${str?upper_case} 全大写<br>
    ${str?lower_case} 全小写<br>
    ${str?starts_with("he")?string} 是否以指定字符开始<br>
    ${str?ends_with("world")?string} 是否以指定字符结束<br>
    ${str?index_of("w")?string} 指定字符串的下标<br>
    A${" a b c "?trim}B 去除前后的空格<br>
    ${str?replace("h","H")} 替换字符串<br>
    ${str?contains("wor")?string("yes","no")} 是否包含某字符串<br>
    <br>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    输出结果
    在这里插入图片描述

    6. null字符问题

    6.1 报错的null字符串

    FreeMarker变量不能为null。

    model.addAttribute("str1",null);//会报错
    model.addAttribute("str2","");//不会报错
    
    • 1
    • 2

    设置字符串为null时会报错
    在这里插入图片描述

    6.2 如何处理null 字符串的问题?

    • !: ${value!} 如果value为null时,会显示空字符串(等价位“”)
    • ?? : ${(str1??)?string} 判断变量是否为null,为null则显示false,否则返回true
    @GetMapping("/nullstr")
        public String nullstr(Model model){
            System.out.println("=======================");
            model.addAttribute("str1",null);//会报错
            model.addAttribute("str2","");//不会报错
            return "nullstr";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    <html>
    <head>
        <title>stringtitle>
    head>
    <body>
    <h1>空字符的问题h1>
    ${str2}<br>
    ${str1!} 如果str为null值,则显示空字符串<br>
    ${(str1??)?string} 判断是否是字符串,返回布尔值。str1=null<br>
    ${(str2??)?string} 判断是否是字符串,返回布尔值。str2=""<br>
    ${str1!"默认值"} 字符串为null时,显示自己定义的值<br>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    输出结果
    在这里插入图片描述

    7. 三目运算

    model.addAttribute("flag",true);
    
    • 1
    ${flag?then('yes','no')} 三目运算<br>
    ${flag?string('y','n')} 三目运算
    
    • 1
    • 2

    两种写法都可以三目运算,没区别。

    8. 对象和map

           User user=new User("小王",20);
    
            model.addAttribute("user",user);
    
            Map<String,String> map=new HashMap<>();
            map.put("beijing","北京");
            map.put("wuhan","武汉");
            map.put("shanghai","上海");
            model.addAttribute("mymap",map);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    <html>
    <head>
        <title>objtitle>
    head>
    <body>
    <h1>对象和maph1>
    <h3>对象h3>
    姓名:${user.name} 从对象里取值$ {obj.fieldName}<br>
    年龄:${user.age}<br>
    <hr>
    <h3>maph3>
    ${mymap.wuhan} 从对象里取值$ {map.key}<br>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    输出结果

    在这里插入图片描述

    第四节 集合的处理

    1. sequence(List,Array,Set)的遍历,排序,反转等

    相当于java里的数组,List,Set等集合

    这里的User类包含了name和age,在下面的集合遍历中用到。

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class User {
        private String name;
        private int age;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    构建的数据

    @GetMapping("/sequence")
        public String sequence(Model model){
            System.out.println("=======================");
            List<User> users=new ArrayList<>();
            users.add(new User("小王",12));
            users.add(new User("小李",13));
            users.add(new User("小刘",11));
            users.add(new User("小张",18));
            model.addAttribute("users",users);
    
            String[] arr={"bb","aa","cc"};
            model.addAttribute("myarray",arr);
    
            Set<String> set=new HashSet<>();
            set.add("苹果");
            set.add("梨");
            set.add("葡萄");
            model.addAttribute("fruits",set);
            return "sequence";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    模板sequence.ftl

    <html>
    <head>
        <title>集合遍历title>
    head>
    <body>
    <h1>集合h1>
    <hr>
    <h3>集合遍历h3>
    users as user<br>
    <table border="1" width="30%"  style="text-align:center;">
        <thead><td>index下标td><td>姓名td><td>年龄td>thead>
        <tbody>
        <#list users as user>
           <tr><td>${user?index}td><td>${user.name}td><td>${user.age}td>tr>
        #list>
        tbody>
        <tfoot>
         <td>总人数td><td colspan="10">${users?size}td>
        tfoot>
    table>
    获取第一个元素: ${users?first.name}<br>
    获取最后一个元素: ${users?last}<br>
    总数: ${users?size}<br>
    <hr>
    <h3>排序h3>
    <h4>倒序h4>
    users?reverse as user<br>
    <table border="1" width="30%"  style="text-align:center;">
        <thead><td>index下标td><td>姓名td><td>年龄td>thead>
        <tbody>
        <#list users?reverse as user>
            <tr><td>${user?index}td><td>${user.name}td><td>${user.age}td>tr>
        #list>
        tbody>
    table>
    
    <h4>升序h4>
    users?sort as user<br>
    英文内容的排序,按照字母顺序排序,中文内容的排序按照对应的拼音字母顺序排序<br>
    <table border="1" width="30%"  style="text-align:center;">
        <thead><td>index下标td><td>姓名td><td>年龄td>thead>
        <tbody>
        <#list users?sort as user>
            <tr><td>${user?index}td><td>${user.name}td><td>${user.age}td>tr>
        #list>
        tbody>
    table>
    
    <h4>按字段排序h4>
    users?sort_by("age") as user<br>
    <table border="1" width="30%"  style="text-align:center;">
        <thead><td>index下标td><td>姓名td><td>年龄td>thead>
        <tbody>
        <#list users?sort_by("age") as user>
            <tr><td>${user?index}td><td>${user.name}td><td>${user.age}td>tr>
        #list>
        tbody>
    table>
    
    <h4>降序h4>
    users?sort?reverse as user<br>
    语法里只有升序,没有降序。降序需要依靠升序+倒序。
    <br>
    <table border="1" width="30%"  style="text-align:center;">
        <thead><td>index下标td><td>姓名td><td>年龄td>thead>
        <tbody>
        <#list users?sort?reverse as user>
            <tr><td>${user?index}td><td>${user.name}td><td>${user.age}td>tr>
        #list>
        tbody>
    table>
    <hr>
    <h1>数组h1>
    数组和list是一样的,都可以进行遍历,排序,获取长度等,下面只列举了遍历操作
    <br>
    <#list myarray as a>
        ${a}<br>
    #list>
    
    <hr>
    <h1>Seth1>
    set和list是一样的,都可以进行遍历,排序,获取长度等,下面只列举了遍历操作
    <br>
    <#list fruits as f>
        ${f}<br>
    #list>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88

    运行查看结果
    在这里插入图片描述
    在这里插入图片描述

    2. hash (Map)的遍历

    类似于 java 中的 Map 类型

        @GetMapping("/hash")
        public String hash(Model model){
            System.out.println("=======================");
            Map<String,String> map=new HashMap<>();
            map.put("WX","微信");
            map.put("QQ","扣扣");
            map.put("FB","Facebook");
            model.addAttribute("chats",map);
            return "hash";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    模板hash.ftl

    <html>
    <head>
        <title>Hashtitle>
    head>
    <body>
    <h1>Hashh1>
    <h3>遍历hashh3><br>
    <#list chats?keys as k>
        ${k} ===${chats[k]}<br>
    #list>
    <h3>遍历valueh3><br>
    <#list chats?values  as v>
        ${v}<br>
    #list>
    长度: ${chats?size}<br>
    
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    运行查看结果

    在这里插入图片描述

    第五节 传送门

    FreeMarker入门教程
    FreeMarker 教程

  • 相关阅读:
    浅析 vSAN 磁盘组架构和缓存盘的“消亡”
    如何简单理解大数据
    合宙Air724UG LuatOS-Air LVGL API控件-页面 (Page)
    【C++】stack、queue、priority_queue的模拟实现
    Python接口调用连接失败情况解决办法
    关于chatGPT对有关Docker Desktop问题的一个回答
    【Python】Hospital ward dynamic contact network网络数据集图信息提取
    go-10-字符串操作
    21李沐动手学深度学习v2/读写文件,加载和保存张量
    【红包雨功能的】环境部署(弹性伸缩、负载均衡、Redis读写分离、云服务器部署)
  • 原文地址:https://blog.csdn.net/u011628753/article/details/126066172