【SpringBoot商城秒杀系统项目实战18】页面优化技术-商品详情页面静态化(前后端分离)

页面静态化+前后端分离

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

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

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

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

商品详情页静态化

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

  1. 为了在浏览器端进行缓存,以及控制缓存时间,在application.properties里面添加配置静态资源配置项:
#static  静态资源配置,设置静态文件路径css,js,图片等等
#spring.mvc.static-path-pattern=/static/**    spring.mvc.static-path-pattern=/**
spring.resources.add-mappings=true
spring.resources.cache-period=3600 
spring.resources.chain.cache=true
spring.resources.chain.enabled=true
spring.resources.chain.gzipped=true 
spring.resources.chain.html-application-cache=true
spring.resources.static-locations=classpath:/static/ 
  1. 在static资源文件夹下面新建我们的静态资源页面文件,(我们以.htm格式结尾),这里为什么不能用.html文件结尾是因为如果不修改继续用.html后缀,系统会默认去找templates下面的同名文件,所以我们修改它以示区别
    在这里插入图片描述

  2. 定义一个GoodsDetailVo封装来专门给页面传值。

	/**
	 * 为了给页面传值
	 */
	public class GoodsDetailVo {
	// 秒杀状态量初始值
	private int status = 0;
	// 开始时间倒计时
	private int remailSeconds = 0;
	private GoodsVo goodsVo;
	private MiaoshaUser user;
	public int getStatus() {
		return status;
	}
	public void setStatus(int status) {
		this.status = status;
	}
	public int getRemailSeconds() {
		return remailSeconds;
	}
	public void setRemailSeconds(int remailSeconds) {
		this.remailSeconds = remailSeconds;
	}
	public GoodsVo getGoodsVo() {
		return goodsVo;
	}
	public void setGoodsVo(GoodsVo goodsVo) {
		this.goodsVo = goodsVo;
	}
	public MiaoshaUser getUser() {
		return user;
	}
	public void setUser(MiaoshaUser user) {
		this.user = user;
	}	
}
  1. 改造商品列表页面(goods_list.html)里面的跳转逻辑,修改跳转请求

之前的请求路径:

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

现在的请求路径:

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

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

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

在这里插入图片描述

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

getDetail方法:

	function getDetail(){
		//getQueryString获取请求路径中的参数
		var goodsId=getQueryString("goodsId");
		//alert(goodsId);
		$.ajax({
			url:"/goods/detail/"+goodsId,
			type:"GET",
			success:function(data){
				if(data.code==0){		
					//使用render方法渲染页面							
					render(data.data);
				}else{
					layer.msg(data.msg);
				}
			},
			error:function(){
				layer.msg("请求有误!");
			}
		});		
	}
  1. getDetail()方法使用ajax异步请求后台取得该页面需要的数据,然后拿到数据之后调用render()方法渲染我们的静态页面,注意在getDetail中第一步做的是去获取商品的goodsId,因为list页面的商品详情请求是:
<td><a th:href="'/goods_detail.htm?goodsId='+${goods.id}">详情</a></td>

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

function getQueryString(name) {
		var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
		var r = window.location.search.substr(1).match(reg);
		if (r != null) {
			return unescape(r[2]);
		}
		return null;
	}
  1. 获取到参数之后就可以去请求后端接口,获取数据去渲染:
	function render(detail) {
		//alert(detail.status);
		var miaoshaStatus = detail.status;
		var remailSeconds = detail.remailSeconds;
		var goods = detail.goodsVo;
		var user = detail.user;
		if (user != null) {
			//展示相应的
			$("#userTip").hide();
		}
		$("#goodsName").text(goods.goodsName);
		$("#goodsImg").attr("src", goods.goodsImg); //.text();
		$("#startTime").text(goods.startDate); //还没有格式化
		$("#remailSeconds").val(remailSeconds);
		$("#goodsId").val(goods.id);
		$("#goodsPrice").text(goods.goodsPrice); //goodsStock----- stockCount
		$("#miaoshaPrice").text(goods.miaoshaPrice);
		$("#stockCount").text(goods.goodsStock);
		countDown();
	}
  1. 倒计时countDown()方法:
	function countDown(){
		//获取秒杀倒计时进行判断,0-->正在进行秒杀,-1-->秒杀结束,remailSeconds>0-->代表倒计时
		var remailSeconds=$("#remailSeconds").val();
		//alert("remailSeconds:"+remailSeconds);
		var timeout;
		
		if(remailSeconds>0){//秒杀还没有开始,进行倒计时功能
			$("#buyButton").attr("disabled",true);
			$("#miaoshaTip").html("秒杀倒计时:"+remailSeconds+"秒");
			//倒计时
			timeout=setTimeout(function(){
				$("#countDown").text(remailSeconds-1);
				$("#remailSeconds").val(remailSeconds-1);//remailSeconds这是input
				countDown();
			},1000);//一秒钟之后回调函数
			
		}else if(remailSeconds==0){//正在进行秒杀
			$("#buyButton").attr("disabled",false);
			if(timeout){//如果timeout有值的情况
				clearTimeout(timeout);
			}
			//将文案修改 df1fab4272a24cdf9432adb9fd69cb38
			$("#miaoshaTip").html("秒杀进行中");
		}else{
			//小于0的情况,秒杀结束,将秒杀按钮设置为不可点击
			$("#buyButton").attr("disabled",true);
			$("#miaoshaTip").html("秒杀结束");
		}
	}
  1. 将后端GoodsController里面接收商品详情页的请求的接口修改为下面代码:
	/**
	 * 作页面静态化的商品详情
	 * 页面存的是html
	 * 动态数据通过接口从服务端获取
	 * @param model
	 * @param user
	 * @param goodsId
	 * @return
	 */
	@RequestMapping(value="/detail/{goodsId}")  //produces="text/html"
	@ResponseBody
	public Result<GoodsDetailVo> toDetail_staticPage(Model model,MiaoshaUser user,
			HttpServletRequest request,HttpServletResponse response,@PathVariable("goodsId")long goodsId) {//id一般用snowflake算法
		System.out.println("页面静态化/detail/{goodsId}");
		model.addAttribute("user", user);
		GoodsVo goodsVo=goodsService.getGoodsVoByGoodsId(goodsId);
		model.addAttribute("goods", goodsVo);
		//既然是秒杀,还要传入秒杀开始时间,结束时间等信息
		long start=goodsVo.getStartDate().getTime();
		long end=goodsVo.getEndDate().getTime();
		long now=System.currentTimeMillis();
		//秒杀状态量
		int status=0;
		//开始时间倒计时
		int remailSeconds=0;
		//查看当前秒杀状态
		if(now<start) {//秒杀还未开始,--->倒计时
			status=0;
			remailSeconds=(int) ((start-now)/1000);  //毫秒转为秒
		}else if(now>end){ //秒杀已经结束
			status=2;
			remailSeconds=-1;  //毫秒转为秒
		}else {//秒杀正在进行
			status=1;
			remailSeconds=0;  //毫秒转为秒
		}
		model.addAttribute("status", status);
		model.addAttribute("remailSeconds", remailSeconds);
		GoodsDetailVo gdVo=new GoodsDetailVo();
		gdVo.setGoodsVo(goodsVo);
		gdVo.setStatus(status);
		gdVo.setRemailSeconds(remailSeconds);
		gdVo.setUser(user);
		//将数据填进去,传至页面
		return Result.success(gdVo);		
	}

goods_detail.htm完整代码:

<!DOCTYPE html>
<html>  
<head>
<meta charset="UTF-8"/>
<title>商品详情</title>
	<!-- jquery -->
	<!-- <script type="text/javascript" src="@{/js/jequery.min.js}"></script> -->
	<script type="text/javascript" src="/jquery-validation/lib/jquery-1.11.1.js"></script>
	<link type="text/css" rel="stylesheet" href="/bootstrap/css/bootstrap.css"/>
	<script type="text/javascript" src="/bootstrap/js/bootstrap.min.js"></script>
	<!-- layer -->
	<script type="text/javascript" src="/layer/layer.js"></script>
</head
<body>
	<div class="panel panel-default">
		<div class="panel-heading">秒杀商品详情</div>
		<div class="panel-body"> 
			<span id="userTip">您还没有登录,请登录后再操作</span>
			<span>没有收货地址的提示。。。</span>
			<input type="hidden" id="goodsId" >  <!-- $("#goodsId").val(goods.id); -->
		</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="80" height="60"></img></td>
		</tr>
		<tr>
			<td>秒杀开始时间</td>
			<td id="startTime"></td>
			<td id="">
				<!-- 先取得这个时间 -->
				<input type="hidden" id="remailSeconds"></input>			
				<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"></input>
				</form>
			</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 type="text/javascript">
	//获取秒杀地址
	function getMiaoshaPath(){
		var goodsId=$("#goodsId").val();
	}
	//做轮询
	function getMiaoshaResult(goodsId){
		$.ajax({
			url:"/miaosha/result",
			type:"GET",
			data:{
				goodsId:$("#goodsId").val()
			},
			success:function(data){
				if(data.code==0){
					var result=data.data;
					if(result<0){
						layer.msg("抱歉,秒杀失败!");
					}else if(result==0){
						//继续轮询
						setTimeout(function(){
							getMiaoshaResult(goodsId);	
						},50);//50ms之后继续轮询
						layer.msg(data.msg);
					}else{
						layer.confirm("恭喜你,秒杀成功!查看订单?",{btn:["确定","取消"]},
								function(){
								//秒杀成功,跳转详情页面
								window.location.href="order_detail.htm?orderId="+result;	
						},
								function(){
								layer.closeAll();
						});
					}
					
					//轮询
					//getMiaoshaResult($("#goodsId").val());
				}else{
					layer.msg(data.msg);
				}
			},
			error:function(){
				layer.msg("请求有误!");
			}
			//token如果cookie里面有,会自己带过去
			
		});
	}
	function doMiaosha(){
		alert("秒杀!");
		$.ajax({
			url:"/miaosha/do_miaosha_ajaxcache",
			type:"POST",
			data:{
				goodsId:$("#goodsId").val()
				
			},
			success:function(data){
				if(data.code==0){
					//秒杀成功,跳转详情页面
					//window.location.href="order_detail.htm?orderId="+data.data.id;	
					//轮询
					getMiaoshaResult($("#goodsId").val());
				}else{
					layer.msg(data.msg);
				}
			},
			error:function(){
				layer.msg("请求有误!");
			}
			//token如果cookie里面有,会自己带过去
			
		});
	}
	$(function(){
		//countDown();
		getDetail();
	});
	
	//渲染页面--------5-17
	function render(detail){
		//alert(detail.status);
		var miaoshaStatus=detail.status;
		var remailSeconds=detail.remailSeconds;
		var goods=detail.goodsVo;
		var user=detail.user;
		if(user!=null){
			//展示相应的
			$("#userTip").hide();
		}
		$("#goodsName").text(goods.goodsName);
		$("#goodsImg").attr("src",goods.goodsImg);    //.text();
		$("#startTime").text(goods.startDate);		//还没有格式化
		$("#remailSeconds").val(remailSeconds);
		$("#goodsId").val(goods.id);
		$("#goodsPrice").text(goods.goodsPrice);		//goodsStock----- stockCount
		$("#miaoshaPrice").text(goods.miaoshaPrice);
		$("#stockCount").text(goods.goodsStock);
		countDown();
	}
	
	function getQueryString(name){
		var reg=new RegExp("(^|&)"+name+"=([^&]*)(&|$)");
		var r=window.location.search.substr(1).match(reg);
		if(r!=null){
			return unescape(r[2]);
		}
		return null;
	}
	
	
	function getDetail(){
		var goodsId=getQueryString("goodsId");
		//alert(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(){
		//获取秒杀倒计时进行判断,0-->正在进行秒杀,-1-->秒杀结束,remailSeconds>0-->代表倒计时
		var remailSeconds=$("#remailSeconds").val();
		//alert("remailSeconds:"+remailSeconds);
		var timeout;
		
		if(remailSeconds>0){//秒杀还没有开始,进行倒计时功能
			$("#buyButton").attr("disabled",true);
			$("#miaoshaTip").html("秒杀倒计时:"+remailSeconds+"秒");
			//倒计时
			timeout=setTimeout(function(){
				$("#countDown").text(remailSeconds-1);
				$("#remailSeconds").val(remailSeconds-1);//remailSeconds这是input
				countDown();
			},1000);//一秒钟之后回调函数
			
		}else if(remailSeconds==0){//正在进行秒杀
			$("#buyButton").attr("disabled",false);
			if(timeout){//如果timeout有值的情况
				clearTimeout(timeout);
			}
			//将文案修改 df1fab4272a24cdf9432adb9fd69cb38
			$("#miaoshaTip").html("秒杀进行中");
		}else{
			//小于0的情况,秒杀结束,将秒杀按钮设置为不可点击
			$("#buyButton").attr("disabled",true);
			$("#miaoshaTip").html("秒杀结束");
		}
	}
</script>
</html>
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值