目录
- 1.FreeMarker说明
- 2.SpringBoot+FreeMarker快速搭建
- Pom文件
- application.properties文件
- Controller文件
- 目录结构
- 3.FreeMarker数据类型
- 3.1.布尔类型
- 3.2.数值类型
- 3.3.字符串类型
- 3.4.日期类型
- 3.5.空值类型
- 3.6.sequence类型
- 3.7.hash类型
- 4.FreeMarker指令
- assign自定义变量指令
- if/elseif/else逻辑判断指令
- list遍历指令
- macro自定义指令(宏)
- nested占位指令
- import导入指令
- include包含指令
1.FreeMarker说明
FreeMarker中文文档:http://freemarker.foofun.cn/index.html
学习视频:https://www.bilibili.com/video/BV1vq4y1p718
2.SpringBoot+FreeMarker快速搭建
参考文章:
(1)https://blog.csdn.net/xhf852963/article/details/116233053
(2)https://www.cnblogs.com/dw3306/p/9602139.html
(3)https://www.cnblogs.com/rainbowbridge/p/11410286.html
(4)https://blog.csdn.net/qq_46921028/article/details/130493378
Pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.asta</groupId>
<artifactId>freemaker-hello</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.4.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 添加freemarker的maven依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.properties文件
server.port=8080
#HttpServletRequest 的属性是否可以覆盖controller中model 的同名项
spring.freemarker.allow-request-override=false
#H ttp Session 的属性是否可以覆盖 controller model 的同名项
spring.freemarker.allow-session-override=false
#是否开启缓存
spring.freemarker.cache=false
#模板文件编码
spring.freemarker.charset=UTF-8
#是否检查模板位置
spring.freemarker.check-template-location=true
#Content-Type的值
spring.freemarker.content-type=text/html
#是否将HttpServletRequest中的属性添加到Model中
spring.freemarker.expose-request-attributes=false
#是否将HttpSession中的属性添加到Model
spring.freemarker.expose-session-attributes=false
#模板文件后缀
spring.freemarker.suffix=.ftl
#模板文件位置
spring.freemarker.template-loader-path=classpath:/templates/
Controller文件
package com.asta.controller;
import com.asta.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.util.*;
/**
* @Author:cs.cao
* @Date:2024/4/14 15:42
*/
@Controller
@RequestMapping("/freemarker")
public class HelloController {
@RequestMapping("/type")
public ModelAndView hello() {
String[] stars = new String[]{"周杰伦", "林俊杰", "陈奕迅", "五月天"};
List<String> cities = Arrays.asList("北京", "上海", "南京", "杭州");
List<User> userList = new ArrayList<>();
userList.add(new User(1, "zhangsan", 22));
userList.add(new User(2, "lisi", 23));
userList.add(new User(3, "wangwu", 18));
Map<String, Object> cityMap = new HashMap<>();
cityMap.put("BJ", "北京");
cityMap.put("SH", "上海");
cityMap.put("HZ", "杭州");
ModelAndView mv = new ModelAndView();
// boolean类型
mv.addObject("flag", true);
// 数值类型
mv.addObject("age", 18);
mv.addObject("salary", 100000);
mv.addObject("avg", 0.545);
// 字符串类型
mv.addObject("name", "cs.cao");
// 日期类型
mv.addObject("now", new Date());
// 空值类型
mv.addObject("nullValue", null);
// sequence类型
mv.addObject("stars", stars);
mv.addObject("cities", cities);
mv.addObject("userList", userList);
// hash类型
mv.addObject("cityMap", cityMap);
mv.setViewName("hello");
return mv;
}
}
目录结构
3.FreeMarker数据类型
FreeMarker模板中的数据类型有如下几种:
- 布尔型:等价于java中的Boolean类型,不同的是不能直接输出,可转换为字符串再输出。
- 日期型:等价于java中的Date类型,不同的是不能直接输出,需要转换成字符串再输出。
- 数值型:等价于java中的int,float,double等数值类型。有三种显示形式:数值型(默认)、货币型、百分比型。
- 字符型:等价于java中的字符串,有很多内置函数
- sequence类型:等价于java中的数组,list,set等集合类型。
- hash类型:等价于java中的Map类型。
3.1.布尔类型
<#--
boolean类型,需要转为字符串:
${flag?c}
${flag?string}
${flag?string("yes","no")}
-->
<h3>boolean类型:</h3>
${flag?c}<br/>
${flag?string}<br/>
${flag?string("yes","no")}<br/>
3.2.数值类型
<#--
数值类型,直接输出或转成字符串
1.转字符串
普通字符串:${num?c}
货币型字符串:${num?string.currency}
百分比型字符串:${num?string.percent}
2.保留浮点型数值指定小数位数(#表示一个小数位)
${num?string["0.##"]}
-->
<h3>数值类型:</h3>
${age}<br/>
${salary}<br/>
${salary?c}<br/>
${salary?string.currency}<br/>
${avg?string.percent}<br/>
${avg?string["0.##"]}<br/>
3.3.字符串类型
<#--
字符串类型:
1.截取字符串(左闭右开):${text?substring(start,end)}
2.首字母小写输出:${text?uncap_first}
3.首字母大写输出:${text?cap_first}
4.字母转小写输出:${text?lower_case}
5.字母转大写输出:${text?upper_case}
6.获取字符串长度:${text?length}
7.是否以指定字符开头(boolean类型):${text?starts_with("xx")?string}
8.是否以指定字符结尾(boolean类型):${text?ends_with("xx")?string}
9.获取指定字符的索引:${text?index_of("xx")}
10.去除字符串前后空格:${text?trim}
11.替换指定字符串:${text?replace("xx","xxx")}
-->
<h3>字符串类型:</h3>
${name?substring(1,4)}<br/>
${name?uncap_first}<br/>
${name?cap_first}<br/>
${name?lower_case}<br/>
${name?upper_case}<br/>
${name?length}<br/>
${name?starts_with("c")?string}<br/>
${name?ends_with("o")?string}<br/>
${name?index_of("cao")}<br/>
${name?trim}<br/>
${name?replace(".","-")}<br/>
3.4.日期类型
<#--
日期类型,需要先转成日期型或字符串:
1.年月日:${now?date}
2.时分秒:${now?time}
3.年月日时分秒:${now?datetime}
4.指定格式:${now?string("自定义格式")}
-->
<h3>日期类型:</h3>
${now?date}<br/>
${now?time}<br/>
${now?datetime}<br/>
${now?string("yyyy年MM月dd日 HH:mm:ss")}<br/>
3.5.空值类型
Freemarker的变量必须赋值,否则就会抛出异常。对于FreeMarker来说,null值和不存在的变量是完全一样的,因为FreeMarker无法理解null值。
<#--
空值类型:
Freemarker的变量必须赋值,否则就会抛出异常。对于FreeMarker来说,null值和不存在的变量是完全一样的,因为FreeMarker无法理解null值。
FreeMarker提供两个运算符来避免空值:
1.!:指定缺失变量的默认值
${value!}:如果value值为空,则默认值为空字符串。
$(value!"默认值"):如果value值为空,则默认值为字符串"默认值"。
2.??:判断变量是否存在
如果变量存在返回true,否则返回false。
${(value??)?string}
-->
<h3>空值类型:</h3>
${nullValue!}<br/>
${nullValue!"空"}<br/>
${(nullValue??)?string}<br/>
3.6.sequence类型
<#--
sequence类型:序列类型(数组、List、Set)
1.通过list执行输出序列:<#list 序列名 as 元素名>${名称}</#list>
2.获取序列的长度:${序列名?size}
3.获取序列元素的下标:${序列名?index}
4.获取第一个元素:${序列名?first}
5.获取最后一个元素:${序列名?last}
6.倒序输出:序列名?reverse
7.升序输出:序列名?sort
9.降序输出:序列名?sort?reverse
10.指定字段名排序:序列名?sort_by("字段名")
注:一般是JavaBean集合,对应的字段名需要提供get方法。
-->
<h3>sequence序列类型:</h3>
<#list stars as star>
下标:${star?index}--名字:${star}<br/>
</#list>
数组的长度:${stars?size}<br/>
第一个元素:${stars?first}<br/>
最后一个元素:${stars?last}<br/>
<#list cities?reverse as city>
下标:${city?index}--城市:${city}<br/>
</#list>
<#list cities?sort as city>
下标:${city?index}--城市:${city}<br/>
</#list>
<#list cities?sort?reverse as city>
下标:${city?index}--城市:${city}<br/>
</#list>
<#list userList?sort_by("age") as user>
序号:${user.index}--名称:${user.name}--年龄:${user.age}<br/>
</#list>
3.7.hash类型
<#--
hash类型(Map):
1.key遍历输出:
<#list hash?keys as key>
${key} -- ${hash[key]}
</#list>
2.value遍历输出:
<#list hash?values as value>
${value}
</#list>
-->
<h3>hash类型:</h3>
<#list cityMap?keys as key>
key:${key}--城市:${cityMap[key]}<br/>
</#list>
<#list cityMap?values as value>
城市:${value}<br/>
</#list>
4.FreeMarker指令
assign自定义变量指令
使用assign
指令可以创建一个新的变量,或者替换一个已经存在的变量。
<#--
assign自定义变量指令
语法:
<#assign 变量名=值>
<#assign 变量名=值 变量名=值> (定义多个变量)
-->
<h3>assign自定义变量指令:</h3>
<#assign num=1 names=["zhangsan","lisi","wangwu"]>
${num} -- ${names?join(",")}
if/elseif/else逻辑判断指令
可以使用if-elseif-else
指令来判断是否满足某些条件
<#--
if/elseif/else逻辑判断指令:
语法:
<#if condition>
...
<#elseif condition2>
...
<#elseif condition3>
...
<#else>
...
</#if>
注意:
1.condition、condition2等:将被计算成布尔值的表达式
2.elseif和else指令是可选的。
-->
<h3>if/elseif/else逻辑判断指令:</h3>
<#assign score=80>
<#if score < 60 >
加油
<#elseif score = 60 >
及格万岁
<#elseif score gt 60 && score lt 80 >
小伙子还不错
<#else>
厉害
</#if>
<br/>
<#assign list="">
<#if list?? >
数据存在
<#else>
数据不存在
</#if>
<br/>
list遍历指令
可以使用list
指令对序列进行遍历
<#--
list遍历指令:
格式1:
<#list sequence as item>
...
</#list>
格式2:
<#list sequence as item>
...
<#else>
当没有选项时执行else指令
</#list>
注:
1.else部分是可选的
2.sequence:想要迭代的项,可以是序列或集合的表达式
3.item:循环变量的名称
4.当没有迭代项时,才使用else指令,可以输出一些特殊的内容而不只是空在那里。
-->
<#assign nameList=[]>
<#--判断数据部位空,再执行遍历(如果序列不存在时直接遍历会报错)-->
<#if nameList??>
<#list nameList?sort?reverse as name>
下标:${name?index}--名称:${name}<br/>
<#else>
哈哈空的
</#list>
</#if>
<br/>
macro自定义指令(宏)
可以使用macro
指令自定义一些指令
<#--
macro自定义指令(宏):
1.基本使用
格式:
<#macro 指令名>
指令内容
</#macro>
使用:
<@指令名></@指令名>
2.有参数的自定义指令
格式:
<#macro 指令名 参数名1 参数名2>
指令内容
</#macro>
使用:
<@指令名 参数名1=参数值1 参数名2=参数值2></@指令名>
注:
1.指令可以被多次使用
2.自定义指令中可以包含字符串,也可以包含内置指令
-->
<h3>macro自定义指令:</h3>
<#--自定义指令-->
<#macro address>
@1995-2024 The FreeMarker Project.
</#macro>
<#--使用指令-->
<@address></@address><br/>
<@address></@address><br/>
<#--自定义指令(含参数)-->
<#macro queryUserByParams uname uage>
通过多个餐宿查询用户信息 - ${uname} - ${uage}
</#macro>
<@queryUserByParams uname="zhangsan" uage="18"></@queryUserByParams><br/>
<#--自定义指令(其中包含内置指令)-->
<#macro cfg>
<#list 1..9 as i>
<#list 1..i as j>
${i}*${j}=${i*j}
</#list>
<br/>
</#list>
<br/>
</#macro>
<@cfg></@cfg><br/>
nested占位指令
nested
指令执行自定义指令开始和结束标签中间的模板片段。嵌套的片段可以包含模板中任意合法的内容。
<#--
nested占位指令:
nested相当于占位符,一般结合macro指令一起使用。
可以将自定义指令中的内容通过nested指令占位,当使用自定义指令时会将占位内容显示。
-->
<h3>nested占位指令:</h3>
<#macro testNested>
测试nested:
<#nested>
<#nested>
</#macro>
<#--使用指令-->
<@testNested><p>占位的内容</p></@testNested><br/>
import导入指令
import
指令可以引入一个库。也就是说,它创建一个新的命名空间,然后在那个命名空间中执行给定路径的模板。可以使用引入的空间中的指令。
commons.ftl文件
<#macro cfg>
<#list 1..9 as i>
<#list 1..i as j>
${i}*${j}=${i*j}
</#list>
<br/>
</#list>
<br/>
</#macro>
在其他ftl页面中通过import导入commons.ftl的命名空间,使用该命名空间的指令。
<#--
import导入指令:
导入命名空间:<#import "ftl文件" as 命名空间>
使用命名空间中的指令:<@命名空间.指令></@命名空间.指令>
-->
<h3>import导入指令:</h3>
<#import "commons.ftl" as common>
<@common.cfg></@common.cfg><br/>
include包含指令
可以使用include
指令在你的模板中插入另一个FreeMarker模板文件。被包含模板的输出格式是在include标签出现的位置插入的。被包含的文件和包含它的模板共享变量,就像是被复制粘贴进去的一样。
<#--
include包含指令:
用来引入其他页面文件(如txt、ftl、html等)
-->
<h3>include包含指令:</h3>
<#include "test.txt">
<#include "test.ftl">
<#include "test.html">