• ▶【SecKill】U3 实现秒杀功能


    ▶【SecKill】U3 实现秒杀功能

    一、数据库设计

    1、商品表和秒杀商品表是两个互相独立的表?

    【正确方法】商品表和秒杀商品表是两个互相独立的表,其中的关联为goods_id

    @Data
    public class GoodsVo extends Goods {
        private Double miaoshaPrice;
        private Integer stockCount;
        private Date startDate;
        private Date endDate;
    }

    2、创建5个对应数据库的domain对象

    Goods:

    package com.kirin.miaosha.domain;
    
    public class Goods {
        private Long id;
        private String goodsName;
        private String goodsTitle;
        private String goodsImg;
        private String goodsDetail;
        private Double goodsPrice;
        private Integer goodsStock;
        
        public Long getId() {
            return id;
        }
        public void setId(Long id) {
            this.id = id;
        }
        public String getGoodsName() {
            return goodsName;
        }
        public void setGoodsName(String goodsName) {
            this.goodsName = goodsName;
        }
        public String getGoodsTitle() {
            return goodsTitle;
        }
        public void setGoodsTitle(String goodsTitle) {
            this.goodsTitle = goodsTitle;
        }
        public String getGoodsImg() {
            return goodsImg;
        }
        public void setGoodsImg(String goodsImg) {
            this.goodsImg = goodsImg;
        }
        public String getGoodsDetail() {
            return goodsDetail;
        }
        public void setGoodsDetail(String goodsDetail) {
            this.goodsDetail = goodsDetail;
        }
        public Double getGoodsPrice() {
            return goodsPrice;
        }
        public void setGoodsPrice(Double goodsPrice) {
            this.goodsPrice = goodsPrice;
        }
        public Integer getGoodsStock() {
            return goodsStock;
        }
        public void setGoodsStock(Integer goodsStock) {
            this.goodsStock = goodsStock;
        }
    }

    MiaoshaGoods:

    package com.kirin.miaosha.domain;
    
    import java.util.Date;
    
    public class MiaoshaGoods {
        private Long id;
        private Long goodsId;
        private Integer stockCount;
        private Date startDate;
        private Date endDate;
        
        public Long getId() {
            return id;
        }
        public void setId(Long id) {
            this.id = id;
        }
        public Long getGoodsId() {
            return goodsId;
        }
        public void setGoodsId(Long goodsId) {
            this.goodsId = goodsId;
        }
        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;
        }
    }

    MiaoshaOrder:

    package com.kirin.miaosha.domain;
    
    public class MiaoshaOrder {
        private Long id;
        private Long userId;
        private Long orderId;
        private Long goodsId;
        
        public Long getId() {
            return id;
        }
        public void setId(Long id) {
            this.id = id;
        }
        public Long getUserId() {
            return userId;
        }
        public void setUserId(Long userId) {
            this.userId = userId;
        }
        public Long getOrderId() {
            return orderId;
        }
        public void setOrderId(Long orderId) {
            this.orderId = orderId;
        }
        public Long getGoodsId() {
            return goodsId;
        }
        public void setGoodsId(Long goodsId) {
            this.goodsId = goodsId;
        }
    }

    MiaoshaUser:

    package com.kirin.miaosha.domain;
    
    import java.util.Date;
    
    public class MiaoshaUser {
        private Long id;
        private String nickname;
        private String password;
        private String salt;
        private String head;
        private Date registerDate;
        private Date lastLoginDate;
        private Integer loginCount;
        
        public Long getId() {
            return id;
        }
        public void setId(Long id) {
            this.id = id;
        }
        public String getNickname() {
            return nickname;
        }
        public void setNickname(String nickname) {
            this.nickname = nickname;
        }
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }
        public String getSalt() {
            return salt;
        }
        public void setSalt(String salt) {
            this.salt = salt;
        }
        public String getHead() {
            return head;
        }
        public void setHead(String head) {
            this.head = head;
        }
        public Date getRegisterDate() {
            return registerDate;
        }
        public void setRegisterDate(Date registerDate) {
            this.registerDate = registerDate;
        }
        public Date getLastLoginDate() {
            return lastLoginDate;
        }
        public void setLastLoginDate(Date lastLoginDate) {
            this.lastLoginDate = lastLoginDate;
        }
        public Integer getLoginCount() {
            return loginCount;
        }
        public void setLoginCount(Integer loginCount) {
            this.loginCount = loginCount;
        }
    }

    OrderInfo:

    package com.kirin.miaosha.domain;
    
    import java.util.Date;
    
    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 status;
        private Date createDate;
        private Date payDate;
        
        public Long getId() {
            return id;
        }
        public void setId(Long id) {
            this.id = id;
        }
        public Long getUserId() {
            return userId;
        }
        public void setUserId(Long userId) {
            this.userId = userId;
        }
        public Long getGoodsId() {
            return goodsId;
        }
        public void setGoodsId(Long goodsId) {
            this.goodsId = goodsId;
        }
        public Long getDeliveryAddrId() {
            return deliveryAddrId;
        }
        public void setDeliveryAddrId(Long deliveryAddrId) {
            this.deliveryAddrId = deliveryAddrId;
        }
        public String getGoodsName() {
            return goodsName;
        }
        public void setGoodsName(String goodsName) {
            this.goodsName = goodsName;
        }
        public Integer getGoodsCount() {
            return goodsCount;
        }
        public void setGoodsCount(Integer goodsCount) {
            this.goodsCount = goodsCount;
        }
        public Double getGoodsPrice() {
            return goodsPrice;
        }
        public void setGoodsPrice(Double goodsPrice) {
            this.goodsPrice = goodsPrice;
        }
        public Integer getOrderChannel() {
            return orderChannel;
        }
        public void setOrderChannel(Integer orderChannel) {
            this.orderChannel = orderChannel;
        }
        public Integer getStatus() {
            return status;
        }
        public void setStatus(Integer status) {
            this.status = status;
        }
        public Date getCreateDate() {
            return createDate;
        }
        public void setCreateDate(Date createDate) {
            this.createDate = createDate;
        }
        public Date getPayDate() {
            return payDate;
        }
        public void setPayDate(Date payDate) {
            this.payDate = payDate;
        }
    }

    二、商品列表页

    1、com.kirin.miaosha.service / GoodsService.java:

    package com.kirin.miaosha.service;
    @Service public class GoodsService { @Autowired GoodsDao goodsDao; public List<GoodsVo> listGoodsVo(){ return goodsDao.listGoodsVo(); } }

    2、com.kirin.miaosha.dao / GoodsDao.java:

    package com.kirin.miaosha.dao;
    
    @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> listGoodsVo();
    }

    3、com.kirin.miaosha.vo / GoodsVo.java:实现联表查询:将商品表和秒杀商品表的数据拼到一起,输出商品列表页

    package com.kirin.miaosha.vo;
    
    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;
        }
    }

    4、com.kirin.miaosha.controller / GoodsController.java:

    package com.kirin.miaosha.controller;
    
    @Controller
    @RequestMapping("/goods")
    public class GoodsController {
    
        @Autowired
        MiaoshaUserService userService;
        
        @Autowired
        RedisService redisService;
        
        @Autowired
        GoodsService goodsService;
        
        @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";
        }
    }

    5、goods_list.html:

    把照片添加在

    <!DOCTYPE HTML>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>商品列表</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <!-- jquery -->
        <script type="text/javascript" th:src="@{/js/jquery.min.js}"></script>
        <!-- bootstrap -->
        <link rel="stylesheet" type="text/css" th:href="@{/bootstrap/css/bootstrap.min.css}" />
        <script type="text/javascript" th:src="@{/bootstrap/js/bootstrap.min.js}"></script>
        <!-- jquery-validator -->
        <script type="text/javascript" th:src="@{/jquery-validation/jquery.validate.min.js}"></script>
        <script type="text/javascript" th:src="@{/jquery-validation/localization/messages_zh.min.js}"></script>
        <!-- layer -->
        <script type="text/javascript" th:src="@{/layer/layer.js}"></script>
        <!-- md5.js -->
        <script type="text/javascript" th:src="@{/js/md5.min.js}"></script>
        <!-- common.js -->
        <script type="text/javascript" th:src="@{/js/common.js}"></script>
    </head>
    <body>
        <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>
                  <!-- 循环展示goodsList的信息 -->
                  <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>
    </body>
    </html>

    三、商品详情页

    1、com.kirin.miaosha.service / GoodsService.java:

    package com.kirin.miaosha.service;
    
    @Service
    public class GoodsService {
        
        @Autowired
        GoodsDao goodsDao;
    
        public List<GoodsVo> listGoodsVo(){
            return goodsDao.listGoodsVo();
        }
    
        public GoodsVo getGoodsVoByGoodsId(long goodsId) {
            return goodsDao.getGoodsVoByGoodsId(goodsId);
        }
    }

    2、com.kirin.miaosha.dao / GoodsDao.java:

    package com.kirin.miaosha.dao;
    
    @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> listGoodsVo();
    
        @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 where g.id = #{goodsId}")
        public GoodsVo getGoodsVoByGoodsId(@Param("goodsId")long goodsId);
    }

    3、com.kirin.miaosha.controller / GoodsController.java:

    package com.kirin.miaosha.controller;
    
    @Controller
    @RequestMapping("/goods")
    public class GoodsController {
    
        @Autowired
        MiaoshaUserService userService;
        
        @Autowired
        RedisService redisService;
        
        @Autowired
        GoodsService goodsService;
        
        //1.用户登录后,跳转到商品列表页
        @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";
        }
        
        //2.查看商品详情
        @RequestMapping("/to_detail/{goodsId}") //根据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;
                remainSeconds = (int)((startAt - now )/1000);
            }else if(now > endAt){
                miaoshaStatus = 2;
                remainSeconds = -1;
            }
            model.addAttribute("miaoshaStatus", miaoshaStatus);
            model.addAttribute("remainSeconds", remainSeconds);
            return "goods_detail";
        }
    }

    运行:

    四、订单详情页

    1、com.kirin.miaosha.controller / MiaoshaController.java:

    package com.kirin.miaosha.controller;
    
    @Controller
    @RequestMapping("/miaosha")
    public class MiaoshaController {
    
        @Autowired
        MiaoshaUserService userService;
        
        @Autowired
        RedisService redisService;
        
        @Autowired
        GoodsService goodsService;
        
        @Autowired
        OrderService orderService;
        
        @Autowired
        MiaoshaService miaoshaService;
        
        @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";
        }
    }

    2、com.kirin.miaosha.result / CodeMsg.java:

    package com.kirin.miaosha.result;
    
    public class CodeMsg {
        private int code;
        private String msg;
        
        //定义通用异常
        public static CodeMsg SUCCESS = new CodeMsg(0, "success");
        public static CodeMsg SERVER_ERROR = new CodeMsg(500100, "服务端异常");
        public static CodeMsg BIND_ERROR = new CodeMsg(500101, "参数校验异常:%s"); //带参数
        
        //登录模块 5002XX
        public static CodeMsg SESSION_ERROR = new CodeMsg(500210, "Session不存在或者已经失效");
        public static CodeMsg PASSWORD_EMPTY = new CodeMsg(500211, "登录密码不能为空");
        public static CodeMsg MOBILE_EMPTY = new CodeMsg(500212, "手机号不能为空");
        public static CodeMsg MOBILE_ERROR = new CodeMsg(500213, "手机号格式错误");
        public static CodeMsg MOBILE_NOT_EXIST = new CodeMsg(500214, "手机号不存在");
        public static CodeMsg PASSWORD_ERROR = new CodeMsg(500215, "密码错误");
    
        //商品模块5003XX
    
        //订单模块5004XX
    
        //秒杀模块5005XX
        public static CodeMsg MIAO_SHA_OVER = new CodeMsg(500500, "商品已经秒杀完毕");
        public static CodeMsg REPEATE_MIAOSHA = new CodeMsg(500501, "不能重复秒杀");
    
          private CodeMsg( ) {
        }
                
        private CodeMsg( int code,String msg ) {
            this.code = code;
            this.msg = msg;
        }
        
        public int getCode() {
            return code;
        }
        public void setCode(int code) {
            this.code = code;
        }
        public String getMsg() {
            return msg;
        }
        public void setMsg(String msg) {
            this.msg = msg;
        }
        
        public CodeMsg fillArgs(Object... args) {
            int code = this.code;
            String message = String.format(this.msg, args); 
            return new CodeMsg(code, message);
        }
    
        @Override
        public String toString() {
            return "CodeMsg [code=" + code + ", msg=" + msg + "]";
        }
    }

    3、com.kirin.miaosha.dao / OrderDao.java:

    package com.kirin.miaosha.dao;
    
    @Mapper
    public interface OrderDao {
        
        @Select("select * from miaosha_order where user_id=#{userId} and goods_id=#{goodsId}")
        public MiaoshaOrder getMiaoshaOrderByUserIdGoodsId(@Param("userId")long userId, @Param("goodsId")long goodsId);
    
        @Insert("insert into order_info(user_id, goods_id, goods_name, goods_count, goods_price, order_channel, status, create_date)values("
                + "#{userId}, #{goodsId}, #{goodsName}, #{goodsCount}, #{goodsPrice}, #{orderChannel},#{status},#{createDate} )")
        @SelectKey(keyColumn="id", keyProperty="id", resultType=long.class, before=false, statement="select last_insert_id()")
        public long insert(OrderInfo orderInfo);
        
        @Insert("insert into miaosha_order (user_id, goods_id, order_id)values(#{userId}, #{goodsId}, #{orderId})")
        public int insertMiaoshaOrder(MiaoshaOrder miaoshaOrder);    
    }

    4、com.kirin.miaosha.service / OrderService.java:

    package com.kirin.miaosha.service;
    
    @Service
    public class OrderService {
        
        @Autowired
        OrderDao orderDao;
        
        public MiaoshaOrder getMiaoshaOrderByUserIdGoodsId(long userId, long goodsId) {
            return orderDao.getMiaoshaOrderByUserIdGoodsId(userId, goodsId);
        }
    
        //生成订单
        @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.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、com.kirin.miaosha.service / MiaoshaService.java:

    package com.kirin.miaosha.service;
    
    @Service
    public class MiaoshaService {
        
        @Autowired
        GoodsService goodsService;
        
        @Autowired
        OrderService orderService;
    
        @Transactional
        public OrderInfo miaosha(MiaoshaUser user, GoodsVo goods) {
            //减库存 下订单 写入秒杀订单
            goodsService.reduceStock(goods);
            return orderService.createOrder(user, goods);
        }
    }

    6、com.kirin.miaosha.service / GoodsService.java:

    package com.kirin.miaosha.service;
    @Service public class GoodsService { @Autowired GoodsDao goodsDao; public List<GoodsVo> listGoodsVo(){ return goodsDao.listGoodsVo(); } public GoodsVo getGoodsVoByGoodsId(long goodsId) { return goodsDao.getGoodsVoByGoodsId(goodsId); }
    public void reduceStock(GoodsVo goods) { MiaoshaGoods g = new MiaoshaGoods(); g.setGoodsId(goods.getId()); goodsDao.reduceStock(g); } }

    7、com.kirin.miaosha.dao / GoodsDao.java:

    package com.kirin.miaosha.dao;
    
    @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> listGoodsVo();
    
        @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 where g.id = #{goodsId}")
        public GoodsVo getGoodsVoByGoodsId(@Param("goodsId")long goodsId);
    
        @Update("update miaosha_goods set stock_count = stock_count - 1 where goods_id = #{goodsId}")
        public int reduceStock(MiaoshaGoods g);
    }

    8、miaosha_fail.html:

    <!DOCTYPE HTML>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>秒杀失败</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    </head>
    <body>
        秒杀失败:<p th:text="${errmsg}"></p>
    </body>
    </html>
  • 相关阅读:
    左耳听风-ARTS-第4周(2019/4/21-2019/4/27)
    Java集合总结
    Zuul网关总结
    左耳听风-ARTS-第3周(2019/4/7-2019/4/13)
    左耳听风-ARTS-第2周(2019/3/31-2019/4/6)
    Java泛型相关总结(下)
    左耳听风-ARTS-第1周
    去长江边走走,看看
    第1记
    c#发送邮件
  • 原文地址:https://www.cnblogs.com/kirin1105916774/p/15912792.html
Copyright © 2020-2023  润新知