写点什么

【Java 实战】实现大转盘抽奖

作者:猫的树
  • 2022 年 7 月 13 日
  • 本文字数:1750 字

    阅读完需:约 6 分钟

【Java 实战】实现大转盘抽奖

项目场景

实现一个大转盘抽奖的功能,能后台自定义奖项,各奖项中奖概率,奖品数量,当日抽奖最大次数等。

一、设计思路

这里简单分享下思路:

1.奖品中奖概率

所有参与抽奖的奖项中奖概率之和为 1

2.抽奖规则

这里首先需要明确如何中奖?


一般来说是生成随机数,然后将随机数与奖品的中奖概率相比较,如果小于中奖概率则中奖。


但是,如果每个奖项或者几个奖项的概率一样,上面的方法就会出现每次抽奖,中奖都是同一个奖品的情况


所以我们采用中奖概率累加的方法,如图所示:



抽奖规则:


  • 获取该游戏的奖品列表,按照中奖概率升序排列 (可以不用排序)

  • 奖品列表中的概率为累加概率,需要按照添加进列表的顺序进行累加

  • 生成一个 0-1 的随机数,与设置好的奖品概率循环比较

  • 若随机数小于概率值,则抽中该奖项

3.奖品发放

在设置奖品的时需要设置类型,例如:优惠券积分商品(实物)虚拟商品 等等。


每个类型的奖品发放规则不同,这里可以利用 Java 多态的特性建立一个工厂类,用不同的实现类来分别实现不同类型的奖品的中奖处理逻辑


这里由于将使用的微服务,所以直接通过 feign 调用对应的服务方法

二、数据库设计

1.转盘游戏表

存储转盘抽奖信息


2.奖品表

存储抽奖奖品信息


3.抽奖记录表

存储抽奖记录信息


三、业务逻辑

1.提供接口

(1)获取转盘游戏(2)获取用户的抽奖记剩余次数(3)参与转盘抽奖(4)抽奖记录

2.核心代码

抽奖逻辑代码


// 获取奖品信息列表List<Entity> prizeList = service.list();// 奖品列表中的概率为累加概率// 需要按照添加进列表的顺序进行累加,为了数据处理方便中奖几率*100double sum = 0;List<Entity> newList = new ArrayList<>();for (int i = 0; i < prizeList.size(); i++) {    Entity entity = prizeList.get(i);    Entity newEntity = new Entity();    BeanUtils.copyProperties(entity, newEntity);    sum = sum + (entity.getRatio() * 100);    newEntity.setRatio(sum);    newList.add(newEntity);}
// 生成一个随机数Random random = new Random();Double userSelect = random.nextDouble() * 10000;for (Entity prize : prizeList) { // 随机数小于中奖几率,则中奖 if (userSelect < prize.getRatio()) { // 最大中奖数(0:代表不限制次数) int maxNum = prize.getMaxNum(); // 判断游戏奖品当前中奖数及最大中奖数 if (maxNum != 0 && maxNum <= prize.getCurrentNum()) { // 超过最大中奖数则不中 break; } else { return prize; } }}// 谢谢参与List<Entity> prize = prizeList.stream().filter(item -> item.getPrizeType() == 4).collect(Collectors.toList());if (prize.size() > 0) { return prize.get(0);}return null;
复制代码


抽奖发放:根据抽中的奖品类型调用对应的服务进行奖品发放;(比如抽中优惠券,就调用优惠券的服务进行发放)


int type = prize.getPrizeType();try {    switch (type) {        // 发放优惠券        case 1:            ApiResult res = couponFeign.sendCouponToUser(userId, prize.getPrizeId(), prize.getPrizeValue());            // 其他业务处理            break;        // 发放商品        case 2:            break;        // 发放积分        case 3:            ApiResult res2 = pointFeign.addPointToUser(gameId, userId, prize.getPrizeValue());            // 其他业务处理            break;        // 谢谢参与        case 4:            break;        default:            break;    }} catch (Exception e) {    e.printStackTrace();}
复制代码


注意事项:抽奖容易出现并发问题,所以在抽奖的地方,需要加上分布式锁,这里使用 Redis 官方推荐的 Java 版的 Redis 客户端Redisson中的分布式锁功能


RLock lock = redisson.getLock("turntable:" + gameId);try {  // 指定超时时间   if (lock.tryLock(10, TimeUnit.SECONDS)) {    // 抽奖业务处理  }
} finally { lock.unlock();}
复制代码


创作不易,关注💖、点赞👍、收藏🎉就是对作者最大的鼓励👏,欢迎在下方评论留言🧐


👉 我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿

发布于: 刚刚阅读数: 3
用户头像

猫的树

关注

记录及分享自己的一点点成长 2022.07.07 加入

「 奋力奔跑的 Java 小白🧐 」 「个人博客」👉 https://www.kirecatyu.top/ 「CSDN 」👉 https://blog.csdn.net/qq_34383510 「博客园 」👉 https://www.cnblogs.com/kire-cat/

评论

发布
暂无评论
【Java 实战】实现大转盘抽奖_Java_猫的树_InfoQ写作社区