秒杀系统Web实践——03秒杀模块

第三章秒杀功能

1.数据库设计

2.商品列表

3.商品详情

4.秒杀功能

5.订单详情

附录:

页面代码


1.数据库设计

秒杀系统Web实践——03秒杀模块_第1张图片

DROP TABLE IF EXISTS `goods`;
CREATE TABLE `goods`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '商品ID',
  `goods_name` varchar(16)  DEFAULT NULL COMMENT '商品名称',
  `goods_title` varchar(64)  DEFAULT NULL COMMENT '商品标题',
  `goods_img` varchar(64)  DEFAULT NULL COMMENT '商品的图片',
  `goods_detail` longtext  COMMENT '商品的详情介绍',
  `goods_price` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '商品单价',
  `goods_stock` int(11) NULL DEFAULT 0 COMMENT '商品库存,-1表示没有限制',
  PRIMARY KEY (`id`) 
) ENGINE = InnoDB  CHARACTER SET = utf8mb4

CREATE TABLE `miaosha_goods`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '秒杀的商品表',
  `goods_id` bigint(20) NULL DEFAULT NULL COMMENT '商品Id',
  `miaosha_price` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '秒杀价',
  `stock_count` int(11) NULL DEFAULT NULL COMMENT '库存数量',
  `start_date` datetime(0) NULL DEFAULT NULL COMMENT '秒杀开始时间',
  `end_date` datetime(0) NULL DEFAULT NULL COMMENT '秒杀结束时间',
  PRIMARY KEY (`id`) 
) ENGINE = InnoDB  CHARACTER SET = utf8mb4 

CREATE TABLE `miaosha_order`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户ID',
  `order_id` bigint(20) NULL DEFAULT NULL COMMENT '订单ID',
  `goods_id` bigint(20) NULL DEFAULT NULL COMMENT '商品ID',
  PRIMARY KEY (`id`) 
) ENGINE = InnoDB  CHARACTER SET = utf8mb4

CREATE TABLE `order_info`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户ID',
  `goods_id` bigint(20) NULL DEFAULT NULL COMMENT '商品ID',
  `delivery_addr_id` bigint(20) NULL DEFAULT NULL COMMENT '收获地址ID',
  `goods_name` varchar(16)  DEFAULT NULL COMMENT '冗余过来的商品名称',
  `goods_count` int(11) NULL DEFAULT 0 COMMENT '商品数量',
  `goods_price` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '商品单价',
  `order_channel` tinyint(4) NULL DEFAULT 0 COMMENT '1pc , 2android , 3ios',
  `status` tinyint(4) NULL DEFAULT 0 COMMENT '订单状态, 0新建未支付,1已支付, 2已发货, 3已收货, 4已退款, 5已完成',
  `create_date` datetime(0) NULL DEFAULT NULL COMMENT '订单的创建时间',
  `ipay_date` datetime(0) NULL DEFAULT NULL COMMENT '支付时间',
  PRIMARY KEY (`id`) 
) ENGINE = InnoDB CHARACTER SET = utf8mb4

2.商品列表

我们希望得到的商品列表,不仅仅只是商品信息,还希望有秒杀的信息,所以要使用多表连接查询,并且使用一个VO来接受查询出的信息

@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 listGoodsVo();
public class GoodsVo extends Goods{
    private Double miaoshaPrice;
    private Integer stockCount;
    private Date startDate;
    private Date endDate;
    
    //get/set方法。。。。。

}
    @RequestMapping(value="/to_list")
    public String list(Model model, MiaoshaUser user,
        HttpServletRequest request, 
        HttpServletResponse response){

        model.addAttribute("user",user);
       
        List goodsList = goodsService.listGoodsVo();
        model.addAttribute("goodsList",goodsList);

        return "goods_list";
}

3.商品详情

对于商品详情信息,获得商品信息的同时,还要关注秒杀的状态,在这里0表示还没开始,1表示秒杀进行中,2表示秒杀已结束,当秒杀还没有开始的时候,要进行秒杀倒计时,也就是代码中的remainSeconds

    @RequestMapping(value="/to_detail2/{goodsId}",produces="text/html")
    public String detai2(HttpServletRequest request, HttpServletResponse response,
        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;
            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";

    }

4.秒杀功能

秒杀功能实现之前,我们要明确,该商品是否还有库存,该用户是否已经秒杀了该商品,当出现没有库存或已经秒杀过的情况将不能继续进入的秒杀的逻辑代码。

同时我们要明确,秒杀的逻辑其实是减小库存同时下订单并写入数据库,只要中间一步产生了失误,就要进行事务的回滚。

@Controller
@RequestMapping("/miaosha")
public class MiaoshaController {
  
    @Autowired
    GoodsService goodsService;

    @Autowired
    OrderService orderService;

    @Autowired
    MiaoshaService miaoshaService;

    @RequestMapping(value = "/do_miaosha")
    public String hellowrold(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";
    }
}

事务处理@Transactional

@Service
public class MiaoshaService {
    @Autowired
    GoodsService goodsService;

    @Autowired
    OrderService orderService;

    //事务
    @Transactional
    public OrderInfo miaosha(MiaoshaUser user, GoodsVo goods) {
        //减库存 下订单 写入秒杀订单
        //减库存
        System.out.println("减库存");
        goodsService.reduceStock(goods);
        //order_info maiosha_order
        //下订单 写入秒杀订单
        System.out.println("添加订单");
        return orderService.createOrder(user, goods);
    }
}

添加订单也是同时向order_info和miaosha_order添加记录

@Service
public class OrderService {
    @Autowired
    OrderDao orderDao;

    public OrderInfo getOrderById(long orderId) {
        return orderDao.getOrderById(orderId);
    }

    @Transactional
    public OrderInfo createOrder(MiaoshaUser user, GoodsVo goods) {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setCreateDate(new Date());
        orderInfo.setDeliveryAddrId(0L);
        orderInfo.setGoodsCount(1);
        orderInfo.setGoodsId(goods.getId());
        orderInfo.setGoodsName(goods.getGoodsName());
        orderInfo.setGoodsPrice(goods.getMiaoshaPrice());
        orderInfo.setOrderChannel(1);
        orderInfo.setStatus(0);
        orderInfo.setUserId(user.getId());
        long orderId = orderDao.insert(orderInfo);
        MiaoshaOrder miaoshaOrder = new MiaoshaOrder();
        miaoshaOrder.setGoodsId(goods.getId());
        miaoshaOrder.setOrderId(orderId);
        miaoshaOrder.setUserId(user.getId());
        orderDao.insertMiaoshaOrder(miaoshaOrder);

        return orderInfo;
    }
}

5.订单详情

订单详情的内容,不仅仅只是订单信息,还要有商品的信息,在这里使用一个VO来封装接口返回的订单详情信息

public class OrderDetailVo {

    private GoodsVo goods;
    private OrderInfo order;
    public GoodsVo getGoods() {
        return goods;
    }
    public void setGoods(GoodsVo goods) {
        this.goods = goods;
    }
    public OrderInfo getOrder() {
        return order;
    }
    public void setOrder(OrderInfo order) {
        this.order = order;
    }
}
@Controller
@RequestMapping("/order")
public class OrderController {

    @Autowired
    OrderService orderService;

    @Autowired
    GoodsService goodsService;

    @RequestMapping("/detail")
    @ResponseBody
    public Result info(Model model, MiaoshaUser user,
                                      @RequestParam("orderId") long orderId) {
        if(user == null) {
            return Result.error(CodeMsg.SESSION_ERROR);
        }
        OrderInfo order = orderService.getOrderById(orderId);
        if(order == null) {
            return 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);
    }
}

附录:

页面代码







    商品列表
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    


秒杀商品列表
商品名称商品图片商品原价秒杀价库存数量详情
详情







    商品详情
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    



秒杀商品详情
您还没有登录,请登陆后再操作
没有收货地址的提示。。。
商品名称
商品图片
秒杀开始时间 秒杀倒计时: 秒杀进行中 秒杀已结束
商品原价
秒杀价
库存数量






    秒杀失败
    


秒杀失败:







    订单详情
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    


秒杀订单详情
商品名称
商品图片
订单价格
下单时间
订单状态 未支付 待发货 已发货 已收货 已退款 已完成
收货人 XXX 18812341234
收货地址 北京市昌平区回龙观龙博一区

 

你可能感兴趣的:(秒杀项目实战,web,java,spring,spring,boot,数据库)