feat: 更新公告和链接状态接口,增强参数校验,支持跳转链接最大长度为5000字符,添加异步保存完成图片功能,优化接口文档和数据库结构
This commit is contained in:
@@ -48,11 +48,12 @@ CREATE TABLE `announcement` (
|
||||
`title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`enabled` tinyint(1) NOT NULL DEFAULT 1,
|
||||
`jump_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||
`jump_url` varchar(5000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
`belong_id` int(11) NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for link_batch
|
||||
|
||||
@@ -184,6 +184,22 @@ curl -X PUT "http://localhost:8080/api/admin/announcement/1/enabled?enabled=fals
|
||||
}
|
||||
```
|
||||
|
||||
**400 Bad Request** - 字段长度超限:
|
||||
```json
|
||||
{
|
||||
"timestamp": "2023-12-01T10:00:00.000+00:00",
|
||||
"status": 400,
|
||||
"error": "Bad Request",
|
||||
"message": "Validation failed",
|
||||
"errors": [
|
||||
{
|
||||
"field": "jumpUrl",
|
||||
"message": "跳转链接长度不能超过5000个字符"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**404 Not Found** - 公告不存在:
|
||||
```json
|
||||
{
|
||||
@@ -200,17 +216,19 @@ curl -X PUT "http://localhost:8080/api/admin/announcement/1/enabled?enabled=fals
|
||||
2. 公告标题和内容不能为空
|
||||
3. `enabled` 字段默认为 `false`
|
||||
4. `jumpUrl` 字段可选,用于设置点击公告后的跳转链接
|
||||
5. 获取启用公告的接口最多返回10条记录
|
||||
6. 所有时间字段使用 ISO 8601 格式
|
||||
5. `jumpUrl` 字段最大长度为 **5000个字符**,超过此限制将返回验证错误
|
||||
6. 获取启用公告的接口最多返回10条记录
|
||||
7. 所有时间字段使用 ISO 8601 格式
|
||||
|
||||
## 数据库表结构
|
||||
|
||||
公告数据存储在 `announcement` 表中,包含以下字段:
|
||||
|
||||
- `id` - 主键,自增
|
||||
- `title` - 公告标题
|
||||
- `content` - 公告内容
|
||||
- `enabled` - 启用状态
|
||||
- `jump_url` - 跳转链接
|
||||
- `created_at` - 创建时间
|
||||
- `updated_at` - 更新时间
|
||||
- `title` - 公告标题 (VARCHAR(100))
|
||||
- `content` - 公告内容 (TEXT)
|
||||
- `enabled` - 启用状态 (TINYINT(1))
|
||||
- `jump_url` - 跳转链接 (VARCHAR(5000)),可选
|
||||
- `belong_id` - 归属ID (INT),关联用户ID
|
||||
- `created_at` - 创建时间 (DATETIME(3))
|
||||
- `updated_at` - 更新时间 (DATETIME(3))
|
||||
|
||||
@@ -6,10 +6,21 @@
|
||||
## 接口说明
|
||||
|
||||
### 1. 获取链接状态(主要接口)
|
||||
|
||||
**推荐格式(路径参数):**
|
||||
```
|
||||
GET /api/link/{codeNo}/status
|
||||
GET /api/link/{code}/status
|
||||
```
|
||||
|
||||
**兼容格式(查询参数,兼容旧版):**
|
||||
```
|
||||
GET /api/link/status?code={code}
|
||||
GET /api/link/status?codeNo={codeNo}
|
||||
GET /api/link/status?linkId={linkId}
|
||||
```
|
||||
|
||||
> 💡 **推荐使用路径参数格式**,因为复制粘贴时不容易丢失参数,更符合 RESTful 规范。查询参数格式保留用于兼容已生成的旧链接。
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
@@ -66,6 +77,7 @@ const LinkPage = () => {
|
||||
const fetchLinkStatus = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
// 使用路径参数格式,更不容易丢失链接信息
|
||||
const response = await fetch(`/api/link/${codeNo}/status`);
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -301,6 +313,7 @@ export default {
|
||||
async fetchLinkStatus() {
|
||||
try {
|
||||
this.loading = true;
|
||||
// 使用路径参数格式,更不容易丢失链接信息
|
||||
const response = await fetch(`/api/link/${this.codeNo}/status`);
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -389,10 +402,57 @@ export default router;
|
||||
## 使用流程
|
||||
|
||||
1. **用户访问链接**:`https://你的域名/ABC12345`
|
||||
2. **前端自动请求**:调用 `/api/link/ABC12345/status` 获取链接信息
|
||||
2. **前端自动请求**:调用 `/api/link/ABC12345/status` 获取链接信息(使用路径参数,更不容易丢失)
|
||||
3. **显示相应内容**:根据链接状态显示不同的界面
|
||||
4. **实时更新**:可以定时刷新状态,显示剩余时间等
|
||||
|
||||
## 接口格式说明
|
||||
|
||||
系统同时支持两种访问格式,保证新旧链接都能正常使用:
|
||||
|
||||
### 方式一:路径参数格式(推荐 ⭐)
|
||||
|
||||
```
|
||||
GET /api/link/{code}/status
|
||||
```
|
||||
|
||||
**示例:**
|
||||
```javascript
|
||||
fetch('/api/link/ABC12345/status')
|
||||
```
|
||||
|
||||
**优势:**
|
||||
- ✅ 复制粘贴时不会丢失参数
|
||||
- ✅ 符合 RESTful 设计规范
|
||||
- ✅ URL 结构更清晰
|
||||
- ✅ 浏览器地址栏直接可见完整路径
|
||||
|
||||
### 方式二:查询参数格式(兼容旧版)
|
||||
|
||||
```
|
||||
GET /api/link/status?code={code}
|
||||
GET /api/link/status?codeNo={codeNo}
|
||||
GET /api/link/status?linkId={linkId}
|
||||
```
|
||||
|
||||
**示例:**
|
||||
```javascript
|
||||
fetch('/api/link/status?code=ABC12345')
|
||||
fetch('/api/link/status?codeNo=ABC12345')
|
||||
fetch('/api/link/status?linkId=123')
|
||||
```
|
||||
|
||||
**说明:**
|
||||
- 保留此格式用于兼容已生成的旧链接
|
||||
- 支持 `code`、`codeNo`、`linkId` 三种参数名
|
||||
- `linkId` 和 `code/codeNo` 至少提供一个即可
|
||||
|
||||
### 兼容性保证
|
||||
|
||||
- ✅ 两种格式返回完全相同的数据结构
|
||||
- ✅ 旧链接继续有效,无需修改
|
||||
- ✅ 新生成的链接推荐使用路径参数格式
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **错误处理**:处理链接不存在、已过期等情况
|
||||
|
||||
384
docs/完成图片保存功能说明.md
Normal file
384
docs/完成图片保存功能说明.md
Normal file
@@ -0,0 +1,384 @@
|
||||
# 完成图片保存功能说明
|
||||
|
||||
## 📋 功能概述
|
||||
|
||||
当游戏任务完成时,系统会自动保存4张关键截图到本地文件系统,并保留24小时。这些图片可以作为任务完成的证明和记录。
|
||||
|
||||
## 🎯 保存的图片
|
||||
|
||||
任务完成时会保存以下4张图片:
|
||||
|
||||
1. **首次主页.png** (homepage)
|
||||
2. **首次赏金.png** (first-reward)
|
||||
3. **中途赏金.png** (mid-reward)
|
||||
4. **结束赏金.png** (end-reward)
|
||||
|
||||
## 🔧 技术实现
|
||||
|
||||
### 1. 核心服务组件
|
||||
|
||||
#### **CompletionImageService**
|
||||
- 负责从脚本端下载图片并保存到本地文件系统
|
||||
- 并发下载4张图片,提高效率
|
||||
- 提供图片访问和清理功能
|
||||
|
||||
#### **GameCompletionDetectionService**
|
||||
- 在任务完成时触发图片保存
|
||||
- 异步执行,不阻塞主流程
|
||||
- 保存成功后更新数据库记录
|
||||
|
||||
#### **CompletionImageController**
|
||||
- 提供HTTP接口访问已保存的图片
|
||||
- 支持单张图片访问和批量URL获取
|
||||
|
||||
#### **CompletionImageCleanupTask**
|
||||
- 定时清理任务(每小时执行)
|
||||
- 自动删除超过24小时的图片文件夹
|
||||
|
||||
### 2. 文件存储结构
|
||||
|
||||
```
|
||||
completion-images/
|
||||
├── 20251103/ # 日期文件夹(yyyyMMdd)
|
||||
│ ├── ABC123XYZ/ # 链接编号(codeNo)
|
||||
│ │ ├── homepage.png
|
||||
│ │ ├── first-reward.png
|
||||
│ │ ├── mid-reward.png
|
||||
│ │ └── end-reward.png
|
||||
│ └── DEF456UVW/
|
||||
│ └── ...
|
||||
└── 20251104/
|
||||
└── ...
|
||||
```
|
||||
|
||||
### 3. 数据库字段
|
||||
|
||||
在 `link_task` 表中新增两个字段:
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| `completion_images` | TEXT | JSON格式存储图片信息 |
|
||||
| `completion_images_saved_at` | DATETIME | 图片保存时间 |
|
||||
|
||||
**completion_images JSON 示例:**
|
||||
```json
|
||||
{
|
||||
"saveTime": "2025-11-03T10:30:45",
|
||||
"codeNo": "ABC123XYZ",
|
||||
"machineId": "f1",
|
||||
"dateFolder": "20251103",
|
||||
"images": {
|
||||
"homepage": "20251103/ABC123XYZ/homepage.png",
|
||||
"first-reward": "20251103/ABC123XYZ/first-reward.png",
|
||||
"mid-reward": "20251103/ABC123XYZ/mid-reward.png",
|
||||
"end-reward": "20251103/ABC123XYZ/end-reward.png"
|
||||
},
|
||||
"totalCount": 4
|
||||
}
|
||||
```
|
||||
|
||||
## 📡 API 接口
|
||||
|
||||
### 1. 获取单张图片
|
||||
|
||||
**首次主页图片**
|
||||
```http
|
||||
GET /api/link/completion/{codeNo}/homepage.png
|
||||
```
|
||||
|
||||
**首次赏金图片**
|
||||
```http
|
||||
GET /api/link/completion/{codeNo}/first-reward.png
|
||||
```
|
||||
|
||||
**中途赏金图片**
|
||||
```http
|
||||
GET /api/link/completion/{codeNo}/mid-reward.png
|
||||
```
|
||||
|
||||
**结束赏金图片**
|
||||
```http
|
||||
GET /api/link/completion/{codeNo}/end-reward.png
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
- 成功:返回图片数据(image/png)
|
||||
- 失败:404 Not Found
|
||||
|
||||
### 2. 获取所有图片URL列表
|
||||
|
||||
```http
|
||||
GET /api/link/completion/{codeNo}/images
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"homepage": "https://uzi1.cn/api/link/completion/ABC123XYZ/homepage.png",
|
||||
"firstReward": "https://uzi1.cn/api/link/completion/ABC123XYZ/first-reward.png",
|
||||
"midReward": "https://uzi1.cn/api/link/completion/ABC123XYZ/mid-reward.png",
|
||||
"endReward": "https://uzi1.cn/api/link/completion/ABC123XYZ/end-reward.png"
|
||||
}
|
||||
```
|
||||
|
||||
## ⚙️ 配置说明
|
||||
|
||||
在 `application.yml` 中配置:
|
||||
|
||||
```yaml
|
||||
# 完成图片存储配置
|
||||
completion:
|
||||
image:
|
||||
storage:
|
||||
path: "./completion-images" # 图片存储路径
|
||||
retention-hours: 24 # 图片保留时间(小时)
|
||||
```
|
||||
|
||||
### 配置项说明
|
||||
|
||||
| 配置项 | 说明 | 默认值 |
|
||||
|--------|------|--------|
|
||||
| `path` | 图片存储路径,支持相对路径和绝对路径 | `./completion-images` |
|
||||
| `retention-hours` | 图片保留时间(小时) | 24 |
|
||||
|
||||
### 生产环境建议
|
||||
|
||||
**推荐配置绝对路径:**
|
||||
```yaml
|
||||
completion:
|
||||
image:
|
||||
storage:
|
||||
path: "/data/gameplatform/completion-images"
|
||||
```
|
||||
|
||||
**磁盘空间预估:**
|
||||
- 单个任务:4张图片,约 800KB - 2MB
|
||||
- 每天100个任务:约 80MB - 200MB
|
||||
- 24小时滚动:约 80MB - 200MB
|
||||
|
||||
## 🔄 执行流程
|
||||
|
||||
### 1. 图片保存流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Detection as 完成检测服务
|
||||
participant ImageService as 图片服务
|
||||
participant ScriptClient as 脚本客户端
|
||||
participant FileSystem as 文件系统
|
||||
participant Database as 数据库
|
||||
|
||||
Detection->>Detection: 检测到任务完成
|
||||
Detection->>ImageService: 异步保存图片
|
||||
ImageService->>ScriptClient: 并发下载4张图片
|
||||
ScriptClient-->>ImageService: 返回图片数据
|
||||
ImageService->>FileSystem: 保存到本地
|
||||
FileSystem-->>ImageService: 保存成功
|
||||
ImageService->>Database: 更新图片信息
|
||||
Database-->>ImageService: 更新完成
|
||||
```
|
||||
|
||||
### 2. 清理流程
|
||||
|
||||
```
|
||||
每小时第5分钟执行
|
||||
↓
|
||||
计算过期时间(当前时间 - 24小时)
|
||||
↓
|
||||
查找过期的日期文件夹
|
||||
↓
|
||||
递归删除过期文件夹
|
||||
↓
|
||||
记录清理日志
|
||||
```
|
||||
|
||||
## 🔒 安全配置
|
||||
|
||||
在 `SecurityConfig.java` 中已配置公开访问权限:
|
||||
|
||||
```java
|
||||
.pathMatchers(HttpMethod.GET, "/api/link/completion/**").permitAll()
|
||||
.pathMatchers(HttpMethod.HEAD, "/api/link/completion/**").permitAll()
|
||||
```
|
||||
|
||||
**说明:**
|
||||
- 完成图片可以公开访问(无需认证)
|
||||
- 图片URL包含链接编号,具有一定的私密性
|
||||
- 24小时后自动删除,减少泄露风险
|
||||
|
||||
## 📊 监控和日志
|
||||
|
||||
### 关键日志
|
||||
|
||||
**图片保存成功:**
|
||||
```
|
||||
INFO - 完成图片保存成功: codeNo=ABC123XYZ, imageInfo={...}
|
||||
```
|
||||
|
||||
**图片保存失败:**
|
||||
```
|
||||
ERROR - 完成图片保存失败: codeNo=ABC123XYZ, error=...
|
||||
```
|
||||
|
||||
**定时清理:**
|
||||
```
|
||||
INFO - === 完成图片清理任务完成:删除文件夹数=5, 耗时=234ms ===
|
||||
```
|
||||
|
||||
### 监控指标
|
||||
|
||||
- 图片保存成功率
|
||||
- 图片下载耗时
|
||||
- 磁盘空间使用
|
||||
- 清理任务执行情况
|
||||
|
||||
## 🚀 部署步骤
|
||||
|
||||
### 1. 数据库迁移
|
||||
|
||||
执行迁移脚本:
|
||||
```bash
|
||||
# 文件位置: src/main/resources/db/migration/V20251103__add_completion_images_saved_at.sql
|
||||
mysql -u username -p database_name < V20251103__add_completion_images_saved_at.sql
|
||||
```
|
||||
|
||||
或者使用 Flyway 自动迁移(推荐)。
|
||||
|
||||
### 2. 创建存储目录
|
||||
|
||||
```bash
|
||||
# 创建图片存储目录
|
||||
mkdir -p /data/gameplatform/completion-images
|
||||
|
||||
# 设置权限
|
||||
chown -R app_user:app_group /data/gameplatform/completion-images
|
||||
chmod 755 /data/gameplatform/completion-images
|
||||
```
|
||||
|
||||
### 3. 更新配置文件
|
||||
|
||||
修改 `application.yml`:
|
||||
```yaml
|
||||
completion:
|
||||
image:
|
||||
storage:
|
||||
path: "/data/gameplatform/completion-images"
|
||||
```
|
||||
|
||||
### 4. 重启应用
|
||||
|
||||
```bash
|
||||
systemctl restart gameplatform-server
|
||||
```
|
||||
|
||||
### 5. 验证功能
|
||||
|
||||
查看日志确认功能正常:
|
||||
```bash
|
||||
tail -f logs/server.log | grep "完成图片"
|
||||
```
|
||||
|
||||
## 🔍 故障排查
|
||||
|
||||
### 问题1:图片保存失败
|
||||
|
||||
**可能原因:**
|
||||
1. 存储目录不存在或无写权限
|
||||
2. 脚本端图片不存在
|
||||
3. 网络连接问题
|
||||
|
||||
**排查步骤:**
|
||||
```bash
|
||||
# 1. 检查目录权限
|
||||
ls -la /data/gameplatform/completion-images
|
||||
|
||||
# 2. 检查磁盘空间
|
||||
df -h
|
||||
|
||||
# 3. 查看详细日志
|
||||
grep "完成图片保存失败" logs/server.log
|
||||
```
|
||||
|
||||
### 问题2:图片无法访问
|
||||
|
||||
**可能原因:**
|
||||
1. 图片已被清理(超过24小时)
|
||||
2. 图片保存时失败
|
||||
3. 文件路径错误
|
||||
|
||||
**排查步骤:**
|
||||
```bash
|
||||
# 查找特定任务的图片
|
||||
find /data/gameplatform/completion-images -name "*ABC123XYZ*"
|
||||
|
||||
# 检查数据库记录
|
||||
SELECT code_no, completion_images, completion_images_saved_at
|
||||
FROM link_task
|
||||
WHERE code_no = 'ABC123XYZ';
|
||||
```
|
||||
|
||||
### 问题3:磁盘空间不足
|
||||
|
||||
**解决方案:**
|
||||
1. 调整保留时间(减少到12小时)
|
||||
2. 增加磁盘空间
|
||||
3. 配置日志轮转和压缩
|
||||
|
||||
## 📝 注意事项
|
||||
|
||||
1. **异步执行**:图片保存是异步的,不会阻塞任务完成流程
|
||||
2. **容错机制**:单张图片下载失败不影响其他图片
|
||||
3. **自动清理**:超过24小时的图片会自动删除,无需手动维护
|
||||
4. **并发安全**:使用日期文件夹隔离,避免并发冲突
|
||||
5. **存储规划**:建议预留至少 500MB 磁盘空间
|
||||
|
||||
## 🎓 使用示例
|
||||
|
||||
### 前端获取完成图片
|
||||
|
||||
```javascript
|
||||
// 获取所有图片URL
|
||||
fetch('/api/link/completion/ABC123XYZ/images')
|
||||
.then(res => res.json())
|
||||
.then(urls => {
|
||||
console.log('首次主页:', urls.homepage);
|
||||
console.log('首次赏金:', urls.firstReward);
|
||||
console.log('中途赏金:', urls.midReward);
|
||||
console.log('结束赏金:', urls.endReward);
|
||||
});
|
||||
|
||||
// 直接显示图片
|
||||
<img src="/api/link/completion/ABC123XYZ/homepage.png" alt="首次主页" />
|
||||
```
|
||||
|
||||
### 查询数据库中的图片信息
|
||||
|
||||
```sql
|
||||
-- 查询最近完成且有图片的任务
|
||||
SELECT
|
||||
code_no,
|
||||
status,
|
||||
completed_points,
|
||||
completion_images_saved_at,
|
||||
JSON_EXTRACT(completion_images, '$.totalCount') as image_count
|
||||
FROM link_task
|
||||
WHERE status = 'COMPLETED'
|
||||
AND completion_images IS NOT NULL
|
||||
AND completion_images_saved_at > DATE_SUB(NOW(), INTERVAL 24 HOUR)
|
||||
ORDER BY completion_images_saved_at DESC
|
||||
LIMIT 10;
|
||||
```
|
||||
|
||||
## 🔮 未来优化方向
|
||||
|
||||
1. **CDN 集成**:将图片上传到 CDN,提高访问速度
|
||||
2. **压缩优化**:自动压缩图片,减少存储空间
|
||||
3. **备份机制**:定期备份重要图片到对象存储
|
||||
4. **统计分析**:添加图片访问统计和热度分析
|
||||
5. **批量下载**:支持批量导出完成图片
|
||||
|
||||
---
|
||||
|
||||
**最后更新时间:** 2025-11-03
|
||||
**版本:** v1.0.0
|
||||
|
||||
252
docs/链接状态接口兼容性说明.md
Normal file
252
docs/链接状态接口兼容性说明.md
Normal file
@@ -0,0 +1,252 @@
|
||||
# 链接状态接口兼容性说明
|
||||
|
||||
## 概述
|
||||
|
||||
为了解决链接复制粘贴时参数丢失的问题,同时保证向后兼容,系统现在支持两种访问格式:
|
||||
1. **路径参数格式**(推荐):`/api/link/{code}/status`
|
||||
2. **查询参数格式**(兼容旧版):`/api/link/status?code={code}`
|
||||
|
||||
## 支持的访问方式
|
||||
|
||||
### 方式一:路径参数(推荐 ⭐)
|
||||
|
||||
**接口:** `GET /api/link/{code}/status`
|
||||
|
||||
**示例:**
|
||||
```bash
|
||||
curl http://localhost:8080/api/link/ABC12345/status
|
||||
```
|
||||
|
||||
```javascript
|
||||
// JavaScript
|
||||
fetch('/api/link/ABC12345/status')
|
||||
```
|
||||
|
||||
**优势:**
|
||||
- ✅ 复制粘贴时不会丢失参数
|
||||
- ✅ 符合 RESTful 设计规范
|
||||
- ✅ URL 结构更清晰
|
||||
- ✅ 浏览器地址栏直接可见完整路径
|
||||
|
||||
---
|
||||
|
||||
### 方式二:查询参数(兼容旧版)
|
||||
|
||||
**接口:** `GET /api/link/status`
|
||||
|
||||
**支持的参数:**
|
||||
- `code` - 链接编号(推荐)
|
||||
- `codeNo` - 链接编号(别名)
|
||||
- `linkId` - 链接数据库ID
|
||||
|
||||
**示例:**
|
||||
|
||||
```bash
|
||||
# 使用 code 参数
|
||||
curl "http://localhost:8080/api/link/status?code=ABC12345"
|
||||
|
||||
# 使用 codeNo 参数
|
||||
curl "http://localhost:8080/api/link/status?codeNo=ABC12345"
|
||||
|
||||
# 使用 linkId 参数
|
||||
curl "http://localhost:8080/api/link/status?linkId=123"
|
||||
```
|
||||
|
||||
```javascript
|
||||
// JavaScript
|
||||
fetch('/api/link/status?code=ABC12345')
|
||||
fetch('/api/link/status?codeNo=ABC12345')
|
||||
fetch('/api/link/status?linkId=123')
|
||||
```
|
||||
|
||||
**说明:**
|
||||
- `linkId` 和 `code/codeNo` 至少提供一个即可
|
||||
- 如果同时提供,优先使用 `codeNo`,其次是 `code`
|
||||
|
||||
---
|
||||
|
||||
## 响应格式
|
||||
|
||||
两种方式返回完全相同的数据结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "NEW",
|
||||
"machineId": null
|
||||
}
|
||||
```
|
||||
|
||||
**status 可能的值:**
|
||||
- `NEW` - 新建
|
||||
- `USING` - 使用中(前端会显示为 NEW)
|
||||
- `LOGGED_IN` - 已登录
|
||||
- `COMPLETED` - 已完成
|
||||
- `REFUNDED` - 已退款
|
||||
- `EXPIRED` - 已过期
|
||||
|
||||
---
|
||||
|
||||
## 测试用例
|
||||
|
||||
### 测试 1:路径参数方式
|
||||
|
||||
```bash
|
||||
# 假设有一个 codeNo 为 ABC12345 的链接
|
||||
curl http://localhost:8080/api/link/ABC12345/status
|
||||
```
|
||||
|
||||
**期望结果:** 返回链接状态信息
|
||||
|
||||
---
|
||||
|
||||
### 测试 2:查询参数方式(code)
|
||||
|
||||
```bash
|
||||
curl "http://localhost:8080/api/link/status?code=ABC12345"
|
||||
```
|
||||
|
||||
**期望结果:** 返回与测试1相同的结果
|
||||
|
||||
---
|
||||
|
||||
### 测试 3:查询参数方式(codeNo)
|
||||
|
||||
```bash
|
||||
curl "http://localhost:8080/api/link/status?codeNo=ABC12345"
|
||||
```
|
||||
|
||||
**期望结果:** 返回与测试1相同的结果
|
||||
|
||||
---
|
||||
|
||||
### 测试 4:查询参数方式(linkId)
|
||||
|
||||
```bash
|
||||
# 假设链接的数据库 ID 为 123
|
||||
curl "http://localhost:8080/api/link/status?linkId=123"
|
||||
```
|
||||
|
||||
**期望结果:** 返回链接状态信息
|
||||
|
||||
---
|
||||
|
||||
### 测试 5:错误处理
|
||||
|
||||
```bash
|
||||
# 不存在的链接
|
||||
curl http://localhost:8080/api/link/INVALID/status
|
||||
|
||||
# 空参数
|
||||
curl "http://localhost:8080/api/link/status?code="
|
||||
|
||||
# 缺少参数
|
||||
curl "http://localhost:8080/api/link/status"
|
||||
```
|
||||
|
||||
**期望结果:** 返回错误信息
|
||||
|
||||
---
|
||||
|
||||
## 迁移建议
|
||||
|
||||
### 对于新开发的前端
|
||||
|
||||
**推荐使用路径参数格式:**
|
||||
```javascript
|
||||
const codeNo = 'ABC12345';
|
||||
const response = await fetch(`/api/link/${codeNo}/status`);
|
||||
```
|
||||
|
||||
### 对于现有系统
|
||||
|
||||
**无需修改,查询参数格式继续有效:**
|
||||
```javascript
|
||||
// 继续使用旧格式
|
||||
const response = await fetch(`/api/link/status?code=${codeNo}`);
|
||||
```
|
||||
|
||||
### 渐进式迁移
|
||||
|
||||
可以逐步将旧代码迁移到新格式:
|
||||
|
||||
```javascript
|
||||
// 旧代码
|
||||
async function getLinkStatus_Old(codeNo) {
|
||||
return fetch(`/api/link/status?code=${codeNo}`);
|
||||
}
|
||||
|
||||
// 新代码(推荐)
|
||||
async function getLinkStatus_New(codeNo) {
|
||||
return fetch(`/api/link/${codeNo}/status`);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 后端实现说明
|
||||
|
||||
### Controller 方法
|
||||
|
||||
系统提供了两个独立的 Controller 方法:
|
||||
|
||||
1. **getUserLinkStatusByPath** - 处理路径参数请求
|
||||
- 路由:`GET /api/link/{code}/status`
|
||||
- 参数:`@PathVariable String code`
|
||||
|
||||
2. **getUserLinkStatusByQuery** - 处理查询参数请求
|
||||
- 路由:`GET /api/link/status`
|
||||
- 参数:`@RequestParam Long linkId`, `@RequestParam String codeNo`, `@RequestParam String code`
|
||||
|
||||
### 日志区分
|
||||
|
||||
两个方法使用不同的日志标识,便于问题排查:
|
||||
- 路径参数:`=== 用户端获取链接状态(路径参数) ===`
|
||||
- 查询参数:`=== 用户端获取链接状态(查询参数,兼容模式) ===`
|
||||
|
||||
---
|
||||
|
||||
## 兼容性保证
|
||||
|
||||
- ✅ 两种格式返回完全相同的数据结构
|
||||
- ✅ 旧链接继续有效,无需修改
|
||||
- ✅ 新生成的链接推荐使用路径参数格式
|
||||
- ✅ 系统会长期维护两种格式的支持
|
||||
- ✅ 不会影响现有功能和性能
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: 为什么推荐使用路径参数格式?
|
||||
|
||||
**A:** 路径参数格式的优势:
|
||||
1. 复制粘贴 URL 时不会丢失参数(查询参数容易在 `?` 后被截断)
|
||||
2. 符合 RESTful API 设计规范
|
||||
3. URL 更清晰,更容易阅读和理解
|
||||
4. 浏览器地址栏显示更完整
|
||||
|
||||
### Q2: 旧链接会失效吗?
|
||||
|
||||
**A:** 不会。查询参数格式会长期保持支持,确保兼容性。
|
||||
|
||||
### Q3: 能否混合使用两种格式?
|
||||
|
||||
**A:** 可以。同一个应用中可以同时使用两种格式,系统都会正确处理。
|
||||
|
||||
### Q4: 性能上有区别吗?
|
||||
|
||||
**A:** 没有。两种格式调用相同的底层服务方法,性能完全一致。
|
||||
|
||||
### Q5: 如何在 Swagger/OpenAPI 中查看?
|
||||
|
||||
**A:** Swagger UI 会显示两个独立的接口:
|
||||
- `GET /api/link/{code}/status` - 推荐格式
|
||||
- `GET /api/link/status` - 兼容格式
|
||||
|
||||
---
|
||||
|
||||
## 更新日志
|
||||
|
||||
- **2025-10-21**:添加路径参数格式支持,同时保留查询参数格式兼容性
|
||||
- 旧的查询参数格式标记为"兼容模式",推荐新项目使用路径参数格式
|
||||
|
||||
Reference in New Issue
Block a user