Files
netdisk-fast-download/.github/copilot-instructions.md
q 2fcf9cfab1 docs: 更新文档导航和解析器指南
- 添加演练场(Playground)文档导航区到主 README
- 新增 Python 解析器文档链接(开发指南、测试报告、LSP集成)
- 更新前端版本号至 0.1.9b19p
- 补充 Python 解析器 requests 库使用章节和官方文档链接
- 添加 JavaScript 和 Python 解析器的语言版本和官方文档
- 优化文档结构,分类为项目文档和外部资源
2026-01-11 22:35:45 +08:00

496 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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`