目录
activityStatusManage服务handerEvent()方法:
drawPrizeService.saveWinnerRecords()方法:
编辑查询相关信息:活动,人员,奖品,活动关联奖品表,构造中奖者信息。
前端逻辑:
判断是否为管理员,管理员可以抽奖:

活动进行中,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()函数调用后端接口,保存中奖信息,将此奖品状态设置为false,state设置为'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查询活动关联奖品信息:

中奖者信息插入数据库:

状态扭转更新数据库:
更新活动状态:

更新中奖人员状态:

更新活动关联奖品状态:

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