当前位置: 首页 > 后端技术 > Java

用Java写一个抽奖功能,太美了~!

时间:2023-04-01 18:28:23 Java

概述在项目开发中,经常需要进行抽奖等营销活动,例如:积分、刮刮乐、老虎机等,其实后台的实现方法是一样的。本文介绍一种常用的开奖抽奖实现方法。整个开奖过程包括以下几个方面:奖池开奖算法奖品限制奖品分配奖品奖品包括奖品、中奖概率和限额、中奖记录。奖品表:CREATETABLE`points_luck_draw_prize`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`name`varchar(50)DEFAULTNULLCOMMENT'奖品名称',`url`varchar(50)DEFAULTNULLCOMMENT'图片地址',`value`varchar(20)DEFAULTNULL,`type`tinyint(4)DEFAULTNULLCOMMENT'type1:红包2:积分3:经验币4:感谢惠顾5:自定义',`status`tinyint(4)DEFAULTNULLCOMMENT'status',`is_del`bit(1)DEFAULTNULLCOMMENT'是否删除',`position`int(5)DEFAULTNULLCOMMENT'position',`phase`int(10)DEFAULTNULLCOMMENT'期间数',`create_time`datetimeDEFAULTNULL,`update_time`datetimeDEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=164DEFAULTCHARSET=utf8mb4COMMENT='prizetable';奖品概率限制表:CREATETABLE`points_luck_draw_probability`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`points_prize_id`bigint(20)DEFAULTNULLCOMMENT'PrizeID',`points_prize_phase`int(10)DEFAULTNULLCOMMENT'PrizePhase',`probability`float(4,2)DEFAULTNULLCOMMENT'Probability',`frozen`int(11)DEFAULTNULLCOMMENT'产品抽取后的冻结次数',`prize_day_max_times`int(11)DEFAULTNULLCOMMENT'产品每天最大抽取次数',`user_prize_month_max_times`int(11)DEFAULTNULLCOMMENT'每个用户每月抽取产品的最大次数',`create_time`datetimeDEFAULTNULL,`update_time`datetimeDEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=114DEFAULTCHARSET=utf8mb4COMMENT='抽奖概率上限表';奖品记录表:CREATETABLE`points_luck_draw_record`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`member_id`bigint(20)DEFAULTNULLCOMMENT'用户ID',`member_mobile`varchar(11)DEFAULTNULLCOMMENT'电话号码winninguser',`points`int(11)DEFAULTNULLCOMMENT'消费积分',`prize_id`bigint(20)DEFAULTNULLCOMMENT'奖品ID',`result`smallint(4)DEFAULTNULLCOMMENT'1:winning2:notwinning',`month`varchar(10)DEFAULTNULLCOMMENT'中奖月份',`daily`dateDEFAULTNULLCOMMENT'中奖日期(不包括时间)',`create_time`datetimeDEFAULTNULL,`update_time`datetimeDEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=3078DEFAULTCHARSET=utf8mb4COMMENT='开奖记录表';奖池奖池是根据由中奖概率和限额组成的彩票池主要包括两个维度:中奖总池值和每个中奖占用的池值(分为起始值和结束值)。奖池总价??值:所有奖池价值的总和。每次奖池值:算法可以灵活,常用的有两种:中奖概率*10000(保证为整数)中奖概率10000奖池bean剩余数量:公共类PrizePool实现Serializable{/***总池值*/privateinttotal;/***奖品池*/privateListpoolBeanList;}奖品池bean:publicclassPrizePoolBeanimplementsSerializable{/***真实奖品在数据库中的ID*/privateLongid;/***奖品的起始池值*/privateintbegin;/***奖品结束池值*/privateintend;}奖池汇编代码:/***获取超大百万富翁奖池*@paramzillionaireProductMap超级百万富翁奖品地图*@paramflagtrue:cashfalse:没有现金*@return*/privatePrizePoolgetZillionairePrizePool(MapzillionaireProductMap,booleanflag){//总奖池值inttotal=0;ListpoolBeanList=newArrayList<>();for(Entryentry:zillionaireProductMap.entrySet()){ActivityProduct产品=entry.getValue();//无现金奖池,过滤掉类型为现金的奖品if(!flag&&product.getCategoryId()==ActivityPrizeTypeEnums.XJ.getType()){continue;}//组装奖池奖品PrizePoolBeanprizePoolBean=newPrizePoolBean();prizePoolBean.setId(product.getProductDescriptionId());prizePoolBean.setBengin(总计);总计=总计+product.getEarnings().multiply(newBigDecimal("10000")).intValue();prizePoolBean.setEnd(总计);poolBeanList.add(prizePoolBean);}PrizePoolprizePool=newPrizePool();prizePool.setTotal(总计);prizePool.setPoolBeanList(poolBeanList);返回奖池;对奖池中所有奖品进行整数循环比较,随机数落入哪个奖池区间即为中奖者开奖代码:publicstaticPrizePoolBeangetPrize(PrizePoolprizePool){//获取总奖池值inttotal=prizePool.getTotal();//获取随机数Randomrand=newRandom();intrandom=rand.nextInt(总计);//循环比较奖池范围for(PrizePoolBeanprizePoolBean:prizePool.getPoolBeanList()){if(random>=prizePoolBean.getBengin()&&randomsendPrize(LongmemberId,ListprizeList){try{for(PrizeDtoprizeDto:prizeList){//过滤器out感谢您的惠顾奖品if(prizeDto.getType()==PointsLuckDrawTypeEnum.XXHG.getType()){continue;}//根据奖品类型,从工厂中获取奖品分配类if(ObjectUtil.isNotNull(sendPrizeProcessor)){//分发奖品sendPrizeProcessor.send(memberId,prizeDto);}}返回新的AsyncResult<>(Boolean.TRUE);}catch(Exceptione){//如果派奖失败会记录日志saveSendPrizeErrorLog(memberId,prizeList);LOGGER.error("积分抽奖分配奖品异常",e);返回新的AsyncResult<>(Boolean.FALSE);}}工厂类:@ComponentpublicclassSendPrizeProcessorFactoryimplementsApplicationContextAware{privateApplicationContextapplicationContext;@OverridepublicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{this.applicationContext=applicationContext;}publicSendPrizeProcessorgetSendPrizeProcessor(PointsLuckDrawTypeEnumtypeEnum){StringprocessorName=typeEnum.getSendPrizeProcessorName();如果(StrUtil.isBlank(处理器名称)){返回空;}SendPrizeProcessorprocessor=applicationContext.getBean(processorName,SendPrizeProcessor.class);如果(ObjectUtil.isNull(processor)){thrownewRuntimeException("没有找到名为["+processorName+"]的奖励交付处理器");}返回处理器;}}奖品发放类别示例:/***红包奖品发放类别*/@Component("sendHbPrizeProcessor")publicclassSendHbPrizeProcessorimplementsSendPrizeProcessor{privateLoggerLOGGER=LoggerFactory.getLogger(SendHbPrizeProcessor.class);@ResourceprivateCouponService优惠券服务;@ResourceprivateMessageLogServicemessageLogService;@Overridepublicvoidsend(LongmemberId,PrizeDtoprizeDto)throwsException{//发放红包优惠券coupon=couponService.receiveCoupon(memberId,Long.parseLong(prizeDto.getValue()));//发送站内消息messageLogService.insertActivityMessageLog(memberId,"您参与积分抽奖活动抽奖"+coupon.getAmount()+"人民币理财红包已到,感谢您参与","活动通知赢取积分抽奖");//输出日志logLOGGER.info(memberId+"中奖积分抽奖"+prizeDto.getPrizeName()+"已经获奖!");}}