mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2026-01-12 17:34:12 +00:00
- 添加演练场(Playground)文档导航区到主 README - 新增 Python 解析器文档链接(开发指南、测试报告、LSP集成) - 更新前端版本号至 0.1.9b19p - 补充 Python 解析器 requests 库使用章节和官方文档链接 - 添加 JavaScript 和 Python 解析器的语言版本和官方文档 - 优化文档结构,分类为项目文档和外部资源
13 KiB
13 KiB
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 简化代码
// ✅ 推荐:使用 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)
// ✅ 推荐:使用 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. 日志记录
// ✅ 推荐:使用 @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. 异常处理
// ✅ 推荐:完整的异常处理
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 相关
测试代码
// ✅ 推荐: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
// ✅ 推荐:使用注解定义路由
@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. 响应处理
// 方式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 路由
@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. 定义实体类
// ✅ 推荐:使用注解定义实体
@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. 自动创建数据库
// ✅ 推荐:自动创建数据库
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- MySQLJDBCType.PostgreSQL- PostgreSQLJDBCType.H2DB- H2 数据库
Parser 模块
- 支持自定义解析器(Java/Python/JavaScript)
- Python 使用 GraalPy 执行
- 需要考虑安全性和沙箱隔离
- WebSocket 支持外部 Python 环境连接
// 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 配置注意事项
测试执行
# 默认打包跳过测试
mvn clean package
# 执行测试
mvn test -Dmaven.test.skip=false
mvn clean package -Dmaven.test.skip=false
模块化构建
# 构建特定模块
mvn clean package -pl parser -am
重要约定
1. 异步优先
- 所有 I/O 操作必须异步
- 使用 Vert.x Future/Promise API
- 避免阻塞 Event Loop
2. 资源管理
// ✅ 推荐:使用 try-with-resources
try (InputStream is = new FileInputStream(file)) {
// 使用资源
}
// 或者确保在 finally 中关闭
HttpClient client = vertx.createHttpClient();
// 使用后必须关闭
client.close();
3. 配置外部化
- 配置文件优先使用 JSON 格式
- 敏感信息不要硬编码
- 支持环境变量覆盖
4. 错误处理
- 使用 Future 的 recover/otherwise
- 记录详细的错误日志
- 向用户返回友好的错误信息
性能考虑
- 使用连接池: 数据库连接、HTTP 客户端
- 缓存策略: 解析结果、静态资源
- 批量操作: 避免 N+1 查询问题
- 异步非阻塞: 充分利用 Vert.x 优势
安全要求
Parser 模块安全
- 执行自定义代码必须沙箱隔离
- 限制资源访问(文件、网络)
- 设置执行超时
- 验证输入参数
// ✅ 推荐:带安全检查的执行
public Future<Result> executeUserCode(String code) {
// 验证代码
if (!SecurityValidator.isValid(code)) {
return Future.failedFuture("Invalid code");
}
// 在沙箱中执行
return sandboxExecutor.execute(code, TIMEOUT);
}
输入验证
// ✅ 推荐:验证所有外部输入
public Future<Result> parse(String url) {
if (StringUtils.isBlank(url) || !UrlValidator.isValid(url)) {
return Future.failedFuture("Invalid URL");
}
// 继续处理
}
文档和注释
JavaDoc 注释
/**
* 解析网盘链接获取下载信息
*
* @param url 网盘分享链接
* @param params 额外参数(如密码)
* @return Future<ParseResult> 解析结果
*/
public Future<ParseResult> parse(String url, Map<String, String> params) {
// 实现
}
复杂逻辑注释
// 处理特殊情况:某些网盘需要二次验证
// 参考文档:docs/parser-flow.md
if (needsSecondaryVerification) {
// 实现二次验证逻辑
}
常见模式
链式异步调用
return fetchMetadata(url)
.compose(meta -> validateMetadata(meta))
.compose(meta -> fetchDownloadUrl(meta))
.compose(downloadUrl -> generateResult(downloadUrl))
.recover(this::handleError);
事件处理
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()));
});
不应该做的事
- ❌ 在 Event Loop 线程中执行阻塞操作
- ❌ 使用
System.out.println()而不是日志框架 - ❌ 硬编码配置值(端口、路径、密钥等)
- ❌ 忽略异常或使用空 catch 块
- ❌ 返回 null,应该使用 Optional 或 Future.failedFuture()
- ❌ 在生产代码中使用
e.printStackTrace() - ❌ 直接操作 Thread 而不使用 Vert.x 的 executeBlocking
- ❌ 提交包含
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