抽奖系统核心——抽奖管理

目录

前端逻辑:

核心全局变量:

reloadConf函数:

nextStep函数:

后端实现:

抽奖接口:

Controller层:

Service层:

MqReceiver:

drawPrizeService:

statusConvert()方法:

activityStatusManage服务handerEvent()方法:

加入设计模式:责任链模式和策略模式。

drawPrizeService.saveWinnerRecords()方法:

并发处理短信通知和邮箱通知:

Mapper层:

校验抽奖请求是否有效,通过活动id查询活动:

​编辑查询相关信息:活动,人员,奖品,活动关联奖品表,构造中奖者信息。

状态扭转更新数据库:


前端逻辑:

判断是否为管理员,管理员可以抽奖:

活动进行中,valid为true,身份为管理员,使用reloadConf初始化页面(nextStep作为回调函数),活动未开始,调用showRecords函数进行展示。

核心全局变量:

javascript 复制代码
    // 奖品列表
    var steps = null
    // 抽到第几个了
    var step = 0
    // 人员列表
    var names = null
    // 正在做什么
    var state = ''

reloadConf函数:

reloadConf函数调用接口,获取活动的详细信息,给全局变量steps(奖品列表)names(人员列表)赋值,调用传过来的回调函数nextStep用于根据当前状态显示下一个步骤的内容。

nextStep函数:

使用data函数拿到奖品列表中的奖品,根据奖品的状态执行不同逻辑:

一开始状态为空(全局变量的state属性默认为空),走else逻辑,将状态设置为showPic,执行showPic() 函数,将奖品信息传入函数中,**showPic()**函数用于显示图片和奖品信息。

调用**changeNextButtonText()**函数 ,改变按钮的文本(比如开始抽奖,已抽完,下一步):

如果活动状态未在进行中,执行**showRecords()**函数:展示中奖信息。

前端点击开始抽奖按钮,接着执行nextStep()函数:奖品为抽取,走if逻辑,,将状态设置为'showBlink',执行showBlink()函数,传入奖品信息。执行changeNextButtonText() 函数切换按钮文本。showBlink函数用于显示闪烁的文字,它首先设置奖品信息,隐藏图片,显示列表,然后创建与data.count相等数量的span元素。使用**window.requestAnimationFrame()循环调用doBlink()**函数模拟抽奖的展示效果,让文字不断闪烁。

继续点击确定按钮,执行nextStep()函数,此时状态state等于showBlink() ,执行此函数,将已中奖的人员和奖品信息移除,执行saveLuck()函数调用后端接口,保存中奖信息,将此奖品状态设置为falsestate设置为'showList' ,执行**showList()**函数,调用changeNextButtonText()函数,切换按钮文本为"已抽完,下一步"。

saveLuck函数:发送请求到后端

showList() 函数用于显示静态的文字列表。它设置奖品信息,隐藏图片,显示列表,并将data.list中的数据添加到列表中。

奖品列表在前端只能临时保存,刷新后丢失,如果列表为空,则需要调用后端接口,进行查询:

使用函数**showWinnerListWithPrize()**传入奖品信息:调用后端的winning-records/show接口:

点击下一步,如果step小于奖品列表长度,将state设置为空,执行nextStep()函数,将按钮重置为开始抽奖。否则代表奖品已经抽完,执行showRecords()方法,改变按钮为已全部抽完。showRecords方法调用后端**"winning-records/show"**接口,展示中奖者信息。

到此前端抽奖核心逻辑梳理完毕。

后端实现:

抽奖接口:

Controller层:

接收前端参数,调用Service服务。

使用DrawPrizeParam类接收前端参数:

活动id,奖品id,奖品等级,中奖时间,中奖者列表(中奖者id和姓名)。

Service层:

drawPrize方法将信息发送到RabbitMQ中:

MqReceiver:

接收来自service层的消息,进行异步消息处理:

Mq接收消息后,首先对抽奖的请求进行校验,调用drawPrizeService的方法校验是否为两个一样的抽奖请求,将中奖的人员,奖品,活动状态进行状态扭转。保存中奖者名单,发送邮箱和短信通知中奖者。遇到异常回滚状态,保持事务一致性。

drawPrizeService:

对抽奖请求进行校验,根据活动id,查询活动信息和活动奖品详细信息。判断活动和活动奖品是否存在,校验抽奖活动的状态是否已经完成,校验抽奖奖品是否有效,校验中奖人数是否和奖品数量相同。

statusConvert()方法:

ConvertActivityStatusDTO类存放活动id,活动目标状态,奖品id,奖品目标状态,人员id,人员目标状态。将这些状态设置为目标状态,调用activityStatusManage服务,将需要扭转的状态进行扭转。

activityStatusManage服务handerEvent()方法:
加入设计模式:责任链模式和策略模式。

策略模式:将活动扭转(ActivityOperater),奖品扭转(PriceOperater),人员扭转(UserOperater)分为3个不同实现类。每个类继承公共的类AbstractActivityOperater,公共类包含处理的顺序码,判断是否需要状态转换的方法,状态转换方法。策略模式增强代码的维护性和可读性。

责任链模式:将活动扭转,奖品扭转,人员扭转看成三个节点,在进行状态扭转操作时,根据不同操作码,区分执行先后顺序。由于活动扭转的前提是参与人员和参与奖品全部扭转,有一个依赖关系,使用责任链模式,极大增强了系统的拓展性和可维护性。比如,在状态转换时,加入新的需要转换的,目前是人员和奖品,后期可以加入参与奖,参与奖是没中奖的人员全部获得参与奖,参与奖状态也会随之改变。

调用processConvertStatus()方法,根据状态码先处理活动参与人员和活动参与奖品状态,在处理活动状态的转换。循环遍历链式结构,处理状态码为1的状态转换,第二次调用该方法,处理状态码为2的状态转换。

调用needConvert()方法,转换状态:

抽奖核心流程结束。

drawPrizeService.saveWinnerRecords()方法:

保存中奖者名单,构造中奖者记录,将中奖者记录入库,然后再加入到缓存中,方便后续查询使用。

并发处理短信通知和邮箱通知:

使用线程池,创建两个线程,执行发送短信和邮箱功能。

Mapper层:

持久层,包含抽奖操作涉及到的全部sql语句。

校验抽奖请求是否有效,通过活动id查询活动:

根据活动id和奖品id查询活动奖品:

查询相关信息:活动,人员,奖品,活动关联奖品表,构造中奖者信息。

根据id查询活动相关信息:

根据中奖者id查询相关活动人员:

根据奖品id查询奖品详细信息:

根据活动关联奖品id查询活动关联奖品信息:

中奖者信息插入数据库:

状态扭转更新数据库:

更新活动状态:

更新中奖人员状态:

更新活动关联奖品状态:

文章到此结束,感谢观看!

相关推荐
lyh13443 天前
【Fiddler工具判断前后端Bug】
状态模式
季鸢3 天前
Java设计模式之状态模式详解
java·设计模式·状态模式
萌新小码农‍4 天前
Spring框架学习day7--SpringWeb学习(概念与搭建配置)
学习·spring·状态模式
EndingCoder5 天前
React从基础入门到高级实战:React 高级主题 - React 微前端实践:构建可扩展的大型应用
前端·javascript·react.js·前端框架·状态模式
何双新8 天前
第14讲、Odoo 18 实现一个Markdown Widget模块
python·状态模式
zwjapple9 天前
react-native的token认证流程
react native·状态模式·token
何中应10 天前
【设计模式-4.6】行为型——状态模式
java·设计模式·状态模式
失败尽是常态Z11 天前
基于JWT+Redis的登录流程实现
java·数据库·redis·状态模式·jwt·用户登录
暴躁哥13 天前
深入理解设计模式之状态模式
设计模式·状态模式