Java高性能高并发实战之秒杀功能设计(三)

前言

此篇文章是系列的第三篇文章,具体文章目录:

章节名称 博客地址
安装部署Redis 集成Redis(已完结)
页面登陆功能设计 登录功能设计(更新优化中)
秒杀页面具体设计 秒杀详情页(已完结)
JMeter初级压测学习 Jmeter压测入门学习(已完结)
页面优化设计 页面优化设计(已完结)
接口优化 RabbbitMq接口优化(已完结)
图形验证码等 图形验证码及接口防刷(更新优化中)

正文

写在前面:在正式开始秒杀功能设计学习之前,先去源码地址查看READMEmiaosha_3部分中数据库的设计,先行完善数据库,源码对应的是miaosha_3部分,然后开始下面的学习。

对于秒杀页面设计,我们想象以下“在秒杀活动开始之前,商家都会向我们发出一个讯息,表示商品要进行秒杀,这个时候我们就可以登录到具体的秒杀页面,先行查看商品的列表信息,点击查看详情部分一般都有商品的具体信息,商品的秒杀价格,商品的主图以及具体的详细信息,一般都会有一个商品的秒杀开始时间与结束时间。

  1. 在没有开始时候会显示倒计时,这里我们设计的是倒计时单位为秒,并且可以进行秒杀的按钮一般都是不能够点击。
  2. 秒杀进行中会提示秒杀进行中,此时我们可以点击秒杀进行秒杀。
  3. 当秒杀的结束时间在当前时间之前,表示秒杀结束,我们就不能够再进行秒杀,此时秒杀按钮也被设置为不可点击。

列表页设计

对于列表页的设计我们是在登录成功之后就会跳转到本地的http://localhost:8080/goods/to_list,实现商品列表的显示,从数据库中读取到设置为秒杀的商品就是我们的秒杀商品表:后端就是简单三层模式,前端就对应数据的显示:

@RequestMapping("/to_list")
    public String list(Model model,MiaoshaUser user) {
    	model.addAttribute("user", user);
    	//查询商品列表
    	List<GoodsVo> goodsList = goodsService.listGoodsVo();
    	model.addAttribute("goodsList", goodsList);
        return "goods_list";
    }
<div class="panel panel-default">
  <div class="panel-heading">秒杀商品列表</div>
  <table class="table" id="goodslist">
  	<tr><td>商品名称</td><td>商品图片</td><td>商品原价</td><td>秒杀价</td><td>库存数量</td><td>详情</td></tr>
  	<tr  th:each="goods,goodsStat : ${goodsList}">  
                <td th:text="${goods.goodsName}"></td>  
                <td ><img th:src="@{${goods.goodsImg}}" width="100" height="100" /></td>  
                <td th:text="${goods.goodsPrice}"></td>  
                <td th:text="${goods.miaoshaPrice}"></td>  
                <td th:text="${goods.stockCount}"></td>
                <td><a th:href="'/goods/to_detail/'+${goods.id}">详情</a></td>  
     </tr>  
  </table>
</div>

在这里插入图片描述

商品详情页

对于我们点击了详情页面以后我们思考需要显示什么信息,对于商品来说,我们需要拿到具体的商品的信息,如商品的主图,名称,价格等,但是还需要拿到具体的开始时间,结束时间,已经秒杀时候的价格,所以我们就需要再封装一个对象将商品的信息与秒杀时候信息进行一个整合,在查找时候就根据id查找这个对象,返回给主页面。
首先来看封装的对象,继承自Goods,并添加些新的参数变量。

public class GoodsVo extends Goods{
	private Double miaoshaPrice;
	private Integer stockCount;
	private Date startDate;
	private Date endDate;
	public Integer getStockCount() {
		return stockCount;
	}
	public void setStockCount(Integer stockCount) {
		this.stockCount = stockCount;
	}
	public Date getStartDate() {
		return startDate;
	}
	public void setStartDate(Date startDate) {
		this.startDate = startDate;
	}
	public Date getEndDate() {
		return endDate;
	}
	public void setEndDate(Date endDate) {
		this.endDate = endDate;
	}
	public Double getMiaoshaPrice() {
		return miaoshaPrice;
	}
	public void setMiaoshaPrice(Double miaoshaPrice) {
		this.miaoshaPrice = miaoshaPrice;
	}
}

完成以后来看后端具体实现:

 @RequestMapping("/to_detail/{goodsId}")
 // 因为要根据id查询到具体是哪个商品的具体信息。传参id。
    public String detail(Model model,MiaoshaUser user,
    		@PathVariable("goodsId")long goodsId) {
    	model.addAttribute("user", user);
    	
    	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;
    		// 具体的status状态看数据库中状态一栏的注释。
    		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);
        return "goods_detail";
    }

秒杀详情页

完成以后就可以读取到具体的具体的商品的详细信息。这个时候开始若是可以开始进行秒杀活动,需要判断以下的情况:

  1. 首先判断库存是否充足,这里暂时不考虑一些其他的高并发的超买超卖的情况(具体的解决方法可以添加版本号进行控制,使用到乐观锁)。
  2. 若是商品充足,我们需要判断是否已经秒杀过,因为我们若是秒杀成功以后会写入到miaosha_order可以根据用户id和商品id在这个表中就可以判断该用户是否已经秒杀了该商品。
  3. 若是以上都已经判断完成,就可以开始进行秒杀:减库存,将订单信息写入到秒杀订单表中。
 @RequestMapping("/do_miaosha")
    public String list(Model model,MiaoshaUser user,
    		@RequestParam("goodsId")long goodsId) {
    	model.addAttribute("user", user);
    	if(user == null) {
    		return "login";
    	}
    	//判断库存
    	GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
    	int stock = goods.getStockCount();
    	if(stock <= 0) {
    		model.addAttribute("errmsg", CodeMsg.MIAO_SHA_OVER.getMsg());
    		return "miaosha_fail";
    	}
    	//判断是否已经秒杀到了
    	MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
    	if(order != null) {
    		model.addAttribute("errmsg", CodeMsg.REPEATE_MIAOSHA.getMsg());
    		return "miaosha_fail";
    	}
    	//减库存 下订单 写入秒杀订单
    	OrderInfo orderInfo = miaoshaService.miaosha(user, goods);
    	model.addAttribute("orderInfo", orderInfo);
    	model.addAttribute("goods", goods);
        return "order_detail";
    }

后记

以上就是简单地对秒杀页面进行的具体设计,实现的也只是简单商品列表的显示, 商品详情显示,已经秒杀业务逻辑的判断与设计,主要是先实现一个大体的框架,后续的优化部分会在后面的章节里面继续讲解。可以对照源码部分进行具体的后续学习,这里也只是我的拙见。有什么不得体或是错误的地方也希望大家能够指出。

猜你喜欢

转载自blog.csdn.net/weixin_44015043/article/details/105907535
今日推荐