声明本文档AI辅助完成内容仅供参考✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨你正在阅读「Java项目-企悦抽」系列文章✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨弹简特 个人主页❄️个人专栏直通车接口测试从入门到跑路☕一个后端的 JavaEE 续命指南网络原理续命手册☕Java项目-轻聊✨靠热爱去书写自己靠勇敢去书写生活✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ 博主简介:文章目录企悦抽-产品需求规格说明书修订记录1. 引言1.1 编写目的1.2 文档关系2. 系统概述2.1 系统名称2.2 技术栈规格2.3 模块划分3. 系统架构规格3.1 逻辑架构3.2 抽奖异步链路规格3.3 缓存规格4. 数据规格4.1 数据库表4.2 枚举规格4.3 字段校验规格4.4 加密规格5. 功能规格详述5.1 FR-001 ~ FR-005 用户与认证5.1.1 注册FR-0015.1.2 发送验证码FR-0045.1.3 密码登录FR-0025.1.4 短信登录FR-0035.1.5 登录拦截FR-0055.2 FR-006 ~ FR-007 人员管理5.2.1 创建普通用户FR-0065.2.2 用户列表FR-0075.3 FR-008 ~ FR-010 奖品管理5.3.1 创建奖品FR-0085.3.2 奖品分页列表FR-0095.3.3 奖品全量列表FR-0105.4 FR-011 ~ FR-013 活动管理5.4.1 创建活动FR-0115.4.2 活动列表FR-0125.4.3 活动详情FR-0135.5 FR-014 ~ FR-016 抽奖与结果5.5.1 提交抽奖FR-0145.5.2 查询中奖记录FR-0155.5.3 抽奖大屏FR-0165.6 FR-017 ~ FR-018 通知5.6.1 中奖邮件FR-0175.6.2 中奖短信FR-0186. 接口规格索引7. 前端页面规格7.1 实现说明7.2 页面清单7.3 通用前端约定8. 状态机规格8.1 状态扭转顺序8.2 抽奖正向扭转8.3 异常回滚9. 安全规格10. 异常与容错规格10.1 MQ 重试10.2 死信队列10.3 校验失败静默返回11. 验收标准11.1 功能验收11.2 非功能验收企悦抽-产品需求规格说明书文档属性内容产品名称企悦抽QiYueChou文档类型产品需求规格说明书PRS文档版本V1.0编写日期2025-07-03上游文档AI赋能产品需求文档关联代码lottery-system文档状态已定稿修订记录版本日期修订说明V1.02025-07-03首版由 PRD 拆解为可开发/可测试规格1. 引言1.1 编写目的本文档在 PRD 基础上将产品需求转化为可实施、可验证的功能规格、数据规格、状态规则与验收标准供研发与测试直接使用。1.2 文档关系PRD为什么做、做什么 ↓ PRS怎么做、做到什么标准 ← 本文档 ↓ 接口设计文档接口级定义 ↓ 接口测试需求文档测试用例输入2. 系统概述2.1 系统名称产品名企悦抽工程名lottery-system默认端口开发用80802.2 技术栈规格层次技术版本/说明后端框架Spring Boot3.2.6语言Java17ORMMyBatis3.0.3注解方式数据库MySQL库名lottery_system缓存RedisLettuce默认端口配置 8888消息队列RabbitMQDirect 交换机 死信队列认证JWTjjwt 0.11.5Header:user_token前端HTML jQuery CSS静态资源/staticUI 借助 AI 辅助实现主打美观效果日志SLF4J Logbacklogback-spring.xml短信Spug 推送SMSUtilHTTP 调用邮件Spring MailQQ SMTP2.3 模块划分模块包路径/组件职责用户模块UserController、UserServiceImpl注册、登录、用户列表验证码模块VerificationCodeServiceImpl验证码生成、Redis 缓存、Spug 发送奖品模块PrizeController、PrizeServiceImpl奖品 CRUD、图片上传活动模块ActivityController、ActivityServiceImpl活动创建、列表、详情、Redis 缓存抽奖模块DrawPrizeController、DrawPrizeServiceImpl发 MQ、校验、落库、查记录MQ 消费MqReceiver、DlxReceiver异步抽奖、回滚、死信重投状态管理ActivityStatusManagerImpl Operator活动/奖品/用户状态扭转通用LoginInterceptor、GlobalException鉴权、统一响应3. 系统架构规格3.1 逻辑架构3.2 抽奖异步链路规格步骤组件行为1DrawPrizeController接收 JSON调用drawPrize()2DrawPrizeServiceImpl.drawPrize构造{messageId, messageData}发 MQ3Controller立即返回{code:200, data:true}4MqReceiver.process消费消息5—checkDrawPrizeParam校验6—ActivityStatusManager.handlerEvent扭转状态7—saveWinnerRecords写库 缓存8—线程池异步发邮件短信占位9异常回滚 抛异常 → MQ 重试 → 死信3.3 缓存规格键前缀内容TTLVERIFICATION_CODE_{phone}4 位验证码60 秒ACTIVITY_{activityId}活动详情 JSON3 天WINNING_RECORDS_{activityId}活动全量中奖记录2 天WINNING_RECORDS_{activityId}_{prizeId}单奖品中奖记录2 天4. 数据规格4.1 数据库表表名说明关键约束user用户邮箱唯一、手机号唯一prize奖品库—activity活动status: RUNNING/COMPLETEDactivity_prize活动-奖品uk(activity_id, prize_id)activity_user活动-用户uk(activity_id, user_id)winning_record中奖记录uk(winner_id, activity_id, prize_id)4.2 枚举规格用户身份UserIdentityEnum值含义ADMIN管理员NORMAL普通用户活动状态ActivityStatusEnum值含义RUNNING进行中COMPLETED已完成活动奖品状态ActivityPrizeStatusEnum值含义INIT未抽取COMPLETED已抽取活动用户状态ActivityUserStatusEnum值含义INIT未中奖COMPLETED已中奖奖品等级ActivityPrizeTiersEnum值code中文FIRST_PRIZE1一等奖SECOND_PRIZE2二等奖THIRD_PRIZE3三等奖4.3 字段校验规格字段规则实现邮箱小写邮箱格式RegexUtil.checkMail手机号1 开头 11 位RegexUtil.checkMobile密码6~12 位字母数字RegexUtil.checkPassword管理员密码必填注册/创建时校验4.4 加密规格数据算法说明密码SHA256 Hex注册/登录时DigestUtil.sha256Hex手机号AESEncryptTypeHandler密钥 16 字节5. 功能规格详述5.1 FR-001 ~ FR-005 用户与认证5.1.1 注册FR-001输入name、mail、phoneNumber、password管理员必填、identityADMIN/NORMAL处理逻辑JSR303 非空校验邮箱/手机号格式校验身份合法性校验管理员密码必填且强度校验邮箱/手机号唯一性校验密码 SHA256 后入库手机号 AES 加密入库输出{ userId }页面register.html管理员后台创建时adminfalsejumpListtrue5.1.2 发送验证码FR-004输入Query 参数phone处理逻辑手机号格式校验MyCaptchaUtil.getCaptcha(4)生成 4 位数字SMSUtil.sendSms(phone, code)调用 SpugRedis 存储键VERIFICATION_CODE_{phone}60 秒输出{ code:200, data:true }5.1.3 密码登录FR-002输入loginName手机/邮箱、password、mandatoryIdentity可选处理逻辑按格式查用户手机需 Encrypt 包装校验用户存在、身份匹配、密码 SHA256 比对JWT Claims:{ id, identity }有效期 1 小时输出{ token, identity }5.1.4 短信登录FR-003输入loginMobile、verificationCode、mandatoryIdentity可选处理逻辑查用户、校验身份从 Redis 取验证码比对签发 JWT5.1.5 登录拦截FR-005白名单无需 Token静态资源/**/*.html、/css/**、/js/**、/pic/**等/**/login含/password/login、/message/login/register/verification-code/send/winning-records/show鉴权失败HTTP 401无 JSON Body5.2 FR-006 ~ FR-007 人员管理5.2.1 创建普通用户FR-006与注册共用/registeridentityNORMAL不传密码。5.2.2 用户列表FR-007输入Queryidentity可选ADMIN/NORMAL空则全部输出[{ userId, userName, identity }]5.3 FR-008 ~ FR-010 奖品管理5.3.1 创建奖品FR-008Content-Typemultipart/form-dataPart 名类型说明paramJSON 字符串{ prizeName, description, price }prizePicFile奖品图片最大 10MB处理图片存本地pic.local-path文件名 UUID后缀imageUrl存文件名输出奖品 IDLong5.3.2 奖品分页列表FR-009输入currentPage默认 1、pageSize默认 10输出{ total, records:[{ prizeId, prizeName, description, price, imageUrl }] }5.3.3 奖品全量列表FR-010输出[{ prizeId, prizeName }]5.4 FR-011 ~ FR-013 活动管理5.4.1 创建活动FR-011输入{activityName:string, 必填,description:string, 必填,activityPrizeList:[{prizeId:long,prizeAmount:long,prizeTiers:FIRST_PRIZE|SECOND_PRIZE|THIRD_PRIZE}],activityUserList:[{userId:long,userName:string}]}校验奖品 ID、用户 ID 均存在于主表参与人数 ≥ 奖品总数奖品等级合法事务写 activity activity_prize activity_user初始状态分别为 RUNNING、INIT、INIT缓存组装ActivityDetailDTO写入 Redis输出{ activityId }5.4.2 活动列表FR-012输出字段validstatus RUNNING为 true前端行为validtrue → 「活动进行中去抽奖」validfalse → 「活动已完成查看中奖名单」5.4.3 活动详情FR-013输入QueryactivityId输出字段说明valid活动是否进行中prizes[].valid奖品是否未抽取INITtrueprizes[].prizeTierName等级中文名prizes按等级 code 升序排列users[].valid用户是否未中奖INITtrue读取顺序Redis → MySQL 多表组装 → 回写 Redis5.5 FR-014 ~ FR-016 抽奖与结果5.5.1 提交抽奖FR-014输入{activityId:long, 必填,prizeId:long, 必填,winningTime:Date, 必填,winnerList:[{userId:long, 必填,userName:string, 必填}]}同步行为仅发送 RabbitMQ 消息不做业务落库MQ 消费校验失败则 return 或回滚活动、活动奖品存在活动非 COMPLETED奖品非 COMPLETEDwinnerList.size() prizeAmount5.5.2 查询中奖记录FR-015输入activityId必填、prizeId可选逻辑无 prizeId查活动维度全量有 prizeId查该奖品维度读取Redis → MySQL → 回写 Redis免登录在白名单中5.5.3 抽奖大屏FR-016URL 参数activityId、activityName、validtrue/false权限validtrue 且 localStorageuser_identityADMIN可抽奖validtrue 且非 ADMIN弹窗提示不可操作validfalse直接展示全量中奖名单刷新恢复已抽完奖品validfalse点击开始 → 直接查/winning-records/show?prizeId展示名单分享复制链接附加validfalsehideButtontrue隐藏操作按钮5.6 FR-017 ~ FR-018 通知5.6.1 中奖邮件FR-017触发MQ 消费成功后线程池异步执行模板实际代码Hi{winnerName} 有个好消息要告诉你你在【{activityName}】活动中获得了{prizeTier中文}的惊喜福利{prizeName} 福利发放时间{HH:mm:ss}快来领取你的专属惊喜吧~收件人中奖用户邮箱5.6.2 中奖短信FR-018状态V1.0 未实现MqReceiver.sendMessage仅打印日志6. 接口规格索引序号方法路径鉴权详细定义1POST/register否见接口设计文档 §4.12GET/verification-code/send否见接口设计文档 §4.23*/password/login否见接口设计文档 §4.34*/message/login否见接口设计文档 §4.45GET/base-user/find-list是见接口设计文档 §4.56*/pic/upload是见接口设计文档 §5.17*/prize/create是见接口设计文档 §5.28GET/prize/find-list是见接口设计文档 §5.39GET/prize/find-listAll是见接口设计文档 §5.410*/activity/create是见接口设计文档 §6.111GET/activity/find-list是见接口设计文档 §6.212GET/activity-detail/find是见接口设计文档 §6.313*/draw-prize是见接口设计文档 §7.114*/winning-records/show否见接口设计文档 §7.2注标注*的接口 Controller 使用RequestMapping未限定 HTTP 方法前端实际使用 POSTJSON或 GETQuery。7. 前端页面规格7.1 实现说明本项目 Web 前端src/main/resources/static在页面结构、样式与部分交互实现上借助 AI 辅助完成设计取向为美观、现代化视觉与现场展示效果而非传统 B 端「功能优先、样式从简」风格。典型体现包括登录/注册页分栏布局、渐变背景与表单视觉优化管理后台iframe 导航 统一卡片/表格样式抽奖大屏draw.html全屏背景、奖品展示、人名滚动动效、中奖确认交互规格边界本文档对前端的约束以页面路由、功能行为、Token 传递、接口调用为准颜色、间距、动效细节以当前 AI 辅助产出为基线不作为像素级设计稿验收项。后端 REST 接口规格不受 UI 实现方式影响。7.2 页面清单页面路径功能后台登录/blogin.html密码/验证码 Tab 登录管理后台/admin.htmliframe 框架注册用户/register.html管理员/普通用户注册人员列表/user-list.html用户列表创建奖品/create-prizes.html表单 图片奖品列表/prizes-list.html分页创建活动/create-activity.html圈选奖品/人员活动列表/activities-list.html分页 跳转 draw抽奖大屏/draw.html核心抽奖交互7.3 通用前端约定Token 存储localStorage.user_token、localStorage.user_identity请求头user_token: {JWT}8. 状态机规格8.1 状态扭转顺序ActivityStatusManagerImpl.handlerEventSequence 1PrizeOperator、UserOperator并行遍历先奖品/用户Sequence 2ActivityOperator全部奖品 COMPLETED 后才转活动8.2 抽奖正向扭转对象原状态目标状态activity_prizeINITCOMPLETEDactivity_user中奖者INITCOMPLETEDactivityRUNNINGCOMPLETED全部奖品抽完后8.3 异常回滚对象回滚目标activity_prizeINITactivity_userINITactivityRUNNINGwinning_record删除对应记录 清缓存9. 安全规格编号规格SEC-01JWT Header 名称固定为user_tokenSEC-02Token 解析失败返回 HTTP 401SEC-03业务异常统一{ code:500, msg:业务消息 }SEC-04图片上传限制 10MBSEC-05手机号不得明文落库10. 异常与容错规格10.1 MQ 重试spring.rabbitmq.listener.simple.retry.enabledtruemax-attempts510.2 死信队列正常队列DirectQueue→ 死信交换机DlxDirectExchange死信消费者DlxReceiver重新投递到正常队列10.3 校验失败静默返回checkDrawPrizeParam返回 false 时MqReceiver直接 return不抛异常消息被 ACK11. 验收标准11.1 功能验收编号验收项通过标准AC-01管理员注册登录可进入 admin.htmlAC-02创建普通用户列表可见 NORMAL 用户AC-03创建奖品列表展示图片与信息AC-04创建活动返回 activityId详情正确AC-05完整抽奖流程每轮落库最终活动 COMPLETEDAC-06刷新恢复已抽奖品不重复抽AC-07分享链接仅展示结果无操作按钮AC-08邮件通知中奖者收到邮件AC-09未登录拦截受保护接口返回 40111.2 非功能验收编号验收项通过标准AC-N01抽奖接口响应500ms 内返回P95AC-N02缓存命中二次查活动详情走 RedisAC-N03异常回滚模拟落库异常后状态恢复文档结束下一文档我们将手动实现数据库的设计。
【Java项目-企悦抽】02-AI赋能产品需求规格说明书
声明本文档AI辅助完成内容仅供参考✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨你正在阅读「Java项目-企悦抽」系列文章✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨弹简特 个人主页❄️个人专栏直通车接口测试从入门到跑路☕一个后端的 JavaEE 续命指南网络原理续命手册☕Java项目-轻聊✨靠热爱去书写自己靠勇敢去书写生活✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ 博主简介:文章目录企悦抽-产品需求规格说明书修订记录1. 引言1.1 编写目的1.2 文档关系2. 系统概述2.1 系统名称2.2 技术栈规格2.3 模块划分3. 系统架构规格3.1 逻辑架构3.2 抽奖异步链路规格3.3 缓存规格4. 数据规格4.1 数据库表4.2 枚举规格4.3 字段校验规格4.4 加密规格5. 功能规格详述5.1 FR-001 ~ FR-005 用户与认证5.1.1 注册FR-0015.1.2 发送验证码FR-0045.1.3 密码登录FR-0025.1.4 短信登录FR-0035.1.5 登录拦截FR-0055.2 FR-006 ~ FR-007 人员管理5.2.1 创建普通用户FR-0065.2.2 用户列表FR-0075.3 FR-008 ~ FR-010 奖品管理5.3.1 创建奖品FR-0085.3.2 奖品分页列表FR-0095.3.3 奖品全量列表FR-0105.4 FR-011 ~ FR-013 活动管理5.4.1 创建活动FR-0115.4.2 活动列表FR-0125.4.3 活动详情FR-0135.5 FR-014 ~ FR-016 抽奖与结果5.5.1 提交抽奖FR-0145.5.2 查询中奖记录FR-0155.5.3 抽奖大屏FR-0165.6 FR-017 ~ FR-018 通知5.6.1 中奖邮件FR-0175.6.2 中奖短信FR-0186. 接口规格索引7. 前端页面规格7.1 实现说明7.2 页面清单7.3 通用前端约定8. 状态机规格8.1 状态扭转顺序8.2 抽奖正向扭转8.3 异常回滚9. 安全规格10. 异常与容错规格10.1 MQ 重试10.2 死信队列10.3 校验失败静默返回11. 验收标准11.1 功能验收11.2 非功能验收企悦抽-产品需求规格说明书文档属性内容产品名称企悦抽QiYueChou文档类型产品需求规格说明书PRS文档版本V1.0编写日期2025-07-03上游文档AI赋能产品需求文档关联代码lottery-system文档状态已定稿修订记录版本日期修订说明V1.02025-07-03首版由 PRD 拆解为可开发/可测试规格1. 引言1.1 编写目的本文档在 PRD 基础上将产品需求转化为可实施、可验证的功能规格、数据规格、状态规则与验收标准供研发与测试直接使用。1.2 文档关系PRD为什么做、做什么 ↓ PRS怎么做、做到什么标准 ← 本文档 ↓ 接口设计文档接口级定义 ↓ 接口测试需求文档测试用例输入2. 系统概述2.1 系统名称产品名企悦抽工程名lottery-system默认端口开发用80802.2 技术栈规格层次技术版本/说明后端框架Spring Boot3.2.6语言Java17ORMMyBatis3.0.3注解方式数据库MySQL库名lottery_system缓存RedisLettuce默认端口配置 8888消息队列RabbitMQDirect 交换机 死信队列认证JWTjjwt 0.11.5Header:user_token前端HTML jQuery CSS静态资源/staticUI 借助 AI 辅助实现主打美观效果日志SLF4J Logbacklogback-spring.xml短信Spug 推送SMSUtilHTTP 调用邮件Spring MailQQ SMTP2.3 模块划分模块包路径/组件职责用户模块UserController、UserServiceImpl注册、登录、用户列表验证码模块VerificationCodeServiceImpl验证码生成、Redis 缓存、Spug 发送奖品模块PrizeController、PrizeServiceImpl奖品 CRUD、图片上传活动模块ActivityController、ActivityServiceImpl活动创建、列表、详情、Redis 缓存抽奖模块DrawPrizeController、DrawPrizeServiceImpl发 MQ、校验、落库、查记录MQ 消费MqReceiver、DlxReceiver异步抽奖、回滚、死信重投状态管理ActivityStatusManagerImpl Operator活动/奖品/用户状态扭转通用LoginInterceptor、GlobalException鉴权、统一响应3. 系统架构规格3.1 逻辑架构3.2 抽奖异步链路规格步骤组件行为1DrawPrizeController接收 JSON调用drawPrize()2DrawPrizeServiceImpl.drawPrize构造{messageId, messageData}发 MQ3Controller立即返回{code:200, data:true}4MqReceiver.process消费消息5—checkDrawPrizeParam校验6—ActivityStatusManager.handlerEvent扭转状态7—saveWinnerRecords写库 缓存8—线程池异步发邮件短信占位9异常回滚 抛异常 → MQ 重试 → 死信3.3 缓存规格键前缀内容TTLVERIFICATION_CODE_{phone}4 位验证码60 秒ACTIVITY_{activityId}活动详情 JSON3 天WINNING_RECORDS_{activityId}活动全量中奖记录2 天WINNING_RECORDS_{activityId}_{prizeId}单奖品中奖记录2 天4. 数据规格4.1 数据库表表名说明关键约束user用户邮箱唯一、手机号唯一prize奖品库—activity活动status: RUNNING/COMPLETEDactivity_prize活动-奖品uk(activity_id, prize_id)activity_user活动-用户uk(activity_id, user_id)winning_record中奖记录uk(winner_id, activity_id, prize_id)4.2 枚举规格用户身份UserIdentityEnum值含义ADMIN管理员NORMAL普通用户活动状态ActivityStatusEnum值含义RUNNING进行中COMPLETED已完成活动奖品状态ActivityPrizeStatusEnum值含义INIT未抽取COMPLETED已抽取活动用户状态ActivityUserStatusEnum值含义INIT未中奖COMPLETED已中奖奖品等级ActivityPrizeTiersEnum值code中文FIRST_PRIZE1一等奖SECOND_PRIZE2二等奖THIRD_PRIZE3三等奖4.3 字段校验规格字段规则实现邮箱小写邮箱格式RegexUtil.checkMail手机号1 开头 11 位RegexUtil.checkMobile密码6~12 位字母数字RegexUtil.checkPassword管理员密码必填注册/创建时校验4.4 加密规格数据算法说明密码SHA256 Hex注册/登录时DigestUtil.sha256Hex手机号AESEncryptTypeHandler密钥 16 字节5. 功能规格详述5.1 FR-001 ~ FR-005 用户与认证5.1.1 注册FR-001输入name、mail、phoneNumber、password管理员必填、identityADMIN/NORMAL处理逻辑JSR303 非空校验邮箱/手机号格式校验身份合法性校验管理员密码必填且强度校验邮箱/手机号唯一性校验密码 SHA256 后入库手机号 AES 加密入库输出{ userId }页面register.html管理员后台创建时adminfalsejumpListtrue5.1.2 发送验证码FR-004输入Query 参数phone处理逻辑手机号格式校验MyCaptchaUtil.getCaptcha(4)生成 4 位数字SMSUtil.sendSms(phone, code)调用 SpugRedis 存储键VERIFICATION_CODE_{phone}60 秒输出{ code:200, data:true }5.1.3 密码登录FR-002输入loginName手机/邮箱、password、mandatoryIdentity可选处理逻辑按格式查用户手机需 Encrypt 包装校验用户存在、身份匹配、密码 SHA256 比对JWT Claims:{ id, identity }有效期 1 小时输出{ token, identity }5.1.4 短信登录FR-003输入loginMobile、verificationCode、mandatoryIdentity可选处理逻辑查用户、校验身份从 Redis 取验证码比对签发 JWT5.1.5 登录拦截FR-005白名单无需 Token静态资源/**/*.html、/css/**、/js/**、/pic/**等/**/login含/password/login、/message/login/register/verification-code/send/winning-records/show鉴权失败HTTP 401无 JSON Body5.2 FR-006 ~ FR-007 人员管理5.2.1 创建普通用户FR-006与注册共用/registeridentityNORMAL不传密码。5.2.2 用户列表FR-007输入Queryidentity可选ADMIN/NORMAL空则全部输出[{ userId, userName, identity }]5.3 FR-008 ~ FR-010 奖品管理5.3.1 创建奖品FR-008Content-Typemultipart/form-dataPart 名类型说明paramJSON 字符串{ prizeName, description, price }prizePicFile奖品图片最大 10MB处理图片存本地pic.local-path文件名 UUID后缀imageUrl存文件名输出奖品 IDLong5.3.2 奖品分页列表FR-009输入currentPage默认 1、pageSize默认 10输出{ total, records:[{ prizeId, prizeName, description, price, imageUrl }] }5.3.3 奖品全量列表FR-010输出[{ prizeId, prizeName }]5.4 FR-011 ~ FR-013 活动管理5.4.1 创建活动FR-011输入{activityName:string, 必填,description:string, 必填,activityPrizeList:[{prizeId:long,prizeAmount:long,prizeTiers:FIRST_PRIZE|SECOND_PRIZE|THIRD_PRIZE}],activityUserList:[{userId:long,userName:string}]}校验奖品 ID、用户 ID 均存在于主表参与人数 ≥ 奖品总数奖品等级合法事务写 activity activity_prize activity_user初始状态分别为 RUNNING、INIT、INIT缓存组装ActivityDetailDTO写入 Redis输出{ activityId }5.4.2 活动列表FR-012输出字段validstatus RUNNING为 true前端行为validtrue → 「活动进行中去抽奖」validfalse → 「活动已完成查看中奖名单」5.4.3 活动详情FR-013输入QueryactivityId输出字段说明valid活动是否进行中prizes[].valid奖品是否未抽取INITtrueprizes[].prizeTierName等级中文名prizes按等级 code 升序排列users[].valid用户是否未中奖INITtrue读取顺序Redis → MySQL 多表组装 → 回写 Redis5.5 FR-014 ~ FR-016 抽奖与结果5.5.1 提交抽奖FR-014输入{activityId:long, 必填,prizeId:long, 必填,winningTime:Date, 必填,winnerList:[{userId:long, 必填,userName:string, 必填}]}同步行为仅发送 RabbitMQ 消息不做业务落库MQ 消费校验失败则 return 或回滚活动、活动奖品存在活动非 COMPLETED奖品非 COMPLETEDwinnerList.size() prizeAmount5.5.2 查询中奖记录FR-015输入activityId必填、prizeId可选逻辑无 prizeId查活动维度全量有 prizeId查该奖品维度读取Redis → MySQL → 回写 Redis免登录在白名单中5.5.3 抽奖大屏FR-016URL 参数activityId、activityName、validtrue/false权限validtrue 且 localStorageuser_identityADMIN可抽奖validtrue 且非 ADMIN弹窗提示不可操作validfalse直接展示全量中奖名单刷新恢复已抽完奖品validfalse点击开始 → 直接查/winning-records/show?prizeId展示名单分享复制链接附加validfalsehideButtontrue隐藏操作按钮5.6 FR-017 ~ FR-018 通知5.6.1 中奖邮件FR-017触发MQ 消费成功后线程池异步执行模板实际代码Hi{winnerName} 有个好消息要告诉你你在【{activityName}】活动中获得了{prizeTier中文}的惊喜福利{prizeName} 福利发放时间{HH:mm:ss}快来领取你的专属惊喜吧~收件人中奖用户邮箱5.6.2 中奖短信FR-018状态V1.0 未实现MqReceiver.sendMessage仅打印日志6. 接口规格索引序号方法路径鉴权详细定义1POST/register否见接口设计文档 §4.12GET/verification-code/send否见接口设计文档 §4.23*/password/login否见接口设计文档 §4.34*/message/login否见接口设计文档 §4.45GET/base-user/find-list是见接口设计文档 §4.56*/pic/upload是见接口设计文档 §5.17*/prize/create是见接口设计文档 §5.28GET/prize/find-list是见接口设计文档 §5.39GET/prize/find-listAll是见接口设计文档 §5.410*/activity/create是见接口设计文档 §6.111GET/activity/find-list是见接口设计文档 §6.212GET/activity-detail/find是见接口设计文档 §6.313*/draw-prize是见接口设计文档 §7.114*/winning-records/show否见接口设计文档 §7.2注标注*的接口 Controller 使用RequestMapping未限定 HTTP 方法前端实际使用 POSTJSON或 GETQuery。7. 前端页面规格7.1 实现说明本项目 Web 前端src/main/resources/static在页面结构、样式与部分交互实现上借助 AI 辅助完成设计取向为美观、现代化视觉与现场展示效果而非传统 B 端「功能优先、样式从简」风格。典型体现包括登录/注册页分栏布局、渐变背景与表单视觉优化管理后台iframe 导航 统一卡片/表格样式抽奖大屏draw.html全屏背景、奖品展示、人名滚动动效、中奖确认交互规格边界本文档对前端的约束以页面路由、功能行为、Token 传递、接口调用为准颜色、间距、动效细节以当前 AI 辅助产出为基线不作为像素级设计稿验收项。后端 REST 接口规格不受 UI 实现方式影响。7.2 页面清单页面路径功能后台登录/blogin.html密码/验证码 Tab 登录管理后台/admin.htmliframe 框架注册用户/register.html管理员/普通用户注册人员列表/user-list.html用户列表创建奖品/create-prizes.html表单 图片奖品列表/prizes-list.html分页创建活动/create-activity.html圈选奖品/人员活动列表/activities-list.html分页 跳转 draw抽奖大屏/draw.html核心抽奖交互7.3 通用前端约定Token 存储localStorage.user_token、localStorage.user_identity请求头user_token: {JWT}8. 状态机规格8.1 状态扭转顺序ActivityStatusManagerImpl.handlerEventSequence 1PrizeOperator、UserOperator并行遍历先奖品/用户Sequence 2ActivityOperator全部奖品 COMPLETED 后才转活动8.2 抽奖正向扭转对象原状态目标状态activity_prizeINITCOMPLETEDactivity_user中奖者INITCOMPLETEDactivityRUNNINGCOMPLETED全部奖品抽完后8.3 异常回滚对象回滚目标activity_prizeINITactivity_userINITactivityRUNNINGwinning_record删除对应记录 清缓存9. 安全规格编号规格SEC-01JWT Header 名称固定为user_tokenSEC-02Token 解析失败返回 HTTP 401SEC-03业务异常统一{ code:500, msg:业务消息 }SEC-04图片上传限制 10MBSEC-05手机号不得明文落库10. 异常与容错规格10.1 MQ 重试spring.rabbitmq.listener.simple.retry.enabledtruemax-attempts510.2 死信队列正常队列DirectQueue→ 死信交换机DlxDirectExchange死信消费者DlxReceiver重新投递到正常队列10.3 校验失败静默返回checkDrawPrizeParam返回 false 时MqReceiver直接 return不抛异常消息被 ACK11. 验收标准11.1 功能验收编号验收项通过标准AC-01管理员注册登录可进入 admin.htmlAC-02创建普通用户列表可见 NORMAL 用户AC-03创建奖品列表展示图片与信息AC-04创建活动返回 activityId详情正确AC-05完整抽奖流程每轮落库最终活动 COMPLETEDAC-06刷新恢复已抽奖品不重复抽AC-07分享链接仅展示结果无操作按钮AC-08邮件通知中奖者收到邮件AC-09未登录拦截受保护接口返回 40111.2 非功能验收编号验收项通过标准AC-N01抽奖接口响应500ms 内返回P95AC-N02缓存命中二次查活动详情走 RedisAC-N03异常回滚模拟落库异常后状态恢复文档结束下一文档我们将手动实现数据库的设计。