• 页面优化技术


    页面优化技术

    1.概述

    Aim:减少对数据库的访问

    • 页面缓存+URL缓存+对象缓存’

    Aim:实现前后端分离

    • 页面静态化,前后端分离

    Aim:

    • 静态资源优化

    Aim:

    • CDN优化

    CND优化

    2.页面缓存+URL缓存+对象缓存

    2.1 页面缓存

    页缓存
    页面缓存(也称为网页缓存)是一种存储网页数据的机制,以便用户可以在将来访问该页面时更快速地加载。

    • 页面缓存通常由浏览器或服务器实现。
      • 浏览器缓存:当您访问一个网页时,您的浏览器会将该页面的数据(包括HTML、CSS、JavaScript文件、图像等)存储在本地磁盘上。
      • 服务器缓存:服务器缓存是一种由服务器实现的机制,用于存储已经请求和生成的网页数据。当多个用户请求同一页面时,服务器可以从其缓存中加载页面,而不是为每个用户重新生成页面。

    步骤

    1. 取缓存
    2. 手动渲染模板
    3. 结果输出
      以下是使用表格的形式总结的关于ThymeleafViewResolverApplicationContext的信息:
    对象描述/功能
    ThymeleafViewResolver1. Thymeleaf的一个类,实现了ViewResolver接口。
    2. 用于解析Thymeleaf视图。
    3. 可以将逻辑视图名称解析为具体的Thymeleaf视图。
    ApplicationContext1. Spring框架的核心接口之一,代表了Spring IoC容器。
    2. 负责实例化、配置和组装Bean,并提供对这些Bean的访问。
    3. 通过ApplicationContext,可以获取和操作应用程序中的Bean,例如获取Bean的引用、获取应用程序的环境变量等。
    4. ApplicationContext有多个实现,例如ClassPathXmlApplicationContext、FileSystemXmlApplicationContext等,用于不同的应用场景。

    添加商品缓存类

    package com.example.redis;
    
    public class GoodsKey extends BasePrefix{
        private GoodsKey(int expireSeconds, String prefix) {
            super(expireSeconds, prefix);
        }
        public static GoodsKey getGoodsList = new GoodsKey(60, "gl");
        public static GoodsKey getGoodsDetail = new GoodsKey(60, "gd");
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    使用缓存

        @RequestMapping(value="/to_list", produces="text/html")
        @ResponseBody
        public String list(HttpServletRequest request, HttpServletResponse response, Model model, MiaoShaUser user) {
            model.addAttribute("user", user);
            //取缓存
            String html = redisService.get(GoodsKey.getGoodsList, "", String.class);
            if(!StringUtils.isEmpty(html)) {
                return html;
            }
    
    
            List<GoodsVo> goodsList = goodsService.listGoodsVo();
            model.addAttribute("goodsList", goodsList);
    
            IWebContext ctx =new WebContext(request,response,
                    request.getServletContext(),request.getLocale(),model.asMap());
    
            //手动渲染
            html = thymeleafViewResolver.getTemplateEngine().process("goods_list", ctx);
            if(!StringUtils.isEmpty(html)) {
                redisService.set(GoodsKey.getGoodsList, "", html);
            }
            return html;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    查看缓存
    在这里插入图片描述
    数据详情页缓存

    
        @RequestMapping("/to_detail/{goodsId}",produces="text/html")
        @ResponseBody
        public String detail(HttpServletRequest request, HttpServletResponse response,Model model,MiaoShaUser user, @PathVariable("goodsId")long goodsId) {
            model.addAttribute("user", user);
    
            //取缓存
            String html = redisService.get(GoodsKey.getGoodsDetail, ""+goodsId, String.class);
            if(!StringUtils.isEmpty(html)) {
                return html;
            }
    
            //手动渲染
            GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
            model.addAttribute("goods", goods);
    
            long startAt = goods.getStartDate().getTime();
            long endAt = goods.getEndDate().getTime();
            long now = System.currentTimeMillis();
    
    
    
            int miaoshaStatus = 0;
            int remainSeconds = 0;
            if(now < startAt ) {//秒杀还没开始,倒计时
                miaoshaStatus = 0;
                remainSeconds = (int)((startAt - now )/1000);
            }else  if(now > endAt){//秒杀已经结束
                miaoshaStatus = 2;
                remainSeconds = -1;
            }else {//秒杀进行中
                miaoshaStatus = 1;
                remainSeconds = 0;
            }
            model.addAttribute("miaoshaStatus", miaoshaStatus);
            model.addAttribute("remainSeconds", remainSeconds);
    
            IWebContext ctx = new WebContext(request,response,
                    request.getServletContext(),request.getLocale(), model.asMap() );
    
            html = thymeleafViewResolver.getTemplateEngine().process("goods_detail", ctx);
            if(!StringUtils.isEmpty(html)) {
                redisService.set(GoodsKey.getGoodsDetail, ""+goodsId, html);
            }
            return html;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    在这里插入图片描述

    2.2 对象缓存

    对象缓存是一种缓存策略,它将特定的对象根据其标识符(如ID)进行缓存。当通过标识符获取对象时,直接从缓存中返回对象,而不是从数据库中查询。对象缓存与页面缓存和URL缓存的主要区别在于,对象缓存是针对单个对象进行的,而页面缓存和URL缓存则是针对整个页面或URL的缓存。

    Q:对象缓存和页面缓存的区别

    • 在页面缓存和URL缓存中,缓存时间通常较短,适用于变化不大的情况,如商品列表等。
      这些缓存策略一般只缓存前一两页的数据,因为大部分用户只会点击一两次页面。当数据更新时,这些缓存策略会自动失效,不需要手动干预。
    • 相比之下,对象缓存的粒度更细,只针对特定的对象进行缓存。
      当对象更新时,必须手动更新缓存,否则会出现数据不一致的情况。在实现对象缓存时,需要注意在更新数据后及时更新缓存,以确保数据的同步性。

    在这里插入图片描述

     @Service
    public class MiaoshaUserService {
    
        public static final String COOKI_NAME_TOKEN = "token";
    
        @Autowired
        MiaoshaUserDao miaoshaUserDao;
    
        @Autowired
        RedisService redisService;
    
        //查询
    //    public MiaoShaUser getById(long id) {
    //        return miaoshaUserDao.getById(id);
    //    }
    
        public MiaoShaUser getById(long id) {
            //取缓存
            MiaoShaUser user = redisService.get(MiaoshaUserKey.getById, ""+id, MiaoShaUser.class);
            if(user != null) {
                return user;
            }
            //取数据库
            user = miaoshaUserDao.getById(id);
            if(user != null) {
                redisService.set(MiaoshaUserKey.getById, ""+id, user);
            }
            return user;
        }
    
        //修改用户密码
        public boolean updatePassword(String token, long id, String formPass) {
            //取user
            MiaoShaUser user = getById(id);
            if(user == null) {
                throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
            }
            //更新数据库
            MiaoShaUser toBeUpdate = new MiaoShaUser();
            toBeUpdate.setId(id);
            toBeUpdate.setPassword(MD5Util.formPassToDBPass(formPass, user.getSalt()));
            miaoshaUserDao.update(toBeUpdate);
            //处理缓存
            redisService.delete(MiaoshaUserKey.getById, ""+id);
            user.setPassword(toBeUpdate.getPassword());
            redisService.set(MiaoshaUserKey.token, token, user);
            return true;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    在这里插入图片描述

    2.3 测试效果

    商品列表
    在这里插入图片描述

    添加缓存之后
    在这里插入图片描述

    获取用户信息用户信息
    在这里插入图片描述

    添加缓存之后
    在这里插入图片描述

    3.页面静态化

    页面静态化是一种将动态生成的页面内容转化为静态 HTML 文件的技术。
    通过将动态页面转化为静态文件,可以减少服务器的负载,提高页面的加载速度,并且有利于搜索引擎的优化(SEO)

    • 优点:利用浏览器缓存页面框架,动态数据通过接口从服务端获取。

    页面静态化介绍

    package com.example.vo;
    
    import com.example.domain.MiaoShaUser;
    
    //表示商品详细信息的值对象(Value Object)
    public class GoodsDetailVo {
        private int miaoshaStatus = 0;
        private int remainSeconds = 0;
        private GoodsVo goods ;
        private MiaoShaUser user;
        public int getMiaoshaStatus() {
            return miaoshaStatus;
        }
        public void setMiaoshaStatus(int miaoshaStatus) {
            this.miaoshaStatus = miaoshaStatus;
        }
        public int getRemainSeconds() {
            return remainSeconds;
        }
        public void setRemainSeconds(int remainSeconds) {
            this.remainSeconds = remainSeconds;
        }
        public GoodsVo getGoods() {
            return goods;
        }
        public void setGoods(GoodsVo goods) {
            this.goods = goods;
        }
        public MiaoShaUser getUser() {
            return user;
        }
        public void setUser(MiaoShaUser user) {
            this.user = user;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    在这里插入图片描述
    在这里插入图片描述

    DOCTYPE HTML>
    <html >
    <head>
      <title>商品详情title>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
      
      <script type="text/javascript" src="/js/jquery.min.js">script>
      
      <link rel="stylesheet" type="text/css" href="/bootstrap/css/bootstrap.min.css" />
      <script type="text/javascript" src="/bootstrap/js/bootstrap.min.js">script>
      
      <script type="text/javascript" src="/jquery-validation/jquery.validate.min.js">script>
      <script type="text/javascript" src="/jquery-validation/localization/messages_zh.min.js">script>
      
      <script type="text/javascript" src="/layer/layer.js">script>
      
      <script type="text/javascript" src="/js/md5.min.js">script>
      
      <script type="text/javascript" src="/js/common.js">script>
    head>
    <body>
    
    <div class="panel panel-default">
      <div class="panel-heading">秒杀商品详情div>
      <div class="panel-body">
        <span id="userTip"> 您还没有登录,请登陆后再操作<br/>span>
        <span>没有收货地址的提示。。。span>
      div>
      <table class="table" id="goodslist">
        <tr>
          <td>商品名称td>
          <td colspan="3" id="goodsName">td>
        tr>
        <tr>
          <td>商品图片td>
          <td colspan="3"><img  id="goodsImg" width="200" height="200" />td>
        tr>
        <tr>
          <td>秒杀开始时间td>
          <td id="startTime">td>
          <td >
            <input type="hidden" id="remainSeconds" />
            <span id="miaoshaTip">span>
          td>
          <td>
            
            <button class="btn btn-primary btn-block" type="button" id="buyButton"onclick="doMiaosha()">立即秒杀button>
            <input type="hidden" name="goodsId"  id="goodsId" />
          td>
        tr>
        <tr>
          <td>商品原价td>
          <td colspan="3" id="goodsPrice">td>
        tr>
        <tr>
          <td>秒杀价td>
          <td colspan="3"  id="miaoshaPrice">td>
        tr>
        <tr>
          <td>库存数量td>
          <td colspan="3"  id="stockCount">td>
        tr>
      table>
    div>
    body>
    <script>
    
      function doMiaosha(){
        $.ajax({
          url:"/miaosha/do_miaosha",
          type:"POST",
          data:{
            goodsId:$("#goodsId").val(),
          },
          success:function(data){
            if(data.code == 0){
              window.location.href="/order_detail.htm?orderId="+data.data.id;
            }else{
              layer.msg(data.msg);
            }
          },
          error:function(){
            layer.msg("客户端请求有误");
          }
        });
    
      }
    
      function render(detail){
        var miaoshaStatus = detail.miaoshaStatus;
        var  remainSeconds = detail.remainSeconds;
        var goods = detail.goods;
        var user = detail.user;
        if(user){
          $("#userTip").hide();
        }
        $("#goodsName").text(goods.goodsName);
        $("#goodsImg").attr("src", goods.goodsImg);
        $("#startTime").text(new Date(goods.startDate).format("yyyy-MM-dd hh:mm:ss"));
        $("#remainSeconds").val(remainSeconds);
        $("#goodsId").val(goods.id);
        $("#goodsPrice").text(goods.goodsPrice);
        $("#miaoshaPrice").text(goods.miaoshaPrice);
        $("#stockCount").text(goods.stockCount);
        countDown();
      }
    
      $(function(){
        //countDown();
        getDetail();
      });
    
      function getDetail(){
        var goodsId = g_getQueryString("goodsId");
        $.ajax({
          url:"/goods/detail/"+goodsId,
          type:"GET",
          success:function(data){
            if(data.code == 0){
              render(data.data);
            }else{
              layer.msg(data.msg);
            }
          },
          error:function(){
            layer.msg("客户端请求有误");
          }
        });
      }
    
      function countDown(){
        var remainSeconds = $("#remainSeconds").val();
        var timeout;
        if(remainSeconds > 0){//秒杀还没开始,倒计时
          $("#buyButton").attr("disabled", true);
          $("#miaoshaTip").html("秒杀倒计时:"+remainSeconds+"秒");
          timeout = setTimeout(function(){
            $("#countDown").text(remainSeconds - 1);
            $("#remainSeconds").val(remainSeconds - 1);
            countDown();
          },1000);
        }else if(remainSeconds == 0){//秒杀进行中
          $("#buyButton").attr("disabled", false);
          if(timeout){
            clearTimeout(timeout);
          }
          $("#miaoshaTip").html("秒杀进行中");
        }else{//秒杀已经结束
          $("#buyButton").attr("disabled", true);
          $("#miaoshaTip").html("秒杀已经结束");
        }
      }
    
    script>
    html>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160

    页面框架
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    秒杀详情页 页面静态化

    接口步骤同上

    在这里插入图片描述

  • 相关阅读:
    flask入门教程之小项目实践
    每日一题 2731. 移动机器人(中等,模拟)
    电子元器件手册中assert和deassert的含义
    代码随想录二刷day59
    gb28181 网守网关分离+推理服务架构
    计算机等级考试—信息安全三级真题九
    【Python学习笔记】Optuna + Transformer B站视频实践
    微信开发者工具 / 反编译工具CrackMinApp 下载安装
    IDEA中如何快速定位到第一行或者最后一行
    【通义千问】Qwen从本地加载分词器报错‘‘tokenizer class not exist‘‘
  • 原文地址:https://blog.csdn.net/meini32/article/details/132812684