FreeMarker基础使用

一、装配使用

1、导入依赖

<!--SpringBootFreemarker模板依赖 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

2、在properties里进行配置

##Freemarker配置
##自定义模板文件配置路径默认模板路径在resources/templates下,默认后缀.ftl
##spring.freemarker.template-loader-path=classpath:/web/
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=true
spring.freemarker.expose-session-attributes=true
spring.freemarker.request-context-attribute=request
spring.freemarker.suffix=.ftl

3、编写controller

package com.tcc.controller;

import java.util.Date;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class TestController {
	
	@RequestMapping("f1")
	public String test1(ModelMap map) {
		//存值
		map.addAttribute("flag", true);
		map.addAttribute("date", new Date());
		map.addAttribute("a",5.5474);
		map.addAttribute("b",18);
		map.addAttribute("c",10000);
		map.addAttribute("t1","Hello");
		map.addAttribute("t2", "world");
		map.addAttribute("t3", "hello world");
		//跳转页面
		return "f1";
	}

}

4、在src/main/resource目录下创建文件夹templates存放.ftl后缀的页面

二、内建函数

1、后台传入数据跳转页面

package com.tcc.controller;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class TestController {
	
	/**
	 * 访问路径:localhost:8080/f1
	 * @param map
	 * @return 返回给页面的数据
	 */
	@RequestMapping("f1")
	public String test1(ModelMap map) {
		//布尔类型
		map.addAttribute("flag", true);
		
		//日期类型
		map.addAttribute("date", new Date());
		
		//数字类型
		map.addAttribute("a",5.5474);
		map.addAttribute("b",18);
		map.addAttribute("c",10000);
		
		//字符串
		map.addAttribute("t1","Hello");
		map.addAttribute("t2", "world");
		map.addAttribute("t3", "hello world");
		
		// 空字符串
		map.addAttribute("test1", "");
		map.addAttribute("test2", null);
		
		//数组类型
		String[] st = {"北京","上海","广东","深圳"};
		map.addAttribute("st",st);
		
		//集合类型
		List<String> cityList = new ArrayList<>();
		cityList.add("北京");
		cityList.add("上海");
		cityList.add("广东");
		cityList.add("深圳");
		map.addAttribute("cityList",cityList);
		
		//map类型
		Map<String,Object> map2 = new HashMap<>();
		map2.put("name", "张三");
		map2.put("age", 22);
		map2.put("sex", "男");
		map.addAttribute("map",map2);
		
		
		//跳转页面
		return "f1";
	}
	

}

2、前台获取不同类型的值

<!-- 
	注释(查看网页源代码可以看到) 访问路径:localhost:8080/f1
 -->
 
 <#--
 	注释(前端看不到)
 -->
 <#-- 布尔类型的值不能直接接收,要在后面添加 ?c  ?string  ?string('yes','no') -->
 <h3>布尔值</h3>
${flag?c} <br/>
${flag?string} <br/>
${flag?string("yes","no")} <br/>
<hr/>

<#-- 日期类型的值不能直接接收,要在后面添加 ?date 或 ?time 或 ?datetime 或 ?string('yyyy/MM/dd') -->
<h3>日期</h3>
${date?date} <br/>
${date?time} <br/>
${date?datetime} <br/>
${date?string("yyyy/MM/dd HH:mm:ss")} <br/>
<hr/>

<#-- 
	数字类型的值可以直接接收,也可以转换类型 
	a:5.5474  b:18  c:10000
-->
<h3>数字</h3>
${a} <br/>
${a?c} <br/> <#-- 转为字符串 -->
${a?floor} <br/> <#-- 返回最近的整数。 如果数字以.5结尾,那么它将进位 -->
${a?round} <br/> <#-- 返回数字的舍掉小数后的整数 (也就是向负无穷舍弃) -->
${a?ceiling} <br/> <#-- 返回数字小数进位后的整数 (也就是向正无穷进位) -->
${c?string.currency} <br/> <#-- 货币类型 -->
${a?string["0.#"]} <br/> <#-- #小数位占位符,几个#代表保留小数点后几位 -->

<hr/>

<#--
	字符串内建函数 t1:Hello	t2:world  t3:hello world
-->
<h3>字符串</h3>
${t1} -- ${t2} <br/>
${t2?cap_first} <br/> <#-- 首字母大写 -->
${t3?capitalize} <br/> <#-- 全部单词首字母大写 -->
${t1?ends_with("o")?c} <br/> <#-- 返回是否这个字符串以参数中指定的子串结尾 返回值为true或false 需要转换 -->
${t1?starts_with("o")?c} <br/> <#-- 返回是否这个字符串以参数中指定的子串开头 返回值为true或false 需要转换 -->
${t3?length} <br/> <#-- 字符串中字符的数量。 -->
${t1?lower_case} <br/> <#-- 全部小写。 -->
${t1?upper_case} <br/> <#-- 全部大写。 -->

<hr/>

<h3>空字符串[特殊]</h3>
<#-- 
	test1:""	test2:null
	test1不报错,test2报错 
	解决办法:在后面加上[!]  [!"为空时候的默认值"]
-->
${test1}
${test2!}
${test2!"yes"} <br/>
${test2!1} <br/>

<hr/>

<#--
	序列内建函数:数组(st)、集合(list)、map(map)
-->
<h3>数组</h3>
${st?join(", ")} <br/> <#-- 使用给定的分隔符来连接序列中的项为一个独立的字符串 -->
${st?first} <br/> <#-- 获取第一个值 -->
${st?last} <br/> <#-- 获取最后一个值 -->

<#-- 
	序列中子变量的数量(作为数字值)。
	假设序列中至少有一个子变量, 那么序列 s 中最大的索引是 s?size - 1 
	(因为第一个子变量的序列是0)。 
-->
${st?size} <br/> 

<#-- 辨别序列中是否包含指定值。它包含一个参数,就是来查找的值。 -->
${st?seq_contains("北京")?string("yes","no")} <br/> 


<#list st?reverse as s> <#-- 序列的反序形式。 -->
	${s}
</#list>

<br/>

<#--
	以升序方式返回序列。(要使用降序排列时,使用它之后使用 reverse 内建函数。) 
	这仅在子变量都是字符串时有效,或者子变量都是数字,
	或者子变量都是日期值 (日期,时间,或日期+时间),
	或者所有子变量都是布尔值时(从2.3.17版本开始)。 
	如果子变量是字符串,它使用本地化(语言)的具体单词排序(通常是大小写不敏感的)。
-->
<#list st?sort as s> 
	${s}
</#list>

<br/>

<#-- 降序输出 -->
<#list st?sort?reverse as s> 
	${s}
</#list>

<hr/>

<h3>集合</h3>
<#-- 可用方法和上面举例一样 -->
${cityList?join(", ")} <br/>
${cityList?size} <br/>

<#list cityList as ct>
	${ct}
</#list>

<br/>

<#list cityList?sort as ct>
	${ct}
</#list>

<hr/>

<h3>Map集合</h3>
<#-- key遍历输出 -->
<#list map?keys as key>
	${key} -- ${map[key]} <br/>
</#list>

<br/>

<#-- value遍历输出 -->
<#list map?values as value>
	${value} <br/>
</#list>

三、常用指令

1、assign定义变量

1.1、概念

使用该指令你可以创建一个新的变量, 或者替换一个已经存在的变量。注意仅仅顶级变量可以被创建/替换 (也就是说你不能创建/替换 some_hash.subvar, 除了 some_hash)。

1.2、使用
  • 变量 seq 存储一个序列:

  • <#assign seq = ["foo","bar","baz"]> <#-- 创建变量 -->
    ${seq?join(", ")} <#-- 遍历变量 -->
    
  • 一次定义多个变量

    • <#assign
        seq = ["foo", "bar", "baz"]
        x++
      >
      
  • 变量中插入变量

    • <#assign z = "张${username}">
      

2、if,else,elseif

2.1、概念

相当于java中的if,else结构, if 中可以包含任意数量的 elseif(包括0个) 而且结束时 else 是可选的

2.2、用法一
  • 只有 if 没有 elseifelse

    <#if x == 1>
      x is 1
    </#if>
    
  • 只有 if 没有 elseif 但是有 else

<#if x == 1>
  x is 1
<#else>
  x is not 1
</#if>
  • if 和两个 elseif 但是没有 else
<#if x == 1>
  x is 1
<#elseif x == 2>
  x is 2
<#elseif x == 3>
  x is 3
</#if>
  • if 和三个 elseif 还有 else:
<#if x == 1>
  x is 1
<#elseif x == 2>
  x is 2
<#elseif x == 3>
  x is 3
<#elseif x == 4>
  x is 4
<#else>
  x is not 1 nor 2 nor 3 nor 4
</#if>
  • 也可以嵌套 if 指令:
<#if x == 1>
  x is 1
  <#if y == 1>
    and y is 1 too
  <#else>
    but y is not
  </#if>
<#else>
  x is not 1
  <#if y < 0>
    and y is less than 0
  </#if>
</#if>
  • 测试:

    <#assign score = 80>
    <#if score lt 60>
    	<h5>不及格</h5>
    <#elseif score = 60>
    	<h5>不多不少刚刚好</h5>
    <#elseif score gt 60 && score lt 80>
    	<h5>革命尚未成功,同志仍需努力</h5>
    <#else>
    	<h5>考的不错呦</h5>
    </#if>
    
  • 注意: 当你想测试是否 x > 0x >= 0,编写 <#if x > 0><#if x >= 0> 是错误的, 因为第一个 > 会结束 #if 标签。要这么来做,可以编写 <#if x gt 0><#if gte 0>。也请注意,如果比较发生在括号内部,那么就没有这样的问题, 比如 <#if foo.bar(x > 0)> 就会得到想要的结果。

2.3、用法二
  • 根据变量有无值显示内容。

  • 测试:

    <#-- 有值 -->
    <#assign a = "">
    <#if a??>
    	<h5>a有值</h5>
    <#else>
    	<h5>a没有值</h5>
    </#if>
    
    <#-- 无值 -->
    <#if a1??>
    	<h5>a1有值</h5>
    <#else>
    	<h5>a1没有值</h5>
    </#if>
    
  • 结果:

    在这里插入图片描述

3、list,else

遍历数组或集合或map。

  • 使用:

    <#-- 数组有值 -->
    <#assign num = [1,2,3,5,4]>
    <#list num as n>
    	${n}
    </#list>
    
    <#-- 数组无值 -->
    <#assign num1 = []>
    <#list num1 as n>
    	${n}
    <#else>
    	<h5>该集合无值</h5>
    </#list>
    
  • 结果:

    在这里插入图片描述

4、macro自定义指令

4.1、概念

​ 宏变量存储模板片段(称为宏定义体)可以被用作 自定义指令。 这个变量也存储自定义指令的被允许的参数名。当你将这个变量作为指令时, 你必须给所有参数赋值,除了有默认值的参数。 默认值当且仅当你调用宏而不给参数赋值时起作用。

4.2、写法
<#macro name param1 param2 ... paramN>
  ...
  <#nested loopvar1, loopvar2, ..., loopvarN>
  ...
  <#return>
  ...
</#macro>
  • name: 宏变量的名称,它不是表达式。和 顶层变量 的语法相同,比如 myMacromy\-macro。 然而,它可以被写成字符串的形式,如果宏名称中包含保留字符时,这是很有用的, 比如 <#macro "foo~bar">...。 注意这个字符串没有扩展插值(如 "${foo}")。
  • param1param2,等…: 局部变量 的名称,存储参数的值 (不是表达式),在 = 号后面和默认值(是表达式)是可选的。 默认值也可以是另外一个参数,比如 <#macro section title label=title>。参数名称和 顶层变量 的语法相同,所以有相同的特性和限制。
  • paramN, 最后一个参数,可能会有三个点(...), 这就意味着宏接受可变数量的参数,不匹配其它参数的参数可以作为最后一个参数 (也被称作笼统参数)。当宏被命名参数调用, paramN 将会是包含宏的所有未声明的键/值对的哈希表。当宏被位置参数调用, paramN 将是额外参数的序列。 (在宏内部,要查找参数,可以使用 myCatchAllParam?is_sequence。)
  • loopvar1loopvar2等…: 可选的,循环变量 的值, 是 nested 指令想为嵌套内容创建的。这些都是表达式。

returnnested 指令是可选的,而且可以在 <#macro ...> 和 </#macro> 之间被用在任意位置和任意次数。

没有默认值的参数必须在有默认值参数 (paramName=defaultValue) 之前。

4.3、用法
  • 创建简单的自定义指令

    <#-- 简单的自定义指令 -->
    <#macro test>
    	This is Test
    </#macro>
    
    <#-- 调用指令 -->
    <@test/>
    
    • 结果:

      在这里插入图片描述

  • 乘法表(自定义指令中包含内置指令)

    <#-- 乘法表(自定义指令中包含内置指令) -->
    <#macro cfb>
    	<#list 1..9 as i>
    		<#list 1..i as j>
    			${i} * ${j} = ${i*j} &nbsp;
    		</#list>
    		<br/>
    	</#list>
    </#macro>
    
    <@cfb/>
    
    • 结果:

      在这里插入图片描述

  • 可以传参的乘法表

    <#-- 可以传参的乘法表 -->
    <#macro cfb02 num>
    	<#list 1..num as i>
    		<#list 1..i as j>
    			${i} * ${j} = ${i*j} &nbsp;
    		</#list>
    		<br/>
    	</#list>
    </#macro>
    
    <#-- 5,5乘法表 -->
    <@cfb02 num=5/>
    
    • 结果:

      在这里插入图片描述

  • 有参数和默认值参数的宏

    <#-- 有参数和默认值参数的宏 -->
    <#macro cfb02 num=9>
    	<#list 1..num as i>
    		<#list 1..i as j>
    			${i} * ${j} = ${i*j} &nbsp;
    		</#list>
    		<br/>
    	</#list>
    </#macro>
    
    <#-- 5,5乘法表 -->
    <@cfb02 num=5/>
    <#-- 9,9乘法表,默认num=9 -->
    <@cfb02/>
    
    • 结果:

      在这里插入图片描述

4.4、nested占位符

nested 指令执行自定义指令开始和结束标签中间的模板片段。 嵌套的片段可以包含模板中任意合法的内容:插值,指令等…它在上下文环境中被执行, 也就是宏被调用的地方,而不是宏定义体的上下文中。因此,比如, 你不能看到嵌套部分的宏的局部变量。如果你没有调用 nested 指令, 自定义指令开始和结束标记中的部分将会被忽略。

使用
  • <#-- nested占位符 -->
    <#macro test>
    	This is Test
    	<#nested>
    </#macro>
    
    <#-- 调用指令 -->
    <@test>xxxx</@test>
    
    • 结果:

      在这里插入图片描述

4.5、注意
  • 变量会在模板开始时被创建;而不管 macro 指令放置在模板的什么位置。所以这样也可以:

    <#-- 调用指令 -->
    <@test/>
    
    <#-- 简单的自定义指令 -->
    <#macro test>
    	This is Test
    </#macro>
    
  • 如果宏定义被插在 include 指令中, 它们直到 FreeMarker 执行 include 指令时才会可用。

5、import

5.1、概念

​ 引入一个库。也就是说,它创建一个新的空命名空间, 然后在那个命名空间中执行给定 path 参数中的模板, 所以模板用变量(宏,函数等)填充命名空间。 然后使得新创建的命名空间对哈希表的调用者可用。 这个哈希表变量将会在命名空间中,由 import (就像你可以用 assign 指令来创建一样。) 的调用者被创建成一个普通变量,名字就是 hash 参数给定的。

5.2、写法
<#import path as hash>
  • path:模板的路径。 这是一个算作是字符串的表达式。(换句话说,它不是一个固定的字符串, 它可以是这样的一些东西,比如,profile.baseDir + "/menu.ftl"。)
  • hash: 访问命名空间的哈希表变量不带引号的名字。不是表达式。 (如果要引入动态创建的名字,那么就不得不使用 这个技巧。)
5.3、用法
  • 在controller写跳转f3.ftl页面的请求路径

    @RequestMapping("f3")
    public String test2(ModelMap map) {
      return "f3";
    }
    
  • 创建commons.ftl用于存放公共的自定义指令

  • 在测试页面中调用公共指令

    <#import "commons.ftl" as cm> <br/>
    <@cm.test/> <br/>
    <@cm.cfb/> <br/>
    <@cm.cfb02 num=8/>
    
    • 结果:

      在这里插入图片描述

6、include包含

6.1、概念

​ 你可以使用它在你的模板中插入另外一个 FreeMarker 模板文件 (由 path 参数指定)。 被包含模板的输出格式是在 include 标签出现的位置插入的。 被包含的文件和包含它的模板共享变量,就像是被复制粘贴进去的一样。 include 指令不能由被包含文件的内容所替代, 它只是当 FreeMarker 每次在模板处理期间到达 include 指令时处理被包含的文件。所以对于如果 includelist 循环之中的例子, 你可以为每个循环周期内指定不同的文件名。

6.2、写法
<#include path><#include path options>
  • path: 要包含文件的路径;一个算作是字符串的表达式。(用其他话说, 它不用是一个固定的字符串,它也可以是像 profile.baseDir + "/menu.ftl"这样的东西。)
  • options: 一个或多个这样的选项: encoding=encoding, parse=parse
  • encoding: 算作是字符串的表达式
  • parse: 算作是布尔值的表达式(为了向下兼容,也接受一部分字符串值)
  • ignore_missing: 算作是布尔值的表达式
6.3、用法
  • 创建.ftl、.html、.txt文件,里面输入任意内容。

  • 在测试页面输入指令测试

    <#-- 引用test.txt里面的内容 -->
    <#include "test.txt"> <br/>
      <#-- 引用test.html里面的内容 -->
    <#include "test.html"> <br/>
      <#-- 引用test.ftl里面的内容 -->
    <#include "test.ftl"> <br/>
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值