1. 常用技术AngularJS、Vue.js
  2. 优点:利用浏览器的缓存

上面的方法比较复杂,我们只是用jQuery来模拟实现页面静态化

将页面直接缓存到用户的浏览器上面,好处:用户访问数据的时候,不用去请求服务器,直接在本地缓存中取得需要的页面缓存。

  • 未作页面静态化: 请求某一个页面,访问缓存,查看缓存中是否有,缓存中有直接返回,缓存中没有的话,将数据渲染到html页面再存到缓存,再将整个html页面返回给客户端显示。

  • 做了页面静态化: 第一次是去请求后台要渲染好的html页面,之后的请求都是直接访问用户本地浏览器的缓存的html页面 ,静态资源,然后前端通过Ajax来访问后端,只去获取页面需要显示的数据返回即可。

商品详情页静态化
在先前的操作中我们将商品详情页面进行了redis缓存,因为这个接口只是展示相应产品详情和秒杀倒计时等信息,只要显示几个关键信息即可,所以其他的都可以实现静态化。这种技术,实际就是前端分为两部分,一部分是不改变的html块,还有一块就是数据,它只要后端传数据到前端即可,用到ajax技术来请求数据。

为了在浏览器端进行缓存,以及控制缓存时间,在application.properties里面添加配置静态资源配置项:

  1. #static 静态资源配置,设置静态文件路径css,js,图片等等
  2. #spring.mvc.static-path-pattern=/static/** spring.mvc.static-path-pattern=/**
  3. spring.resources.add-mappings=true
  4. spring.resources.cache-period=3600
  5. spring.resources.chain.cache=true
  6. spring.resources.chain.enabled=true
  7. spring.resources.chain.gzipped=true
  8. spring.resources.chain.html-application-cache=true
  9. spring.resources.static-locations=classpath:/static/

在static资源文件夹下面新建我们的静态资源页面文件,(我们以.htm格式结尾),这里为什么不能用.html文件结尾是因为如果不修改继续用.html后缀,系统会默认去找templates下面的同名文件,所以我们修改它以示区别

  • 定义一个GoodsDetailVo封装来专门给页面传值。
  1. /**
  2. * 为了给页面传值
  3. */
  4. @Setter
  5. @Getter
  6. public class GoodsDetailVo {
  7. // 秒杀状态量初始值
  8. private int status = 0;
  9. // 开始时间倒计时
  10. private int remailSeconds = 0;
  11. private GoodsVo goodsVo;
  12. private MiaoshaUser user;

改造商品列表页面(goods_list.html)里面的跳转逻辑,修改跳转请求
之前的请求路径:

  1. <td><a th:href="\'/goods/to_detail/\'+${goods.id}">详情</a></td>

现在的请求路径:

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

而我们现在是不需要再去服务端请求跳转,直接去客户端静态资源里面请求商品详情静态页面goods_detail.htm,这里注意一下修改一下后缀名称

修改之前的商品详情页面,删除thymeleaf具有的标签,让它成为最初始的html静态页面(现在静态页面不需要thymeleaf),修改使其都使用id来标识各个组件。

  • 刚转到goods_detail.htm页面时,js初始化,执行下面方法:
  1. $(function(){
  2. getDetail();
  3. });

getDetail方法:

  1. function getDetail(){
  2. //getQueryString获取请求路径中的参数
  3. var goodsId=getQueryString("goodsId");
  4. //alert(goodsId);
  5. $.ajax({
  6. url:"/goods/detail/"+goodsId,
  7. type:"GET",
  8. success:function(data){
  9. if(data.code==0){
  10. //使用render方法渲染页面
  11. render(data.data);
  12. }else{
  13. layer.msg(data.msg);
  14. }
  15. },
  16. error:function(){
  17. layer.msg("请求有误!");
  18. }
  19. });
  20. }

getDetail()方法使用ajax异步请求后台取得该页面需要的数据,然后拿到数据之后调用render()方法渲染我们的静态页面,注意在getDetail中第一步做的是去获取商品的goodsId,因为list页面的商品详情请求是:

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

商品详情点击链接里面是带有我们的商品的goodsId的,那么我们通过方法getQueryString来获取请求路径url里面参数的值

  1. function getQueryString(name) {
  2. var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
  3. var r = window.location.search.substr(1).match(reg);
  4. if (r != null) {
  5. return unescape(r[2]);
  6. }
  7. return null;
  8. }

获取到参数之后就可以去请求后端接口,获取数据去渲染:

  1. function render(detail) {
  2. //alert(detail.status);
  3. var miaoshaStatus = detail.status;
  4. var remailSeconds = detail.remailSeconds;
  5. var goods = detail.goodsVo;
  6. var user = detail.user;
  7. if (user != null) {
  8. //展示相应的
  9. $("#userTip").hide();
  10. }
  11. $("#goodsName").text(goods.goodsName);
  12. $("#goodsImg").attr("src", goods.goodsImg); //.text();
  13. $("#startTime").text(goods.startDate); //还没有格式化
  14. $("#remailSeconds").val(remailSeconds);
  15. $("#goodsId").val(goods.id);
  16. $("#goodsPrice").text(goods.goodsPrice); //goodsStock----- stockCount
  17. $("#miaoshaPrice").text(goods.miaoshaPrice);
  18. $("#stockCount").text(goods.goodsStock);
  19. countDown();
  20. }

倒计时countDown()方法:

  1. function countDown(){
  2. //获取秒杀倒计时进行判断,0-->正在进行秒杀,-1-->秒杀结束,remailSeconds>0-->代表倒计时
  3. var remailSeconds=$("#remailSeconds").val();
  4. //alert("remailSeconds:"+remailSeconds);
  5. var timeout;
  6. if(remailSeconds>0){//秒杀还没有开始,进行倒计时功能
  7. $("#buyButton").attr("disabled",true);
  8. $("#miaoshaTip").html("秒杀倒计时:"+remailSeconds+"秒");
  9. //倒计时
  10. timeout=setTimeout(function(){
  11. $("#countDown").text(remailSeconds-1);
  12. $("#remailSeconds").val(remailSeconds-1);//remailSeconds这是input
  13. countDown();
  14. },1000);//一秒钟之后回调函数
  15. }else if(remailSeconds==0){//正在进行秒杀
  16. $("#buyButton").attr("disabled",false);
  17. if(timeout){//如果timeout有值的情况
  18. clearTimeout(timeout);
  19. }
  20. //将文案修改 df1fab4272a24cdf9432adb9fd69cb38
  21. $("#miaoshaTip").html("秒杀进行中");
  22. }else{
  23. //小于0的情况,秒杀结束,将秒杀按钮设置为不可点击
  24. $("#buyButton").attr("disabled",true);
  25. $("#miaoshaTip").html("秒杀结束");
  26. }
  27. }
  • 将后端GoodsController里面接收商品详情页的请求的接口修改为下面代码:
  1. /**
  2. * 作页面静态化的商品详情
  3. * 页面存的是html
  4. * 动态数据通过接口从服务端获取
  5. * @param model
  6. * @param user
  7. * @param goodsId
  8. * @return
  9. */
  10. @RequestMapping(value="/detail/{goodsId}") //produces="text/html"
  11. @ResponseBody
  12. public Result<GoodsDetailVo> toDetail_staticPage(Model model,MiaoshaUser user,
  13. HttpServletRequest request,HttpServletResponse response,@PathVariable("goodsId")long goodsId) {//id一般用snowflake算法
  14. System.out.println("页面静态化/detail/{goodsId}");
  15. model.addAttribute("user", user);
  16. GoodsVo goodsVo=goodsService.getGoodsVoByGoodsId(goodsId);
  17. model.addAttribute("goods", goodsVo);
  18. //既然是秒杀,还要传入秒杀开始时间,结束时间等信息
  19. long start=goodsVo.getStartDate().getTime();
  20. long end=goodsVo.getEndDate().getTime();
  21. long now=System.currentTimeMillis();
  22. //秒杀状态量
  23. int status=0;
  24. //开始时间倒计时
  25. int remailSeconds=0;
  26. //查看当前秒杀状态
  27. if(now<start) {//秒杀还未开始,--->倒计时
  28. status=0;
  29. remailSeconds=(int) ((start-now)/1000); //毫秒转为秒
  30. }else if(now>end){ //秒杀已经结束
  31. status=2;
  32. remailSeconds=-1; //毫秒转为秒
  33. }else {//秒杀正在进行
  34. status=1;
  35. remailSeconds=0; //毫秒转为秒
  36. }
  37. model.addAttribute("status", status);
  38. model.addAttribute("remailSeconds", remailSeconds);
  39. GoodsDetailVo gdVo=new GoodsDetailVo();
  40. gdVo.setGoodsVo(goodsVo);
  41. gdVo.setStatus(status);
  42. gdVo.setRemailSeconds(remailSeconds);
  43. gdVo.setUser(user);
  44. //将数据填进去,传至页面
  45. return Result.success(gdVo);
  46. }
  • goods_detail.htm完整代码:
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8"/>
  5. <title>商品详情</title>
  6. <!-- jquery -->
  7. <!-- <script type="text/javascript" src="@{/js/jequery.min.js}"></script> -->
  8. <script type="text/javascript" src="/jquery-validation/lib/jquery-1.11.1.js"></script>
  9. <link type="text/css" rel="stylesheet" href="/bootstrap/css/bootstrap.css"/>
  10. <script type="text/javascript" src="/bootstrap/js/bootstrap.min.js"></script>
  11. <!-- layer -->
  12. <script type="text/javascript" src="/layer/layer.js"></script>
  13. </head
  14. <body>
  15. <div class="panel panel-default">
  16. <div class="panel-heading">秒杀商品详情</div>
  17. <div class="panel-body">
  18. <span id="userTip">您还没有登录,请登录后再操作</span>
  19. <span>没有收货地址的提示。。。</span>
  20. <input type="hidden" id="goodsId" > <!-- $("#goodsId").val(goods.id); -->
  21. </div>
  22. <table class="table" id="goodslist">
  23. <tr>
  24. <td>商品名称</td>
  25. <td colspan="3" id="goodsName"></td>
  26. </tr>
  27. <tr>
  28. <td>商品图片</td>
  29. <td colspan="3"><img id="goodsImg" width="80" height="60"></img></td>
  30. </tr>
  31. <tr>
  32. <td>秒杀开始时间</td>
  33. <td id="startTime"></td>
  34. <td id="">
  35. <!-- 先取得这个时间 -->
  36. <input type="hidden" id="remailSeconds"></input>
  37. <span id="miaoshaTip"></span>
  38. </td>
  39. <td>
  40. <form id="miaoshaForm" method="post" action="/miaosha/do_miaosha">
  41. <button class="btn btn-primary btn-block" type="submit" id="buyButton">立即秒杀</button>
  42. <input type="hidden" name="goodsId" id="goodsId"></input>
  43. </form>
  44. </td>
  45. </tr>
  46. <tr>
  47. <td>商品原价</td>
  48. <td colspan="3" id="goodsPrice"></td>
  49. </tr>
  50. <tr>
  51. <td>秒杀价</td>
  52. <td colspan="3" id="miaoshaPrice"></td>
  53. </tr>
  54. <tr>
  55. <td>库存数量</td>
  56. <td colspan="3" id="stockCount"></td>
  57. </tr>
  58. </table>
  59. </div>
  60. </body>
  61. <script type="text/javascript">
  62. //获取秒杀地址
  63. function getMiaoshaPath(){
  64. var goodsId=$("#goodsId").val();
  65. }
  66. //做轮询
  67. function getMiaoshaResult(goodsId){
  68. $.ajax({
  69. url:"/miaosha/result",
  70. type:"GET",
  71. data:{
  72. goodsId:$("#goodsId").val()
  73. },
  74. success:function(data){
  75. if(data.code==0){
  76. var result=data.data;
  77. if(result<0){
  78. layer.msg("抱歉,秒杀失败!");
  79. }else if(result==0){
  80. //继续轮询
  81. setTimeout(function(){
  82. getMiaoshaResult(goodsId);
  83. },50);//50ms之后继续轮询
  84. layer.msg(data.msg);
  85. }else{
  86. layer.confirm("恭喜你,秒杀成功!查看订单?",{btn:["确定","取消"]},
  87. function(){
  88. //秒杀成功,跳转详情页面
  89. window.location.href="order_detail.htm?orderId="+result;
  90. },
  91. function(){
  92. layer.closeAll();
  93. });
  94. }
  95. //轮询
  96. //getMiaoshaResult($("#goodsId").val());
  97. }else{
  98. layer.msg(data.msg);
  99. }
  100. },
  101. error:function(){
  102. layer.msg("请求有误!");
  103. }
  104. //token如果cookie里面有,会自己带过去
  105. });
  106. }
  107. function doMiaosha(){
  108. alert("秒杀!");
  109. $.ajax({
  110. url:"/miaosha/do_miaosha_ajaxcache",
  111. type:"POST",
  112. data:{
  113. goodsId:$("#goodsId").val()
  114. },
  115. success:function(data){
  116. if(data.code==0){
  117. //秒杀成功,跳转详情页面
  118. //window.location.href="order_detail.htm?orderId="+data.data.id;
  119. //轮询
  120. getMiaoshaResult($("#goodsId").val());
  121. }else{
  122. layer.msg(data.msg);
  123. }
  124. },
  125. error:function(){
  126. layer.msg("请求有误!");
  127. }
  128. //token如果cookie里面有,会自己带过去
  129. });
  130. }
  131. $(function(){
  132. //countDown();
  133. getDetail();
  134. });
  135. //渲染页面--------5-17
  136. function render(detail){
  137. //alert(detail.status);
  138. var miaoshaStatus=detail.status;
  139. var remailSeconds=detail.remailSeconds;
  140. var goods=detail.goodsVo;
  141. var user=detail.user;
  142. if(user!=null){
  143. //展示相应的
  144. $("#userTip").hide();
  145. }
  146. $("#goodsName").text(goods.goodsName);
  147. $("#goodsImg").attr("src",goods.goodsImg); //.text();
  148. $("#startTime").text(goods.startDate); //还没有格式化
  149. $("#remailSeconds").val(remailSeconds);
  150. $("#goodsId").val(goods.id);
  151. $("#goodsPrice").text(goods.goodsPrice); //goodsStock----- stockCount
  152. $("#miaoshaPrice").text(goods.miaoshaPrice);
  153. $("#stockCount").text(goods.goodsStock);
  154. countDown();
  155. }
  156. function getQueryString(name){
  157. var reg=new RegExp("(^|&)"+name+"=([^&]*)(&|$)");
  158. var r=window.location.search.substr(1).match(reg);
  159. if(r!=null){
  160. return unescape(r[2]);
  161. }
  162. return null;
  163. }
  164. function getDetail(){
  165. var goodsId=getQueryString("goodsId");
  166. //alert(goodsId);
  167. $.ajax({
  168. url:"/goods/detail/"+goodsId,
  169. type:"GET",
  170. success:function(data){
  171. if(data.code==0){
  172. render(data.data);
  173. }else{
  174. layer.msg(data.msg);
  175. }
  176. },
  177. error:function(){
  178. layer.msg("请求有误!");
  179. }
  180. });
  181. }
  182. function countDown(){
  183. //获取秒杀倒计时进行判断,0-->正在进行秒杀,-1-->秒杀结束,remailSeconds>0-->代表倒计时
  184. var remailSeconds=$("#remailSeconds").val();
  185. //alert("remailSeconds:"+remailSeconds);
  186. var timeout;
  187. if(remailSeconds>0){//秒杀还没有开始,进行倒计时功能
  188. $("#buyButton").attr("disabled",true);
  189. $("#miaoshaTip").html("秒杀倒计时:"+remailSeconds+"秒");
  190. //倒计时
  191. timeout=setTimeout(function(){
  192. $("#countDown").text(remailSeconds-1);
  193. $("#remailSeconds").val(remailSeconds-1);//remailSeconds这是input
  194. countDown();
  195. },1000);//一秒钟之后回调函数
  196. }else if(remailSeconds==0){//正在进行秒杀
  197. $("#buyButton").attr("disabled",false);
  198. if(timeout){//如果timeout有值的情况
  199. clearTimeout(timeout);
  200. }
  201. //将文案修改 df1fab4272a24cdf9432adb9fd69cb38
  202. $("#miaoshaTip").html("秒杀进行中");
  203. }else{
  204. //小于0的情况,秒杀结束,将秒杀按钮设置为不可点击
  205. $("#buyButton").attr("disabled",true);
  206. $("#miaoshaTip").html("秒杀结束");
  207. }
  208. }
  209. </script>
  210. </html>

版权声明:本文为changshao原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/changshao/p/12914158.html