java初探(1)之静态页面化——客户端缓存
利用服务端缓存技术,将页面和对象缓存在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>
删去所有与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类,向页面发送所需要的数据
@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>
入口函数,请求数据的逻辑
//入口函数 $(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); }
到此,页面的静态化就完成了