新增系统配置表及默认配置,更新链接生成请求DTO以支持链接数量参数,重构链接生成服务逻辑,添加链接状态查询和有效性检查接口,优化日志记录。

This commit is contained in:
zyh
2025-08-26 10:33:26 +08:00
parent 7317866f98
commit 599ec0a36b
73 changed files with 1829 additions and 50 deletions

View File

@@ -39,7 +39,7 @@ Content-Type: application/json
{
"times": 10,
"perTimeQuantity": 5
"linkCount": 5
}
```
@@ -56,7 +56,7 @@ Content-Type: application/json
```json
{
"times": 10, // 本次打脚本的次数
"perTimeQuantity": 5 // 每次打的数量
"linkCount": 5 // 生成多少个链接
}
```

View File

@@ -144,4 +144,33 @@ CREATE TABLE `user_account` (
CONSTRAINT `chk_points_nonneg` CHECK (`points_balance` >= 0)
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for system_config
-- ----------------------------
DROP TABLE IF EXISTS `system_config`;
CREATE TABLE `system_config` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
`config_key` varchar(100) NOT NULL COMMENT '配置键',
`config_value` text NOT NULL COMMENT '配置值',
`config_type` varchar(50) NOT NULL DEFAULT 'STRING' COMMENT '配置类型STRING, INTEGER, BOOLEAN, JSON',
`description` varchar(500) NULL DEFAULT NULL COMMENT '配置描述',
`is_system` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否系统配置1是0否',
`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),
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_config_key`(`config_key` ASC) USING BTREE,
INDEX `idx_config_type`(`config_type` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- 插入默认配置
INSERT INTO `system_config` (`config_key`, `config_value`, `config_type`, `description`, `is_system`) VALUES
('link.default_quantity', '50', 'INTEGER', '链接生成默认奖励点数', 1),
('link.refresh_interval', '300', 'INTEGER', '链接刷新间隔(秒)', 1),
('link.qr_expire_time', '600', 'INTEGER', '二维码过期时间(秒)', 1),
('link.max_times_per_batch', '100', 'INTEGER', '每批次最大刷奖励次数', 1),
('link.min_quantity', '10', 'INTEGER', '最小奖励点数', 1),
('link.max_quantity', '1000', 'INTEGER', '最大奖励点数', 1),
('script.server_url', 'http://36.138.184.60:12345', 'STRING', '脚本服务器地址', 1),
('script.qr_path_template', '/{machineId}/二维码.png', 'STRING', '二维码图片路径模板', 1);
SET FOREIGN_KEY_CHECKS = 1;

View File

@@ -0,0 +1,403 @@
# 前端链接访问示例
## 概述
当用户访问链接页面时(如 `https://你的域名/ABC12345`),前端需要自动请求后端获取链接的详细信息,并根据状态显示相应的内容。
## 接口说明
### 1. 获取链接状态(主要接口)
```
GET /api/link/{codeNo}/status
```
**响应示例:**
```json
{
"codeNo": "ABC12345",
"batchId": 123,
"status": "NEW",
"statusDesc": "新建",
"expireAt": "2024-01-15T16:30:00",
"isExpired": false,
"remainingSeconds": 3600,
"quantity": 50,
"times": 10,
"totalPoints": 500,
"region": null,
"machineId": null,
"loginAt": null,
"createdAt": "2024-01-15T12:00:00",
"updatedAt": "2024-01-15T12:00:00"
}
```
### 2. 检查链接是否存在
```
GET /api/link/{codeNo}/exists
```
**响应:** `true``false`
### 3. 检查链接是否有效
```
GET /api/link/{codeNo}/valid
```
**响应:** `true``false`
## 前端实现示例
### React 组件示例
```jsx
import React, { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
const LinkPage = () => {
const { codeNo } = useParams();
const [linkStatus, setLinkStatus] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetchLinkStatus();
}, [codeNo]);
const fetchLinkStatus = async () => {
try {
setLoading(true);
const response = await fetch(`/api/link/${codeNo}/status`);
if (!response.ok) {
if (response.status === 404) {
setError('链接不存在');
} else {
setError('获取链接信息失败');
}
return;
}
const data = await response.json();
setLinkStatus(data);
} catch (err) {
setError('网络错误');
console.error('获取链接状态失败:', err);
} finally {
setLoading(false);
}
};
const formatTime = (seconds) => {
if (seconds <= 0) return '已过期';
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const secs = seconds % 60;
if (hours > 0) {
return `${hours}小时${minutes}分钟`;
} else if (minutes > 0) {
return `${minutes}分钟${secs}秒`;
} else {
return `${secs}秒`;
}
};
if (loading) {
return <div className="loading">加载中...</div>;
}
if (error) {
return (
<div className="error">
<h2>链接错误</h2>
<p>{error}</p>
<p>链接编号: {codeNo}</p>
</div>
);
}
if (!linkStatus) {
return <div>未找到链接信息</div>;
}
return (
<div className="link-page">
<div className="link-header">
<h1>游戏任务链接</h1>
<div className="link-code">链接编号: {linkStatus.codeNo}</div>
</div>
<div className="link-status">
<div className="status-item">
<span className="label">状态:</span>
<span className={`value status-${linkStatus.status.toLowerCase()}`}>
{linkStatus.statusDesc}
</span>
</div>
<div className="status-item">
<span className="label">任务信息:</span>
<span className="value">
{linkStatus.times}次副本每次{linkStatus.quantity}
总计{linkStatus.totalPoints}
</span>
</div>
<div className="status-item">
<span className="label">过期时间:</span>
<span className="value">
{linkStatus.expireAt}
</span>
</div>
<div className="status-item">
<span className="label">剩余时间:</span>
<span className={`value ${linkStatus.isExpired ? 'expired' : ''}`}>
{formatTime(linkStatus.remainingSeconds)}
</span>
</div>
</div>
{linkStatus.isExpired && (
<div className="expired-notice">
<p>⚠️ 此链接已过期无法使用</p>
</div>
)}
{!linkStatus.isExpired && linkStatus.status === 'NEW' && (
<div className="action-section">
<h3>开始任务</h3>
<p>点击下方按钮开始执行任务</p>
<button className="start-btn" onClick={() => startTask()}>
开始任务
</button>
</div>
)}
{linkStatus.status === 'USING' && (
<div className="task-progress">
<h3>任务进行中</h3>
<p>请按照提示完成游戏任务</p>
<div className="progress-bar">
<div className="progress-fill" style={{width: '50%'}}></div>
</div>
</div>
)}
{linkStatus.status === 'LOGGED_IN' && (
<div className="task-complete">
<h3>任务完成</h3>
<p>恭喜任务已完成奖励点数已发放</p>
<div className="reward-info">
获得奖励: {linkStatus.totalPoints}
</div>
</div>
)}
<div className="qr-section">
<h3>扫码访问</h3>
<img
src={`/api/link/${codeNo}/qr.png`}
alt="二维码"
className="qr-code"
/>
<p>使用手机扫描二维码访问</p>
</div>
</div>
);
};
const startTask = () => {
// 实现开始任务的逻辑
console.log('开始任务');
};
export default LinkPage;
```
### Vue 组件示例
```vue
<template>
<div class="link-page">
<div v-if="loading" class="loading">加载中...</div>
<div v-else-if="error" class="error">
<h2>链接错误</h2>
<p>{{ error }}</p>
<p>链接编号: {{ codeNo }}</p>
</div>
<div v-else-if="linkStatus" class="link-content">
<div class="link-header">
<h1>游戏任务链接</h1>
<div class="link-code">链接编号: {{ linkStatus.codeNo }}</div>
</div>
<div class="link-status">
<div class="status-item">
<span class="label">状态:</span>
<span :class="['value', `status-${linkStatus.status.toLowerCase()}`]">
{{ linkStatus.statusDesc }}
</span>
</div>
<div class="status-item">
<span class="label">任务信息:</span>
<span class="value">
{{ linkStatus.times }}次副本每次{{ linkStatus.quantity }}
总计{{ linkStatus.totalPoints }}
</span>
</div>
<div class="status-item">
<span class="label">剩余时间:</span>
<span :class="['value', { 'expired': linkStatus.isExpired }]">
{{ formatTime(linkStatus.remainingSeconds) }}
</span>
</div>
</div>
<div v-if="linkStatus.isExpired" class="expired-notice">
<p>⚠️ 此链接已过期无法使用</p>
</div>
<div v-if="!linkStatus.isExpired && linkStatus.status === 'NEW'" class="action-section">
<h3>开始任务</h3>
<button class="start-btn" @click="startTask">开始任务</button>
</div>
<div class="qr-section">
<h3>扫码访问</h3>
<img
:src="`/api/link/${codeNo}/qr.png`"
alt="二维码"
class="qr-code"
/>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'LinkPage',
data() {
return {
codeNo: '',
linkStatus: null,
loading: true,
error: null
};
},
async mounted() {
this.codeNo = this.$route.params.codeNo;
await this.fetchLinkStatus();
},
methods: {
async fetchLinkStatus() {
try {
this.loading = true;
const response = await fetch(`/api/link/${this.codeNo}/status`);
if (!response.ok) {
if (response.status === 404) {
this.error = '链接不存在';
} else {
this.error = '获取链接信息失败';
}
return;
}
this.linkStatus = await response.json();
} catch (err) {
this.error = '网络错误';
console.error('获取链接状态失败:', err);
} finally {
this.loading = false;
}
},
formatTime(seconds) {
if (seconds <= 0) return '已过期';
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const secs = seconds % 60;
if (hours > 0) {
return `${hours}小时${minutes}分钟`;
} else if (minutes > 0) {
return `${minutes}分钟${secs}秒`;
} else {
return `${secs}秒`;
}
},
startTask() {
// 实现开始任务的逻辑
console.log('开始任务');
}
}
};
</script>
```
## 路由配置
### React Router
```jsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import LinkPage from './components/LinkPage';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/:codeNo" element={<LinkPage />} />
{/* 其他路由 */}
</Routes>
</BrowserRouter>
);
}
```
### Vue Router
```javascript
import { createRouter, createWebHistory } from 'vue-router';
import LinkPage from '@/components/LinkPage.vue';
const routes = [
{
path: '/:codeNo',
name: 'LinkPage',
component: LinkPage
}
];
const router = createRouter({
history: createWebHistory(),
routes
});
export default router;
```
## 使用流程
1. **用户访问链接**`https://你的域名/ABC12345`
2. **前端自动请求**:调用 `/api/link/ABC12345/status` 获取链接信息
3. **显示相应内容**:根据链接状态显示不同的界面
4. **实时更新**:可以定时刷新状态,显示剩余时间等
## 注意事项
1. **错误处理**:处理链接不存在、已过期等情况
2. **加载状态**:显示加载中的状态,提升用户体验
3. **响应式设计**:确保在不同设备上都能正常显示
4. **缓存策略**:可以适当缓存链接状态,减少请求次数
5. **实时更新**:对于进行中的任务,可以定时刷新状态

View File

@@ -0,0 +1,150 @@
# 数据库修改总结
## 修改概述
根据需求文档和用户要求,对游戏平台系统进行了以下主要修改:
## 1. LinkBatch表结构调整
### 修改前
- `quantity`: 代表批次大小
- `times`: 代表生成次数
- `batchSize`: 每次的奖励点数
- `deductPoints`: 扣除的点数
### 修改后
- `quantity`: 每次副本的奖励点数从配置表获取默认50
- `times`: 打副本的次数
- 移除了 `batchSize``deductPoints` 字段
### 字段含义
- `quantity`: 每次副本完成后获得的点数,从配置表 `link.default_quantity` 获取
- `times`: 一个批次中打副本的总次数
- `agent_id`: 代理商ID
- `operator_id`: 操作者ID
- `created_at`: 创建时间
### 参数说明
- **`times`**: 打多少次副本,决定总的目标值
- **`linkCount`**: 生成多少个链接决定链接任务的数量默认值1
- **总目标值计算**: `times` × 配置表中的默认奖励点数
## 2. 新增系统配置表
### 表名system_config
用于存储系统各种配置参数,支持动态配置和运行时修改。
#### 主要配置项
**链接生成相关:**
- `link.default_quantity`: 默认奖励点数50
- `link.refresh_interval`: 链接刷新间隔300秒
- `link.qr_expire_time`: 二维码过期时间600秒
- `link.max_times_per_batch`: 每批次最大刷奖励次数100
- `link.min_quantity`: 最小奖励点数10
- `link.max_quantity`: 最大奖励点数1000
**脚本服务器相关:**
- `script.server_url`: 脚本服务器地址
- `script.qr_path_template`: 二维码图片路径模板
## 3. 代码结构更新
### 新增文件
1. **实体类**
- `SystemConfig.java` - 系统配置实体
2. **Mapper接口**
- `SystemConfigMapper.java` - 系统配置数据访问接口
3. **XML映射文件**
- `SystemConfigMapper.xml` - MyBatis映射配置
4. **服务类**
- `SystemConfigService.java` - 系统配置业务逻辑服务
5. **控制器**
- `SystemConfigController.java` - 系统配置REST API接口
6. **DTO类**
- `SystemConfigRequest.java` - 配置创建/更新请求
- `SystemConfigResponse.java` - 配置查询响应
- `SystemConfigConverter.java` - 配置对象转换工具
### 修改文件
1. **LinkBatch.java** - 移除不需要的字段
2. **LinkBatchMapper.xml** - 更新SQL映射
3. **LinkGenerationService.java** - 使用配置服务,修复字段设置
## 4. API接口
### 系统配置管理接口
- `GET /api/admin/config/list` - 获取配置列表
- `GET /api/admin/config/key/{configKey}` - 根据键获取配置
- `GET /api/admin/config/type/{configType}` - 根据类型获取配置
- `POST /api/admin/config` - 创建配置
- `PUT /api/admin/config/{id}` - 更新配置
- `DELETE /api/admin/config/{id}` - 删除配置
- `GET /api/admin/config/link/defaults` - 获取链接默认配置
- `GET /api/admin/config/script/config` - 获取脚本配置
## 5. 配置使用方式
### 在服务中使用
```java
@Autowired
private SystemConfigService systemConfigService;
// 获取默认奖励点数
Integer defaultQuantity = systemConfigService.getDefaultQuantity();
// 获取刷新间隔
Integer refreshInterval = systemConfigService.getRefreshInterval();
```
### 动态修改配置
```java
// 更新配置
SystemConfig config = systemConfigService.getConfigByKey("link.default_quantity");
config.setConfigValue("100");
systemConfigService.updateConfig(config);
```
## 6. 数据库脚本
### 执行顺序
1. 执行 `docs/game.sql` 中的新表创建语句
2. 系统会自动插入默认配置数据
### 注意事项
- 新表使用 `utf8mb4` 字符集
- 配置键具有唯一性约束
- 系统配置标记为 `is_system=1`,不建议删除
## 7. 业务逻辑调整
### LinkGenerationService
- 使用配置服务获取过期时间等参数
- 修复了字段设置问题
- `quantity` 现在代表每次的奖励点数
- `times` 代表总次数
### 配置管理
- 支持运行时动态修改配置
- 提供完整的CRUD操作
- 支持配置类型验证
- 提供便捷的配置获取方法
## 8. 后续扩展建议
1. **缓存机制**: 对频繁访问的配置添加缓存
2. **配置验证**: 在更新配置时添加值格式验证
3. **配置变更日志**: 记录配置变更历史
4. **配置导入导出**: 支持配置文件导入导出
5. **权限控制**: 对敏感配置的修改权限控制
## 9. 测试建议
1. 测试配置的增删改查功能
2. 验证LinkBatch表的字段映射
3. 测试配置的动态修改是否生效
4. 验证默认配置值的正确性
5. 测试配置服务的异常处理

151
docs/系统配置说明.md Normal file
View File

@@ -0,0 +1,151 @@
# 系统配置说明
## 概述
系统配置表用于存储游戏平台的各种配置参数,支持动态配置和运行时修改。
## 配置表结构
表名:`system_config`
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint | 主键ID |
| config_key | varchar(100) | 配置键(唯一) |
| config_value | text | 配置值 |
| config_type | varchar(50) | 配置类型STRING, INTEGER, BOOLEAN, JSON |
| description | varchar(500) | 配置描述 |
| is_system | tinyint(1) | 是否系统配置1是0否 |
| created_at | datetime(3) | 创建时间 |
| updated_at | datetime(3) | 更新时间 |
## 默认配置项
### 链接生成相关配置
- `link.default_quantity`: 每次副本的奖励点数默认值50
- `link.refresh_interval`: 链接刷新间隔单位默认值300
- `link.qr_expire_time`: 二维码过期时间单位默认值600
- `link.max_times_per_batch`: 每批次最大打副本次数默认值100
- `link.min_quantity`: 最小奖励点数默认值10
- `link.max_quantity`: 最大奖励点数默认值1000
### 脚本服务器相关配置
- `script.server_url`: 脚本服务器地址默认值http://36.138.184.60:12345
- `script.qr_path_template`: 二维码图片路径模板(默认值:/{machineId}/二维码.png
## 参数说明
### 链接生成接口参数
- **`times`**: 打多少次副本,决定总的目标值
- **`linkCount`**: 生成多少个链接决定链接任务的数量默认值1
### 业务逻辑
1. 每次副本的奖励点数从配置表 `link.default_quantity` 获取
2. 总目标值 = `times` × 配置表中的默认奖励点数
3. 生成 `linkCount` 个链接任务供用户使用
4. 用户完成链接后,根据 `times` 和配置的奖励点数计算总奖励
## API接口
### 获取配置列表
```
GET /api/admin/config/list?page=1&size=20
```
### 根据键获取配置
```
GET /api/admin/config/key/{configKey}
```
### 根据类型获取配置
```
GET /api/admin/config/type/{configType}
```
### 创建配置
```
POST /api/admin/config
Content-Type: application/json
{
"configKey": "custom.setting",
"configValue": "value",
"configType": "STRING",
"description": "自定义设置",
"isSystem": false
}
```
### 更新配置
```
PUT /api/admin/config/{id}
Content-Type: application/json
{
"configKey": "custom.setting",
"configValue": "new_value",
"configType": "STRING",
"description": "自定义设置",
"isSystem": false
}
```
### 删除配置
```
DELETE /api/admin/config/{id}
DELETE /api/admin/config/key/{configKey}
```
### 获取链接默认配置
```
GET /api/admin/config/link/defaults
```
### 获取脚本配置
```
GET /api/admin/config/script/config
```
## 使用示例
### 在服务中使用配置
```java
@Autowired
private SystemConfigService systemConfigService;
// 获取默认奖励点数
Integer defaultQuantity = systemConfigService.getDefaultQuantity();
// 获取刷新间隔
Integer refreshInterval = systemConfigService.getRefreshInterval();
// 获取脚本服务器地址
String serverUrl = systemConfigService.getScriptServerUrl();
```
### 动态修改配置
```java
// 更新配置
SystemConfig config = systemConfigService.getConfigByKey("link.default_quantity");
config.setConfigValue("100");
systemConfigService.updateConfig(config);
```
## 注意事项
1. **系统配置**标记为系统配置的项is_system=1通常不建议删除这些是平台运行必需的基础配置。
2. **配置类型**根据实际需要选择合适的配置类型数值类型建议使用INTEGER布尔值使用BOOLEAN。
3. **配置键命名**:建议使用点号分隔的层次结构,如:`module.submodule.setting`
4. **配置值验证**:在更新配置时,建议对配置值进行格式验证,确保符合预期类型。
5. **缓存策略**:对于频繁访问的配置,建议在服务层添加缓存机制,提高性能。
## 扩展配置
可以根据业务需要添加更多配置项,例如:
- 用户权限相关配置
- 游戏规则配置
- 第三方服务配置
- 日志级别配置
- 性能调优参数

View File

@@ -0,0 +1,275 @@
# 链接状态接口测试文档
## 接口概览
新增了三个接口用于前端获取链接状态信息:
1. **获取链接状态** - `GET /api/link/{codeNo}/status`
2. **检查链接是否存在** - `GET /api/link/{codeNo}/exists`
3. **检查链接是否有效** - `GET /api/link/{codeNo}/valid`
## 测试步骤
### 1. 准备工作
首先需要生成一个链接用于测试:
```bash
# 1. 登录获取JWT令牌
curl -X POST http://localhost:18080/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"username": "your_username",
"password": "your_password"
}'
```
从响应中获取JWT令牌后续请求都需要在Header中带上
```bash
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
```
### 2. 生成测试链接
```bash
# 2. 生成链接
curl -X POST http://localhost:18080/api/link/generate \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"times": 5,
"linkCount": 2
}'
```
响应示例:
```json
{
"batchId": 123,
"deductPoints": 250,
"expireAt": "2024-01-15T16:30:00",
"codeNos": ["ABC12345", "DEF67890"]
}
```
记录其中一个 `codeNo`,比如 `ABC12345`,用于后续测试。
### 3. 测试获取链接状态接口
```bash
# 3. 获取链接状态
curl -X GET http://localhost:18080/api/link/ABC12345/status \
-H "Accept: application/json"
```
**预期响应:**
```json
{
"codeNo": "ABC12345",
"batchId": 123,
"status": "NEW",
"statusDesc": "新建",
"expireAt": "2024-01-15T16:30:00",
"isExpired": false,
"remainingSeconds": 7200,
"quantity": 50,
"times": 5,
"totalPoints": 250,
"region": null,
"machineId": null,
"loginAt": null,
"createdAt": "2024-01-15T12:00:00",
"updatedAt": "2024-01-15T12:00:00"
}
```
### 4. 测试检查链接是否存在接口
```bash
# 4. 检查链接是否存在
curl -X GET http://localhost:18080/api/link/ABC12345/exists \
-H "Accept: application/json"
```
**预期响应:** `true`
### 5. 测试检查链接是否有效接口
```bash
# 5. 检查链接是否有效
curl -X GET http://localhost:18080/api/link/ABC12345/valid \
-H "Accept: application/json"
```
**预期响应:** `true`
### 6. 测试错误情况
#### 6.1 测试不存在的链接
```bash
# 测试不存在的链接
curl -X GET http://localhost:18080/api/link/INVALID123/status \
-H "Accept: application/json"
```
**预期响应:**
```json
{
"timestamp": "2024-01-15T12:00:00.000+00:00",
"status": 400,
"error": "Bad Request",
"message": "链接不存在: INVALID123",
"path": "/api/link/INVALID123/status"
}
```
#### 6.2 测试空链接编号
```bash
# 测试空链接编号
curl -X GET http://localhost:18080/api/link//status \
-H "Accept: application/json"
```
**预期响应:** 404 Not Found
## 状态值说明
### 链接状态 (status)
- `NEW` - 新建,未开始使用
- `USING` - 使用中,正在执行任务
- `LOGGED_IN` - 已登录,任务完成
- `REFUNDED` - 已退款
- `EXPIRED` - 已过期
### 区域 (region)
- `Q` - Q区
- `V` - V区
- `null` - 未分配区域
## 测试数据验证
### 1. 数值计算验证
- `totalPoints` = `quantity` × `times`
- `remainingSeconds` 应该大于0如果未过期
- `isExpired` 应该与当前时间和 `expireAt` 一致
### 2. 状态一致性验证
- 如果 `status``EXPIRED`,那么 `isExpired` 应该是 `true`
- 如果 `status``LOGGED_IN`,那么 `loginAt` 不应该为 `null`
### 3. 时间验证
- `createdAt``updatedAt`
- `expireAt` > `createdAt`
- 如果 `loginAt` 不为空,那么 `loginAt``createdAt`
## 性能测试
### 1. 响应时间测试
```bash
# 使用time命令测试响应时间
time curl -X GET http://localhost:18080/api/link/ABC12345/status
```
### 2. 并发测试
```bash
# 使用ab工具进行并发测试
ab -n 100 -c 10 http://localhost:18080/api/link/ABC12345/status
```
## 错误处理测试
### 1. 数据库连接异常
模拟数据库连接失败的情况,验证错误处理。
### 2. 网络超时
模拟网络延迟,验证超时处理。
### 3. 内存不足
模拟内存不足情况,验证系统稳定性。
## 安全测试
### 1. 权限验证
```bash
# 不带JWT令牌访问应该被拦截
curl -X GET http://localhost:18080/api/link/ABC12345/status
```
### 2. SQL注入防护
```bash
# 测试SQL注入
curl -X GET "http://localhost:18080/api/link/ABC12345'; DROP TABLE link_task; --/status"
```
### 3. XSS防护
```bash
# 测试XSS攻击
curl -X GET "http://localhost:18080/api/link/<script>alert('xss')</script>/status"
```
## 测试报告模板
### 测试结果记录
| 测试项目 | 测试结果 | 响应时间 | 备注 |
|---------|---------|---------|------|
| 获取链接状态 | ✅ 通过 | 45ms | 正常 |
| 检查链接存在 | ✅ 通过 | 23ms | 正常 |
| 检查链接有效 | ✅ 通过 | 28ms | 正常 |
| 错误处理 | ✅ 通过 | 15ms | 正常 |
| 性能测试 | ✅ 通过 | 平均35ms | 满足要求 |
### 问题记录
| 问题描述 | 严重程度 | 状态 | 备注 |
|---------|---------|------|------|
| 无 | - | - | - |
### 建议改进
1. 可以考虑添加缓存机制,减少数据库查询
2. 可以添加链接访问统计功能
3. 可以考虑添加链接状态变更通知功能
## 自动化测试
### 使用Postman Collection
可以创建Postman Collection来自动化测试这些接口
1. 创建环境变量存储JWT令牌和链接编号
2. 设置测试脚本验证响应数据
3. 使用Postman Runner批量执行测试
### 使用JUnit测试
```java
@SpringBootTest
@AutoConfigureTestDatabase
class LinkStatusControllerTest {
@Test
void testGetLinkStatus() {
// 测试获取链接状态
}
@Test
void testLinkNotExists() {
// 测试链接不存在的情况
}
}
```
## 总结
这些接口为前端提供了完整的链接状态查询功能,支持:
1. **完整的状态信息** - 包括任务详情、过期时间、奖励点数等
2. **实时状态计算** - 自动计算是否过期、剩余时间等
3. **友好的错误处理** - 提供清晰的错误信息和状态码
4. **高性能查询** - 使用响应式编程,支持高并发访问
前端可以根据这些接口实现丰富的用户界面,提供良好的用户体验。