最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java實(shí)現(xiàn)砸金蛋抽獎(jiǎng)功能

 更新時(shí)間:2020年11月26日 11:42:58   作者:門衛(wèi)向大爺  
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)砸金蛋抽獎(jiǎng)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了java實(shí)現(xiàn)砸金蛋抽獎(jiǎng)的具體代碼,供大家參考,具體內(nèi)容如下

代碼如下

需求:用戶每一次砸金蛋,抽中一等獎(jiǎng)的概率為2% 二等獎(jiǎng)10% 三等獎(jiǎng)18% 四等獎(jiǎng)70%。

累計(jì)砸第n次時(shí)必抽中x等獎(jiǎng)以上的獎(jiǎng)品。比如,累計(jì)砸第5次,則此次必中二等獎(jiǎng)及以上的獎(jiǎng)品。且配置的此次必中中獎(jiǎng)概率不一樣。

/**
 * 金蛋抽獎(jiǎng)
 * userId : 抽獎(jiǎng)用戶ID
 * consumeType : 抽獎(jiǎng)消耗的物品 1:金幣 2:次數(shù)
 */
 @Override
 public Map<String, Object> eggsLottery(Integer userId, Integer consumeType) {
   /*******first : check user ************/
   checkUserIsLock(userId);
   logger.info("userId {} start lottery -eggs.", userId);
   Jedis jedis = RedisPool.getJedis();
   try {
     //查詢活動(dòng)開關(guān)
     String hget = jedis.hget(Rkey.SMASH_GOLD_EGGS_GLOBAL_CONFIG, "status");
     if (null == hget || "0".equals(hget)) {
       throw new BusiException(E.INVALID_PARAMETER, "活動(dòng)暫未開啟,敬請期待");
     }
     //check lottery type
     Long consumeScore = 0L;

     /**score lottery**/
     consumeScore = jedis.hincrBy(Rkey.SMASH_GOLD_EGGS_GLOBAL_CONFIG, "consumeGoldScore", 0);
     if (consumeScore < 1) {
       throw new BusiException(E.EGGS_ACTIVITY_CONFIG_EXCEPTION, "活動(dòng)配置有誤!");
     }
     long surScore = goldWalletMapper.selectAmountGoldByUserId(userId);
     surScore = surScore - consumeScore;
     if (surScore < 0) {
       throw new BusiException(E.SCORE_NOT_ENOUGH, "您的金幣不足");
     }
     // 砸金蛋之前扣除金幣
     Date now = new Date();
     reduceGold(consumeScore, now, userId);

     /*******second : lottery ************/
     Map<String, Object> map;
     try {
       map = lottery(jedis, now, userId, consumeScore);
       // 抽獎(jiǎng)結(jié)束后 記錄今日總共完成的抽獎(jiǎng)次數(shù) +1
       // 必中 不加
       jedis.hincrBy(Rkey.SMASH_GOLD_EGGS_USER_WIN_TOTAL_COUNT, userId.toString(), 1);
     } catch (Exception e) {
       throw e;
     }
     return map;
   } finally {
     RedisPool.returnJedis(jedis);
   }
 }

 /**
 * 抽獎(jiǎng) begin----
 */
 private Map<String, Object> lottery(Jedis jedis, Date now, Integer userId, Long consumeScore) {
   Map<String, Object> map = new HashMap<String, Object>();
   // 判斷本次是否是必中? jackpotType=1: 不是 2:是必中
   Integer jackpotType = 1;
   // 剩余次數(shù)
   Integer freeCount = 0;
   String countStr = jedis.hget(Rkey.SMASH_GOLD_EGGS_USER_WIN_COUNT, userId.toString());
   if (StringUtils.isNotEmpty(countStr)) {
     Integer count = Integer.valueOf(countStr);
     String whenAwardCount = jedis.hget(Rkey.SMASH_GOLD_EGGS_GLOBAL_CONFIG, "whenAwardCount");

     if (StringUtils.isEmpty(whenAwardCount)) {
       throw new BusiException(E.INVALID_REQUEST, "請先完善砸金蛋全局配置");
     }
     freeCount = Integer.valueOf(whenAwardCount) - count - 1;

     if (count >= Integer.valueOf(whenAwardCount) - 1) {
       logger.info("此次是必中....");
       // 此次是必中
       jackpotType = 2;
       // 抽獎(jiǎng)結(jié)束后 先把記錄總共完成的抽獎(jiǎng)次數(shù) 置為0次
       jedis.hdel(Rkey.SMASH_GOLD_EGGS_USER_WIN_COUNT, userId.toString());
       jedis.hincrBy(Rkey.SMASH_GOLD_EGGS_USER_WIN_COUNT, userId.toString(), 0);
     } else {
       logger.info("此次不是必中....");
     }

     if (freeCount == 0) {
       freeCount = Integer.valueOf(whenAwardCount);
     }
   }

   // 根據(jù)配置得到總的獎(jiǎng)品數(shù)量
   Integer totalCount = 0;
   if (jackpotType == 1) {
     totalCount = getAwardTotalCount(1);
   } else {
     totalCount = getAwardTotalCount(2);
   }
   Integer award = getRandomNumber(totalCount);
   // 看落在哪個(gè)區(qū)間
   Integer awardId = getWinAwardId(award, jackpotType);
   BsGoldEggsConfig goldEggsConfig = goldEggsConfigMapper.selectById(awardId);
   if (goldEggsConfig == null) {
     throw new BusiException(E.INVALID_REQUEST, "獎(jiǎng)品信息未找到");
   }

   map.put("freeCount", freeCount);
   map.put("userId", userId);
   map.put("awardId", awardId);
   map.put("awardName", goldEggsConfig.getDescribe());
   map.put("goldCount", goldEggsConfig.getGoldCount());
   map.put("awardImg", goldEggsConfig.getAwardImg());
   logger.info("userId {} win award {}, 獎(jiǎng)勵(lì)金幣:{}, 隨機(jī)生成抽獎(jiǎng)數(shù):{}", userId, goldEggsConfig.getDescribe(), goldEggsConfig.getGoldCount(), award);
   // 抽獎(jiǎng)結(jié)束 action:
   if (jackpotType == 1) {
     // 抽獎(jiǎng)結(jié)束后 記錄累計(jì)抽獎(jiǎng)次數(shù) +1
     // 必中 不加
     jedis.hincrBy(Rkey.SMASH_GOLD_EGGS_USER_WIN_COUNT, userId.toString(), 1);
   }
   // 獎(jiǎng)勵(lì)金幣結(jié)算
   Date now1 = new Date();
   lotteryAddGold(goldEggsConfig.getGoldCount().longValue(), now1, userId);
   return map;
 }

 /**
 * 得到中獎(jiǎng)id
 *
 * @param award : 隨機(jī)生成的抽獎(jiǎng)數(shù)字
 * @return
 */
 private Integer getWinAwardId(Integer award, Integer jackpotType) {
   List<BsGoldEggsConfig> goldEggsConfigList = goldEggsConfigMapper.queryAllList();
   if (goldEggsConfigList == null || goldEggsConfigList.size() < 4) {
     throw new BusiException(E.INVALID_REQUEST, "請先完成砸金蛋獎(jiǎng)品配置!");
   }

   Integer[] weight = new Integer[4];
   if (jackpotType == 1) {
     // 基礎(chǔ)抽獎(jiǎng)
     for (int i = 0; i < goldEggsConfigList.size(); i++) {
       weight[i] = goldEggsConfigList.get(i).getBaseWeight();
     }
   } else {
     // 必中抽獎(jiǎng)
     for (int i = 0; i < goldEggsConfigList.size(); i++) {
       weight[i] = goldEggsConfigList.get(i).getWinWeight();
     }
   }
   // 判斷隨機(jī)數(shù)落在了哪個(gè)區(qū)間 左開右閉   ---------- 這里如果用redis的set來做區(qū)間?如何實(shí)現(xiàn)?
   Integer awardId = 1;
   if (0 < award && award <= weight[0]) {
     // 一等獎(jiǎng)
     awardId = 1;
   } else if (weight[0] < award && award <= (weight[0] + weight[1])) {
     // 二等獎(jiǎng)
     awardId = 2;

   } else if ((weight[0] + weight[1]) < award && award <= (weight[1] + weight[2])) {
     // 三等獎(jiǎng)
     awardId = 3;
   } else {
     // 四等獎(jiǎng)
     awardId = 4;
   }
   return awardId;
 }
 /**
 * 獲取1-max范圍內(nèi) 一個(gè)隨機(jī)數(shù)
 *
 * @param max
 * @return
 */
 private Integer getRandomNumber(Integer max) {
   int i = (int) (Math.random() * max + 1);

   return i;
 }

下面是用獎(jiǎng)池寫的一個(gè)算法 讀者可忽略,博主只是記錄一下。

思路:

根據(jù)需求:

1.生成兩類獎(jiǎng)池(普通獎(jiǎng)池,和必中獎(jiǎng)池),中獎(jiǎng)概率不一樣!為了保證概率正確,我們生成100組(1-100)的數(shù)字,隨機(jī)打亂放入redis中,作為一個(gè)獎(jiǎng)池。

2.生成中獎(jiǎng)區(qū)間,放入redis

3.每次用戶砸金蛋,從獎(jiǎng)池里面取一個(gè)數(shù),

4.判斷該數(shù)在哪個(gè)中獎(jiǎng)區(qū)間

/**
 * 抽獎(jiǎng) begin---- 該方法廢除
 */
 private Map<String, Object> lottery2(Jedis jedis, Date now, Integer userId, Long consumeScore) {
   // 從獎(jiǎng)池中拿出第一個(gè)獎(jiǎng)品
   String jackpotKey = Rkey.SMASH_GOLD_EGGS_JACKPOT_ + "one";
   String baseWinLimitKey = Rkey.SMASH_GOLD_EGGS_AWARD_WIN_LIMIT_BASE;
   String nextWinLimitKey = Rkey.SMASH_GOLD_EGGS_AWARD_WIN_LIMIT_NEXT;
   Map<String, Object> map = new HashMap<String, Object>();

   // 獎(jiǎng)池存在 且獎(jiǎng)池不為空
   String awardFlag = jedis.lpop(jackpotKey);  // 如:20
   Integer award = Integer.valueOf(awardFlag);

   //

   if (!StringUtils.isEmpty(awardFlag)) {
     // 判斷該獎(jiǎng)品的等級
     // 這里是有問題的 博主后面糾正
     Set<String> winLimitSet = jedis.zrange(baseWinLimitKey, 0, award - 1);
     if (winLimitSet != null && !winLimitSet.isEmpty()) {
       Integer size = winLimitSet.size();
       List list = new ArrayList(winLimitSet);
       // 取區(qū)間最后一個(gè)
       String lastAwardLevel = String.valueOf(list.get(size - 1));

       // 獲取獎(jiǎng)品info
       Integer id = null;
       if ("one".equals(lastAwardLevel)) {
         id = 1;
       } else if ("two".equals(lastAwardLevel)) {
         id = 2;
       } else if ("three".equals(lastAwardLevel)) {
         id = 3;
       } else if ("four".equals(lastAwardLevel)) {
         id = 4;
       }
       BsGoldEggsConfig goldEggsConfig = goldEggsConfigMapper.selectById(id);
       if (goldEggsConfig == null) {
         throw new BusiException(E.INVALID_REQUEST, "獎(jiǎng)品信息未找到");
       }
       map.put("userId", userId);
       map.put("awardId", id);
       map.put("awardName", goldEggsConfig.getDescribe());
       map.put("goldCount", goldEggsConfig.getGoldCount());
       logger.info("userId {} win award {}, 獎(jiǎng)勵(lì)金幣:{}, 隨機(jī)生成抽獎(jiǎng)數(shù):{}", userId, goldEggsConfig.getDescribe(), goldEggsConfig.getGoldCount(), award);
     }
   }
   return map;
 }
/**
 * 生成獎(jiǎng)池
 *
 * @param jackpotType : 獎(jiǎng)池類型 1:普通獎(jiǎng)池 2:必中獎(jiǎng)池
 * @param jackpotSort :獎(jiǎng)池序號 1,2,3...... 如普通獎(jiǎng)池1,普通獎(jiǎng)池2,
 */
 @Override
 public void addAwardToJackpot(Integer jackpotType, Integer jackpotSort) {

   // 存放獎(jiǎng)池?cái)?shù)據(jù)
   List<String> awadList = new ArrayList<>();
   // 獎(jiǎng)池key
   String jackpotKey = "";
   String jackpotTypeToStr = "";
   if (jackpotType == 1) {
     jackpotTypeToStr = "普通";
     jackpotKey = Rkey.SMASH_GOLD_EGGS_JACKPOT_ + jackpotSort;
   } else {
     jackpotTypeToStr = "必中";
     jackpotKey = Rkey.SMASH_GOLD_EGGS_NEXT_WIN_JACKPOT_ + jackpotSort;
   }

   logger.info("開始生成{}獎(jiǎng)池{}。。。。。", jackpotTypeToStr, jackpotSort);
   Jedis jedis = RedisPool.getJedis();
   try {

     if (jedis.exists(jackpotKey)) {
       // 判斷獎(jiǎng)池中是否還有獎(jiǎng)品
       Long length = jedis.llen(jackpotKey);
       if (length <= 0) {
         // 獎(jiǎng)池空了,重新放入獎(jiǎng)品
         logger.info("{}獎(jiǎng)池{}空了,重新放入獎(jiǎng)品。。。。。", jackpotTypeToStr, jackpotSort);
         // 根據(jù)配置得到總的獎(jiǎng)品數(shù)量
         Integer totalCount = getAwardTotalCount(1);

         setSingleAwardToJackpot(awadList, jedis, jackpotKey, totalCount);
       }

     } else {
       // 直接生成獎(jiǎng)池
       logger.info("{}獎(jiǎng)池{}不存在,直接放入獎(jiǎng)品。。。。。", jackpotTypeToStr, jackpotSort);
       Integer totalCount = getAwardTotalCount(1);
       setSingleAwardToJackpot(awadList, jedis, jackpotKey, totalCount);
     }
   } finally {
     RedisPool.returnJedis(jedis);
   }
 }


 /**
 * 獲取獎(jiǎng)池獎(jiǎng)品數(shù)量
 *
 * @param type 獎(jiǎng)池類型:1:普通獎(jiǎng)池 2:必中獎(jiǎng)池
 * @return
 */
 Integer getAwardTotalCount(Integer type) {
   List<BsGoldEggsConfig> goldEggsConfigList = goldEggsConfigMapper.queryAllList();
   if (goldEggsConfigList == null || goldEggsConfigList.size() < 4) {
     throw new BusiException(E.INVALID_REQUEST, "請先完成砸金蛋獎(jiǎng)品配置!");
   }
   Integer totalCount = 0;
   if (type == 1) {
     // 普通獎(jiǎng)池獎(jiǎng)品數(shù)量
     for (BsGoldEggsConfig goldEggsConfig : goldEggsConfigList) {
       totalCount += goldEggsConfig.getBaseWeight();
     }


   } else {
     // 必中獎(jiǎng)池?cái)?shù)量
     Jedis jedis = RedisPool.getJedis();
     try {
       String mustAwardLevel = jedis.hget(Rkey.SMASH_GOLD_EGGS_GLOBAL_CONFIG, "mustAwardLevel");
       if (StringUtils.isEmpty(mustAwardLevel)) {
         throw new BusiException(E.INVALID_REQUEST, "請先完成砸金蛋獎(jiǎng)品配置!");
       }
       for (int i = 0; i < Integer.valueOf(mustAwardLevel); i++) {
         totalCount += goldEggsConfigList.get(i).getWinWeight();
       }
     } finally {
       RedisPool.returnJedis(jedis);
     }


   }

   return totalCount;
 }

 /**
 * @param awadList
 * @param jedis
 * @param jackpotKey
 * @param totalCount 總的獎(jiǎng)品個(gè)數(shù) 比如一等獎(jiǎng)10個(gè),二等獎(jiǎng)20個(gè),三等獎(jiǎng)30,四等獎(jiǎng)40 則totalCount = 10+20+30+40=100
 */
 private void setSingleAwardToJackpot(List<String> awadList, Jedis jedis, String jackpotKey, Integer totalCount) {
   // 1.生成 100組 [1-100] 隨機(jī)數(shù) awadList
   for (int i = 0; i < 2; i++) {
     List<Integer> list = getOneToHundredNumber(totalCount);
     for (Integer j : list) {
       awadList.add(j.toString());
     }
   }

   // 2.awadList打亂放入redis(list) 這里打亂2次
   Collections.shuffle(awadList);
   Collections.shuffle(awadList);

   // 3.放入redis
   awadList.forEach(s -> jedis.lpush(jackpotKey, s));
   logger.info("獎(jiǎng)品info:預(yù)設(shè)值:{} 實(shí)際設(shè)置:{}", 10000, awadList.size());
 }

 /**
 * jdk8 得到包含1-end數(shù)字的list
 * end : 生成數(shù)字的個(gè)數(shù)
 *
 * @return
 */
 private List<Integer> getOneToHundredNumber(Integer end) {
   // 起始數(shù)字
   int start = 1;
   // 生成數(shù)字的個(gè)數(shù)
   // int end = 100;
   // 生成1,2,3,4,5...100
   List<Integer> list = Stream.iterate(start, item -> item + 1).limit(end).collect(Collectors.toList());
   return list;
 }

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java通過反射訪問注解信息的方法示例

    Java通過反射訪問注解信息的方法示例

    這篇文章主要介紹了Java通過反射訪問注解信息的方法,結(jié)合實(shí)例形式分析了java基于反射訪問類成員方法注解信息的相關(guān)操作技巧,需要的朋友可以參考下
    2019-08-08
  • SpringBoot整合Mybatis實(shí)現(xiàn)多數(shù)據(jù)源配置與跨數(shù)據(jù)源事務(wù)實(shí)例

    SpringBoot整合Mybatis實(shí)現(xiàn)多數(shù)據(jù)源配置與跨數(shù)據(jù)源事務(wù)實(shí)例

    開發(fā)中經(jīng)常有這樣的需要: 讀寫分離。微服務(wù)環(huán)境下可以實(shí)現(xiàn)一個(gè)服務(wù)讀取一個(gè)數(shù)據(jù)庫,另一個(gè)服務(wù)寫庫。但是在實(shí)際應(yīng)用中有時(shí)也需要在一個(gè)服務(wù)中讀寫不同的數(shù)據(jù)庫。可以在一個(gè)SpringBoot單體項(xiàng)目中配置多個(gè)數(shù)據(jù)源解決讀寫庫分離
    2022-11-11
  • 詳解如何查看Elasticsearch的Debug日志

    詳解如何查看Elasticsearch的Debug日志

    這篇文章主要為大家介紹了詳解如何查看Elasticsearch的Debug日志,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • Java中class和Class的區(qū)別示例詳解

    Java中class和Class的區(qū)別示例詳解

    class 是java的關(guān)鍵字,在聲明java類時(shí)使用,Class是java JDK提供的一個(gè)類,完整路徑為java.lang.Class,下面這篇文章主要給大家介紹了關(guān)于Java中class和Class區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • SpringBoot開發(fā)中的組件和容器詳解

    SpringBoot開發(fā)中的組件和容器詳解

    這篇文章主要介紹了SpringBoot開發(fā)中的組件和容器詳解,SpringBoot 提供了一個(gè)內(nèi)嵌的 Tomcat 容器作為默認(rèn)的 Web 容器,同時(shí)還支持其他 Web 容器和應(yīng)用服務(wù)器,需要的朋友可以參考下
    2023-09-09
  • Java對象方法的調(diào)用執(zhí)行過程詳解

    Java對象方法的調(diào)用執(zhí)行過程詳解

    這篇文章主要介紹了Java對象方法的調(diào)用執(zhí)行過程,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • 基于Java解析國密數(shù)字證書的操作方法

    基于Java解析國密數(shù)字證書的操作方法

    在Java環(huán)境中解析使用國密算法(如SM3WITHSM2)的數(shù)字證書可能遇到挑戰(zhàn),使用BouncyCastle加密庫可以解決Java標(biāo)準(zhǔn)庫無法識別國密算法橢圓曲線的問題,成功解析國密數(shù)字證書,添加BouncyCastle依賴并修改代碼,使其支持國密算法,即可解析采用SM3WITHSM2算法的數(shù)字證書
    2024-09-09
  • SpringBoot整合JPA方法及配置解析

    SpringBoot整合JPA方法及配置解析

    這篇文章主要介紹了SpringBoot整合JPA方法及配置過程,JPA是Java Persistence API的簡稱,中文名Java持久層API,感興趣想要詳細(xì)了解可以參考下文
    2023-05-05
  • SpringBoot多種生產(chǎn)打包方式詳解

    SpringBoot多種生產(chǎn)打包方式詳解

    生產(chǎn)上發(fā)布?Spring?Boot?項(xiàng)目時(shí),流程頗為繁瑣且低效,但凡代碼有一丁點(diǎn)改動(dòng),就得把整個(gè)項(xiàng)目重新打包部署,耗時(shí)費(fèi)力不說,生成的?JAR?包還特別臃腫,體積龐大,本文給大家介紹了SpringBoot多種生產(chǎn)打包方式,需要的朋友可以參考下
    2025-01-01
  • SpringBoot可視化監(jiān)控的具體應(yīng)用

    SpringBoot可視化監(jiān)控的具體應(yīng)用

    最近越發(fā)覺得,任何一個(gè)系統(tǒng)上線,運(yùn)維監(jiān)控都太重要了,本文介紹了SpringBoot可視化監(jiān)控的具體應(yīng)用,分享給大家,有興趣的同學(xué)可以參考一下
    2021-06-06

最新評論

陆丰市| 黔江区| 牡丹江市| 马龙县| 宁陕县| 个旧市| 阜南县| 资溪县| 黑山县| 施秉县| 和林格尔县| 安徽省| 汽车| 中西区| 曲水县| 健康| 通许县| 茂名市| 台南市| 敦化市| 莒南县| 五家渠市| 吴桥县| 台中市| 毕节市| 井冈山市| 盐城市| 陆良县| 安溪县| 卓资县| 白水县| 达日县| 元江| 河北省| 敖汉旗| 石家庄市| 四川省| 静乐县| 政和县| 武胜县| 克拉玛依市|