秒杀项目(3) 实现秒杀功能

一、实现秒杀功能

1.1 数据库设计

1.2 商品列表页

1.3 商品详情页

1.4 订单详情页

1.5 流程

用户进入商品列表页,选中要秒杀的商品,点击详情进入商品详情页,点击秒杀,秒杀成功,进入订单详情页。

二、秒杀商品列表页

2.1 页面展示

在这里插入图片描述

2.2 商品列表页对应的数据实体

秒杀商品表有以一个主键,一个外键,需要把商品和用户分开再建立一个表。

//将Goods表和MiaoshaGoods表合并
public class GoodsVo extends Goods {
	private Integer stockCount; //库存
	private Date startDate;
	private Date endDate;
	private Double miaoshaPrice;
    .......
    }

2.3 查找所有商品

@Mapper
public interface GoodsDao {
    @Select("select g.*,mg.stock_count,mg.start_date,mg.end_date,mg.miaosha_price from miaosha_goods mg left join goods g on mg.goods_id=g.id")
    public List<GoodsVo> selectGoods();
}

2.4 查找所有商品的业务逻辑

查找所有商品返回列表页

public String to_login(HttpServletResponse response, Model model,/* @CookieValue(name = MiaoShaUserService.COOKIE_NAME, required = false)String token,
                           @PathVariable(name = MiaoShaUserService.COOKIE_NAME,required = false)String token1*/MiaoshaUser user){
        //得不到任何的cookie信息,则说明未登陆过,返回到登录界面
       /* if(StringUtils.isEmpty(token)&&StringUtils.isEmpty(token1)){
            return "login";
        }
        String realToken = StringUtils.isEmpty(token1) ? token : token1;
        MiaoshaUser byToken = miaoShaUserService.getByToken(token, response);
        System.out.println("拿到token对应的user");*/
        List<GoodsVo> goods = goodsService.selectAll();

        System.out.println(goods.size());
        model.addAttribute("goodsList",goods);
        return "goods_list";
    }

三、商品详情页

3.1 页面展示

在这里插入图片描述

3.2 页面展示逻辑

点击详情,前端会把商品对应的商品id传给后端,后端根据商品id的到对应的秒杀商品信息传给前端。进行展示。

  @RequestMapping("/to_detail/{goodsId}")
    public String goodsDetail(@PathVariable("goodsId")Long goodsId,Model model,MiaoshaUser miaoshaUser){
        GoodsVo goodsVo = goodsService.seleteReferGoods(goodsId);
        GoodsDetailVo goodsDetailVo = new GoodsDetailVo();
        goodsDetailVo.setGoodsVo(goodsVo);
        goodsDetailVo.setUser(miaoshaUser);
        goodsDetailVo.setStatus(goodsVo.getStockCount());
        System.out.println(goodsVo.getMiaoshaPrice() + " " + "库存" + goodsVo.getStockCount());
        System.out.println("商品的要点:" + goodsDetailVo.getRemailSeconds() + " " + goodsDetailVo.getStatus());
        long end = goodsVo.getEndDate().getTime();
        long start = goodsVo.getStartDate().getTime();
        long now = System.currentTimeMillis();
        int remainSeconds = 0;
        int miaoshastatus = 0;
        //判断秒杀是否开始
        if(start > now){
            //秒杀未开始
            miaoshastatus = 0;
            remainSeconds = (int)(end - start)/1000;
        }
        else if(end <= now){
            //秒杀已经结束
            miaoshastatus = 2;
            remainSeconds = -1;
        }
        else{
            //秒杀正在进行
            miaoshastatus = 1;
            remainSeconds = (int)(end - now)/1000;
        }
        if(miaoshaUser == null){
            System.out.println("秒杀对象为空");
        }else {
            System.out.println("秒杀对象不为空");
        }
        goodsDetailVo.setRemailSeconds(remainSeconds);
        model.addAttribute("goods",goodsVo);
        model.addAttribute("remainSeconds",remainSeconds);
        model.addAttribute("user",miaoshaUser);
        return "goods_detail";
    }

3.3 秒杀是否开始

取现在的时间与秒杀开始时间和秒杀结束时间进行比较,将时间差传递给前端。倒计时等交给前端去处理。

  • 秒杀未开始和秒杀结束情况下,秒杀按钮是不能点击的。
  • 秒杀未开始会有一个倒计时提醒还有多长时间才能进行秒杀。
  • 秒杀进行中提示是秒杀进行中。
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("秒杀进行中");
			//添加验证码
			$("#vertifyCodeImg").attr("src","/miaosha/vertifyCode?goodsId="+$("#goodsId").val());
			$("#vertifyCodeImg").show();
			$("#vertifyCode").show();
			
		} else {
			//小于0的情况,秒杀结束,将秒杀按钮设置为不可点击
			$("#buyButton").attr("disabled", true);
			$("#miaoshaTip").html("秒杀结束");
			//隐藏验证码
			$("#vertifyCodeImg").hide();
			$("#vertifyCode").hide();
		}
	}

四、点击秒杀

4.1 判断用户是否登录,并根据goodsID得到对应的商品信息

根据请求所带的cookie,取到对应的session信息,再有sessionID从redis中取到对应的用户信息,如果能取到则证明用户已经登录,否则未登录。

@RequestMapping("/do_miaosha")
    public String doMiaoSha(Model model, MiaoshaUser miaoshaUser, @RequestParam("goodsId")long goodsId){
        //1.判断用户是否登录
        if(miaoshaUser == null){
            return "login";
        }
        GoodsVo goodsVo = goodsService.seleteReferGoods(goodsId);
        ......
  }

4.2 判断商品的库存够不够

由上面拿到的对应的商品ID,从Goods表中得到对应商品的库存,判断库存是否支持秒杀。

 //2.判断库存是否足够秒杀
        Integer stockCount = goodsVo.getStockCount();
        if(stockCount <= 0){
            model.addAttribute("errmsg", CodeMsg.MIAOSHA_OVER_ERROR.getMsg());
            return "miaosha_fail";
        }

4.3 判断用户是不是重复秒杀

  • 从redis中如果取到用户对应的秒杀信息,则证明用户已经秒杀过商品
  • 从redis中取不到则从MiaoshaOrder表中去取,如果能取到则证明用户已经秒杀过商品
  • 否则不是重复秒杀,每一步都需要把对应的信息添加到Model对象中
 //3.判断是否重复秒杀
        //先从缓存中取
        OrderInfo orderInfo = null;
        OrderInfo orderInfo1 = redisService.get(MiaoshaOrderKey.OrderByManyID, "" + miaoshaUser.getId() + goodsVo.getId(), OrderInfo.class);
        if(orderInfo1 != null){
            model.addAttribute("errmsg",CodeMsg.REPEATE_MIAOSHA.getMsg());
            return "miaosha_fail";

        }else{
            orderInfo = orderService.getOrderInfo(miaoshaUser.getId(), goodsVo.getId());
        }
        if(orderInfo != null){
            model.addAttribute("errmsg",CodeMsg.REPEATE_MIAOSHA.getMsg());
            return "miaosha_fail";
        }

4.4 进行秒杀

4.4.1 减少库存

需要减少Goods表中的库存,和MiaoshaGoods表中的库存。

 //减少库存,Goods表的库存得减少,MiaoshaGoods表的库存也得减少
        goodsVo.setStockCount(goodsVo.getStockCount() - 1);
        System.out.println("步骤3.1");
        goodsService.reduceGoodsStock(goodsVo.getId());
        System.out.println("步骤3.2");
        miaoshaGoodsService.reduceMiaoshaGoodsCount(goodsVo.getId());
        System.out.println("步骤3.3");

4.4.2 将秒杀商品的信息存到OrderInfo表中和Miaosha_order表中

 //根据MiaoshaUser和goodsvo生成OrderInfor对象的信息,并将OrderInfo信息插入到Order_Info表中,将MiaoshaOrder信息插入到miaosha_order表中。
    public OrderInfo creatOrder(MiaoshaUser user, GoodsVo goodsvo) {
        //1.生成order_info
        OrderInfo orderInfo=new OrderInfo();
        orderInfo.setDeliveryAddrId(0L);//long类型 private Long deliveryAddrId;   L
        orderInfo.setCreateDate(new Date());
        orderInfo.setGoodsCount(1);
        orderInfo.setGoodsId(goodsvo.getId());
        //秒杀价格
        orderInfo.setGoodsPrice(goodsvo.getMiaoshaPrice());
        orderInfo.setOrderChannel(1);
        //订单状态  ---0-新建未支付  1-已支付  2-已发货  3-已收货
        orderInfo.setOrderStatus(0);
        //用户id
        orderInfo.setUserId(user.getId());
        //返回orderId
        //long orderId=
        insertOrderInfo(orderInfo);
        System.out.println("步骤4.1");
        //2.生成miaosha_order
        MiaoshaOrder miaoshaorder =new MiaoshaOrder();
        miaoshaorder.setGoodsId(goodsvo.getId());
        //将订单id传给秒杀订单里面的订单orderid
        miaoshaorder.setOrderId(orderInfo.getId());
        miaoshaorder.setUserId(user.getId());
        System.out.println("步骤5.1");
        insertMiaoshaOrder(miaoshaorder);
        System.out.println("步骤5.2");
        return orderInfo;
    }

4.5 秒杀完成,将秒杀信息存到缓存中

秒杀信息的key是用户ID和GoodsID,因为每个客户只能进行一次秒杀

 //5.秒杀成功,存入redis中
redisService.set(MiaoshaOrderKey.OrderByManyID,""+miaoshaUser.getId() +      goodsVo.getId(),orderInfo);

4.6 返回订详情页

五、订单详情页

5.1 页面展示

在这里插入图片描述

5.2 对应的封装类

public class OrderInfo {
	private Long id;
	private Long userId;//用户
	private Long goodsId;
	private Long deliveryAddrId;//收货地址
	private String goodsName;//商品名称
	private Integer goodsCount;//商品下单数量
	private Double goodsPrice;//下单价格
	private Integer orderChannel;//下单渠道
	private Integer orderStatus;//下单状态,0:未支付,1:已支付,2:已发货,3:已收货,4:已退款,5:已完成
	private Date createDate;//下单时间
	private Date payDate;//支付时间
	}

5.3 MiaoshaOrder表对应的封装类

public class MiaoshaOrder {
	private Long id;
	private Long userId;
	private Long orderId;//订单ID
	private Long goodsId;//商品ID
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值