Initial commit

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
liu
2026-02-03 10:10:11 +08:00
commit 14289beb66
45 changed files with 15479 additions and 0 deletions

View File

@@ -0,0 +1,965 @@
# 模块11API接口设计规范
---
## 🎨 UI设计系统概览
> **完整设计系统文档请参考:** `UI设计系统.md`
### 核心设计原则
- **现代简约**:界面清晰,层次分明
- **专业高效**:减少操作步骤,提升工作效率
- **一致性**:统一的视觉语言和交互模式
- **可访问性**符合WCAG 2.1 AA标准
### 关键设计令牌
**颜色系统:**
- 主色:`#0d6efd`(操作按钮、选中状态)
- 成功:`#198754`(连接成功状态)
- 危险:`#dc3545`(删除操作、错误提示)
- 深灰:`#212529`(导航栏背景)
- 浅灰:`#e9ecef`(工具栏背景)
**字体系统:**
- 字体族:系统字体栈(-apple-system, Segoe UI, Roboto等
- 正文14px行高1.5
- 标题20-32px行高1.2-1.4
- 小号文字12px文件大小、日期等
**间距系统:**
- 基础单位8px
- 标准间距16px1rem
- 组件内边距8px-16px
**组件规范:**
- 导航栏高度48px深色背景
- 工具栏浅灰背景按钮间距8px
- 文件项最小高度44px悬停效果150ms
- 按钮圆角4px过渡150ms
**交互规范:**
- 悬停效果150ms过渡
- 触摸目标最小44x44px
- 键盘导航Tab、Enter、Delete、F2、F5、Esc
- 焦点状态2px蓝色轮廓
**响应式断点:**
- 移动端:< 768px双面板垂直排列
- 平板768px - 1024px
- 桌面:> 1024px标准布局
---
## 11.1 RESTful设计原则
### 11.1.1 URL设计规范
**设计原则:**
1. 使用名词复数形式(/api/files
2. 使用HTTP方法表示操作类型
3. 使用查询参数传递可选参数
4. 使用路径参数传递必需参数
**命名规范:**
- URL使用小写字母
- 单词之间使用连字符(-)分隔
- 资源名称使用复数形式
- 层级关系使用斜杠(/)分隔
**示例:**
```
✅ 正确:
GET /api/files/list
POST /api/files/upload
DELETE /api/files/{id}
❌ 错误:
GET /api/getFiles
POST /api/files/create
DELETE /api/deleteFile/123
```
### 11.1.2 HTTP方法映射
| 方法 | 操作 | 是否幂等 | 说明 | 示例 |
|------|------|---------|------|------|
| GET | 查询 | 是 | 获取资源列表或详情 | GET /api/files/list |
| POST | 创建 | 否 | 创建新资源 | POST /api/files/mkdir |
| PUT | 更新 | 是 | 完整更新资源 | PUT /api/files/rename |
| DELETE | 删除 | 是 | 删除资源 | DELETE /api/files/delete |
### 11.1.3 统一响应格式
**成功响应:**
```json
{
"success": true,
"message": "操作成功",
"data": {}
}
```
**失败响应:**
```json
{
"success": false,
"message": "操作失败",
"error": "错误详细信息"
}
```
**列表响应:**
```json
{
"success": true,
"message": "查询成功",
"data": [
{},
{},
{}
],
"total": 100
}
```
**分页响应:**
```json
{
"success": true,
"message": "查询成功",
"data": [],
"pagination": {
"page": 1,
"pageSize": 20,
"total": 100,
"totalPages": 5
}
}
```
## 11.2 完整API列表
### 11.2.1 连接管理API
#### 建立SFTP连接
**请求:**
```
POST /api/connection/connect
Content-Type: application/json
{
"name": "测试服务器",
"host": "192.168.1.100",
"port": 22,
"username": "root",
"password": "123456",
"privateKeyPath": "/path/to/private/key",
"passPhrase": "key_password",
"rootPath": "/home/user"
}
```
**响应:**
```json
{
"success": true,
"message": "连接成功",
"data": {
"sessionId": "sftp-12345678-1234-1234-1234-123456789abc"
}
}
```
**错误响应:**
```json
{
"success": false,
"message": "连接失败",
"error": "认证失败:用户名或密码错误"
}
```
#### 断开连接
**请求:**
```
POST /api/connection/disconnect
Content-Type: application/json
{
"sessionId": "sftp-12345678-1234-1234-1234-123456789abc"
}
```
**响应:**
```json
{
"success": true,
"message": "断开成功",
"data": null
}
```
#### 保存连接配置
**请求:**
```
POST /api/connection/save
Content-Type: application/json
{
"id": 1,
"name": "测试服务器",
"host": "192.168.1.100",
"port": 22,
"username": "root",
"password": "encrypted_password",
"privateKeyPath": "/path/to/private/key",
"passPhrase": "encrypted_key_password",
"rootPath": "/home/user",
"connectTimeout": 10000
}
```
**响应:**
```json
{
"success": true,
"message": "保存成功",
"data": {
"id": 1,
"name": "测试服务器",
"host": "192.168.1.100",
"port": 22,
"username": "root",
"createdAt": "2024-02-02T10:00:00",
"updatedAt": "2024-02-02T10:00:00"
}
}
```
#### 获取所有保存的连接
**请求:**
```
GET /api/connection/list
```
**响应:**
```json
{
"success": true,
"message": "查询成功",
"data": [
{
"id": 1,
"name": "测试服务器",
"host": "192.168.1.100",
"port": 22,
"username": "root",
"createdAt": "2024-02-02T10:00:00",
"updatedAt": "2024-02-02T10:00:00"
}
]
}
```
#### 获取指定连接
**请求:**
```
GET /api/connection/{id}
```
**响应:**
```json
{
"success": true,
"message": "查询成功",
"data": {
"id": 1,
"name": "测试服务器",
"host": "192.168.1.100",
"port": 22,
"username": "root",
"createdAt": "2024-02-02T10:00:00",
"updatedAt": "2024-02-02T10:00:00"
}
}
```
**错误响应(连接不存在):**
```json
{
"success": false,
"message": "连接不存在",
"error": "ID为1的连接不存在"
}
```
#### 删除连接配置
**请求:**
```
DELETE /api/connection/{id}
```
**响应:**
```json
{
"success": true,
"message": "删除成功",
"data": null
}
```
#### 获取活跃连接列表
**请求:**
```
GET /api/connection/active
```
**响应:**
```json
{
"success": true,
"message": "查询成功",
"data": {
"sftp-12345678-1234-1234-1234-123456789abc": {
"id": 1,
"name": "测试服务器",
"host": "192.168.1.100",
"port": 22,
"username": "root"
},
"sftp-87654321-4321-4321-4321-cba987654321": {
"id": 2,
"name": "生产服务器",
"host": "192.168.1.200",
"port": 22,
"username": "admin"
}
}
}
```
### 11.2.2 文件操作API
#### 列出文件
**请求:**
```
POST /api/files/list
Content-Type: application/json
{
"sessionId": "sftp-12345678-1234-1234-1234-123456789abc",
"path": "/home/user"
}
```
**响应:**
```json
{
"success": true,
"message": "查询成功",
"data": [
{
"name": "Documents",
"path": "/home/user/Documents",
"size": 0,
"isDirectory": true,
"modifiedTime": "2024-02-02T10:00:00",
"permissions": "drwxr-xr-x"
},
{
"name": "test.txt",
"path": "/home/user/test.txt",
"size": 1024,
"isDirectory": false,
"modifiedTime": "2024-02-02T10:00:00",
"permissions": "-rw-r--r--"
}
]
}
```
#### 获取文件信息
**请求:**
```
POST /api/files/info
Content-Type: application/json
{
"sessionId": "sftp-12345678-1234-1234-1234-123456789abc",
"path": "/home/user/test.txt"
}
```
**响应:**
```json
{
"success": true,
"message": "查询成功",
"data": {
"name": "test.txt",
"path": "/home/user/test.txt",
"size": 1024,
"isDirectory": false,
"modifiedTime": "2024-02-02T10:00:00",
"permissions": "-rw-r--r--"
}
}
```
#### 获取当前路径
**请求:**
```
GET /api/files/path?sessionId=sftp-12345678-1234-1234-1234-123456789abc
```
**响应:**
```json
{
"success": true,
"message": "查询成功",
"data": {
"path": "/home/user"
}
}
```
#### 上传文件
**请求:**
```
POST /api/files/upload
Content-Type: multipart/form-data
file: [文件内容]
targetSessionId: sftp-12345678-1234-1234-1234-123456789abc
targetPath: /home/user/
```
**响应:**
```json
{
"success": true,
"message": "上传成功",
"data": null
}
```
**错误响应:**
```json
{
"success": false,
"message": "上传失败",
"error": "目标目录不存在"
}
```
#### 下载文件
**请求:**
```
GET /api/files/download?sessionId=sftp-12345678-1234-1234-1234-123456789abc&path=/home/user/test.txt
```
**响应:**
```
[文件流]
```
**响应头:**
```
Content-Type: application/octet-stream
Content-Disposition: attachment; filename=test.txt
Content-Length: 1024
```
#### 服务器间传输
**请求:**
```
POST /api/files/transfer
Content-Type: application/json
{
"sourceSessionId": "sftp-12345678-1234-1234-1234-123456789abc",
"sourcePath": "/home/user/test.txt",
"targetSessionId": "sftp-87654321-4321-4321-4321-cba987654321",
"targetPath": "/home/target/"
}
```
**响应:**
```json
{
"success": true,
"message": "传输成功",
"data": null
}
```
#### 删除文件
**请求:**
```
DELETE /api/files/delete?sessionId=sftp-12345678-1234-1234-1234-123456789abc&path=/home/user/test.txt
```
**响应:**
```json
{
"success": true,
"message": "删除成功",
"data": null
}
```
#### 批量删除
**请求:**
```
POST /api/files/batch-delete
Content-Type: application/json
{
"sessionId": "local",
"paths": [
"C:/test/file1.txt",
"C:/test/file2.txt",
"C:/test/file3.txt"
]
}
```
**响应:**
```json
{
"success": true,
"message": "删除完成",
"data": {
"successCount": 2,
"failCount": 1,
"failedFiles": [
"C:/test/file3.txt - 没有删除权限"
]
}
}
```
#### 重命名
**请求:**
```
POST /api/files/rename
Content-Type: application/json
{
"sessionId": "sftp-12345678-1234-1234-1234-123456789abc",
"oldPath": "/home/user/old.txt",
"newPath": "/home/user/new.txt"
}
```
**响应:**
```json
{
"success": true,
"message": "重命名成功",
"data": null
}
```
#### 新建文件夹
**请求:**
```
POST /api/files/mkdir
Content-Type: application/json
{
"sessionId": "local",
"path": "C:/test/newfolder"
}
```
**响应:**
```json
{
"success": true,
"message": "创建成功",
"data": null
}
```
## 11.3 错误码定义
### 11.3.1 HTTP状态码
| 状态码 | 说明 | 使用场景 |
|--------|------|---------|
| 200 | OK | 请求成功 |
| 201 | Created | 资源创建成功 |
| 400 | Bad Request | 请求参数错误 |
| 401 | Unauthorized | 未授权(连接失败) |
| 403 | Forbidden | 权限不足 |
| 404 | Not Found | 资源不存在 |
| 500 | Internal Server Error | 服务器内部错误 |
### 11.3.2 业务错误码
```java
public enum ErrorCode {
SUCCESS(0, "成功"),
INVALID_PARAMETER(1001, "参数错误"),
CONNECTION_NOT_FOUND(2001, "连接不存在"),
CONNECTION_FAILED(2002, "连接失败"),
FILE_NOT_FOUND(3001, "文件不存在"),
FILE_ALREADY_EXISTS(3002, "文件已存在"),
INSUFFICIENT_PERMISSION(3003, "权限不足"),
DISK_SPACE_FULL(3004, "磁盘空间不足"),
OPERATION_FAILED(5000, "操作失败");
private final int code;
private final String message;
ErrorCode(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}
```
### 11.3.3 错误响应格式
```json
{
"success": false,
"message": "操作失败",
"error": {
"code": 3001,
"message": "文件不存在",
"details": "文件 /home/user/test.txt 不存在"
}
}
```
## 11.4 API版本管理
### 11.4.1 URL版本控制
```
/api/v1/connection/connect
/api/v2/connection/connect
```
### 11.4.2 请求头版本控制
```
GET /api/connection/list
Accept: application/vnd.sftp-manager.v1+json
```
### 11.4.3 查询参数版本控制
```
GET /api/connection/list?version=1
```
## 11.5 API文档生成
### 11.5.1 Swagger集成
```xml
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.14</version>
</dependency>
```
### 11.5.2 Swagger配置
```java
@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI springShopOpenAPI() {
return new OpenAPI()
.info(new Info().title("SFTP文件管理系统API")
.description("SFTP文件管理系统REST API文档")
.version("v1.0.0"));
}
}
```
### 11.5.3 注解示例
```java
@RestController
@RequestMapping("/api/connection")
@Tag(name = "连接管理", description = "SFTP连接相关接口")
public class ConnectionController {
@Operation(summary = "建立SFTP连接", description = "根据连接参数建立SFTP连接")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "连接成功"),
@ApiResponse(responseCode = "400", description = "参数错误"),
@ApiResponse(responseCode = "500", description = "连接失败")
})
@PostMapping("/connect")
public ApiResponse<String> connect(
@Parameter(description = "连接参数", required = true)
@RequestBody ConnectionRequest request) {
// 实现
}
}
```
## 11.6 API测试
### 11.6.1 Postman测试
导入以下JSON到Postman
```json
{
"info": {
"name": "SFTP Manager API",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "连接管理",
"item": [
{
"name": "建立SFTP连接",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"url": {
"raw": "{{baseUrl}}/api/connection/connect",
"host": ["{{baseUrl}}"],
"path": ["api", "connection", "connect"]
},
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"测试服务器\",\n \"host\": \"192.168.1.100\",\n \"port\": 22,\n \"username\": \"root\",\n \"password\": \"123456\"\n}"
}
}
}
]
}
]
}
```
### 11.6.2 curl测试
```bash
# 测试连接API
curl -X POST http://localhost:8080/sftp-manager/api/connection/connect \
-H "Content-Type: application/json" \
-d '{"name":"测试","host":"192.168.1.100","port":22,"username":"root","password":"123456"}'
# 测试文件列表API
curl -X POST http://localhost:8080/sftp-manager/api/files/list \
-H "Content-Type: application/json" \
-d '{"sessionId":"local","path":"C:/Users"}'
```
## 11.7 安全规范
### 11.7.1 认证与会话
- **Session 管理**:连接建立后服务端维护 `sessionId`,前端在后续请求中携带
- **敏感字段**:密码、密钥口令等不入库明文,保存连接配置时使用加密存储
- **请求头**:可在 Header 中传递 `X-Session-Id` 作为会话标识(与 body 中的 sessionId 二选一或并存校验)
### 11.7.2 CORS 配置
```java
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOriginPatterns("http://localhost:*", "https://your-domain.com")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
```
### 11.7.3 敏感数据脱敏
- 列表/详情接口返回连接信息时,不返回 `password``passPhrase`
- 日志中禁止打印密码、密钥内容;错误信息可返回“认证失败”等笼统描述
---
## 11.8 限流与性能建议
### 11.8.1 建议限流策略
| 接口类型 | 建议限流 |
|----------------|-----------------------------|
| 连接/断开 | 每 IP 每分钟 10 次 |
| 文件列表/信息 | 每 session 每秒 20 次 |
| 上传/下载 | 按连接数 + 单文件大小限制 |
| 删除/重命名 | 每 session 每秒 10 次 |
### 11.8.2 大文件与流式传输
- **上传**:使用 `multipart/form-data`,服务端流式写入,避免整文件进内存
- **下载**:使用 `InputStreamResource``StreamingResponseBody` 流式输出
- **服务器间传输**:服务端到服务端流式转发,不落本地盘(或使用临时缓冲区流式处理)
---
## 11.9 前端调用示例Vue 3 + Axios
### 11.9.1 封装 baseURL 与响应处理
```typescript
// api/client.ts
import axios, { type AxiosInstance } from 'axios';
const api: AxiosInstance = axios.create({
baseURL: '/sftp-manager/api',
timeout: 30000,
headers: { 'Content-Type': 'application/json' },
});
api.interceptors.response.use(
(res) => {
const { success, data, message } = res.data ?? {};
if (!success) return Promise.reject(new Error(message || '请求失败'));
return res.data;
},
(err) => Promise.reject(err.response?.data?.message || err.message)
);
export default api;
```
### 11.9.2 连接管理示例
```typescript
// api/connection.ts
import api from './client';
export interface ConnectParams {
name: string;
host: string;
port: number;
username: string;
password?: string;
privateKeyPath?: string;
passPhrase?: string;
rootPath?: string;
}
export function connect(params: ConnectParams) {
return api.post<{ data: { sessionId: string } }>('/connection/connect', params);
}
export function disconnect(sessionId: string) {
return api.post('/connection/disconnect', { sessionId });
}
export function getConnectionList() {
return api.get<{ data: Array<{ id: number; name: string; host: string; port: number; username: string }> }>('/connection/list');
}
```
### 11.9.3 文件操作示例
```typescript
// api/files.ts
import api from './client';
export interface FileItem {
name: string;
path: string;
size: number;
isDirectory: boolean;
modifiedTime: string;
permissions?: string;
}
export function listFiles(sessionId: string, path: string) {
return api.post<{ data: Array<FileItem> }>('/files/list', { sessionId, path });
}
export function uploadFile(sessionId: string, targetPath: string, file: File) {
const form = new FormData();
form.append('file', file);
form.append('targetSessionId', sessionId);
form.append('targetPath', targetPath);
return api.post('/files/upload', form, {
headers: { 'Content-Type': 'multipart/form-data' },
});
}
export function downloadFile(sessionId: string, path: string) {
return api.get('/files/download', {
params: { sessionId, path },
responseType: 'blob',
});
}
export function deleteFile(sessionId: string, path: string) {
return api.delete('/files/delete', { params: { sessionId, path } });
}
```
---
## 11.10 健康检查与就绪探针(可选)
便于容器化部署与负载均衡探测:
| 路径 | 方法 | 说明 |
|-------------------|------|----------------|
| `/actuator/health` | GET | 应用存活检查 |
| `/actuator/ready` | GET | 就绪(依赖就绪)|
---
## 注意事项
1. **统一响应格式**所有API使用统一的响应格式
2. **错误处理**:提供详细的错误信息
3. **参数验证**:严格验证请求参数
4. **安全性**:敏感数据加密传输
5. **性能**:大文件使用流式传输
## 下一步
完成模块11后继续模块12错误处理与日志