Java秒殺系統--5.秒殺功能模塊


簡介

  實現秒殺接口

1.訪問秒殺接口

  在秒殺商品詳情頁面中,點擊立即秒殺按鈕就可以訪問秒殺接口了。

  onclick="getPath()" id="buyButton">開始秒殺</button>:調用getPath(),因為對秒殺接口進行了接口隱藏,所以要先獲取path值,然后到url中,才能對秒殺接口進行訪問。

2.后端處理獲取path的請求,起到隱藏秒殺接口的功能(沒用,不如在后端進行時間判斷)

  

1 @AccessLimit(seconds = 120,maxCount = 5)
2     @RequestMapping(value = "/getPath",method = RequestMethod.GET)
3     @ResponseBody
4     public Result<String> getPath(Model model,MiaoshaUser user, @RequestParam("goodsId")long goodsId) {
5         String path = MD5Util.md5(UUIDUtil.UUID());
6         redisService.set(PathPrefix.Path,user.getId()+"_"+goodsId,path);
7         return Result.success(path);
8     }

path:一個隨機字符串,然后進行一次MD5加密(MD5加密好像可有可無)得到的字符串。

對path使用了redis緩存。

隱藏秒殺接口的目的:為了防止惡意用戶提前訪問秒殺商品。普通用戶在秒殺時間來到時,才可以點擊秒殺按鈕訪問秒殺接口,因為前端設計為在時間未到時秒殺按鈕是無效的;惡意用戶可能通過查看網頁源碼得到秒殺接口,在秒殺時間未到時訪問秒殺接口。

沒用:可以寫一個腳本,先獲得path變量完成拼接,再訪問秒殺接口;還不如在后端添加一個時間判斷。

3.前端獲的path的值,開始訪問秒殺接口

 

 1 success:function(data) {
 2             //獲得path參數后,調用秒殺接口函數
 3             go_miaosha(data.data)
 4         },
 5 //調用秒殺接口
 6     function go_miaosha(path) {
 7         $.ajax({
 8             url:"/miaosha/"+path+"/do_miaosha",
 9             type:"POST",
10             data:{
11                 goodsId:$("#goodsId").val(),
12             },
13             success:function (data){
14                 if (data.code==0){
15                     getResult($("#goodsId").val());
16                 }else layer.msg(data.msg)
17             },
18             error:function () {
19                 layer.msg("客戶端有誤1")
20             }
21         });
22     }

4.后端秒殺接口

  第一個驗證:限制某個用戶在5秒鍾內,不能調用該接口超過5次,並且必須進行登錄。

  @AccessLimit(seconds = 5,maxCount = 1,needLogin = true)

  第二個驗證:驗證url中的path值是否相同,path為一個字符串,被存儲在redis中,key由userId和goodsId構成,生存期為60秒。

  訪問redis得到其中存儲的path值,然后進行比較。

  

1 @AccessLimit(seconds = 120,maxCount = 5)
2     @RequestMapping(value = "/getPath",method = RequestMethod.GET)
3     @ResponseBody
4     public Result<String> getPath(Model model,MiaoshaUser user, @RequestParam("goodsId")long goodsId) {
5         String path = MD5Util.md5(UUIDUtil.UUID());
6         redisService.set(PathPrefix.Path,user.getId()+"_"+goodsId,path);
7         return Result.success(path);
8     }

 

  第三個驗證:驗證商品的庫存數量,利用afterPropertiesSet方法,在spring容器初始化時將數據庫中的商品數量緩存到redis中。

  

 1 //該方法在初始化之前執行,將數據庫中的商品庫存緩存到redis服務器中
 2     private Map<Long,Boolean> goodsStatus = new HashMap<>();
 3     @Override
 4     public void afterPropertiesSet() throws Exception {
 5         List<GoodsVo> goodsList = miaoshaGoodsService.getGoodsList();
 6         for (GoodsVo goods:goodsList
 7              ) {
 8             long id = goods.getId();
 9             long stock = goods.getStockCount();
10             goodsStatus.put(id,false);
11             redisService.set(GoodsPrefix.getGoodsStack,""+id,stock);
12         }
13     }

  當redis中的商品庫存被減到零后,所有后來的秒殺請求均被拒絕,並且只會觸發一次集合的get操作,連redis操作也不會觸發。

  

1     if (goodsStatus.get(goodsId)) {
2             return Result.error(CodeMsg.SECKILL_OVER);
3         }
4         long stock = redisService.decr(GoodsPrefix.getGoodsStack, "" + goodsId);
5         if (stock < 0) {
6             goodsStatus.replace(goodsId, true);
7             return Result.error(CodeMsg.SECKILL_OVER);
8         }

  第四個驗證:驗證是否包含該用戶秒殺該商品的訂單,每當完成一次秒殺。都將秒殺訂單緩存到redis中,方便快速驗證。

1                                                                                                                         //驗證4.判斷是否有該用戶和該商品的訂單存在
2         MiaoshaOrder miaoOrder = redisService.get(OrderPrefix.getGoodIdAndUserId, "" + user.getId() + goodsId, MiaoshaOrder.class);
3         if (miaoOrder != null) {
4             return Result.error(CodeMsg.REPEATE_SECKILL);
5         }

  使用rabbitmq將秒殺操作信息封裝發送到接收端,然后執行秒殺的動作。使用MiaoshaMessage.class來封裝秒殺操作信息。

1 import lombok.Data;
2 
3 @Data
4 public class MiaoshaMessage {
5     private MiaoshaUser miaoshaUser;
6     private long goodsId;
7 }
1      MiaoshaMessage mm = new MiaoshaMessage();
2         mm.setGoodsId(goodsId);
3         mm.setMiaoshaUser(user);
4         mqSender.sendMiaoshaMessage(mm);

  在監聽器端還有驗證一下數據庫中記錄的庫存,然后再執行秒殺,第五個驗證:驗證數據庫中的商品庫存數量。

@RabbitListener(queues = MQConfig.MIAOSHA_QUEUE)
    public void reciveMiaosha(String msg) {
        MiaoshaMessage mm = RedisService.strToBean(msg, MiaoshaMessage.class);
        MiaoshaUser user = mm.getMiaoshaUser();
        long goodsId = mm.getGoodsId();
                                                                                                                        //通過數據庫中的數據來判斷庫存的多少
        GoodsVo goodsVo = miaoshaGoodsService.getGoodsVoById(goodsId);
        int kucun = goodsVo.getStockCount();
        if (kucun == 0) {
            return;
        }
        //進行數據庫中的秒殺操作
        miaoshaService.miaoSha(user.getId(), goodsId);
    }

 5.使用MiaoshaService.class中的miaoSha(long useId, long goodsId)方法來完成秒殺工作。

  在該方法上使用@Transactional標簽,當事務來處理。總共分為3大步,減庫存,下訂單,redis緩存秒殺訂單。

  

 1 @Transactional
 2     public OrderInfo miaoSha(long useId, long goodsId) {
 3                                                                                                                         //減庫存,並設置減庫存的結果
 4         boolean reduceResult=miaoshaGoodsService.reduceStock(goodsId);
 5         setReduceResult(goodsId,reduceResult);
 6         miaoshaGoodsService.reduceFMStock(goodsId);
 7                                                                                                                         //下訂單
 8         orderInfoService.createOrder(useId,goodsId);
 9         long orderId = orderInfoService.getByUserIdGoodsId(useId,goodsId).getId();
10         MiaoshaOrder miaoshaOrder = new MiaoshaOrder();
11         miaoshaOrder.setMiaoshagoodsId(goodsId);
12         miaoshaOrder.setOrderId(orderId);
13         miaoshaOrder.setUserId(useId);
14         orderInfoService.createMiaoshaOrder(miaoshaOrder);
15                                                                                                                         //為秒殺訂單做一個redis緩存
16         redisService.set(OrderPrefix.getGoodIdAndUserId,""+useId+goodsId,miaoshaOrder);
17         return orderInfoService.getByUserIdGoodsId(useId,goodsId);
18     }

至此秒殺功能基本完成。

  

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM