在项目开发中,对于一些访问量较大的页面,可以提前基于数据生成静态页面,当数据有变化时再重新生成并更新静态页面,这样可以减轻数据库压力,提高网站的并发访问效率。常用的技术就是使用 FreeMarker 模板引擎,它是一款高性能的,基于模板和数据, 生成输出文本的通用工具。本篇博客基于 FreeMarker 的常用指令,介绍如何生成静态页面,在博客最后会提供源代码下载。
FreeMarker 的官网地址是:https://freemarker.apache.org/index.html
一、搭建工程
新建一个 springboot 工程,名称为 springboot_freemarker,结构如下:
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.jobs</groupId>
<artifactId>springboot_freemarker</artifactId>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
</parent>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引入 freemarker 的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.4.5</version>
</plugin>
</plugins>
</build>
</project>
最主要的是引入了 spring-boot-starter-freemarker 依赖包,然后配置文件如下:
server:
port: 8080
spring:
freemarker:
# 关闭模板缓存
cache: false
# 设置模板文件的后缀名,默认值是 .ftlh
suffix: .ftlh
# 设置模板的目录,默认值是 classpath:/templates/
template-loader-path: classpath:/templates/
这里使用的都是 FreeMarker 的默认配置,默认的模板文件存放位置是 resources 下的 templates 目录,默认的模板文件的后缀名是 .ftlh,默认也关闭缓存。在使用 FreeMarker 生成静态页面之前,我们最好能够通过浏览器访问页面,查看数据和模板结合的效果。由于 SpringMvc 默认就支持 FreeMarker 视图格式,因此本篇博客的 Demo 提供 Controller 访问地址,通过浏览器可以实际效果。本篇博客的 Demo 在测试类 FreemarkTest 中实现了生成静态页面的代码。
二、代码详细介绍
Controller 类中的代码与 FreeMarkerTest 类中的代码一样,这里就不列出了,为了减少篇幅冗余,这里直接列出生成静态页面的代码,另外在 Freemarker 模板里面,注释也很详细,相信大家应该能够看懂。这里只列出常用的 FreeMarker 指令,如果想了解更多指令,可以参考官网。
首先看一下 Demo 中的实体类 Employee 内容:
package com.jobs.pojo;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class Employee {
//员工姓名
private String name;
//员工年龄
private Integer age;
//员工部门
private String depart;
}
然后看一下 Sample.ftlh 模板的内容,这个里面使用了一些简单的指令:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>简单用法展示</title>
</head>
<body>
<b>普通文本展示:</b><br/>
<#--【变量!默认值】表示如果变量为 null,则使用默认值-->
员工姓名为:${name!'name 为null,这里显示默认文本'}<br/>
<hr>
<b>对象实例中的数据展示:</b><br/>
<#--【(变量.属性)!默认值】表示如果变量为 null 或者变量的属性为 null,则使用默认值-->
员工姓名:${(emp.name)!'姓名默认值'}<br/>
员工年龄:${(emp.age)!38}<br/>
员工部门:${(emp.depart)!'部门默认值'}<br/>
<hr>
<b>数字展示:</b><br/>
默认数字展示带有逗号:${num}<br/>
<#--【变量?c】如果变量是数字,可以取消显示数字中的逗号-->
取消数字中的逗号:${num?c}<br/>
<hr>
<b>日期时间展示展示:</b><br/>
日期展示:${today?date}<br/>
时间展示:${today?time}<br/>
日期时间展示:${today?datetime}<br/>
自定义展示:${today?string("yyyy年MM月dd日 HH时mm分ss秒")}<br/>
<hr>
<b>json字符串转对象:</b><br/>
<#--【变量?eval】如果变量是 json 字符串,可以转换为对象-->
<#assign emp="${jsonStr}"?eval/>
json中的姓名:${(emp.name)!'姓名默认值'}<br/>
json中的年龄:${(emp.age)!0}<br/>
</body>
</html>
然后再看一下 list_map.flth 模板,这里面使用了 list 集合和 map 集合的一些常用指令:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>列表数据和map数据的展示</title>
</head>
<body>
<#-- list 数据的展示 -->
<b>展示 list 中的数据:</b><br>
<table border="1" cellpadding="1" cellspacing="1">
<tr>
<td>序号</td>
<td>姓名</td>
<td>年龄</td>
<td>部门</td>
</tr>
<#--【变量??】表示判断变量是否为 null,如果不为 null 则执行下面的代码-->
<#if empList??>
<#--list【变量】as【变量】表示循环遍历list中的每一条数据-->
<#list empList as emp>
<#if emp_index%2=0>
<tr style="background-color: lightyellow">
<td>${emp_index + 1}</td>
<td>${emp.name}</td>
<td>${emp.age}</td>
<td>${emp.depart}</td>
</tr>
<#else>
<tr>
<td>${emp_index + 1}</td>
<td>${emp.name}</td>
<td>${emp.age}</td>
<td>${emp.depart}</td>
</tr>
</#if>
</#list>
</#if>
</table>
<br>
<#--list【变量】?size 表示获取列表的大小-->
<#if empList??>
list集合的大小为:${empList?size}
</#if>
<hr>
<#-- Map 数据的展示 -->
<b>展示 map 中的数据:</b><br/>
通过 map['keyname'].property 获取数据:<br/>
姓名:${empMap['emp1'].name}<br/>
年龄:${empMap['emp1'].age}<br/>
部门:${empMap['emp1'].depart}<br/>
<br/>
通过map.keyname.property 获取数据:<br/>
姓名:${empMap.emp2.name}<br/>
年龄:${empMap.emp2.age}<br/>
部门:${empMap.emp2.depart}<br/>
<br/>
遍历 map 中的数据:
<table border="1" cellpadding="1" cellspacing="1">
<tr>
<td>序号</td>
<td>姓名</td>
<td>年龄</td>
<td>员工</td>
</tr>
<#if empMap??>
<#list empMap?keys as key>
<tr>
<td>${key_index + 1}</td>
<td>${empMap[key].name}</td>
<td>${empMap[key].age}</td>
<td>${empMap[key].depart}</td>
</tr>
</#list>
</#if>
</table>
<br/>
<#if empMap??>
map集合的大小为:${empMap?keys?size}
</#if>
</body>
</html>
最后我们在 FreeMarkerTest 类中,自己造一些数据,然后使用上面的 2 个模板生成静态页面:
package com.jobs;
import com.jobs.pojo.Employee;
import freemarker.template.Template;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.FileWriter;
import java.util.*;
@SpringBootTest
public class FreemarkerTest {
@Autowired
private freemarker.template.Configuration configuration;
@Test
void createSampleHtmlPage() throws Exception {
//获取模板
Template template = configuration.getTemplate("sample.ftlh");
//获取数据
Map data = getSampleData();
//生成静态页面
template.process(data, new FileWriter("d:/sample.html"));
}
@Test
void createListMapPage() throws Exception {
//获取模板
Template template = configuration.getTemplate("list_map.ftlh");
//获取数据
Map data = getListMapData();
//生成静态页面
template.process(data, new FileWriter("d:/listmap.html"));
}
Map getSampleData() {
Map<String, Object> map = new HashMap<>();
//普通文本展示
map.put("name", "乔豆豆");
//对象实例中的数据展示
Employee emp = new Employee().setName("任肥肥")
.setAge(36).setDepart("技术部");
map.put("emp", emp);
//数字展示
map.put("num", 123456789L);
//日期时间展示展示
map.put("today", new Date());
//json字符串转对象
String json = "{'name':'侯胖胖','age':38}";
map.put("jsonStr", json);
return map;
}
Map getListMapData() {
Map<String, Object> map = new HashMap<>();
Employee emp1 = new Employee().setName("任肥肥").setAge(36).setDepart("运营部");
Employee emp2 = new Employee().setName("侯胖胖").setAge(38).setDepart("技术部");
Employee emp3 = new Employee().setName("乔豆豆").setAge(40).setDepart("销售部");
//添加到 list 中
List<Employee> empList = new ArrayList<>();
empList.add(emp1);
empList.add(emp2);
empList.add(emp3);
map.put("empList", empList);
//添加到 map 中
Map<String, Employee> empMap = new HashMap<>();
empMap.put("emp1", emp1);
empMap.put("emp2", emp2);
empMap.put("emp3", emp3);
map.put("empMap", empMap);
return map;
}
}
三、实际效果
运行 2 个测试方法,代码中是将静态页面生成到了 d 盘目录中。
其中 createSampleHtmlPage 测试方法,生成的静态页面效果如下:
测试方法 createListMapPage 生成的静态页面,效果如下:
本篇博客的源代码下载地址为:https://files.cnblogs.com/files/blogs/699532/springboot_freemarker.zip