【项目】【抽奖系统】抽奖 - 查询活动完整信息 - 详解

news/2026/1/20 17:52:58/文章来源:https://www.cnblogs.com/yangykaifa/p/19508070

目录

  • 一、抽奖流程
  • 二、查询活动完整信息简介
  • 三、参数列表
  • 四、接口规范
  • 五、controller层
    • 5.1 GetActivityDetailResult:controller层返回类
    • 5.2 convertTOGetActivityDetailResult:service返回结果 转换 controller返回结果 方法
    • 5.3 新增错误码
  • 六、service层
    • 6.1 创建接口
    • 6.2 实现接口
  • 七、dao层
  • 八、测试

一、抽奖流程

  1. 参与者注册与奖品建⽴
    1.1. 参与者注册:管理员通过管理端新增⽤⼾, 填写必要的信息,如姓名、联系⽅式等。
    1.2. 奖品建⽴:奖品需要提前建⽴好
  2. 抽奖活动设置
    2.1. 活动创建:管理员在系统中创建抽奖活动,输⼊活动名称、描述、奖品列表等信息。
    2.2. 圈选⼈员: 关联该抽奖活动的参与者。
    2.3. 圈选奖品:圈选该抽奖活动的奖品,设置奖品等级、个数等。
    2.4. 活动发布:活动信息发布后,系统通过管理端界⾯展⽰活动列表。
  3. 抽奖请求处理(重要)
    3.1. 随机抽取:前端随机选择后端提供的参与者,确保每次抽取的结果是公平的。
    3.2. 请求提交:在活动进⾏时,管理员可发起抽奖请求。请求包含活动ID、奖品ID和中奖⼈员等附加
    信息。
    3.3. 消息队列通知:有效的抽奖请求被发送⾄MQ队列中,等待MQ消费者真正处理抽奖逻辑。
    请求返回:抽奖的请求处理接⼝将不再完成任何的事情,直接返回。
  4. 抽奖结果公布
    4.1. 前端展⽰:中奖名单通过前端随机抽取的⼈员,公布展⽰出来。
  5. 抽奖逻辑执⾏(重要)
    5.1. 消息消费:MQ消费者收到异步消息,系统开始执⾏以下抽奖逻辑。
  6. 中奖结果处理(重要)
    6.1. 请求验证:
    6.2. 系统验证抽奖请求的有效性,如是否满⾜系统根据设定的规则(如奖品数量、每⼈中奖次数限制等)等;
    6.3. 幂等性:若消息多发,已抽取的内容不能再次抽取
    6.4. 状态扭转:根据中奖结果扭转活动/奖品/参与者状态,如奖品是否已被抽取,⼈员是否已中奖等。
    6.5. 结果记录:中奖结果被记录在数据库中,并同步更新Redis缓存。
  7. 中奖者通知
    7.1. 通知中奖者:通知中奖者和其他相关系统(如邮件发送服务)。
    7.2. 奖品领取:中奖者根据通知中的指引领取奖品。
  8. 抽奖异常处理
    8.1. 回滚处理:当抽奖过程中发⽣异常,需要保证事务⼀致性。
    8.2. 补救措施:抽奖⾏为是⼀次性的,因此异步处理抽奖任务必须保证成功,若过程异常,需采取补救措施

技术实现细节

  • 异步处理:提⾼抽奖性能,不影响抽奖流程,将抽奖处理放⼊队列中进⾏异步处理,且保证了幂等性。
  • 活动状态扭转处理:状态扭转会涉及活动及奖品等多横向维度扭转,不能避免未来不会有其他内容牵扯进活动中,因此对于状态扭转处理,需要⾼扩展性(设计模式)与维护性。
  • 事务处理:在抽奖逻辑执⾏时,如若发⽣异常,需要确保数据库表原⼦性、事务⼀致性,因此要做好事务处理。

二、查询活动完整信息简介

时序图:

三、参数列表

参数名描述类型默认值条件
activityId活动idLong必须

四、接口规范

[请求] /activity-detail/find?activityId=24 GET
[响应]
{
"code": 200,
"data": {
"activityId": 24,
"activityName": "测试抽奖活动",
"description": "测试抽奖活动",
"valid": true,
"prizes": [
{
"prizeId": 18,
"name": "⼿机",
"description": "⼿机",
"price": 5000.00,
"imageUrl": "e606c8db-218a-40c2-8946-0d9f8570626d.jpg",
"prizeAmount": 1,
"prizeTierName": "⼀等奖",
"valid": true
},
{
"prizeId": 19,
"name": "吹⻛机",
"description": "吹⻛机",
"price": 200.00,
"imageUrl": "63404e12-26f7-4974-9a99-41993586093c.jpg",
"prizeAmount": 1,
"prizeTierName": "⼆等奖",
"valid": true
}
],
"users": [
{
"userId": 44,
"userName": "郭靖",
"valid": true
},
{
"userId": 45,
"userName": "杨康",
"valid": true
}
]
},
"msg": ""
}

五、controller层

com/yj/lottery_system/controller 包下 ActivityController 类中:

  • 非空校验
  • 调用service
  • GetActivityDetailResult:controller层返回类
  • convertTOGetActivityDetailResult:service返回结果 转换 controller返回结果 方法
@RequestMapping("/activity-detail/find")
public CommonResult<GetActivityDetailResult> getActivityDetailFind (Long activityId) {//日志打印log.info("getActivityDetailFind activityId: {}", JacksonUtil.writeValueAsString(activityId));//调用service服务ActivityDetailDTO activityDetailDTO = activityService.getActivityDetailFind(activityId);return CommonResult.success(convertTOGetActivityDetailResult(activityDetailDTO));}

5.1 GetActivityDetailResult:controller层返回类

com.yj.lottery_system.controller.result 包下:

  • 其实跟前面创建活动的service层返回的ActivityDetailDTO类差不多,只不过将状态表示直接换成Boolean,不需要提供单独方法
  • 也可以对照请求响应,一一填写
package com.yj.lottery_system.controller.result;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
/**
* @author: yibo
*/
@Data
public class GetActivityDetailResult implements Serializable {
/**
* 活动id
*/
private Long activityId;
/**
* 活动名称
*/
private String activityName;
/**
* 活动描述
*/
private String description;
/**
* 活动是否有效
*/
private Boolean valid;
/**
* 奖品信息(列表)
*/
private List<Prize> prizes;/*** 人员信息(列表)*/private List<User> users;@Datapublic static class Prize {/*** 奖品Id*/private Long prizeId;/*** 奖品名*/private String name;/*** 图片索引*/private String imageUrl;/*** 价格*/private BigDecimal price;/*** 描述*/private String description;/*** 奖品等奖*/private String prizeTierName;/*** 奖品数量*/private Long prizeAmount;/*** 奖品是否有效*/private Boolean valid;}@Datapublic static class User {/*** 用户id*/private Long userId;/*** 姓名*/private String userName;/*** 人员是否被抽取*/private Boolean valid;}}

5.2 convertTOGetActivityDetailResult:service返回结果 转换 controller返回结果 方法

com/yj/lottery_system/controller 包下 ActivityController 类中:

  • 对于类中的List,使用老方法流来赋值即可。
  • 在对奖品赋值的时候,我们将奖品按照等级排个序
private GetActivityDetailResult convertTOGetActivityDetailResult(ActivityDetailDTO activityDetailDTO) {
if(null == activityDetailDTO) {
throw new ControllerException(ControllerErrorCodeConstants.GET_ACTIVITY_DETAILS_ERROR);
}
GetActivityDetailResult getActivityDetailResult = new GetActivityDetailResult();
getActivityDetailResult.setActivityId(activityDetailDTO.getActivityId());
getActivityDetailResult.setActivityName(activityDetailDTO.getActivityName());
getActivityDetailResult.setDescription(activityDetailDTO.getDesc());
getActivityDetailResult.setValid(activityDetailDTO.valid());
getActivityDetailResult.setPrizes(activityDetailDTO.getPrizeDTOList().stream()
//按照奖品等级排序
.sorted(Comparator.comparingInt(prizeDTO -> prizeDTO.getTires().getCode()))
.map(prizeDTO -> {
GetActivityDetailResult.Prize prize = new GetActivityDetailResult.Prize();
prize.setPrizeId(prizeDTO.getPrizeId());
prize.setDescription(prizeDTO.getDescription());
prize.setImageUrl(prizeDTO.getImageUrl());
prize.setName(prizeDTO.getName());
prize.setPrice(prizeDTO.getPrice());
prize.setPrizeTierName(prizeDTO.getTires().getMessage());
prize.setPrizeAmount(prizeDTO.getPrizeAmount());
prize.setValid(prizeDTO.valid());
return prize;
}).collect(Collectors.toList())
);
getActivityDetailResult.setUsers(activityDetailDTO.getUserDTOList().stream()
.map(userDTO -> {
GetActivityDetailResult.User user = new GetActivityDetailResult.User();
user.setUserId(userDTO.getUserId());
user.setUserName(userDTO.getUserName());
user.setValid(userDTO.valid());
return user;
}).collect(Collectors.toList())
);
return getActivityDetailResult;
}

5.3 新增错误码

com/yj/lottery_system/common/errorcode 包下 ControllerErrorCodeConstants.java类

ErrorCode GET_ACTIVITY_DETAILS_ERROR = new ErrorCode(302,"查询活动详情失败");

六、service层

6.1 创建接口

com/yj/lottery_system/service 包下 IActivityService接口类中:

/**
* 获取活动详情信息
* @param activityId
* @return
*/
ActivityDetailDTO getActivityDetailFind(Long activityId);

6.2 实现接口

com/yj/lottery_system/service/impl 包下 ActivityServiceImpl 类中:

  • 非空校验
  • 先在 Redis 里面查找,方法创建活动时已写好
  • 有直接返回,没有进行下一步查表
  • 调 dao 查 活动表,拿到活动信息
  • 调 dao 查 活动奖品表,拿到活动关联奖品信息
  • 调 dao 查 活动人员表,拿到活动关联人员信息
  • 调 dao 查 奖品表,拿到活动关联奖品详细信息
  • 整合详细信息,方法创建活动时已写好
  • 存放Redis,方法创建活动时已写好
/**
* 获取活动详情信息
* @param activityId
* @return
*/
@Override
public ActivityDetailDTO getActivityDetailFind(Long activityId) {
//查Redis
if(null == activityId) {
log.warn("查询活动详细信息失败 activityId不存在");
return null;
}
ActivityDetailDTO activityFromCache = getActivityFromCache(activityId);
if(activityFromCache != null) {
log.warn("查询活动详细信息成功 activityFromCache:{}", JacksonUtil.writeValueAsString(activityFromCache));
return activityFromCache;
}
//如果Redis没有,
// 查表 活动表
ActivityDO activityDO = activityMapper.selectById(activityId);
// 活动奖品表
List<ActivityPrizeDO> activityPrizeDOList = activityPrizeMapper.selectByActivityId(activityId);// 活动人员表List<ActivityUserDO> activityUserDOList = activityUserMapper.selectByActivityId(activityId);// 奖品表//先拿奖品idList<Long> prizeIdList = activityPrizeDOList.stream().map(ActivityPrizeDO::getPrizeId).collect(Collectors.toList());List<PrizeDO> prizeDOList = prizeMapper.batchSelectByIds(prizeIdList);//整合详细信息,存放RedisActivityDetailDTO activityDetailDTO = convertActivityDetailDTO(activityDO, activityUserDOList, activityPrizeDOList, prizeDOList);//存放RediscacheActivity(activityDetailDTO);return activityDetailDTO;}

七、dao层

com/yj/lottery_system/dao/mapper 包下 ActivityMapper.java 类

/**
* 根据活动id查活动信息
* @param id
* @return
*/
@Select("select * from activity where id = #{id}")
ActivityDO selectById(@Param("id") Long id);

com/yj/lottery_system/dao/mapper 包下 ActivityPrizeMapper.java 类

/**
* 根据活动id 查活动关联奖品信息
* @param activityId
* @return
*/
@Select("select * from activity_prize where activity_id = #{activityId}")
List<ActivityPrizeDO> selectByActivityId(@Param("activityId") Long activityId);

com/yj/lottery_system/dao/mapper 包下 ActivityUserMapper.java 类

/**
* 根据活动id 查活动关联人员信息
* @param activityId
* @return
*/
@Select("select * from activity_user where activity_user activity_id = #{activityId}")
List<ActivityUserDO> selectByActivityId(@Param("activityId") Long activityId);

八、测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1190133.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高效抖音视频批量采集:打造个人专属内容资源库的终极方案

高效抖音视频批量采集&#xff1a;打造个人专属内容资源库的终极方案 【免费下载链接】douyinhelper 抖音批量下载助手 项目地址: https://gitcode.com/gh_mirrors/do/douyinhelper 还在为抖音视频素材管理而烦恼&#xff1f;这款专业的批量采集工具将彻底改变您的内容获…

2025双片钉箱机哪家强?国内口碑榜TOP5供应商揭晓!市场双片钉箱机优选实力品牌 - 品牌推荐师

随着包装行业智能化转型加速,双片钉箱机作为纸箱生产的核心设备,其性能稳定性、技术先进性及售后服务能力直接影响企业生产效率与成本。然而,市场供应商鱼龙混杂,企业选型时面临技术参数虚标、服务响应滞后等痛点。…

收藏备用!程序员转型大模型全攻略:从入门到职业落地无死角

AI大模型浪潮正以不可阻挡之势席卷全球科技领域&#xff0c;成为驱动行业变革的核心赛道。无论你是深耕前端、后端、移动端的开发者&#xff0c;还是全能型全栈工程师&#xff0c;都渴望抓住这波技术红利&#xff0c;实现职业赛道的升级与跃迁。但大模型领域知识体系繁杂庞大&a…

【实战指南】零基础极速搭建开源财务工具:5分钟拥有专属个人财务管理系统

【实战指南】零基础极速搭建开源财务工具&#xff1a;5分钟拥有专属个人财务管理系统 【免费下载链接】moneynote-api 开源免费的个人记账解决方案 项目地址: https://gitcode.com/gh_mirrors/mo/moneynote-api 在数字化时代&#xff0c;如何选择一款既安全又功能全面的…

收藏!大模型应用开发:程序员突破内卷的百万年薪新赛道

2025年春季&#xff0c;一则招聘动态在程序员圈层引发轩然大波&#xff1a;国内某头部科技企业为“大模型应用开发工程师”岗位开出154万年薪&#xff0c;这并非博人眼球的营销操作&#xff0c;而是招聘市场中真实达成的就业案例。当“35岁职业天花板”“技术内卷致身心俱疲”成…

免费网易云音乐NCM格式转换终极教程:一键解锁加密音频文件

免费网易云音乐NCM格式转换终极教程&#xff1a;一键解锁加密音频文件 【免费下载链接】ncmdump 转换网易云音乐 ncm 到 mp3 / flac. Convert Netease Cloud Music ncm files to mp3/flac files. 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdump 还在为网易云音乐…

Edge TTS终极指南:跨平台语音合成完整解决方案

Edge TTS终极指南&#xff1a;跨平台语音合成完整解决方案 【免费下载链接】edge-tts Use Microsoft Edges online text-to-speech service from Python WITHOUT needing Microsoft Edge or Windows or an API key 项目地址: https://gitcode.com/GitHub_Trending/ed/edge-tt…

2026年正规的大连智能锁维修安装,大连密码锁维修安装,大连智能锁维修安装公司选购指南与推荐 - 品牌鉴赏师

引言在当今数字化与智能化飞速发展的时代,智能锁、密码锁等各类先进锁具在大连家庭与企业中的应用日益广泛。随之而来的是对锁具维修安装服务的大量需求。为了帮助大连地区的消费者在众多的大连智能锁维修安装、大连密…

眼调节训练灯:守护孩子视力,筑牢近视防控防线

孩子近视后&#xff0c;除了佩戴眼镜矫正视力&#xff0c;如何有效防控度数加深&#xff0c;成为无数家长心头的难题。我们都清楚&#xff0c;孩子日常学业压力大&#xff0c;长时间近距离读书、写作业是常态&#xff0c;这种持续的用眼状态容易让眼部调节功能处于紧张状态&…

Python扩散模型实战核心拆解:文本生成图像与视频全流程

一、文章核心价值与适用人群 这篇《Python 扩散模型实战:从文本生成图像到视频生成》是国内少有的 “原理 + 实战 + 优化” 三位一体的扩散模型教程,核心价值在于:避开复杂数学公式,用通俗语言解释扩散模型 “逐步…

ComfyUI Manager全面指南:轻松掌握AI工作流插件管理技巧

ComfyUI Manager全面指南&#xff1a;轻松掌握AI工作流插件管理技巧 【免费下载链接】ComfyUI-Manager 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-Manager ComfyUI Manager作为AI工作流管理的关键工具&#xff0c;为ComfyUI用户提供了强大的插件管理能力&a…

3分钟快速上手:小红书无水印下载神器XHS-Downloader完整教程

3分钟快速上手&#xff1a;小红书无水印下载神器XHS-Downloader完整教程 【免费下载链接】XHS-Downloader 免费&#xff1b;轻量&#xff1b;开源&#xff0c;基于 AIOHTTP 模块实现的小红书图文/视频作品采集工具 项目地址: https://gitcode.com/gh_mirrors/xh/XHS-Download…

电子万能材料试验机哪个牌子好质量好?源头制造商生产商供应商盘点 - 品牌推荐大师1

电子万能材料试验机哪个牌子好质量好?源头制造商生产商供应商盘点 一、电子万能材料试验机行业背景与发展趋势 材料是工业制造与科研创新的核心基石,电子万能材料试验机作为“材料性能量化工具”,其精度与可靠性直接…

轻量级Alienware硬件控制工具:告别臃肿官方软件的终极替代指南

轻量级Alienware硬件控制工具&#xff1a;告别臃肿官方软件的终极替代指南 【免费下载链接】alienfx-tools Alienware systems lights, fans, and power control tools and apps 项目地址: https://gitcode.com/gh_mirrors/al/alienfx-tools 厌倦了Alienware Command Ce…

条件编译控制

在 xxx.go 文件开头添加代码 //go:build debug ✅ 不加 //go:build debug 的文件 → 永远会被编译&#xff08;默认行为&#xff09; ✅ 加了 //go:build debug 的文件 → 「默认不编译」&#xff0c;只有运行编译命令时手动加 -tags debug 才会编译 通俗解释 加了这个注释的文…

番茄小说完整下载指南:高效构建个人数字图书馆

番茄小说完整下载指南&#xff1a;高效构建个人数字图书馆 【免费下载链接】fanqienovel-downloader 下载番茄小说 项目地址: https://gitcode.com/gh_mirrors/fa/fanqienovel-downloader 在数字化阅读时代&#xff0c;你是否曾因网络中断而无法继续追更精彩章节&#x…

BT下载加速终极指南:如何通过Tracker优化实现下载速度翻倍

BT下载加速终极指南&#xff1a;如何通过Tracker优化实现下载速度翻倍 【免费下载链接】trackerslist Updated list of public BitTorrent trackers 项目地址: https://gitcode.com/GitHub_Trending/tr/trackerslist 你可能遇到过这样的情况&#xff1a;下载种子文件时速…

实用指南:3步轻松解密网易云音乐,实现全平台播放自由

实用指南&#xff1a;3步轻松解密网易云音乐&#xff0c;实现全平台播放自由 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 你是否曾经在网易云音乐下载了心爱的歌曲&#xff0c;却发现只能在特定客户端播放&#xff1f;这种格式限…

5个实战技巧让Vue3树形选择器开发效率翻倍

5个实战技巧让Vue3树形选择器开发效率翻倍 【免费下载链接】vue3-treeselect tree select component for vue 3 (next) 项目地址: https://gitcode.com/gh_mirrors/vu/vue3-treeselect Vue3树形选择组件是现代Web应用中处理层级数据选择的首选方案&#xff0c;它能优雅地…

终极无配置远程游戏串流完整解决方案

终极无配置远程游戏串流完整解决方案 【免费下载链接】Internet-Hosting-Tool Enable Moonlight streaming from your PC over the Internet with no configuration required 项目地址: https://gitcode.com/gh_mirrors/in/Internet-Hosting-Tool 想要在任何地方畅享PC游…