前言
我们在使用购物网站的时候,会选择相应的商品点击查看详情,其实会发现每件商品的商品详情页面都是差不多的,除了一些数据外,其余结构布局都是一模一样的,那么是为每件商品都写一个详情页面吗?很显然这是不可能的,数以百万千万的商品都写页面,会把人逼疯。既然结构布局都一样,只是数据不同,那么有什么办法解决这种情况吗?使用页面静态技术可以很完美的解决。
1、什么是页面静态化
先来了解一下静态化技术:所谓的静态化技术就是 将查询好的数据填充到模板中,然后将生成的html写入到指定的文件中。页面静态化就是使用静态化技术生成html页面。
2、为什么要进行页面静态化
像电商网站的商品详细页来说,至少几百万个商品,每个商品又有大量的信息,这样的情况同样也适用于使用网页静态化来解决。页面静态化的好处如下:
- 静态页面相对于动态页面更容易被搜索引擎收录。
- 访问静态页面不需要经过程序处理,因此可以提高运行速度。
- 减轻服务器负担。
- HTML页面不会受Asp相关漏洞的影响。
网页静态化技术是为了减轻数据库的访问压力,比较适合大规模且相对变化不太频繁的数据。另外网页静态化还有利于SEO。
3、如何进行页面静态化
一个页面等于模板加数据。页面静态化就是将页面模板和数据通过技术手段将二者合二为一,生成一个html网页文件。因此,我们需要获取模板,然后获取数据模型,那么模板+数据模型就可以生成一个html页面了。下面以Freemarker作为模板来实现页面静态化过程。
4、使用Freemarker进行页面静态化
(1)准备模板
模板一般由我们根据数据模型的结构来进行编写的,模板只有一个,但是数据模型的不同,那么按照模型+数据的组合可以产生不同的html页面。
将模板放在test包下的classpath下的templates文件夹下,那么我就用这个test.ftl模板来进行测试了。
模板内容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello</title>
</head>
<body>
Hello ${name}!
<br>
<br>
集合中的学生个数:${stus?size}人
<table style="font-size:20px;font-weight:bolder;">
<tr>
<td>序号</td>
<td>姓名</td>
<td>年龄</td>
<td>钱包</td>
</tr>
<!-- 遍历List -->
<!-- 判断为空 -->
<#if stus??>
<#list stus as stu>
<tr <#if stu.name=='落落'>style="color:orange;"</#if>>
<td>${stu_index+1}</td>
<td <#if stu.age gt 17>style="background:pink;"</#if>>${stu.name}</td>
<td <#if stu.age gt 17>style="background:pink;"</#if>>${stu.age}</td>
<td>${stu.money}</td>
</tr>
</#list>
</#if>
</table>
<br><br>
输出stu0学生信息:<br>
姓名:${(stuMap['stu0'].name)!'对象不存在'}<br>
年龄:${(stuMap['stu0'].age)!'对象不存在'}<br>
钱包:${(stuMap['stu0'].money)!'对象不存在'}<br>
<hr>
输出stu2学生信息:<br>
姓名:${(stuMap.stu2.name)!'对象不存在'}<br>
年龄:${(stuMap.stu2.age)!'对象不存在'}<br>
钱包:${(stuMap.stu2.money)!'对象不存在'}<br>
生日:${(stuMap.stu2.birthday?string("yyyy年MM月dd日"))!'对象不存在'}<br>
账户余额:${account?c}
<hr>
遍历Map中全部学生信息:<br>
<table>
<tr>
<td>序号</td>
<td>姓名</td>
<td>年龄</td>
<td>钱包</td>
</tr>
<!-- 遍历出map中的全部key -->
<#list stuMap?keys as k>
<tr>
<!-- 通过map的key来取值 -->
<td>${k_index+1}</td>
<td>${stuMap[k].name}</td>
<td>${stuMap[k].age}</td>
<td>${stuMap[k].money}</td>
</tr>
</#list>
</table>
<hr>
json字符串转为对象:
<#assign text="{
'bank':'建设银行',
'name':'老云',
'tel':'124523431',
'money':'9000.7'
}"/>
<#assign data=text?eval/>
开户行:${data.bank}<br>
客户名称:${data.name}<br>
联系方式:${data.tel}<br>
账户余额:${data.money}
</body>
</html>
(2)pojo
实体类如下:
public class Student {
@Getter
@Setter
private String name;//姓名
@Getter
@Setter
private int age;//年龄
@Getter
@Setter
private Date birthday;//生日
@Getter
@Setter
private Float money;//工资
@Getter
@Setter
private List<Student> friends;//朋友列表
@Getter
@Setter
private Student bestFriend;//最好的朋友
}
(3)yml配置
## freemarker模板配置
freemarker:
cache: false ##关闭缓存
settings:
template_update_delay: 0 # 检查模板更新时间
这里就简单配置了。
(4)pom依赖
引入freemarker的依赖:
<!-- freemarker模板依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
(5)测试
这里我直接在测试包下写了,如下:
@SpringBootTest
public class TestFreemarker {
//测试基于ftl模板生成html文件
@Test
public void testGenerateHtml() throws Exception {
//定义配置类对象
Configuration configuration = new Configuration(Configuration.getVersion());
//获取classpath路径
String classpath = this.getClass().getResource("/").getPath();
//模板文件所在目录
File file = new File(classpath + "/templates/");
//加载模板所在目录
configuration.setDirectoryForTemplateLoading(file);
//获取配置类对象获取模板
Template template = configuration.getTemplate("test.ftl");
//获取模型数据
Map map = this.getMap();
//进行静态化,得到字符串
String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
//将字符串转为输入流
InputStream inputStream = IOUtils.toInputStream(content);
//输入流对象
OutputStream outputStream = new FileOutputStream(new File("d:/test.html"));
//流复制
IOUtils.copy(inputStream, outputStream);
//关闭流
outputStream.close();
inputStream.close();
System.out.println("文件已生成!");
}
//模型数据用静态数据来代替
public Map getMap() {
Map map = new HashMap<>();
map.put("name", "陈长生");
//List数据
List<Student> stus = new ArrayList<>();
Student stu0 = new Student();
stu0.setName("陈长生");
stu0.setAge(19);
stu0.setMoney(3000.5f);
stu0.setBirthday(new Date());
Student stu3 = new Student();
stu3.setName("徐有容");
stu3.setAge(18);
stu3.setMoney(10000.5f);
stu3.setBirthday(new Date());
Student stu2 = new Student();
stu2.setName("落落");
stu2.setAge(17);
stu2.setMoney(5030.5f);
stu2.setBirthday(new Date());
List<Student> frieList = new ArrayList<>();
frieList.add(stu0);
frieList.add(stu3);
stu2.setFriends(frieList);// 设置好友列表
stu2.setBestFriend(stu0);// 设置最好的朋友
stus.add(stu0);
stus.add(stu2);
stus.add(stu3);
// 存到数据模型中
map.put("stus", stus);
//Map数据
Map <String,Student> stuMap = new HashMap<>();
stuMap.put("stu0", stu0);
stuMap.put("stu2", stu2);
stuMap.put("stu3", stu3);
map.put("stuMap", stuMap);
map.put("account",45243243);
return map;
}
}
运行这个测试方法,控制台输出如下:
那么这个方法run成功了,去d盘根路径查看:
查看html内容:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello</title>
</head>
<body>
Hello 陈长生!
<br>
<br>
集合中的学生个数:3人
<table style="font-size:20px;font-weight:bolder;">
<tr>
<td>序号</td>
<td>姓名</td>
<td>年龄</td>
<td>钱包</td>
</tr>
<!-- 遍历List -->
<!-- 判断为空 -->
<tr >
<td>1</td>
<td style="background:pink;">陈长生</td>
<td style="background:pink;">19</td>
<td>3,000.5</td>
</tr>
<tr style="color:orange;">
<td>2</td>
<td >落落</td>
<td >17</td>
<td>5,030.5</td>
</tr>
<tr >
<td>3</td>
<td style="background:pink;">徐有容</td>
<td style="background:pink;">18</td>
<td>10,000.5</td>
</tr>
</table>
<br><br>
输出stu0学生信息:<br>
姓名:陈长生<br>
年龄:19<br>
钱包:3,000.5<br>
<hr>
输出stu2学生信息:<br>
姓名:落落<br>
年龄:17<br>
钱包:5,030.5<br>
生日:2020年12月24日<br>
账户余额:45243243
<hr>
遍历Map中全部学生信息:<br>
<table>
<tr>
<td>序号</td>
<td>姓名</td>
<td>年龄</td>
<td>钱包</td>
</tr>
<!-- 遍历出map中的全部key -->
<tr>
<!-- 通过map的key来取值 -->
<td>1</td>
<td>落落</td>
<td>17</td>
<td>5,030.5</td>
</tr>
<tr>
<!-- 通过map的key来取值 -->
<td>2</td>
<td>徐有容</td>
<td>18</td>
<td>10,000.5</td>
</tr>
<tr>
<!-- 通过map的key来取值 -->
<td>3</td>
<td>陈长生</td>
<td>19</td>
<td>3,000.5</td>
</tr>
</table>
<hr>
json字符串转为对象:
开户行:建设银行<br>
客户名称:老云<br>
联系方式:124523431<br>
账户余额:9000.7
</body>
</html>
可以看到,数据模型填充到了模板中,二者结合生成了一个新的html页面,用浏览器打开这个页面:
那么使用freemarker作为模板进行页面静态化就完成了。
5、总结
页面静态化就是获取到模板,获取到数据模型,然后模板+数据模型最终生成html页面。