1.为什么要使用网页静态化技术
网页静态化解决方案在实际开发中运用比较多,例如新闻网站,门户网站中的新闻频道或者是文章类的频道。
对于电商网站的商品详细页来说,至少几百万个商品,每个商品又有大量的信息,这样的情况同样也适用于使用网页静态化来解决。
网页静态化技术和缓存技术的共同点都是为了减轻数据库的访问压力,但是具体的应用场景不同,缓存比较适合小规模的数据,而网页静态化比较适合大规模且相对变化不太频繁的数据。另外网页静态化还有利于SEO。
另外我们如果将网页以纯静态化的形式展现,就可以使用Nginx这样的高性能的web服务器来部署。Nginx可以承载5万的并发,而Tomcat只有几百。关于Nginx我们在后续的课程中会详细讲解。
2.页面静态化Demo
2.1.搭建一个SpringBoot工程
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bruceliu.nginx.demo</groupId>
<artifactId>JD</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--导入模板引擎的相关启动器-->
<!--thymeleaf模板引擎 自动配置 SpringMvc自动适配模板引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--页面热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.22</version>
</dependency>
<dependency>
<groupId>ognl</groupId>
<artifactId>ognl</artifactId>
<version>3.1.12</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.2.准备一个模板
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>测试</title>
</head>
<body>
<div>
<h2 th:text="${hello}"></h2>
<h1 th:each="user:${users}">
<span th:text="${user.name}">XXX</span>
<span th:text="${user.address}">XXX</span>
</h1>
</div>
</body>
</html>
2.3.控制器
package com.bruceliuy.condtroller;
import com.bruceliuy.bean.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class LearnController {
("/thymeleaf/{msg}")
public void learn( String msg) throws IOException {
User user1=new User("name1","address1");
User user2=new User("name2","address2");
User user3=new User("name3","address3");
User user4=new User("name4","address4");
List<User> users=new ArrayList<>();
users.add(user1);
users.add(user2);
users.add(user3);
users.add(user4);
//创建模版加载器
ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
resolver.setPrefix("templates/"); //模板文件的所在目录
resolver.setSuffix(".html"); //模板文件后缀
//创建模板引擎
TemplateEngine templateEngine = new TemplateEngine();
//将加载器放入模板引擎
templateEngine.setTemplateResolver(resolver);
//创建字符输出流并且自定义输出文件的位置和文件名
FileWriter writer = new FileWriter("D:/html/index.html");
//创建Context对象(存放Model)
Context context = new Context();
//放入数据
context.setVariable("hello",msg);
context.setVariable("users",users);
//创建静态文件,"text"是模板html名字
templateEngine.process("test",context,writer);
}
}
2.4.测试模板生成静态页面
3.商品详情页-数据显示
3.1.需求分析
运用thymeleaf技术来实现商品详细页的静态化。
3.2.准备详情页面需要的数据
System.out.println("商品上架静态页面生成中....");
//SPU
Goods goods = goodsApi.getGoodsById(id);
GoodsDesc goodsDesc = goodsApi.getGoodsDescById(id);
//3.商品分类 一级分类名 二级分类名 三级分类名
String itemCat1 = goodsApi.itemCat_getById(Integer.parseInt(goods.getCategory1Id().toString())).getName();
String itemCat2 = goodsApi.itemCat_getById(Integer.parseInt(goods.getCategory2Id().toString())).getName();
String itemCat3 = goodsApi.itemCat_getById(Integer.parseInt(goods.getCategory3Id().toString())).getName();
//创建模版加载器
ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
resolver.setPrefix("templates/"); //模板文件的所在目录
resolver.setSuffix(".html"); //模板文件后缀
//创建模板引擎
TemplateEngine templateEngine = new TemplateEngine();
//将加载器放入模板引擎
templateEngine.setTemplateResolver(resolver);
String filePath=pagedir + id + ".html";
//创建字符输出流并且自定义输出文件的位置和文件名
FileWriter writer = new FileWriter(filePath);
//创建Context对象(存放Model)
Context context = new Context();
//放入数据
context.setVariable("goods", goods);
context.setVariable("goodsDesc", goodsDesc);
context.setVariable("itemCat1", itemCat1);
context.setVariable("itemCat2", itemCat2);
context.setVariable("itemCat3", itemCat3);
//创建静态文件,"text"是模板html名字
templateEngine.process("item", context, writer);
3.3.Item模板页面
将item.html拷贝至templates下 ,修改扩展名为ftl ,将商品名称模板标签代替
- 商品标题
<div class="des_name">
<p th:text="${goods.goodsName}">Dior/迪奥 真我香水EDP 克丽丝汀迪奥 全新 30ml</p>
<span th:text="${goods.caption}"></span>
</div>
- 商品价格
本店价格:<b>¥<span th:text="${goods.price}"></span></b><br />
- 详情
<div class="des_border" id="p_details">
<div class="des_t">商品详情</div>
<div class="des_con" th:utext="${goodsDesc.introduction}">
XXXXXX
</div>
</div>
- 包装列表
<div class="des_border" id="p_attribute1">
<div class="des_t">商品包装</div>
<div class="des_con" th:text="${goodsDesc.packageList}">
XXXXXXX
</div>
</div>
- 商品售后
<div class="des_border" id="p_comment">
<div class="des_t">商品售后</div>
<div class="des_con" th:text="${goodsDesc.saleService}">
XXXXX
</div>
<div class="pages">
<a href="#" class="p_pre">上一页</a><a href="#" class="cur">1</a><a href="#">2</a><a href="#">3</a>...<a href="#">20</a><a href="#" class="p_pre">下一页</a>
</div>
</div>
3.3.生成图片列表
编辑模板文件
<div id="tsShopContainer">
<#--图片列表 -->
<div id="tsImgS"><a th:href="@{${goods.smallPic}}" href="images/p_big.jpg" title="Images" class="MagicZoom" id="MagicZoom"><img th:src="@{${goods.smallPic}}" src="images/p_big.jpg" width="390" height="390" /></a></div>
<div id="tsPicContainer">
<div id="tsImgSArrL" onclick="tsScrollArrLeft()"></div>
<div id="tsImgSCon">
<ul>
<li th:each="orderItem:${imagesItems}" onclick="showPic(1)" rel="MagicZoom">
<img th:src="@{${orderItem.url}}" src="images/ps2.jpg" tsImgS="images/ps2.jpg" width="79" height="79" /></li>
</ul>
</div>
<div id="tsImgSArrR" onclick="tsScrollArrRight()"></div>
</div>
<img class="MagicZoomLoading" width="16" height="16" src="images/loading.gif" alt="Loading..." />
</div>
准备后台数据:
String itemImages = goodsDesc.getItemImages();
ObjectMapper mapper = new ObjectMapper();
//JSON工具类型:
List<OrderAndUrl> imagesItems = mapper.readValue(itemImages, new TypeReference<ArrayList<OrderAndUrl>>() {});
System.out.println("图片集合是:"+imagesItems);
context.setVariable("imagesItems", imagesItems);
3.4.生成商品类型面包屑
<div class="postion">
<span class="fl">全部 > <span th:text="${itemCat1}"></span> > <span th:text="${itemCat2}"></span> > <span th:text="${itemCat3}"></span> </span>
</div>