java抽奖_Java实现抽奖功能
需求简介
新项目有一个类似王者荣耀抽奖的功能:抽取花费积分,积累幸运值,每阶段幸运值可以抽取到不同的奖品,幸运值集满时,必得稀有道具
功能实现预期:建立一个抽奖池(抽奖池级别根据type区分),奖品在不同的抽奖池中,获取用户幸运值,创建一个List,达到要求就将该抽奖池中的奖品放入该抽奖集合中,进行抽奖,如果幸运值为满,则只将特殊道具放入抽奖池中,进行抽奖
第一步:创建数据库相关数据表
抽奖池表:此处原本要建立两张表(抽奖池(如果是两张表lucky_restrict 是可以直接限制奖池条件的,一张表时,该字段废弃),和奖池道具),但是因为项目没啥特殊要求,所以就先凑合用了
CREATE TABLE `t_draw_pool` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`prop_id` int(11) DEFAULT NULL COMMENT '道具ID',
`type` int(1) DEFAULT '1' COMMENT '奖池级别,0号奖池,1号奖池,2号奖池,3稀有奖池',
`lucky_restrict` varchar(255) DEFAULT NULL COMMENT '(废弃)限制条件:奖池抽奖限制幸运值限制',
`probability` int(11) DEFAULT NULL COMMENT '中奖概率,总概率的多少分之一,如果所有道具的概率总和为100 当前奖品的概率是1,那么中奖概率就是百分之一',
`top` int(11) DEFAULT '0' COMMENT '道具排序',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4
道具表:此表为奖品池中的道具
CREATE TABLE `t_prop` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL COMMENT '物品名称',
`description` varchar(512) DEFAULT NULL COMMENT '描述',
`type` int(11) DEFAULT NULL COMMENT '0实体,1虚拟,2价值点',
`status` int(11) DEFAULT NULL COMMENT '物品状态,0正常,1删除',
`num` int(11) DEFAULT NULL COMMENT '物品数量',
`price` double DEFAULT NULL COMMENT '价值点',
`price_type` int(11) DEFAULT NULL COMMENT '2积分',
`url` varchar(1024) DEFAULT NULL COMMENT '道具展示图',
`create_time` datetime DEFAULT NULL COMMENT '物品创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4
抽奖套餐表:这张表,原先是用来存放购买积分套餐的,但是因为字段相同,没必要新增一张表,就加个type进行了区分
CREATE TABLE `t_starlight_set_meal` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ios_id` varchar(255) DEFAULT NULL COMMENT 'IOS内购id',
`price` double DEFAULT NULL COMMENT '价格 金额 | 积分',
`amount` int(11) DEFAULT NULL COMMENT '套餐内积分数量 | 套餐内抽奖次数',
`name` varchar(255) DEFAULT NULL COMMENT '套餐名称',
`description` varchar(255) DEFAULT NULL COMMENT '套餐描述',
`url` varchar(512) DEFAULT NULL COMMENT '积分展示图片',
`top` int(11) DEFAULT NULL COMMENT '套餐排序',
`type` int(1) DEFAULT '0' COMMENT '2抽奖套餐',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='星云币充值套餐'
用户钱包表:存放积分(即抽奖积分)、幸运值等信息,当前项目中,积分不计入账单,所以就没有相对应的账单列表,有需要的可以在每次修改钱包时去记录账单,此处不做赘述
CREATE TABLE `t_wallet` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '用户id',
`starlight` int(11) NOT NULL DEFAULT '0' COMMENT '积分',
`lucky` int(11) NOT NULL DEFAULT '0' COMMENT '幸运值',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_userId` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='钱包:积分、幸运值'
用户背包表:背包也是应该建立两张表(背包表:应包含礼物数量限制 和 背包容量,背包物品表:关联背包和物品信息),同是因为没有必须要,就使用一张表代替了
CREATE TABLE `t_knapsack` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '用户id',
`gift_id` int(11) NOT NULL COMMENT '道具id | 礼物id',
`numble` int(11) DEFAULT '1' COMMENT '礼物数量,无限制',
`capacity` int(11) DEFAULT '100' COMMENT '(废弃)背包容量,无限制',
`occupying_dosage` int(11) DEFAULT '0' COMMENT '(废弃)背包占用量,无限制',
`type` int(1) DEFAULT '0' COMMENT '0道具背包,1礼物背包',
PRIMARY KEY (`id`),
UNIQUE KEY `IDX_userId` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='用户背包'
以上相关数据表建立完成,生成相对应的对象即可(DrawPool、Prop、Wallet、Knapsack、StarlightSetMeal)
第二步:代码逻辑
public classDrawPoolService {
@ResourceprivateDrawPoolMapper drawPoolMapper;
@ResourceprivatePropMapper propMapper;
@ResourceprivateWalletMapper walletMapper;
@ResourceprivateKnapsackMapper knapsackMapper;
@ResourceprivateStarlightSetMealMapper starlightSetMealMapper;
/***奖池列表*@return*/publicMap list(Integer currentUserId) {
Map result = newHashMap<>();
List drawPoolList = drawPoolMapper.selectByType(null);
for(DrawPool drawPool : drawPoolList){
drawPool.setPropInfo(propMapper.selectByPrimaryKey(drawPool.getPropId()));
}
//封装奖品信息result.put("prop", drawPoolList);
//封装幸运值上限,暂定500result.put("upperLucky", 500);
//封装用户星云币、积分、幸运值信息if(currentUserId != null){
result.put("walletInfo", walletMapper.selectByUserId(currentUserId));
}else{
result.put("walletInfo", null);
}
List starlightSetMeals = starlightSetMealMapper.selectByType(2);
result.put("starlightSetMeals", starlightSetMeals);
returnresult;
}
/***抽奖*@paramcurrentUserId抽奖用户*@paramstarlightSetMealId抽奖套餐ID*@return*/publicResponseVO luckDraw(intcurrentUserId, intstarlightSetMealId){
Map result = newHashMap<>();
List propList = newArrayList<>();
Wallet wallet = walletMapper.selectByUserId(currentUserId);
StarlightSetMeal starlightSetMeal = starlightSetMealMapper.selectByPrimaryKey(starlightSetMealId);
if(wallet == null|| starlightSetMeal == null){
returnResponseVO.error("不满足抽奖条件");
}
//此次抽奖应该消耗的积分intusrStarlight = starlightSetMeal.getPrice().intValue();
intnum = starlightSetMeal.getAmount();
if(wallet.getStarlight() < usrStarlight){
returnResponseVO.error("积分不足");
}
//更新积分数量, 积分不用记录账单wallet.setStarlight(wallet.getStarlight() - usrStarlight);
walletMapper.updateByPrimaryKeySelective(wallet);
//一号奖池上限intoneUpperLucky = 200;
//二号奖池上限inttowUpperLucky = 300;
booleanisResetLucky = false;
for(inti = 0; i < num; i++){
//更新幸运值wallet = walletMapper.selectByUserId(currentUserId);
//返回抽奖池列表结果List drawPoolList = newArrayList<>();
//根据幸运值获取不同的抽奖池if(wallet.getLucky() >= 0&& wallet.getLucky() < towUpperLucky){
drawPoolList.addAll(drawPoolMapper.selectByType(1));
}
if(wallet.getLucky() >= towUpperLucky && wallet.getLucky() < oneUpperLucky){
drawPoolList.addAll(drawPoolMapper.selectByType(2));
}
if(wallet.getLucky() >= oneUpperLucky){
//如果当前用户的幸运值大于550,必得特殊道具drawPoolList.addAll(drawPoolMapper.selectByType(3));
isResetLucky = true;
}
intprizeId = getPrizeIndex(drawPoolList);
//如果奖品是价值点之类的,直接增加Prop prop = propMapper.selectByPrimaryKey(prizeId);
if(prop.getType() == 2){
wallet.setStarlight(wallet.getStarlight() + prop.getNum());
walletMapper.updateByPrimaryKeySelective(wallet);
}else{
//如果是道具,就存放到用户背包Knapsack knapsack = knapsackMapper.getKnapsack(currentUserId, Constants.Knapsack.Type.PROP, prizeId);
if(ValidateUtils.isNull(knapsack)){
knapsack = newKnapsack();
knapsack.setUserId(currentUserId);
knapsack.setGiftId(prizeId);
knapsack.setType(Constants.Knapsack.Type.PROP);
knapsack.setNumble(prop.getNum());
knapsackMapper.insertSelective(knapsack);
}else{
knapsack.setNumble(knapsack.getNumble() + prop.getNum());
knapsackMapper.updateByPrimaryKeySelective(knapsack);
}
}
//没进行一轮如果抽到了特殊奖池,那么都要清空幸运值,不然如果是多次抽奖,那么后面的每次都会是特殊道具if(isResetLucky){
//清空幸运值wallet.setLucky(0);
walletMapper.updateByPrimaryKeySelective(wallet);
}else{
//增加 幸运值,每抽奖一次, 幸运值+1wallet.setLucky(wallet.getLucky() + 1);
walletMapper.updateByPrimaryKeySelective(wallet);
}
propList.add(prop);
}
//清空幸运值if(isResetLucky){
wallet.setLucky(0);
walletMapper.updateByPrimaryKeySelective(wallet);
}
result.put("propList", propList);
//封装用户积分、幸运值信息result.put("walletInfo", walletMapper.selectByUserId(currentUserId));
returnResponseVO.succeess(result);
}
/***中奖概率,总概率的多少分之一,如果所有道具的概率总和为100当前奖品的概率是1,那么中奖概率就是百分之一*根据Math.random()产生一个double型的随机数,判断每个奖品出现的概率*@paramdrawPools*@returnrandom:奖品列表drawPools中的序列(drawPools中的第random个就是抽中的奖品),返回中奖的道具ID*/public static intgetPrizeIndex(List drawPools) {
// DecimalFormat df = new DecimalFormat("######0.00");intprizeId = 0;
try{
//计算总权重doublesumWeight = 0;
for(DrawPool drawPool : drawPools){
sumWeight += drawPool.getProbability();
}
//产生随机数doublerandomNumber;
randomNumber = Math.random();
//根据随机数在所有奖品分布的区域并确定所抽奖品doubled1 = 0;
doubled2 = 0;
for(inti=0;i
//依次获取奖品所在的范围//获取当前奖品所在的中奖概率范围 最大值d2 += Double.parseDouble(String.valueOf(drawPools.get(i).getProbability()))/sumWeight;
if(i==0){
d1 = 0;
}else{
//获取上一个奖品所在的中奖概率范围 最大值d1 +=Double.parseDouble(String.valueOf(drawPools.get(i-1).getProbability()))/sumWeight;
}
//如果中奖随机数 大于上一个奖品的最大值 并且小于当前奖品的最大值,那么表示中奖随机数在当前奖品的中奖范围内,当前奖品中奖if(randomNumber >= d1 && randomNumber <= d2){
prizeId = drawPools.get(i).getPropId();
break;
}
}
}catch(Exception e){
System.out.println("生成抽奖随机数出错,出错原因:"+e.getMessage());
}
returnprizeId;
}
}
以上代码,list函数返回抽奖页面的相关信息,luckDraw函数进行抽奖,返回中奖信息,以及积分修改后的信息,
java抽奖_Java实现抽奖功能相关推荐
- java点赞_java实现点赞功能示例
最近做了一个评论的点赞功能,感觉有必要记录一下. 思路: 点赞功能,看起来挺简单,但是做的高效稳定还是需要一些处理. 归纳思路如下: 1.点赞接口要利用redis做点赞次数限制,比如一分钟之内最多点赞 ...
- java 搜索_Java实现搜索功能代码详解
首先,我们要清楚搜索框中根据关键字进行条件搜索发送的是Get请求,并且是向当前页面发送Get请求 //示例代码 请求路径为当前页面路径 "/product" 当我们要实现多条件搜索 ...
- java 气泡_Java气泡提示功能实现
一个用Swing实现的java气泡提示效果. 运行效果如下图: package org.loon.swing.display; import java.awt.BorderLayout; import ...
- java抢红包_Java实现抢红包功能
采用多线程模拟多人同时抢红包.服务端将玩家发出的红包保存在一个队列里,然后用Job定时将红包信息推送给玩家.每一批玩家的抢红包请求,其实操作的都是从队列中弹出的第一个红包元素,但当前的红包数量为空的时 ...
- java实现抽奖_Java实现简单抽奖功能界面
本文实例为大家分享了Java实现简单抽奖功能的具体代码,供大家参考,具体内容如下 要求:定义文本框添加姓名,将姓名存储并且在界面中可见,点击抽奖按钮进行抽奖并输出最后的中奖得主. 关于抽奖当然需要用到 ...
- 砸金蛋java代码_java实现砸金蛋抽奖功能
本文实例为大家分享了java实现砸金蛋抽奖的具体代码,供大家参考,具体内容如下 代码如下 需求:用户每一次砸金蛋,抽中一等奖的概率为2% 二等奖10% 三等奖18% 四等奖70%. 累计砸第n次时必抽 ...
- JAVA基于权重的抽奖
https://blog.csdn.net/huyuyang6688/article/details/50480687 如有4个元素A.B.C.D,权重分别为1.2.3.4,随机结果中A:B:C:D的 ...
- java 9宫格抽奖_九宫格抽奖HTML+JS版
div{ margin: 100px auto 0px; // 居中 width:500px; height:250px; border:3px solid black; // 边框 } li{ wi ...
- Java——有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池用一个数组int[] arr = {10,5,20,50,100,200,500,800,2,80,300}
有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池用一个数组int[] arr = {10,5,20,50,100,200,500,800,2,80,300}; 创建两个抽奖箱(线程)设置线程名称分别 ...
最新文章
- python里dir是什么意思_python中dir什么作用
- php 设计五子棋游戏,基于js+canvas实现五子棋小游戏
- Spring 连接 PostgreSQL
- AD在原理图中高亮网络的两种方法,altium designer 20
- 有关centos7 图形化root用户登录
- swagger 上传文件 参数_如何使用Swagger上传文件
- 入行必看、经验不足必看:财务会计需要会的那些软件工具
- 汽车零部件行业PLM解决方案
- u3d:200个插件免费分享
- 2022-03-清华管理学-清华大学-宁向东
- (附源码)springboot社区养老医疗服务平台 毕业设计 041148
- python和scre_前端大牛们都学过哪些东西?
- 前端js实现文字自动转拼音方法
- JAVA 实现语音播报
- HTML+CSS+JS实现 ❤️ 立方体旋转图片切换特效❤️
- 使用CvvImage类在MFC的static控件显示图片
- 200+款神器,全网最好用的免费在线工具,都在这里了!
- Python脚本——信手拈来的自动化测试工具
- 游戏开发计划——数据元素设计(人物)
- RuntimeError: Expected 4-dimensional input for 4-dimensional weight, but got 3-dimensional input
热门文章
- 三段诡异的JavaScript代码,结果出乎意料
- 小鹏汽车CEO疑似隔空回应偷窃技术传闻;​苹果明年新款iPhone将使用增强版5nm芯片;Windows诞生35周年|极客头条...
- 超10000支团队参赛,阿里云首届云原生编程挑战赛完美收官
- 程序员!别逼自己刷题了!每天花10分钟做这件事,编程能力暴增!
- Python 爬取 201865 条《隐秘的角落》弹幕,发现看剧不如爬山?
- 一文搞懂 Spring JPA
- 阿里回应“拼多多员工淘宝账号被封”;微信脸书合办新冠病毒黑客马拉松;Kubernetes 1.18发布 | 极客头条...
- 库克:苹果从没有垄断;微信搜索升级;微软发布首款支持 Linux 的 Office 应用 | 极客头条...
- 【快报】程序员,别再埋头学Python了!
- 虾米音乐的监控体系升级之路