mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2026-01-13 01:44:12 +00:00
docs: 更新文档导航和解析器指南
- 添加演练场(Playground)文档导航区到主 README - 新增 Python 解析器文档链接(开发指南、测试报告、LSP集成) - 更新前端版本号至 0.1.9b19p - 补充 Python 解析器 requests 库使用章节和官方文档链接 - 添加 JavaScript 和 Python 解析器的语言版本和官方文档 - 优化文档结构,分类为项目文档和外部资源
This commit is contained in:
495
.github/copilot-instructions.md
vendored
Normal file
495
.github/copilot-instructions.md
vendored
Normal file
@@ -0,0 +1,495 @@
|
||||
# GitHub Copilot Instructions - NetDisk Fast Download
|
||||
|
||||
## 项目简介
|
||||
网盘快速下载项目,支持多种网盘链接解析和下载加速的 Java Web 应用。
|
||||
|
||||
## 技术栈要求
|
||||
|
||||
### 核心技术
|
||||
- **Java**: JDK 17(必须)
|
||||
- **框架**: Vert.x 4.5.23(异步响应式框架)
|
||||
- **构建**: Maven 3.x
|
||||
- **日志**: SLF4J 2.0.5 + Logback 1.5.19
|
||||
- **前端**: Vue.js + Monaco Editor
|
||||
|
||||
### 重要依赖
|
||||
- Lombok 1.18.38 - 简化 Java 代码
|
||||
- Jackson 2.14.2 - JSON 处理
|
||||
- Commons Lang3 3.18.0 - 工具类
|
||||
- Reflections 0.10.2 - 反射工具
|
||||
|
||||
## 代码生成规范
|
||||
|
||||
### Java 代码风格
|
||||
|
||||
#### 1. 使用 Lombok 简化代码
|
||||
```java
|
||||
// ✅ 推荐:使用 Lombok 注解
|
||||
@Data
|
||||
@Builder
|
||||
@Slf4j
|
||||
public class Example {
|
||||
private String name;
|
||||
private int value;
|
||||
}
|
||||
|
||||
// ❌ 避免:手写 getter/setter
|
||||
public class Example {
|
||||
private String name;
|
||||
public String getName() { return name; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 异步编程模式(Vert.x)
|
||||
```java
|
||||
// ✅ 推荐:使用 Vert.x Future
|
||||
public Future<String> fetchData() {
|
||||
return vertx.createHttpClient()
|
||||
.request(HttpMethod.GET, "http://example.com")
|
||||
.compose(HttpClientRequest::send)
|
||||
.compose(response -> response.body())
|
||||
.map(Buffer::toString);
|
||||
}
|
||||
|
||||
// ❌ 避免:阻塞操作
|
||||
public String fetchData() {
|
||||
// 不要在 Event Loop 中执行阻塞代码
|
||||
Thread.sleep(1000); // ❌
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 日志记录
|
||||
```java
|
||||
// ✅ 推荐:使用 @Slf4j + 参数化日志
|
||||
@Slf4j
|
||||
public class Service {
|
||||
public void process(String id) {
|
||||
log.info("Processing item: {}", id);
|
||||
try {
|
||||
// ...
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to process item: {}", id, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ❌ 避免:字符串拼接
|
||||
log.info("Processing item: " + id); // 性能差
|
||||
System.out.println("Debug info"); // 不使用 System.out
|
||||
```
|
||||
|
||||
#### 4. 异常处理
|
||||
```java
|
||||
// ✅ 推荐:完整的异常处理
|
||||
public Future<Result> operation() {
|
||||
return service.execute()
|
||||
.recover(err -> {
|
||||
log.error("Operation failed", err);
|
||||
return Future.succeededFuture(Result.error(err.getMessage()));
|
||||
});
|
||||
}
|
||||
|
||||
// ❌ 避免:空的 catch 块或吞掉异常
|
||||
try {
|
||||
doSomething();
|
||||
} catch (Exception e) {
|
||||
// ❌ 空 catch
|
||||
}
|
||||
```
|
||||
|
||||
### 包和类命名
|
||||
|
||||
- 基础包名:`cn.qaiu`
|
||||
- 模块包结构:
|
||||
- `cn.qaiu.core.*` - 核心功能
|
||||
- `cn.qaiu.parser.*` - 解析器相关
|
||||
- `cn.qaiu.db.*` - 数据库相关
|
||||
- `cn.qaiu.service.*` - 业务服务
|
||||
- `cn.qaiu.web.*` - Web 相关
|
||||
|
||||
### 测试代码
|
||||
|
||||
```java
|
||||
// ✅ 推荐:JUnit 4 测试
|
||||
public class ServiceTest {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
// 初始化
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethod() {
|
||||
// Given
|
||||
String input = "test";
|
||||
|
||||
// When
|
||||
String result = service.process(input);
|
||||
|
||||
// Then
|
||||
assertEquals("expected", result);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
// 清理
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 特定模块指导
|
||||
|
||||
### Core 模块 - Web 路由封装(必须使用,禁止重复造轮子)
|
||||
|
||||
**核心思想:使用注解定义路由,框架自动处理请求和响应**
|
||||
|
||||
#### 1. 使用 @RouteHandler 和 @RouteMapping
|
||||
```java
|
||||
// ✅ 推荐:使用注解定义路由
|
||||
@RouteHandler(value = "/api/v1", order = 10)
|
||||
@Slf4j
|
||||
public class UserController {
|
||||
|
||||
private final UserService userService = AsyncServiceUtil.getAsyncServiceInstance(UserService.class);
|
||||
|
||||
// GET /api/v1/users
|
||||
@RouteMapping(value = "/users", method = RouteMethod.GET)
|
||||
public Future<JsonResult<List<User>>> getUsers() {
|
||||
return userService.findAll()
|
||||
.map(JsonResult::success)
|
||||
.otherwise(err -> JsonResult.error(err.getMessage()));
|
||||
}
|
||||
|
||||
// GET /api/v1/user/:id (路径参数自动注入)
|
||||
@RouteMapping(value = "/user/:id", method = RouteMethod.GET)
|
||||
public Future<User> getUser(String id) {
|
||||
// 返回值自动序列化为 JSON
|
||||
return userService.findById(id);
|
||||
}
|
||||
|
||||
// POST /api/v1/user (查询参数自动注入)
|
||||
@RouteMapping(value = "/user", method = RouteMethod.POST)
|
||||
public Future<JsonResult<User>> createUser(HttpServerRequest request, String name, Integer age) {
|
||||
return userService.create(name, age)
|
||||
.map(JsonResult::success);
|
||||
}
|
||||
|
||||
// 重定向示例
|
||||
@RouteMapping(value = "/redirect/:id", method = RouteMethod.GET)
|
||||
public void redirect(HttpServerResponse response, String id) {
|
||||
String targetUrl = "https://example.com/" + id;
|
||||
ResponseUtil.redirect(response, targetUrl);
|
||||
}
|
||||
}
|
||||
|
||||
// ❌ 避免:手动创建 Router 和 Handler
|
||||
Router router = Router.router(vertx);
|
||||
router.get("/api/users").handler(ctx -> {
|
||||
// 不要这样写!使用注解方式
|
||||
});
|
||||
```
|
||||
|
||||
#### 2. 自动参数注入规则
|
||||
- **路径参数**:`/user/:id` → `public Future<User> getUser(String id)`
|
||||
- **查询参数**:`?name=xxx&age=18` → `public Future<User> create(String name, Integer age)`
|
||||
- **Vert.x 对象**:自动注入 `HttpServerRequest`, `HttpServerResponse`, `RoutingContext`
|
||||
- **请求体**:POST/PUT 的 JSON 自动反序列化为方法参数对象
|
||||
|
||||
#### 3. 响应处理
|
||||
```java
|
||||
// 方式1:返回 Future,框架自动处理
|
||||
public Future<User> getUser(String id) {
|
||||
return userService.findById(id); // 自动序列化为 JSON
|
||||
}
|
||||
|
||||
// 方式2:返回 JsonResult 统一格式
|
||||
public Future<JsonResult<User>> getUser(String id) {
|
||||
return userService.findById(id).map(JsonResult::success);
|
||||
}
|
||||
|
||||
// 方式3:手动控制响应(仅在特殊情况使用)
|
||||
public void customResponse(HttpServerResponse response) {
|
||||
ResponseUtil.fireJsonObjectResponse(response, jsonObject);
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. WebSocket 路由
|
||||
```java
|
||||
@RouteHandler("/ws")
|
||||
public class WebSocketHandler {
|
||||
|
||||
@SockRouteMapper("/chat")
|
||||
public void handleChat(SockJSSocket socket) {
|
||||
socket.handler(buffer -> {
|
||||
log.info("Received: {}", buffer.toString());
|
||||
socket.write(buffer); // Echo
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Core-Database 模块 - DDL 自动生成(必须使用,禁止重复造轮子)
|
||||
|
||||
**核心思想:使用注解定义实体,自动生成建表 SQL**
|
||||
|
||||
#### 1. 定义实体类
|
||||
```java
|
||||
// ✅ 推荐:使用注解定义实体
|
||||
@Data
|
||||
@Table(value = "t_user", keyFields = "id") // 表名和主键
|
||||
public class User {
|
||||
|
||||
@Constraint(autoIncrement = true)
|
||||
private Long id; // 主键自增
|
||||
|
||||
@Constraint(notNull = true, uniqueKey = "uk_email")
|
||||
@Length(varcharSize = 100)
|
||||
private String email; // 非空 + 唯一索引 + 长度100
|
||||
|
||||
@Constraint(notNull = true)
|
||||
@Length(varcharSize = 50)
|
||||
private String name;
|
||||
|
||||
@Constraint(defaultValue = "0")
|
||||
private Integer status; // 默认值 0
|
||||
|
||||
@Constraint(defaultValue = "NOW()", defaultValueIsFunction = true)
|
||||
private Date createdAt; // 默认当前时间
|
||||
|
||||
@TableGenIgnore // 忽略此字段,不生成列
|
||||
private transient String tempField;
|
||||
}
|
||||
|
||||
// 应用启动时自动建表
|
||||
CreateTable.createTable(pool, JDBCType.MySQL);
|
||||
|
||||
// ❌ 避免:手写建表 SQL
|
||||
String sql = "CREATE TABLE t_user (id BIGINT AUTO_INCREMENT PRIMARY KEY, ...)";
|
||||
pool.query(sql).execute(); // 不要这样写!
|
||||
```
|
||||
|
||||
#### 2. 支持的注解
|
||||
|
||||
**@Table** - 表定义
|
||||
- `value` - 表名(默认类名转下划线)
|
||||
- `keyFields` - 主键字段名(默认 "id")
|
||||
|
||||
**@Constraint** - 字段约束
|
||||
- `notNull = true` - 非空约束
|
||||
- `uniqueKey = "uk_name"` - 唯一索引(相同名称的字段组成联合唯一索引)
|
||||
- `defaultValue = "value"` - 默认值
|
||||
- `defaultValueIsFunction = true` - 默认值是函数(如 NOW())
|
||||
- `autoIncrement = true` - 自增(仅用于主键)
|
||||
|
||||
**@Length** - 字段长度
|
||||
- `varcharSize = 255` - VARCHAR 长度(默认 255)
|
||||
- `decimalSize = {10, 2}` - DECIMAL 精度(默认 {22, 2})
|
||||
|
||||
**@Column** - 自定义列名
|
||||
- `name = "column_name"` - 指定数据库列名
|
||||
|
||||
**@TableGenIgnore** - 忽略字段(不生成列)
|
||||
|
||||
#### 3. 自动创建数据库
|
||||
```java
|
||||
// ✅ 推荐:自动创建数据库
|
||||
JsonObject dbConfig = new JsonObject()
|
||||
.put("jdbcUrl", "jdbc:mysql://localhost:3306/mydb")
|
||||
.put("username", "root")
|
||||
.put("password", "password");
|
||||
|
||||
CreateDatabase.createDatabase(dbConfig);
|
||||
|
||||
// ❌ 避免:手动连接和执行 CREATE DATABASE
|
||||
```
|
||||
|
||||
#### 4. 支持的数据库类型
|
||||
- `JDBCType.MySQL` - MySQL
|
||||
- `JDBCType.PostgreSQL` - PostgreSQL
|
||||
- `JDBCType.H2DB` - H2 数据库
|
||||
|
||||
### Parser 模块
|
||||
- 支持自定义解析器(Java/Python/JavaScript)
|
||||
- Python 使用 GraalPy 执行
|
||||
- 需要考虑安全性和沙箱隔离
|
||||
- WebSocket 支持外部 Python 环境连接
|
||||
|
||||
```java
|
||||
// Parser 接口实现示例
|
||||
public class CustomParser implements IParser {
|
||||
@Override
|
||||
public Future<ParseResult> parse(String url, Map<String, String> params) {
|
||||
return Future.future(promise -> {
|
||||
// 异步解析逻辑
|
||||
promise.complete(result);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Maven 配置注意事项
|
||||
|
||||
### 测试执行
|
||||
```bash
|
||||
# 默认打包跳过测试
|
||||
mvn clean package
|
||||
|
||||
# 执行测试
|
||||
mvn test -Dmaven.test.skip=false
|
||||
mvn clean package -Dmaven.test.skip=false
|
||||
```
|
||||
|
||||
### 模块化构建
|
||||
```bash
|
||||
# 构建特定模块
|
||||
mvn clean package -pl parser -am
|
||||
```
|
||||
|
||||
## 重要约定
|
||||
|
||||
### 1. 异步优先
|
||||
- 所有 I/O 操作必须异步
|
||||
- 使用 Vert.x Future/Promise API
|
||||
- 避免阻塞 Event Loop
|
||||
|
||||
### 2. 资源管理
|
||||
```java
|
||||
// ✅ 推荐:使用 try-with-resources
|
||||
try (InputStream is = new FileInputStream(file)) {
|
||||
// 使用资源
|
||||
}
|
||||
|
||||
// 或者确保在 finally 中关闭
|
||||
HttpClient client = vertx.createHttpClient();
|
||||
// 使用后必须关闭
|
||||
client.close();
|
||||
```
|
||||
|
||||
### 3. 配置外部化
|
||||
- 配置文件优先使用 JSON 格式
|
||||
- 敏感信息不要硬编码
|
||||
- 支持环境变量覆盖
|
||||
|
||||
### 4. 错误处理
|
||||
- 使用 Future 的 recover/otherwise
|
||||
- 记录详细的错误日志
|
||||
- 向用户返回友好的错误信息
|
||||
|
||||
## 性能考虑
|
||||
|
||||
1. **使用连接池**: 数据库连接、HTTP 客户端
|
||||
2. **缓存策略**: 解析结果、静态资源
|
||||
3. **批量操作**: 避免 N+1 查询问题
|
||||
4. **异步非阻塞**: 充分利用 Vert.x 优势
|
||||
|
||||
## 安全要求
|
||||
|
||||
### Parser 模块安全
|
||||
- 执行自定义代码必须沙箱隔离
|
||||
- 限制资源访问(文件、网络)
|
||||
- 设置执行超时
|
||||
- 验证输入参数
|
||||
|
||||
```java
|
||||
// ✅ 推荐:带安全检查的执行
|
||||
public Future<Result> executeUserCode(String code) {
|
||||
// 验证代码
|
||||
if (!SecurityValidator.isValid(code)) {
|
||||
return Future.failedFuture("Invalid code");
|
||||
}
|
||||
|
||||
// 在沙箱中执行
|
||||
return sandboxExecutor.execute(code, TIMEOUT);
|
||||
}
|
||||
```
|
||||
|
||||
### 输入验证
|
||||
```java
|
||||
// ✅ 推荐:验证所有外部输入
|
||||
public Future<Result> parse(String url) {
|
||||
if (StringUtils.isBlank(url) || !UrlValidator.isValid(url)) {
|
||||
return Future.failedFuture("Invalid URL");
|
||||
}
|
||||
// 继续处理
|
||||
}
|
||||
```
|
||||
|
||||
## 文档和注释
|
||||
|
||||
### JavaDoc 注释
|
||||
```java
|
||||
/**
|
||||
* 解析网盘链接获取下载信息
|
||||
*
|
||||
* @param url 网盘分享链接
|
||||
* @param params 额外参数(如密码)
|
||||
* @return Future<ParseResult> 解析结果
|
||||
*/
|
||||
public Future<ParseResult> parse(String url, Map<String, String> params) {
|
||||
// 实现
|
||||
}
|
||||
```
|
||||
|
||||
### 复杂逻辑注释
|
||||
```java
|
||||
// 处理特殊情况:某些网盘需要二次验证
|
||||
// 参考文档:docs/parser-flow.md
|
||||
if (needsSecondaryVerification) {
|
||||
// 实现二次验证逻辑
|
||||
}
|
||||
```
|
||||
|
||||
## 常见模式
|
||||
|
||||
### 链式异步调用
|
||||
```java
|
||||
return fetchMetadata(url)
|
||||
.compose(meta -> validateMetadata(meta))
|
||||
.compose(meta -> fetchDownloadUrl(meta))
|
||||
.compose(downloadUrl -> generateResult(downloadUrl))
|
||||
.recover(this::handleError);
|
||||
```
|
||||
|
||||
### 事件处理
|
||||
```java
|
||||
vertx.eventBus().<JsonObject>consumer("parser.request", msg -> {
|
||||
JsonObject body = msg.body();
|
||||
parse(body.getString("url"))
|
||||
.onSuccess(result -> msg.reply(JsonObject.mapFrom(result)))
|
||||
.onFailure(err -> msg.fail(500, err.getMessage()));
|
||||
});
|
||||
```
|
||||
|
||||
## 不应该做的事
|
||||
|
||||
1. ❌ 在 Event Loop 线程中执行阻塞操作
|
||||
2. ❌ 使用 `System.out.println()` 而不是日志框架
|
||||
3. ❌ 硬编码配置值(端口、路径、密钥等)
|
||||
4. ❌ 忽略异常或使用空 catch 块
|
||||
5. ❌ 返回 null,应该使用 Optional 或 Future.failedFuture()
|
||||
6. ❌ 在生产代码中使用 `e.printStackTrace()`
|
||||
7. ❌ 直接操作 Thread 而不使用 Vert.x 的 executeBlocking
|
||||
8. ❌ 提交包含 `logs/` 目录的代码
|
||||
|
||||
## 代码审查清单
|
||||
|
||||
生成代码时请确保:
|
||||
- [ ] 使用 Lombok 注解简化代码
|
||||
- [ ] 异步操作使用 Vert.x Future
|
||||
- [ ] 添加了 @Slf4j 和适当的日志
|
||||
- [ ] 异常处理完整
|
||||
- [ ] 输入参数已验证
|
||||
- [ ] 资源正确释放
|
||||
- [ ] 添加了必要的 JavaDoc
|
||||
- [ ] 遵循项目包命名规范
|
||||
- [ ] 没有阻塞操作在 Event Loop 中
|
||||
- [ ] 测试用例覆盖主要场景
|
||||
|
||||
## 参考资源
|
||||
|
||||
- Vert.x 文档: https://vertx.io/docs/
|
||||
- 项目 Parser 文档: `parser/doc/`
|
||||
- 前端文档: `web-front/doc/`
|
||||
- 安全测试指南: `parser/doc/SECURITY_TESTING_GUIDE.md`
|
||||
Reference in New Issue
Block a user