声明:本期的接口文档由AI辅助完成
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨🎯 你正在阅读「Java项目-企悦抽」系列文章 🎯
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
🔥 弹简特 个人主页
❄️ 个人专栏直通车:
- 🔌 接口测试从入门到跑路
- ☕ 一个后端的 JavaEE 续命指南
- 🛜 网络原理续命手册
- ☕ Java项目-轻聊
✨ 靠热爱去书写自己,靠勇敢去书写生活!
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
🌟 博主简介:

文章目录:
- 一、前言
- 二、项目演示
- [三、企悦抽 --- 接口设计文档(AI赋能)](#三、企悦抽 — 接口设计文档(AI赋能))
-
- 修订记录
- [1. 通用约定](#1. 通用约定)
-
- [1.1 协议与编码](#1.1 协议与编码)
- [1.2 前端与接口关系说明](#1.2 前端与接口关系说明)
- [1.3 Content-Type](#1.3 Content-Type)
- [1.4 HTTP 方法说明](#1.4 HTTP 方法说明)
- [1.5 接口清单总览](#1.5 接口清单总览)
- [2. 统一响应结构](#2. 统一响应结构)
-
- [2.1 CommonResult](#2.1 CommonResult)
- [2.2 成功判定](#2.2 成功判定)
- [2.3 业务异常响应](#2.3 业务异常响应)
- [2.4 鉴权失败](#2.4 鉴权失败)
- [3. 认证与鉴权](#3. 认证与鉴权)
-
- [3.1 JWT 传递](#3.1 JWT 传递)
- [3.2 JWT 载荷(Claims)](#3.2 JWT 载荷(Claims))
- [3.3 白名单(无需 Token)](#3.3 白名单(无需 Token))
- [4. 用户模块接口](#4. 用户模块接口)
-
- [4.1 API-01 用户注册](#4.1 API-01 用户注册)
- [4.2 API-02 发送验证码](#4.2 API-02 发送验证码)
- [4.3 API-03 密码登录](#4.3 API-03 密码登录)
- [4.4 API-04 短信验证码登录](#4.4 API-04 短信验证码登录)
- [4.5 API-05 查询用户列表](#4.5 API-05 查询用户列表)
- [5. 奖品模块接口](#5. 奖品模块接口)
-
- [5.1 API-06 上传图片](#5.1 API-06 上传图片)
- [5.2 API-07 创建奖品](#5.2 API-07 创建奖品)
- [5.3 API-08 奖品分页列表](#5.3 API-08 奖品分页列表)
- [5.4 API-09 奖品全量列表](#5.4 API-09 奖品全量列表)
- [6. 活动模块接口](#6. 活动模块接口)
-
- [6.1 API-10 创建活动](#6.1 API-10 创建活动)
- [6.2 API-11 活动分页列表](#6.2 API-11 活动分页列表)
- [6.3 API-12 活动详情](#6.3 API-12 活动详情)
- [7. 抽奖模块接口](#7. 抽奖模块接口)
-
- [7.1 API-13 提交抽奖结果](#7.1 API-13 提交抽奖结果)
- [7.2 API-14 查询中奖记录](#7.2 API-14 查询中奖记录)
- [8. 错误码说明](#8. 错误码说明)
-
- [8.1 HTTP 层](#8.1 HTTP 层)
- [8.2 响应 code 字段](#8.2 响应 code 字段)
- [8.3 业务错误信息(msg)](#8.3 业务错误信息(msg))
- [9. 枚举与数据字典](#9. 枚举与数据字典)
-
- [9.1 identity 用户身份](#9.1 identity 用户身份)
- [9.2 prizeTiers 奖品等级](#9.2 prizeTiers 奖品等级)
- [9.3 活动/奖品/用户状态(库表)](#9.3 活动/奖品/用户状态(库表))
- [10. MQ 消息格式(内部)](#10. MQ 消息格式(内部))
-
- [10.1 交换机与队列](#10.1 交换机与队列)
- [10.2 消息体](#10.2 消息体)
- 四、项目源码
一、前言
我们上一期将数据设计完毕之后,我们按理来说进入编码阶段了,但是在编码之前,我们得需要参考自己的项目接口文档,所以本期我们就先演示出我们的项目,然后借助AI完成接口文档的编写,最后再分享我们的项目源码。
二、项目演示
注意:本项目的CSS样式借助AI完成美观的效果,我们后续的核心是自己完成后端以及前端的JS逻辑。
1、注册

2、登录


3、人员管理


4、奖品管理


5、开始抽奖
企悦抽演示
6、中奖


三、企悦抽 --- 接口设计文档(AI赋能)
| 文档属性 | 内容 |
|---|---|
| 产品名称 | 企悦抽(QiYueChou) |
| 文档类型 | 接口设计文档(API Design) |
| 文档版本 | V1.0 |
| 编写日期 | 2025-07-03 |
| 上游文档 | PRD V1.0、PRS V1.0 |
| 代码基线 | lottery-system(com.zhongge.lotterysystem) |
| 服务地址 | http://{host}:8080 |
| 文档状态 | 已定稿 |
修订记录
| 版本 | 日期 | 修订说明 |
|---|---|---|
| V1.0 | 2025-07-03 | 首版,与 lottery-system 源码逐接口对齐 |
1. 通用约定
1.1 协议与编码
| 项目 | 约定 |
|---|---|
| 协议 | HTTP/HTTPS |
| 字符编码 | UTF-8 |
| 日期时间 | JSON 序列化为 ISO-8601 或毫秒时间戳(Jackson 默认) |
| 时区 | 服务器本地时区 |
1.2 前端与接口关系说明
Web 前端页面位于 src/main/resources/static,UI 层借助 AI 辅助设计与实现,主打美观、现代化视觉呈现(尤其登录页与抽奖大屏)。本文档仅定义后端 REST 接口契约;前端如何组织页面、样式与动效不在接口文档范围内,但各接口的入参/出参、鉴权方式须与前端实际调用保持一致(见各接口「前端调用页面」说明,如有)。
1.3 Content-Type
| 场景 | Content-Type |
|---|---|
| JSON 请求 | application/json |
| 文件上传 | multipart/form-data |
| JSON 响应 | application/json(CommonResult 接口) |
1.4 HTTP 方法说明
本项目 Controller 大量使用 @RequestMapping 且未限定 method,Spring 默认接受 GET/POST 等。下表「推荐方法」为前端实际调用方式;测试时可优先使用推荐方法。
1.5 接口清单总览
| 编号 | 推荐方法 | 路径 | 需要 Token | Controller |
|---|---|---|---|---|
| API-01 | POST | /register |
否 | UserController |
| API-02 | GET | /verification-code/send |
否 | UserController |
| API-03 | POST | /password/login |
否 | UserController |
| API-04 | POST | /message/login |
否 | UserController |
| API-05 | GET | /base-user/find-list |
是 | UserController |
| API-06 | POST | /pic/upload |
是 | PrizeController |
| API-07 | POST | /prize/create |
是 | PrizeController |
| API-08 | GET | /prize/find-list |
是 | PrizeController |
| API-09 | GET | /prize/find-listAll |
是 | PrizeController |
| API-10 | POST | /activity/create |
是 | ActivityController |
| API-11 | GET | /activity/find-list |
是 | ActivityController |
| API-12 | GET | /activity-detail/find |
是 | ActivityController |
| API-13 | POST | /draw-prize |
是 | DrawPrizeController |
| API-14 | POST | /winning-records/show |
否 | DrawPrizeController |
2. 统一响应结构
2.1 CommonResult
除 API-06 外,业务接口均返回 CommonResult<T>:
json
{
"code": 200,
"data": {},
"msg": ""
}
| 字段 | 类型 | 说明 |
|---|---|---|
| code | Integer | 200=成功;500=失败(GlobalException 统一包装) |
| data | T | 成功时业务数据;失败时一般为 null |
| msg | String | 成功时通常为空字符串;失败时为错误描述 |
2.2 成功判定
javascript
result.code === 200 // 前端判定方式
2.3 业务异常响应
GlobalException 捕获 ServiceException / ControllerException:
json
{
"code": 500,
"data": null,
"msg": "具体业务错误信息"
}
2.4 鉴权失败
LoginInterceptor 拦截:HTTP Status 401 ,无 JSON Body。
3. 认证与鉴权
3.1 JWT 传递
| 项目 | 值 |
|---|---|
| Header 名称 | user_token |
| 示例 | user_token: eyJhbGciOiJIUzI1NiJ9... |
3.2 JWT 载荷(Claims)
登录成功后 Token 中包含:
| Claim | 类型 | 说明 |
|---|---|---|
| id | Long/Integer | 用户 ID |
| identity | String | ADMIN / NORMAL |
有效期:3600 秒(1 小时)
3.3 白名单(无需 Token)
配置来源:AppConfig.excludes
| 模式 | 说明 |
|---|---|
/**/*.html |
静态 HTML |
/css/**、/js/**、/pic/** |
静态资源 |
/*.jpg、/*.png |
图片 |
/**/login |
含 /password/login、/message/login |
/register |
注册 |
/verification-code/send |
验证码 |
/winning-records/show |
中奖记录查询 |
4. 用户模块接口
4.1 API-01 用户注册
| 项目 | 内容 |
|---|---|
| 路径 | /register |
| 方法 | POST (@PostMapping) |
| 鉴权 | 否 |
| Controller | UserController.userRegister |
Request Body
json
{
"name": "张三",
"mail": "zhangsan@example.com",
"phoneNumber": "13188888888",
"password": "123456",
"identity": "ADMIN"
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| name | String | 是 | 用户姓名,@NotBlank |
| String | 是 | 邮箱 | |
| phoneNumber | String | 是 | 手机号 |
| password | String | 条件 | 管理员必填;普通用户不传 |
| identity | String | 是 | ADMIN 或 NORMAL |
Response data
json
{
"userId": 22
}
业务错误 msg 示例
| msg | 触发条件 |
|---|---|
| 注册信息为空 | param 为空 |
| 邮箱错误 | 格式不合法 |
| 手机号错误 | 格式不合法 |
| 身份错误 | identity 非法或管理员无密码 |
| 邮箱被使用了 | 邮箱重复 |
| 手机号被使用了 | 手机号重复 |
4.2 API-02 发送验证码
| 项目 | 内容 |
|---|---|
| 路径 | /verification-code/send |
| 方法 | GET |
| 鉴权 | 否 |
Query 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| phone | String | 是 | 手机号(注意:参数名为 phone,非 phoneNumber) |
请求示例
GET /verification-code/send?phone=13188888888
Response data
json
true
实现说明
- 验证码:4 位数字(
MyCaptchaUtil.getCaptcha(4)) - Redis Key:
VERIFICATION_CODE_{phone},TTL 60 秒 - 短信通道:Spug (
SMSUtil.sendSms,非阿里云)
4.3 API-03 密码登录
| 项目 | 内容 |
|---|---|
| 路径 | /password/login |
| 方法 | POST(推荐) |
| 鉴权 | 否 |
Request Body
json
{
"loginName": "13188888888",
"password": "123456",
"mandatoryIdentity": "ADMIN"
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| loginName | String | 是 | 手机号或邮箱 |
| password | String | 是 | 明文密码(后端 SHA256 比对) |
| mandatoryIdentity | String | 否 | 强制身份:ADMIN / NORMAL |
Response data
json
{
"token": "eyJhbGciOiJIUzI1NiJ9...",
"identity": "ADMIN"
}
业务错误 msg 示例
| msg | 触发条件 |
|---|---|
| 登录信息不存在 | 参数类型不匹配 |
| 登录方式不存在 | loginName 既非手机也非邮箱 |
| 用户信息为空 | 用户不存在 |
| 身份错误 | mandatoryIdentity 不匹配 |
| 身份错误 | 密码错误(代码中 PASSWORD_ERROR 文案为「身份错误」) |
4.4 API-04 短信验证码登录
| 项目 | 内容 |
|---|---|
| 路径 | /message/login |
| 方法 | POST(推荐) |
| 鉴权 | 否 |
Request Body
json
{
"loginMobile": "13188888888",
"verificationCode": "1234",
"mandatoryIdentity": "ADMIN"
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| loginMobile | String | 是 | 手机号 |
| verificationCode | String | 是 | 4 位验证码 |
| mandatoryIdentity | String | 否 | ADMIN / NORMAL |
Response data:同 API-03
业务错误 msg 示例
| msg | 触发条件 |
|---|---|
| 验证码校验失败 | Redis 中无验证码或不匹配 |
4.5 API-05 查询用户列表
| 项目 | 内容 |
|---|---|
| 路径 | /base-user/find-list |
| 方法 | GET |
| 鉴权 | 是 |
Query 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| identity | String | 否 | ADMIN / NORMAL;不传返回全部 |
Response data
json
[
{
"userId": 15,
"userName": "郭靖",
"identity": "NORMAL"
}
]
5. 奖品模块接口
5.1 API-06 上传图片
| 项目 | 内容 |
|---|---|
| 路径 | /pic/upload |
| 方法 | POST |
| 鉴权 | 是 |
| 响应格式 | 纯文本 String(非 CommonResult) |
Request
| 参数 | 类型 | 说明 |
|---|---|---|
| file | MultipartFile | 表单字段名 file |
Response Body 示例
e606c8db-218a-40c2-8946-0d9f8570626d.jpg
说明 :返回文件名;访问路径为静态资源映射 file:${pic.local-path}
5.2 API-07 创建奖品
| 项目 | 内容 |
|---|---|
| 路径 | /prize/create |
| 方法 | POST |
| 鉴权 | 是 |
| Content-Type | multipart/form-data |
Form Data
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| param | String (JSON) | 是 | 奖品信息 JSON 字符串 |
| prizePic | File | 是 | 奖品图片 |
param JSON 结构
json
{
"prizeName": "吹风机",
"description": "家用吹风机",
"price": 199.00
}
| 字段 | 类型 | 必填 |
|---|---|---|
| prizeName | String | 是 |
| description | String | 否 |
| price | BigDecimal | 是 |
Response data
json
17
类型为 Long,奖品 ID。
5.3 API-08 奖品分页列表
| 项目 | 内容 |
|---|---|
| 路径 | /prize/find-list |
| 方法 | GET |
| 鉴权 | 是 |
Query 参数
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| currentPage | Integer | 1 | 当前页 |
| pageSize | Integer | 10 | 每页条数 |
Response data
json
{
"total": 3,
"records": [
{
"prizeId": 17,
"prizeName": "吹风机",
"description": "家用吹风机",
"price": 199.00,
"imageUrl": "e606c8db-218a-40c2-8946-0d9f8570626d.jpg"
}
]
}
5.4 API-09 奖品全量列表
| 项目 | 内容 |
|---|---|
| 路径 | /prize/find-listAll |
| 方法 | GET |
| 鉴权 | 是 |
Response data
json
[
{
"prizeId": 17,
"prizeName": "吹风机"
}
]
6. 活动模块接口
6.1 API-10 创建活动
| 项目 | 内容 |
|---|---|
| 路径 | /activity/create |
| 方法 | POST |
| 鉴权 | 是 |
Request Body
json
{
"activityName": "2026年会抽奖",
"description": "年终福利抽奖活动",
"activityPrizeList": [
{
"prizeId": 13,
"prizeAmount": 1,
"prizeTiers": "FIRST_PRIZE"
},
{
"prizeId": 12,
"prizeAmount": 2,
"prizeTiers": "SECOND_PRIZE"
}
],
"activityUserList": [
{
"userId": 25,
"userName": "郭靖"
},
{
"userId": 23,
"userName": "杨康"
}
]
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| activityName | String | 是 | 活动名称 |
| description | String | 是 | 活动描述 |
| activityPrizeList | Array | 是 | 至少 1 项 |
| activityPrizeList\[\].prizeId | Long | 是 | 奖品 ID |
| activityPrizeList\[\].prizeAmount | Long | 是 | 奖品数量 |
| activityPrizeList\[\].prizeTiers | String | 是 | FIRST_PRIZE / SECOND_PRIZE / THIRD_PRIZE |
| activityUserList | Array | 是 | 至少 1 项 |
| activityUserList\[\].userId | Long | 是 | 用户 ID |
| activityUserList\[\].userName | String | 是 | 用户姓名 |
Response data
json
{
"activityId": 23
}
业务错误 msg 示例
| msg | 触发条件 |
|---|---|
| 创建的活动信息为空 | param 为空 |
| 活动关联的人员异常 | 用户 ID 不存在 |
| 活动关联的奖品异常 | 奖品 ID 不存在 |
| 活动关联的奖品及人员数量设置异常 | 人数 < 奖品总数 |
| 活动奖品等奖设置错误 | prizeTiers 非法 |
6.2 API-11 活动分页列表
| 项目 | 内容 |
|---|---|
| 路径 | /activity/find-list |
| 方法 | GET |
| 鉴权 | 是 |
Query 参数
| 参数 | 类型 | 默认 |
|---|---|---|
| currentPage | Integer | 1 |
| pageSize | Integer | 10 |
Response data
json
{
"total": 10,
"records": [
{
"activityId": 23,
"activityName": "2026年会抽奖",
"description": "年终福利抽奖活动",
"valid": true
}
]
}
| 字段 | 说明 |
|---|---|
| valid | true=进行中(RUNNING);false=已完成(COMPLETED) |
6.3 API-12 活动详情
| 项目 | 内容 |
|---|---|
| 路径 | /activity-detail/find |
| 方法 | GET |
| 鉴权 | 是 |
Query 参数
| 参数 | 类型 | 必填 |
|---|---|---|
| activityId | Long | 是 |
Response data
json
{
"activityId": 24,
"activityName": "2026年会抽奖",
"description": "年终福利抽奖活动",
"valid": true,
"prizes": [
{
"prizeId": 18,
"name": "手机",
"description": "智能手机",
"price": 5000.00,
"imageUrl": "e606c8db-218a-40c2-8946-0d9f8570626d.jpg",
"prizeAmount": 1,
"prizeTierName": "一等奖",
"valid": true
}
],
"users": [
{
"userId": 44,
"userName": "郭靖",
"valid": true
}
]
}
字段语义
| 字段 | true 含义 | false 含义 |
|---|---|---|
| 活动 valid | RUNNING | COMPLETED |
| 奖品 valid | INIT(未抽取) | COMPLETED(已抽取) |
| 用户 valid | INIT(未中奖) | COMPLETED(已中奖) |
排序:奖品按等级 code 升序(一等奖在前)
activityId 为空:返回 code=500,msg=「查询活动详细信息失败」
7. 抽奖模块接口
7.1 API-13 提交抽奖结果
| 项目 | 内容 |
|---|---|
| 路径 | /draw-prize |
| 方法 | POST |
| 鉴权 | 是 |
| 说明 | 同步仅发 MQ,落库由消费者异步完成 |
Request Body
json
{
"activityId": 23,
"prizeId": 13,
"winningTime": "2026-07-03T10:30:00.000+00:00",
"winnerList": [
{
"userId": 15,
"userName": "张三"
}
]
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| activityId | Long | 是 | 活动 ID |
| prizeId | Long | 是 | 奖品 ID |
| winningTime | Date | 是 | 中奖时间 |
| winnerList | Array | 是 | 至少 1 人 |
| winnerList\[\].userId | Long | 是 | 中奖用户 ID |
| winnerList\[\].userName | String | 是 | 中奖用户姓名 |
注意:源码中 无
prizeTiers字段(已注释)。
Response data
json
true
异步消费校验规则 (checkDrawPrizeParam)
| 条件 | 失败行为 |
|---|---|
| 活动或活动奖品不存在 | 消费 return,不落库 |
| 活动 status=COMPLETED | 消费 return |
| 奖品 status=COMPLETED | 消费 return |
| winnerList.size() ≠ prizeAmount | 消费 return |
消费成功后续:状态扭转 → 写 winning_record → 缓存 → 异步邮件
7.2 API-14 查询中奖记录
| 项目 | 内容 |
|---|---|
| 路径 | /winning-records/show |
| 方法 | POST |
| 鉴权 | 否(白名单) |
Request Body
json
{
"activityId": 23,
"prizeId": 13
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| activityId | Long | 是 | 活动 ID |
| prizeId | Long | 否 | 不传=活动全量;传=指定奖品 |
Response data
json
[
{
"winnerId": 15,
"winnerName": "张三",
"prizeName": "手机",
"prizeTier": "一等奖",
"winningTime": "2026-07-03T10:30:00.000+00:00"
}
]
| 字段 | 说明 |
|---|---|
| prizeTier | 中文描述(非枚举名) |
空结果 :返回 data: [](code 仍为 200)
8. 错误码说明
8.1 HTTP 层
| HTTP Status | 场景 |
|---|---|
| 200 | 正常(含业务失败 code=500) |
| 401 | Token 缺失或无效 |
8.2 响应 code 字段
| code | 含义 |
|---|---|
| 200 | 成功 |
| 500 | 失败(GlobalErrorCodeConstants.INTERNAL_SYSTEM_ERROR) |
8.3 业务错误信息(msg)
Service 层错误码常量(通过 GlobalException 输出 msg):
| 模块 | 典型 msg |
|---|---|
| 用户 | 注册信息为空、邮箱错误、手机号错误、身份错误、邮箱被使用了、手机号被使用了、登录信息不存在、登录方式不存在、用户信息为空、验证码校验失败 |
| 活动 | 创建的活动信息为空、活动关联的人员异常、活动关联的奖品异常、活动关联的奖品及人员数量设置异常、活动奖品等奖设置错误、活动相关状态转换失败 |
| 抽奖 | MQ 消费校验失败时静默 return,不返回给前端 |
| 图片 | 图片上传失败 |
Controller 层异常 msg:
| msg | 接口 |
|---|---|
| 注册失败 | /register |
| 登录失败 | 登录接口 |
| 查询奖品列表失败 | 奖品列表 |
| 创建活动失败 | /activity/create |
| 获取活动列表错误 | /activity/find-list |
| 查询活动详细信息失败 | /activity-detail/find |
9. 枚举与数据字典
9.1 identity 用户身份
| 值 | 说明 |
|---|---|
| ADMIN | 管理员 |
| NORMAL | 普通用户 |
9.2 prizeTiers 奖品等级
| 值 | 中文 |
|---|---|
| FIRST_PRIZE | 一等奖 |
| SECOND_PRIZE | 二等奖 |
| THIRD_PRIZE | 三等奖 |
9.3 活动/奖品/用户状态(库表)
| 表 | 字段 status | 取值 |
|---|---|---|
| activity | status | RUNNING, COMPLETED |
| activity_prize | status | INIT, COMPLETED |
| activity_user | status | INIT, COMPLETED |
10. MQ 消息格式(内部)
10.1 交换机与队列
| 名称 | 常量值 |
|---|---|
| 交换机 | DirectExchange |
| 路由键 | DirectRouting |
| 队列 | DirectQueue |
| 死信交换机 | DlxDirectExchange |
| 死信队列 | DlxDirectQueue |
10.2 消息体
json
{
"messageId": "550e8400-e29b-41d4-a716-446655440000",
"messageData": "{\"activityId\":23,\"prizeId\":13,\"winningTime\":\"...\",\"winnerList\":[...]}"
}
| 字段 | 说明 |
|---|---|
| messageId | UUID 字符串 |
| messageData | DrawPrizeParam 的 JSON 字符串 |
四、项目源码
本项目源码已上传至Gitee码云仓库✨,有需要的小伙伴可自行拉取,方便对照操作复现完整项目流程~
项目👉企悦抽项目源码
到这里项目文档就全部整理好咯📄!下一期直接上手实操,手把手带大家做完项目,多多关注,后面还有超多实用干货~