【电商网站 005】页面静态化(项目实践:商品详情页,页面静态化)

一、前言

二、简介

2.1 问题分析

一般流程:前端页面是通过Thymeleaf模板引擎渲染后返回到浏览器,在后台需要大量的数据查询,而后渲染得到HTML页面
问题:第一,后台大量数据查询,对数据库造成压力;第二,响应慢,请求的响应时间过长,并发能力不高
方案1:缓存技术,比如Redis。但是,Redis适合数据规模比较小的情况。假如数据量比较大,例如我们的商品详情页。每个页面如果10kb,100万商品,就是10GB空间,对内存占用比较大。此时就给缓存系统带来极大压力,如果缓存崩溃,接下来倒霉的就是数据库了。

2.2 what 什么是静态化

定义:将动态生成的HTML页面变为静态内容保存在Nginx服务器上,以后用户的请求到来,直接访问静态页面,不再经过服务的渲染。
小结:静态的HTML页面可以部署在nginx中,从而大大提高并发能力,减小tomcat压力。
理由1:web服务器和web应用服务器
web服务器的优点并发量大,缺点是只能处理静态资源,nginx并发量50000但是只能处理静态页面
web应用服务器的缺点是并发量小,优点是可以处理动态页面,tomcat并发量200但是可以处理动态页面
理由2:Nginx和Redis:
页面静态化,将商品详情页是访问频率大、数据量大而且包含各种图片,干脆将商品详情页整个html变为静态页面,存放在Nginx上,下次直接从Nginx上面拿(redis只能存放访问频率大的热点数据,key-value键值对,不能存放页面)
ps:页面静态化是将整个html页面静态化存放到Nginx上,不是数据和图片一点点存放

2.3 how 如何实现静态化

第一,静态化页面都是通过模板引擎来生成,
第二,生成的静态化页面保存到nginx服务器来部署。
一句话小结:模板引擎整个html页面生成静态化页面nginx服务器将生成的静态化页面存储起来,需要的时候取出。

常用的模板引擎比如:Freemarker、Velocity、Thymeleaf
对于Thymeleaf,我们之前就使用的Thymeleaf,来渲染html返回给用户。Thymeleaf除了可以把渲染结果写入Response,也可以写到本地文件,从而实现静态化。
一句话小结:Thymeleaf可以把渲染结果写入Response返回给前端;也可以将渲染结果写到本地文件得到静态页面存放到Nginx服务器,从而实现静态化。

三、Thymeleaf实现静态化(将渲染结果写到本地文件得到静态页面存放到Nginx服务器)

3.1 Thymeleaf中的几个概念

先说下Thymeleaf中的几个概念:
Context:运行上下文
TemplateResolver:模板解析器
TemplateEngine:模板引擎

Context
定义:上下文,用来保存模型数据,保存的模型数据有什么用呢?当模板引擎TemplateEngine渲染时,可以从Context上下文中获取数据用于渲染。
与SpringBoot结合使用:当与SpringBoot结合使用时,放入Model的数据就自动会被处理到Context,作为模板渲染的数据使用。

TemplateResolver
定义:模板解析器,用来读取模板相关的配置,例如:模板存放的位置信息,模板文件名称,模板文件的类型等等。
与SpringBoot结合使用:当与SpringBoot结合时,TemplateResolver已经由其创建完成,并且各种配置也都有默认值,比如模板存放位置,其默认值就是:templates。比如模板文件类型,其默认值就是html。

TemplateEngine(Thymeleaf就是一个模板引擎)
定义:模板引擎,用来解析模板的引擎,需要使用到上下文、模板解析器。分别从上下文Context、模板解析器TemplateResolver中获取模板中需要的数据(即模板文件)。然后利用内置的语法规则解析,从而输出解析后的文件。来看下模板引擎进行处理的函数:
templateEngine.process(“模板名”, context, writer);
三个参数:
(1)模板名称
(2)上下文对象:里面包含模型数据 //
(3)writer:输出目的地的流 //该参数作用:在输出时,我们可以指定输出的目的地,如果目的地是Response的流,那就是网络响应。如果目的地是本地文件,那就实现静态化了。
ps:在SpringBoot中已经自动配置了模板引擎,我们做静态化,就是把输出的目的地改成本地文件即可!

3.2 实践:SpringBoot项目中,Thymeleaf实现静态化

在这里插入图片描述

Service代码:

@Service
public class GoodsHtmlService {
    
       // 商品详情页面Html页面

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private TemplateEngine templateEngine;  // 模板引擎

    private static final Logger LOGGER = LoggerFactory.getLogger(GoodsHtmlService.class);

    public void createHtml(Long spuId) {
    
       // 创建html页面
        PrintWriter writer = null;
        try {
    
    
            // 第二个参数,创建thymeleaf上下文context对象
            Context context = new Context();
            // 获取页面数据
            Map<String, Object> spuMap = this.goodsService.loadModel(spuId);
            // 把数据放入上下文对象
            context.setVariables(spuMap);

            // 第三个参数,创建输出流  指定输出位置  输出为html文件
            File file = new File("C:\\project\\nginx-1.14.0\\html\\item\\" + spuId + ".html");
            writer = new PrintWriter(file);

            // 执行页面静态化方法
            templateEngine.process("item", context, writer);
        } catch (Exception e) {
    
    
            LOGGER.error("页面静态化出错:{},"+ e, spuId);
        } finally {
    
    
            if (writer != null) {
    
    
                writer.close();
            }
        }
    }

    /**
     * 新建线程处理页面静态化
     * @param spuId
     */
    public void asyncExcute(Long spuId) {
    
    
        ThreadUtils.execute(()->createHtml(spuId));  
        /*ThreadUtils.execute(new Runnable() {
            @Override
            public void run() {
                createHtml(spuId);
            }
        });*/
    }
}

线程工具类:

public class ThreadUtils {
    
    

    private static final ExecutorService es = Executors.newFixedThreadPool(10);

    public static void execute(Runnable runnable) {
    
    
        es.submit(runnable);
    }
}

3.2.1 什么时候创建静态文件

我们编写好了创建静态文件的service,那么问题来了:什么时候去调用它呢

想想这样的场景:

假如大部分的商品都有了静态页面。那么用户的请求都会被nginx拦截下来,根本不会到达我们的leyou-goods-web服务。只有那些还没有页面的请求,才可能会到达这里。

因此,如果请求到达了这里,我们除了返回页面视图外,还应该创建一个静态页面,那么下次就不会再来麻烦我们了。

所以,我们在GoodsController中添加逻辑,去生成静态html文件:

@GetMapping("{id}.html")
public String toItemPage(@PathVariable("id")Long id, Model model){
    
    

    // 原有业务逻辑,加载所需的数据
    Map<String, Object> map = this.goodsService.loadModel(id);
    // 原有业务逻辑,把数据放入数据模型
    model.addAllAttributes(map);

    // 新增业务逻辑,页面静态化
    this.goodsHtmlService.asyncExcute(id);

    return "item";
}

注意:生成html 的代码不能对用户请求产生影响,所以这里我们使用额外的线程进行异步创建。

3.2.2 重启测试:

访问一个商品详情,然后查看nginx目录:

在这里插入图片描述

3.3 nginx代理静态页面

我们修改nginx,让它对商品请求进行监听,指向本地静态页面,如果本地没找到,才进行反向代理到实际服务器

server {
    listen       80;
    server_name  www.leyou.com;

    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    location /item {
        # 先找本地
        root html;
        if (!-f $request_filename) { #请求的文件不存在,就反向代理
            proxy_pass http://127.0.0.1:8084;
            break;
        }
    }

    location / {
        proxy_pass http://127.0.0.1:9002;
        proxy_connect_timeout 600;
        proxy_read_timeout 600;
    }
}

重启测试:

发现请求速度得到了极大提升:

在这里插入图片描述

四、面试金手指

面试的时候,能够搞懂几个问题:
1、为什么要使用页面静态化?
2、what 什么是静态化?静态化的原理?
3、how 如何实现静态化?
4、Thymeleaf实现静态化(将渲染结果写到本地文件得到静态页面存放到Nginx服务器)
4.1 Thymeleaf中的三个概念
4.2 controller接口什么时候调用静态化service
4.3 nginx配置:修改nginx配置,让它对商品请求进行监听,指向本地静态页面,如果本地没找到,才进行反向代理到实际服务器
ps:原则:生成html 的代码不能对用户请求产生影响,所以这里我们使用额外的线程进行异步创建。
这些记下来,一气呵成,页面静态化这个问题就好了。

4.1 页面静态化基础知识

4.1.1 为什么要使用静态化

一般流程:前端页面是通过Thymeleaf模板引擎渲染后返回到浏览器,在后台需要大量的数据查询,而后渲染得到HTML页面
问题:第一,后台大量数据查询,对数据库造成压力;第二,响应慢,请求的响应时间过长,并发能力不高
方案1:缓存技术,比如Redis。但是,Redis适合数据规模比较小的情况。假如数据量比较大,例如我们的商品详情页。每个页面如果10kb,100万商品,就是10GB空间,对内存占用比较大。此时就给缓存系统带来极大压力,如果缓存崩溃,接下来倒霉的就是数据库了。

4.1.2 what 什么是静态化?静态化的原理?

定义:将动态生成的HTML页面变为静态内容保存在Nginx服务器上,以后用户的请求到来,直接访问静态页面,不再经过服务的渲染。
小结:静态的HTML页面可以部署在nginx中,从而大大提高并发能力,减小tomcat压力。
理由1:web服务器和web应用服务器
web服务器的优点并发量大,缺点是只能处理静态资源,nginx并发量50000但是只能处理静态页面
web应用服务器的缺点是并发量小,优点是可以处理动态页面,tomcat并发量200但是可以处理动态页面
理由2:Nginx和Redis:
页面静态化,将商品详情页是访问频率大、数据量大而且包含各种图片,干脆将商品详情页整个html变为静态页面,存放在Nginx上,下次直接从Nginx上面拿(redis只能存放访问频率大的热点数据,key-value键值对,不能存放页面)
ps:页面静态化是将整个html页面静态化存放到Nginx上,不是数据和图片一点点存放

4.1.3 how 如何实现静态化

第一,静态化页面都是通过模板引擎来生成,
第二,生成的静态化页面保存到nginx服务器来部署。
一句话小结:模板引擎整个html页面生成静态化页面nginx服务器将生成的静态化页面存储起来,需要的时候取出。

常用的模板引擎比如:Freemarker、Velocity、Thymeleaf
对于Thymeleaf,我们之前就使用的Thymeleaf,来渲染html返回给用户。Thymeleaf除了可以把渲染结果写入Response,也可以写到本地文件,从而实现静态化。
一句话小结:Thymeleaf可以把渲染结果写入Response返回给前端;也可以将渲染结果写到本地文件得到静态页面存放到Nginx服务器,从而实现静态化。

4.2 Thymeleaf实现静态化(将渲染结果写到本地文件得到静态页面存放到Nginx服务器)

4.2.1 Thymeleaf中的几个概念

先说下Thymeleaf中的几个概念:
Context:运行上下文
TemplateResolver:模板解析器
TemplateEngine:模板引擎

Context
定义:上下文,用来保存模型数据,保存的模型数据有什么用呢?当模板引擎TemplateEngine渲染时,可以从Context上下文中获取数据用于渲染。
与SpringBoot结合使用:当与SpringBoot结合使用时,放入Model的数据就自动会被处理到Context,作为模板渲染的数据使用。

TemplateResolver
定义:模板解析器,用来读取模板相关的配置,例如:模板存放的位置信息,模板文件名称,模板文件的类型等等。
与SpringBoot结合使用:当与SpringBoot结合时,TemplateResolver已经由其创建完成,并且各种配置也都有默认值,比如模板存放位置,其默认值就是:templates。比如模板文件类型,其默认值就是html。

TemplateEngine(Thymeleaf就是一个模板引擎)
定义:模板引擎,用来解析模板的引擎,需要使用到上下文、模板解析器。分别从上下文Context、模板解析器TemplateResolver中获取模板中需要的数据(即模板文件)。然后利用内置的语法规则解析,从而输出解析后的文件。来看下模板引擎进行处理的函数:
templateEngine.process(“模板名”, context, writer);
三个参数:
(1)模板名称
(2)上下文对象:里面包含模型数据 //
(3)writer:输出目的地的流 //该参数作用:在输出时,我们可以指定输出的目的地,如果目的地是Response的流,那就是网络响应。如果目的地是本地文件,那就实现静态化了。
ps:在SpringBoot中已经自动配置了模板引擎,我们做静态化,就是把输出的目的地改成本地文件即可!

4.2.2 when 什么时候调用静态化页面Service

第一,controller调用静态化页面service
我们编写好了创建静态文件的service,那么问题来了:什么时候去调用它呢
想想这样的场景:
假如大部分的商品都有了静态页面。那么用户的请求都会被nginx拦截下来,根本不会到达我们的leyou-goods-web服务。只有那些还没有页面的请求,才可能会到达这里。
因此,如果请求到达了这里,我们除了返回页面视图外,还应该创建一个静态页面,那么下次就不会再来麻烦我们了。

第二,Nginx配置:修改nginx配置,让它对商品请求进行监听,指向本地静态页面,如果本地没找到,才进行反向代理到实际服务器

注意:生成html 的代码不能对用户请求产生影响,所以这里我们使用额外的线程进行异步创建。

五、小结

页面静态化(项目实践:商品详情页,页面静态化),完成了。

天天打码,天天进步!!!

猜你喜欢

转载自blog.csdn.net/qq_36963950/article/details/109038348