java初探之静态页面化——客户端缓存

Posted lovejune

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java初探之静态页面化——客户端缓存相关的知识,希望对你有一定的参考价值。

利用服务端缓存技术,将页面和对象缓存在redis中,可以减少时间浪费,内存开销。但在每次请求的过程中,仍然会有大量静态资源的请求和返回。

使用静态页面技术,页面不必要使用页面交互技术,比如thymeleaf,jsp等。而是写一个纯的html静态页面,然后在页面端通过js的ajax请求,获得数据,并通过配置,将静态页面直接缓存到客户端,等下次请求的时候,如果页面没有发生变化,则可以不用对静态资源进行提交和返回。

当进入商品列表页面时,详情的点击不在通过controller类来将缓存的html返回,而是直接跳转到商品详情的页面,并给一个商品id的参数

 

<td><a th:href="‘/goods_detail.htm?goodsId=‘+${goods.id}">详情</a></td>

 

  • 商品详情页纯html页面  

技术图片
<!DOCTYPE HTML>
<html >
<head>
    <title>商品详情</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <!-- jquery -->
    <script type="text/javascript" src="/js/jquery.min.js"></script>
    <!-- bootstrap -->
    <link rel="stylesheet" type="text/css" href="/bootstrap/css/bootstrap.min.css" />
    <script type="text/javascript" src="/bootstrap/js/bootstrap.min.js"></script>
    <!-- jquery-validator -->
    <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>
    <!-- layer -->
    <script type="text/javascript" src="/layer/layer.js"></script>
    <!-- md5.js -->
    <script type="text/javascript" src="/js/md5.min.js"></script>
    <!-- common.js -->
    <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>
                <!--
                    <form id="miaoshaForm" method="post" action="/miaosha/do_miaosha">
                        <button class="btn btn-primary btn-block" type="submit" id="buyButton">立即秒杀</button>
                        <input type="hidden" name="goodsId"  id="goodsId" />
                    </form>-->
                <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>
</html>
View Code

删去所有与thymeleaf相关的标签,将需要展示变量的地方,设置id属性

然后提供一个入口函数

$(function () {
        getDetail();
    });
    
    function getDetail() {
        //获取goodsId
        var goodsId=g_getQueryString("goodsId");

        //设置ajax请求,得到数据
        $.ajax({

            url:"/goods/detail/"+goodsId,
            type:"GET",
            success:function (data) {
                if(data.code==0){
                    //展示数据
                }else{
                    //展示错误信息
                    layer.msg(data.msg);
                }
            },
            error:function () {
                //未请求成功信息
                layer.msg("客户端请求有误")
            }
        });
    }

 

修改controller类,向页面发送所需要的数据

  •  

    detail方法

  

@RequestMapping(value = "/to_detail/{goodsId}")
    @ResponseBody
    public Result<GoodsDetailVo> detail( MiaoshaUser user,
                                        @PathVariable("goodsId") long goodsId){

        //得到商品信息
        GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);

        //得到秒杀的开始时间、结束时间、以及当前时间
        long startAt = goods.getStartDate().getTime();
        long endAt = goods.getEndDate().getTime();
        long now = System.currentTimeMillis();

        //设置剩余时间
        int remainSeconds=0;

        //设置秒杀状态
        int miaoshaStatus=0;

        //判断
        if(now<startAt){
            //秒杀还没开始
            miaoshaStatus=0;
            remainSeconds= (int) ((startAt-now)/1000);
        }else if(now>endAt){
            //秒杀已经结束
            miaoshaStatus=2;
            remainSeconds=-1;
        }else {
            //秒杀正在进行
            miaoshaStatus=1;
            remainSeconds=0;
        }

        //创建商品详情的类
        GoodsDetailVo vo=new GoodsDetailVo();
        vo.setGoods(goods);
        vo.setRemainSeconds(remainSeconds);
        vo.setUser(user);
        vo.setMiaoshaStatus(miaoshaStatus);

        //返回页面需要的信息
        return Result.success(vo);
    }

 

当入口函数得到数据之后,就可以编写展示数据的js代码,一般这些代码是使用前端框架进行编写的。

 

function render(detail) {
        //取到vo传过来的四个属性

        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() {

        //获取剩余时间
        var remainSeconds = $("#remainSeconds").val();

        //定义超时变量
        var timeout;
        if(remainSeconds>0){
            //秒杀还没有开始
            //隐藏秒杀的按钮,展示倒计时提醒
            $("#buyButton").attr("disabled", true);
            $("#miaoshaTip").html("秒杀倒计时:"+remainSeconds+"秒");

            //利用setTimeout进行时间控制
            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("秒杀已经结束");
        }
    }

 

 

以上就将详情页静态化了

 

  • 秒杀的静态化

点击立即秒杀按钮,将执行doMiaosha()的js代码,又是一个ajax请求,但这次不是跳转到静态页面,而是通过Controller类来做一定的秒杀逻辑,然后返回值,如果秒杀成功,则跳转到静态页面。而静态页面也将静态化。

 

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("客户端请求有误");
            }
        });
    }

 

修改controller类的"/miaosha/do_miaosha"请求,将直接返回页面,到现在将结果返回来判断是否跳转到另一个静态页面。

 

@RequestMapping(value = "/do_miaosha",method = RequestMethod.POST)
    @ResponseBody
    public Result<OrderInfo> list(Model model, MiaoshaUser user,
                       @RequestParam("goodsId") long goodsId){

        model.addAttribute("user",user);
        if(user==null){
            //如果没有获取到user值,报异常
            return Result.error(CodeMsg.SESSION_ERROR);
        }

        //判断库存
        GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
        Integer stock= goods.getStockCount();

        if(stock<=0){
            model.addAttribute("errmsg", CodeMsg.MIAO_SHA_OVER.getMsg());
            return Result.error(CodeMsg.MIAO_SHA_OVER);
        }

        //判断是否已经秒杀到了
        MiaoshaOrder order=orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);

        if(order!=null){
            return Result.error(CodeMsg.REPEATE_MIAOSHA);
        }

        //进行秒杀逻辑
        //减库存,下订单,写入秒杀订单
        OrderInfo orderInfo=miaoshaService.miaosha(user, goods);

        return Result.success(orderInfo);
    }

 

当秒杀成功,将返回一个订单信息的类,然后将订单id拿到作为参数跳转到订单页面

 

当然,订单页面也将是一个纯html的静态页面,并将通过入口函数,得到所有需要的数据。

  • 订单的html页面

技术图片
<!DOCTYPE HTML>
<html>
<head>
    <title>订单详情</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <!-- jquery -->
    <script type="text/javascript" src="/js/jquery.min.js"></script>
    <!-- bootstrap -->
    <link rel="stylesheet" type="text/css" href="/bootstrap/css/bootstrap.min.css" />
    <script type="text/javascript" src="/bootstrap/js/bootstrap.min.js"></script>
    <!-- jquery-validator -->
    <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>
    <!-- layer -->
    <script type="text/javascript" src="/layer/layer.js"></script>
    <!-- md5.js -->
    <script type="text/javascript" src="/js/md5.min.js"></script>
    <!-- common.js -->
    <script type="text/javascript" src="/js/common.js"></script>
</head>
<body>
<div class="panel panel-default">
    <div class="panel-heading">秒杀订单详情</div>
    <table class="table" id="goodslist">
        <tr>
            <td>商品名称</td>
            <td colspan="3" id="goodsName"></td>
        </tr>
        <tr>
            <td>商品图片</td>
            <td colspan="2"><img  id="goodsImg" width="200" height="200" /></td>
        </tr>
        <tr>
            <td>订单价格</td>
            <td colspan="2"  id="orderPrice"></td>
        </tr>
        <tr>
            <td>下单时间</td>
            <td id="createDate" colspan="2"></td>
        </tr>
        <tr>
            <td>订单状态</td>
            <td id="orderStatus">
            </td>
            <td>
                <button class="btn btn-primary btn-block" type="submit" id="payButton">立即支付</button>
            </td>
        </tr>
        <tr>
            <td>收货人</td>
            <td colspan="2">玉皇大帝</td>
        </tr>
        <tr>
            <td>收货地址</td>
            <td colspan="2">天宫一号</td>
        </tr>
    </table>
</div>
</body>
View Code

 

入口函数,请求数据的逻辑

 //入口函数
    $(function () {
        getOrderDetail();
    })

    function getOrderDetail() {

        //一个ajax请求
        var orderId = g_getQueryString("orderId");
        $.ajax({
            url:"/order/detail",
            type:"GET",
            data:{
                orderId:orderId
            },
            success:function(data){
                if(data.code == 0){
                    //展示数据
                    render(data.data);
                }else{
                    layer.msg(data.msg);
                }
            },
            error:function(){
                layer.msg("客户端请求有误");
            }
        });

    }

 

控制器代码

@Controller
@RequestMapping("/order")
public class OrderController {


    @Autowired
    private OrderService orderService;

    @Autowired
    private GoodsService goodsService;

    @RequestMapping("/detail")
    @ResponseBody
    public Result<OrderDetailVo> info(Model model, MiaoshaUser user,
                                      @RequestParam("orderId") long orderId){

        //判断用户是否存在
        if(user==null){
            return Result.error(CodeMsg.SESSION_ERROR);
        }

        //获取order
        OrderInfo order = orderService.getOrderById(orderId);
        if(order==null){
            Result.error(CodeMsg.ORDER_NOT_EXIST);
        }
        //得到订单页面需要的参数
        long goodsId = order.getGoodsId();
        GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
        OrderDetailVo vo = new OrderDetailVo();
        vo.setOrder(order);
        vo.setGoods(goods);
        return Result.success(vo);

    }

}

 

订单页面内js的数据展示代码

function render(detail) {
    //获取商品和订单信息
    var goods = detail.goods;
    var order = detail.order;

    //对数据进行展示
    $("#goodsName").text(goods.goodsName);
    $("#goodsImg").attr("src", goods.goodsImg);
    $("#orderPrice").text(order.goodsPrice);
    $("#createDate").text(new Date(order.createDate).format("yyyy-MM-dd hh:mm:ss"));

    //对订单的状态进行判断

    var status = "";
    if(order.status == 0){
        status = "未支付"
    }else if(order.status == 1){
        status = "待发货";
        $("payButton").hide();
    }
    $("#orderStatus").text(status);

}

到此,页面的静态化就完成了

 

 

  

以上是关于java初探之静态页面化——客户端缓存的主要内容,如果未能解决你的问题,请参考以下文章

Java秒杀项目之页面优化

如何处理java高并发问题---之页面静态化

第七节:框架搭建之页面静态化的剖析

magento优化之模板静态化

java初探之登录补充

死磕基础系列之自定义静态化页面的过滤器