网页右边,向下滑有目录索引,可以根据标题跳转到你想看的内容 |
如果右边没有就找找左边 |
一、环境搭建
- 创建工程,引入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.12.RELEASE</version>
</parent>
<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>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
- 配置文件
server:
port: 8088 #服务端口
spring:
application:
name: test‐freemarker #指定服务名
freemarker:
cache: false #关闭模板缓存,方便测试
settings:
template_update_delay: 0 #检查模板更新延迟时间,设置为0表示立即检查,如果时间大于0会有缓存不方便 进行模板测试
- 日志文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--定义日志文件的存储地址,使用绝对路径-->
<property name="LOG_HOME" value="d:/logs"/>
<!-- Console 输出设置 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>utf8</charset>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<fileNamePattern>${LOG_HOME}/xc.%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 异步输出 -->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>512</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="FILE"/>
</appender>
<logger name="org.apache.ibatis.cache.decorators.LoggingCache" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
</logger>
<logger name="org.springframework.boot" level="DEBUG"/>
<root level="info">
<!--<appender-ref ref="ASYNC"/>-->
<appender-ref ref="FILE"/>
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
- 启动类
- 实体类
package com.yzpnb.freemarker_test.model;
import lombok.Data;
import lombok.ToString;
import java.util.Date;
import java.util.List;
@Data
@ToString
@AllArgsConstructor
public class Student {
private String name;
private int age;
private Date birthday;
private Float money;//钱包
private List<Student> friends;//朋友列表
private Student bestFriend;//最好的朋友
}
- freemarker模板文件(resources下创建templates文件夹,文件夹下创建test1.ftl模板文件)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HelloWorld!</title>
</head>
<body>
Hello ${name}!
</body>
</html>
- controller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
@RequestMapping("/freemarker")
@Controller
public class FreemarkerController {
// @Autowired
// private RestTemplate restTemplate;
@RequestMapping("/test1")
public String freemarker(Map<String,Object> map){
map.put("name","yzpnb");
return "test1";
}
}
- 启动工程测试
二、核心指令
Freemarker静态化依赖数据模型和模板,下边定义数据模型,下边方法形参map即为freemarker静态化所需要的数据模型,在map中填充数据 |
@RequestMapping("/test1")
public String freemarker(Map<String,Object> map){
//创建两个学生实例
Student stu1 = new Student("小明",18,new Date(),1000.86f,null,null);
ArrayList<Student> friends = new ArrayList<>();
friends.add(stu1);
Student stu2 = new Student("小红",19,new Date(),200.1f,friends,stu1);
//创建一个集合,添加两个学生,用于测试集合数据
ArrayList<Student> students = new ArrayList<>();
students.add(stu1);
students.add(stu2);
//创建map,添加两个学生,用于测试map数据
HashMap<String, Student> stringStudentHashMap = new HashMap<>();
stringStudentHashMap.put("stu1",stu1);
stringStudentHashMap.put("stu2",stu2);
//将上面创建的放到数据模型中
map.put("name","yzpnb");
map.put("stus",students);
map.put("stu1",stu1);
map.put("stuMap",stringStudentHashMap);
return "test1";
}
freemarker的注释等内容 |
- 注释,<#–注释内容–>
- 插值,${变量},最终展示的是变量值内容
- FTL指令,与HTML标签类似,名字前加#区分,标签中的表达式和逻辑,都会解析
- 文本,直接输出
1. List指令
1. 遍历List
2. 测试
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HelloWorld!</title>
</head>
<body>
Hello ${name}!
<table>
<tr>
<td>序号</td>
<td>姓名</td>
<td>年龄</td>
<td>钱包</td>
</tr>
<#list stus as stu><#--list指令,格式<#list list集合 as 变量>,变量会依次取出list集合中的值-->
<tr>
<td>${stu_index + 1}</td><#--插值表达式,解析其中变量和表达式,stu_index表示下标-->
<td>${stu.name}</td>
<td>${stu.age}</td>
<td>${stu.money}</td>
</tr>
</#list>
</table>
</body>
</html>
2. 遍历map
<body>
Hello ${name}!
<table>
直接通过插值表达式输出map集合中stu1的学生信息<br/>
姓名:${stuMap['stu1'].name}<br/>
年龄:${stuMap['stu1'].age}<br/>
<br/><br/>
通过.的形式输出stu2<br/>
姓名:${stuMap.stu2.name}<br/>
年龄:${stuMap.stu2.age}<br/>
<br/><br/>
遍历map数据:输出map集合中学生信息<br/>
<tr>
<td>序号</td>
<td>姓名</td>
<td>年龄</td>
<td>钱包</td>
</tr>
<#list stuMap?keys as k><#--stuMap?keys 表示依次遍历stuMap的key值,保存到k中-->
<tr>
<td>${k_index + 1}</td>
<td>${stuMap[k].name}</td>
<td>${stuMap[k].age}</td>
<td>${stuMap[k].money}</td>
</tr>
</#list>
</table>
</body>
2. if指令
<body>
Hello ${name}!
<table>
<tr>
<td>姓名</td>
<td>年龄</td>
<td>钱包</td>
</tr>
<#list stus as stu>
<tr>
<#--如果当前遍历的name是小明,那么输出为红色
style="background-color: red"生效,否则不生效
if指令,条件成立,解析里面内容,否则不解析
-->
<td <#if stu.name == '小明'>style="background-color: red"</#if>>
${stu.name}
</td>
<td>${stu.age}</td>
<td>${stu.money}</td>
</tr>
</#list>
</table>
</body>
3. 其它指令
1. 运算符
+ - * / %
:算数运算符都支持&&(与) ||(或) !(非)
:逻辑运算符,只能用于布尔值=、==、!=、>(使用gt也可以)、>=(gte)、<(lt)、<=(lte)
:比较运算符,尽量使用gt而不使用>,因为会解析成标签,可以使用括号解决问题,比如<#if (x>y)>。=和!=可用于字符串,数值和日期,但是两边类型必须相同,freemarker是精确比较,‘x’、‘X’、'x '都不相等。另外,除去=和!=两个运算符外,其它运算符不能作用于字符串
2. 空值处理
- 判断某变量是否存在使用??,用法为
变量??
,如果存在返回true,否则返回false,例如,放在stus为空报错可以加上如下判断
<#if stus??>
<#list stus as stu>
<tr>
<#--如果当前遍历的name是小明,那么输出为红色
style="background-color: red"生效,否则不生效
if指令,条件成立,解析里面内容,否则不解析
-->
<td <#if stu.name == '小明'>style="background-color: red"</#if>>
${stu.name}
</td>
<td>${stu.age}</td>
<td>${stu.money}</td>
</tr>
</#list>
</#if>
- 确实变量默认使用"!",使用!要指定一个默认值,当变量为空时,显示默认值,例如$ {name!’’}表示如果name为空显示空字符串,再比如,$ {(stu.bestFriend.name)!‘null’},表示stu或bestFriend或name为空,默认显示null字符串。另外,(stu.bestFriend.name)这样的嵌套对象最后使用括号括起来
3. 内建函数
语法:变量+?+函数名称 |
<body>
stus集合的大小为:${stus?size}<br/>
显示stu1的生日,格式<br/>
显示年月日:${stu1.birthday?date}<br/>
显示时分秒:${stu1.birthday?time}<br/>
显示日期+时间:${stu1.birthday?datetime}<br/>
自定义格式化:${stu1.birthday?string("yyyy年MM月")}<br/>
freemarker默认显示数值,为每三位使用逗号分隔:${stu1.money}<br/>
如果不想以逗号分隔,可以使用内建函数c:${stu1.money?c}<br/>
使用assign标签定义变量text:<br/>
<#assign text="{'bank':'工商银行','account':'10101920201928212'}"/>
${text}
将json字符串变为对象,保存到data变量中<br>
<#assign data=text?eval/>
开户行:${data.bank}<br/>
账号:${data.account}<br/>
</body>
三、生成静态化页面
1. 通过模板文件
在controller层,添加一个方法
@RequestMapping("/test2")
public String testGenerateHtml(Map<String,Object> map) throws IOException, TemplateException {
//1.数据模型
//创建两个学生实例
Student stu1 = new Student("小明",18,new Date(),1000.86f,null,null);
ArrayList<Student> friends = new ArrayList<>();
friends.add(stu1);
Student stu2 = new Student("小红",19,new Date(),200.1f,friends,stu1);
//创建一个集合,添加两个学生,用于测试集合数据
ArrayList<Student> students = new ArrayList<>();
students.add(stu1);
students.add(stu2);
//将上面创建的放到数据模型中
map.put("stus",students);
map.put("stu1",stu1);
//2.创建配置类
Configuration configuration = new Configuration(Configuration.getVersion());
//3.设置模板路径
String path = this.getClass().getResource("/").getPath();
configuration.setDirectoryForTemplateLoading(new File(path+"templates/"));
//4.设置字符集
configuration.setDefaultEncoding("utf-8");
//5.加载模板
Template template = configuration.getTemplate("test1.ftl");
//6.静态化
String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
//7.静态化内容
System.out.println(content);
InputStream inputStream = IOUtils.toInputStream(content);
//8.输出文件
FileOutputStream fileOutputStream = new FileOutputStream(new File("D:/test1.html"));
int copy = IOUtils.copy(inputStream, fileOutputStream);
return "test1";
}
2. 通过模板字符串静态化
@RequestMapping("/test3")
public String testGenerateHtmlByString(Map<String,Object> map) throws IOException, TemplateException {
//1.数据模型
//创建两个学生实例
Student stu1 = new Student("小明",18,new Date(),1000.86f,null,null);
ArrayList<Student> friends = new ArrayList<>();
friends.add(stu1);
Student stu2 = new Student("小红",19,new Date(),200.1f,friends,stu1);
//创建一个集合,添加两个学生,用于测试集合数据
ArrayList<Student> students = new ArrayList<>();
students.add(stu1);
students.add(stu2);
//将上面创建的放到数据模型中
map.put("stus",students);
map.put("stu1",stu1);
//2.创建配置类
Configuration configuration = new Configuration(Configuration.getVersion());
//3.设置模版内容
String templateString ="<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>HelloWorld!</title>\n" +
"</head>\n" +
"<body>\n" +
" stus集合的大小为:${stus?size}<br/>\n" +
" 显示stu1的生日,格式<br/>\n" +
" 显示年月日:${stu1.birthday?date}<br/>\n" +
" 显示时分秒:${stu1.birthday?time}<br/>\n" +
" 显示日期+时间:${stu1.birthday?datetime}<br/>\n" +
" 自定义格式化:${stu1.birthday?string(\"yyyy年MM月\")}<br/>\n" +
" freemarker默认显示数值,为每三位使用逗号分隔:${stu1.money}<br/>\n" +
" 如果不想以逗号分隔,可以使用内建函数c:${stu1.money?c}<br/>\n" +
"\n" +
" 使用assign标签定义变量text:<br/>\n" +
" <#assign text=\"{'bank':'工商银行','account':'10101920201928212'}\"/>\n" +
" ${text}\n" +
" 将json字符串变为对象,保存到data变量中<br>\n" +
" <#assign data=text?eval/>\n" +
" 开户行:${data.bank}<br/>\n" +
" 账号:${data.account}<br/>\n" +
"</body>\n" +
"</html>";
//4.模板加载器
StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
stringTemplateLoader.putTemplate("template",templateString);
configuration.setTemplateLoader(stringTemplateLoader);
//5.获取到模板
Template template = configuration.getTemplate("template", "utf-8");
//6.静态化
String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
//7.静态化内容
System.out.println(content);
InputStream inputStream = IOUtils.toInputStream(content);
//8.输出文件
FileOutputStream fileOutputStream = new FileOutputStream(new File("D:/test3.html"));
int copy = IOUtils.copy(inputStream, fileOutputStream);
return "test1";
}