抽奖系统(6)

1.抽奖需求分析

可以看一下我们的ui图来看一下我们前端和后端需要做什么,来分析一下需求

文字已经总结了我们通过前端的ui图我们可以知道,前端主要是做1.控制抽奖流程,2.展示奖品信息,3.抽奖此时名字会闪动,4,确定中奖人(确定中奖人是由前端完成这个不要搞混了),点击下一步如果后面还有奖品重复以上操作,没有就会展示中奖名单 后端主要是 1给前端提供完整的活动信息来让前端进行展示 2当前端传来中奖人信息以后,后端需要将他们保存起来,以及注意我们的活动,人员,奖品是有状态的,抽完之后需要扭转其中的一些状态 ,还有一点上面图片没有展示出来,就是抽完奖之后,我们是有个通知中奖的环节,有短信通知和邮箱通知 3 当全部抽完以后,后端需要给前端提供中奖名单给前端来展示。 以上就是我们通过ui需求来分析出来的一些前端后端需要做的事情

2.查询活动详细信息后端实现

我们先来完成一下查询活动完整信息的接口图示即为后端的流程图,我们先前将活动的完整信息定义在activityDetailDTO这个对象里面,我们先前将他存放在了redis中(先前没有存放redis成功也没有关系),因为我们如果在redis找到直接返回,没有找到就去库表里面查找,然后在整合完整信息存放进redis中(为下次查询加快速度),然后返回结果,以下是时序图以及接口定义

注意几点我们这个接口给前端返回的奖品等级的时候返回的是中文"一等奖",所以我们这里定义controller层返回的奖品等级是枚举类里面的message,还有我们不给前端返回status我们直接给他返回是否有效,可以通过我们之前写好的valid()方法快速获取到,定义好了响应对象,controller层调用service层的方法后返回DTO,controller需要完成convert方法,这里需要注意一个点,就是我们希望,我们给前端返回的是排序后的奖品列表,我们希望有顺序的抽奖,而不是一下一等奖,一下三等奖,一下又一等奖,所以我们设置result的prizeList可以参考以下写法,这里sorted(Comparator.comparingInt())里面是一个比较器,我们选择的是prizeList里面的prizeDO的奖品等级属性的code属性来比较,默认是从小到大排序的,所以我们这里是先一等奖,后二等奖..

这里就是先对detailDTO里面的prizeList先根据code排序然后再做映射

controller相关的操作完成之后接下来完成service层的相关操作我们可以先校验一下activity是否为空来防止非正常用户的接口攻击,为空直接返回null,返回null给controller层也没有关系,因为我们controller层都有对service层返回的结果进行判空然后抛异常,如果redis不存在,存在以下情况 1.是根本不存在该活动(后续可以通过查活动表,如果没有查到直接返回null即可) 2.是创建活动的时候出现了异常,入库了,但是没有存到redis里面 3.redis存放的数据到了过期时间所以没有了 。

后面的两种情况是预料之中的,我们直接查四张表获取到相应的数据,通过这四个表然后在整合完整的活动信息构建ActivityDetailDTO对象然后将他存放到redis中去,最后直接返回。注意这里通过四个表构建ActivityDetailDTO方法和,存放redis(在该方法中我们已经设置好了存放的key,以及过期时间,直接调用即可),以及从redis中取ActivityDetailDTO,这些方法我们在创建活动的时候,以及写了,我们这里直接调用即可,以及在这里写一些sql即可完成该方法

3.抽奖接口设计

我们在这里正式开始设计抽奖接口的时候我们先来分析一下,现在我们来完成后端需要干的第二个事情,就是抽奖,这里包括,保存抽奖人的信息,相应的状态扭转,以及完成通知行为,这里的前提是前端已经为我们确定好了中奖人,看一下我分析的以下视图

由以上视图可以看出来我们这里采用的是异步处理的方式,而我们为了实现异步处理我们使用MQ,RabbitMQ消息队列来实现异步处理可以看一下流程图

前端抽奖之前就是一些奖品创建人员创建以及活动创建我们可以知道我们的抽奖请求处理的接口,只是接收请求以后,将有效的抽奖请求送至MQ队列以后,直接返回了,看以上对一些流程图中一些重要部分做了一些描述,这里补充一点幂等性,就是保证了一个相同的请求可以发送多次,不过我们可以保证只执行一次,这就是保证了幂等性,

阅读以下我对于抽奖接口的总结与一些技术细节

通过以上流程,抽奖系统能够确保抽奖过程的公平性和⾼效性,同时提供良好的⽤⼾体验。⽽且还整合了 Redis 和 MQ , 进⼀步提⾼系统的性能。

4.MQ介绍以及RabbitMQ的简单使用

MQ简单介绍以及RabbitMQ基础使用,快速上手-CSDN博客https://blog.csdn.net/2301_80293365/article/details/156691913?spm=1011.2124.3001.6209

这个文章已经很详细的介绍了mq的介绍,以及rabbitmq的简单使用,需要引入在服务器上面下载好相关的rabbitmq服务,以及需要在项目中引入相关的依赖,配置项,配置类,之后

完成了rabbitmq的配置以后我们相当于完成了中间部分的代码,我们现在只需要完成生产者和消费者,我们的生产者就是抽奖接口,这个接口就是接收前端发来的带着参数的抽奖请求,我们这个接口只做两个事情,将消息放入消息队列,然后直接给前端返回结果 消费者就是:处理抽奖流程的方法,他从消息队列中拿消息,并且处理,这里比如保存中奖人,扭转状态,以及通知行为等,我们接下来就是需要完成这两部分的代码

5.抽奖异步接口实现

注意我们抽奖是将同一种奖品一次性抽完(就是比如手机有三个直接一次性抽完,然后前端将三人中奖信息发给后端,而不是抽三次)

这个接口我们很简单只做这几件事情,接收前端传来的抽奖请求,然后将该请求消息推送至消息队列当中,然后直接返回,看一下接口文档定义,来编写该部分的代码

这里我们涉及到新的模块,抽奖模块,创建新的controller以及service,这里响应的data只有boolean,所以不需要创建新的响应类,只需要构建一下请求类接收即可,注意加上注解校验,列表内的元素的注解校验也要生效需要加上@Valid,controller层代码完成后接下来是完成servcie层的代码,service层我们只需要做将消息推入消息队列,对于rabbitmq的操作,我们需要使用这个对象

这个对象定义了rabbitmq所有的发送接收的行为,使用这个方法来对消息队列进行一些操作,这里我们向消息队列推送的方法使用convertAndSend(交换机名String,交换机队列绑定的keyString,消息体),(这个方法重载了很多可以自行阅读一下)注意我们这里消息体会被自动转换成json(我们在配置类中设置了转化成json),因为对于rabbitmq和redis这种,

  • Redis 只能存储字符串、哈希、列表等字节 / 字符串类的基础数据结构,无法识别 JVM/Python 解释器的内存对象;
  • MQ 的消息传输是基于网络字节流的,网络传输只能传二进制数据,无法直接传内存中的对象引用。

Redis/MQ 不认识你代码里的 "对象",只认识 "字节 / 字符串",序列化就是把 "对象" 翻译成 "字节 / 字符串" 的过程。对于消息体我们一般把他设置为map这里我们可以定义成{"messageId":独属id,"messageDate":消息体json},然后调用发送方法他就会推送给消息队列,最后可以log打印一下map,就完成了service层的代码,这里convertAndSend这个方法假设出现了异常,我们这里没有配置,他会直接抛出异常,我们程序就会直接走统一异常处理了,不过也符合我们的逻辑,相当于大话没有说出去

这里我们可以先测试一下能不能往消息队列中推送消息成功,写一个测试方法即可,测试后我们可以去RabbitMq的web控制页面查看是否推送成功,因为我们现在只有生产者,没有消费者,所以这个消息会一直存在在队列里面。看如下视图ready,和total

注意这里要使用rabbitmq的时候,先要去服务器平台添加规则 开放一下端口5672打开(要使用web控制端同样需要打开15672端口),并且如果测试的时候发现有权限问题的话可以使用以下指令在服务器上面运行,然后给他权限。

这里不需要用xshell与服务器保持连接就可以直接运行代码,也许有人会有疑问,为什么我们使用redis的时候我们需要与服务器保持连接,而使用rabbitMq的时候不需要保持连接,注意因为我们之前使用服务器上的redis的时候,用的是隧道,本质上是把云服务器上的redis通过xshell转发到本地的,假设我们没有使用隧道转发,直接开放redis的端口(默认6379) 的话,我们也可以不用保持xshell与服务器连接,就可以使用redis了

总结以上原因就是因为我们redis使用了隧道所以需要保持xshell与服务器连接,没有使用就不需要使用xshell与服务器连接了,但是必须要先去服务器管理平台添加规则,将相应的端口开放(使用隧道就开放隧道的端口,没有就直接开放相应服务的端口即可)

相关推荐
独断万古他化17 小时前
【SpringBoot 日志】日志级别与配置:分类、使用及持久化全攻略
java·spring boot·后端·java-ee
Java 码农17 小时前
RabbitMQ集群部署方案及配置指南04
分布式·rabbitmq
SimonKing17 小时前
基于Netty的TCP协议的Socket服务端
java·后端·程序员
予枫的编程笔记17 小时前
Elasticsearch深度搜索与查询DSL实战:精准定位数据的核心技法
java·大数据·人工智能·elasticsearch·搜索引擎·全文检索
while(1){yan}17 小时前
拦截器(详解)
数据库·spring boot·spring·java-ee·拦截器
荒诞硬汉17 小时前
面向对象(三)
java·开发语言
柒.梧.17 小时前
Spring Boot集成JWT Token实现认证授权完整实践
java·spring boot·后端
白露与泡影17 小时前
放弃 IntelliJ IDEA,转 VS Code 了。。
java·ide·intellij-idea
独自破碎E17 小时前
在RabbitMQ中,怎么确保消息不会丢失?
分布式·rabbitmq