Skip to main contentjava-code-review
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DDL质量)。
跳到安装 用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/luokai0/ai-agent-skills-by-luo-kai --skill java-code-review命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
writers-room-story-engine Writers Room Story Engine mega-skill. Creates, structures, drafts, and revises compelling standalone stories from zero using premise generation, audience engagement, thematic design, character arcs, Story Spine structure, causal beats, worldbuilding in service of story, scene construction, and revision diagnostics. Use when developing short stories, standalone fiction, scripts, or narrative concepts from scratch or when improving weak drafts.
| name | java-code-review |
| description | Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DDL质量)。 |
| category | development |
| risk | safe |
| source | custom |
| date_added | 2026-04-28 |
| author | user |
| tags | ["java","code-review","git-diff","business-analysis","risk-detection","performance","optimization","spring","mybatis","transaction","sql-ddl","concurrency","scoring","prd","null-safety","streams","exception-handling","resource-management","api-design"] |
| tools | ["git","glob","grep","read","write","bash","lsp_diagnostics","ast_grep_search","lsp_find_references","lsp_goto_definition"] |
| compatibility | opencode |
| trigger_phrase | ["代码评审","review代码","分析变更","代码检查","检查bug","风险分析","性能检查","需求分析","业务分析","生成PRD"] |
Java Code Review - Java项目代码评审工具
概述
智能化Java项目代码评审工具,完整流程(7步):
- Git Diff 变更获取 - 拉取代码变更内容(支持 --cached / 分支对比)
- 完整上下文分析 - 分析调用链路,推断业务逻辑
- PRD文档生成 - 覆盖所有变更点(新增+修改)
- 代码检测(P0/P1快速扫描) - 严重缺陷和代码缺陷快速定位
- 细粒度代码审查清单 - 12类深度检查(A-L):Null安全、异常处理、Streams、并发、Java惯用法、资源管理、API设计、性能、测试、MyBatis/ORM、事务边界、SQL/DDL质量
- 多维度评分 - 代码质量评分
- Review报告生成 - 输出结构化报告
何时使用此技能
- 用户需要进行代码评审
- 用户需要理解变更的业务含义
- 用户需要生成完整PRD文档
- 用户需要评分和质量评估
- 用户说 "review代码" / "检查PR" / "代码review" / "检查下代码"
第1步:Git Diff 变更获取
1.1 确定基准分支
优先询问用户,如用户未指定则使用以下策略:
- 当前分支有上游跟踪 → 使用
@{u}(上游分支)
- 存在
develop 分支 → 使用 develop
- 存在
main/master 分支 → 使用 main/master
- 否则 → 使用
HEAD~10(最近10次提交)
1.2 获取变更
git diff <基准分支>..HEAD --name-only
git diff <基准分支>..HEAD -U500
git diff <基准分支>..HEAD --stat
git diff --cached -U500
git diff --cached --stat
git diff -U500
1.3 收集信息
- 新增的文件(新增功能)
- 修改的文件(功能修改)
- 删除的文件(功能删除)
- 变更行数统计
第2步:完整上下文分析
2.1 确定入口点
对于每个变更的方法/类,向上追溯找到业务入口:
- Controller层的HTTP入口(@PostMapping/@GetMapping)
- Service层的业务入口方法
- MQ消息入口(@RabbitListener/@KafkaListener)
- 定时任务入口(@Scheduled)
- 外部API入口(Feign Client)
2.2 追踪方法链
使用 lsp_find_references 分析每个关键方法:
入口点
↓ 调用
变更方法
↓ 调用
子方法1 → 子方法2 → ... → 数据库/外部服务
2.3 业务逻辑推断
基于完整链路推断业务逻辑:
变更方法:InventoryService.deduct()
完整链路:
Controller.createOrder() [下单入口]
↓
OrderService.create() [订单创建]
↓
InventoryService.deduct() [变更点] ← 库存扣减
↓
PaymentService.pay() [支付]
↓
NotificationService.notify() [通知]
推断业务需求:
用户下单 → 自动扣减库存 → 支付 → 通知
核心流程:订单+库存+支付+消息 四模块联动
第3步:PRD文档生成(核心能力)
重要:PRD必须覆盖所有变更点,包括新增功能和修改功能。
3.1 PRD文档结构
# 产品需求文档 PRD
## 1. 概述
### 1.1 产品名称
[模块名称-版本号]
### 1.2 需求背景
[为什么需要这个功能,解决什么问题]
### 1.3 需求范围
- 涉及模块:xxx
- 用户类型:xxx
- 使用场景:xxx
---
## 2. 功能需求
### 2.1 功能清单
| # | 功能点名称 | 功能类型 | 优先级 | 涉及文件 | 行号 |
|---|-----------|--------|--------|---------|-----|
| 1 | 功能点A | 新增 | P0 | XxxService.java | 1-100 |
| 2 | 功能点B | 新增 | P1 | XxxServiceImpl.java | 200-300 |
| 3 | 功能点C | 修改 | P2 | XxxConverter.java | 10-30 |
| 4 | 字段调整 | 修改 | P2 | DDL脚本 | - |
### 2.2 功能详情(每个变更点都需要详细描述)
#### 2.2.1 [功能点A-新增功能]
**功能类型**:新增
**功能描述**:
[详细描述这个功能做什么]
**业务规则**:
- 规则1
- 规则2
**核心链路**:
[入口] Controller.method() [POST /api/xxx]
↓ Service.method()
[核心] 核心业务逻辑 ← 变更内容
↓ DAO.method()
[终点] 数据库/外部服务
**入参说明**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| param1 | String | 是 | xxx |
| param2 | Integer | 否 | xxx |
**出参说明**:
| 参数 | 类型 | 说明 |
|------|------|------|
| result1 | String | xxx |
**异常处理**:
| 异常场景 | 错误码 | 提示信息 |
|----------|--------|----------|
| 场景1 | E_xxx | xxx |
---
#### 2.2.2 [功能点B-修改功能]
**功能类型**:修改
**涉及文件**:`xxx.java`
**涉及行号**:xxx-xxx
**修改前**:
```java
// 原代码
[入口] Controller.method() [POST /api/xxx]
↓ Service.method()
[核心] 修改的方法 ← 变更内容
↓ DAO.method()
[终点] 数据库/外部服务
- 影响的上游:xxx
- 影响的下游:xxx
- 兼容性:是否向前兼容
- 数据库:是否需要迁移
2.2.3 [功能点C-优化功能]
3. 数据库变更
3.1 新增表
CREATE TABLE xxx (
id VARCHAR(36) PRIMARY KEY,
tenant_id VARCHAR(32) NOT NULL,
org_id VARCHAR(32),
doc_id VARCHAR(36) NOT NULL,
retry_type VARCHAR(32),
retry_count INT DEFAULT 0,
last_retry_time DATETIME,
create_time DATETIME NOT NULL,
PRIMARY KEY (id),
KEY idx_doc_id (doc_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='xxx表';
3.2 修改表
ALTER TABLE xxx MODIFY COLUMN goods_name VARCHAR(300) COMMENT '商品名称';
ALTER TABLE xxx ADD COLUMN operator VARCHAR(300) COMMENT '操作人';
3.3 数据迁移
4. 接口设计
4.1 新增接口
| 接口名称 | 请求方式 | 路径 | 说明 |
|---|
| 接口A | POST | /api/xxx | xxx |
{
"ids": ["xxx"],
"operator": "xxx"
}
{
"code": "0",
"message": "成功",
"data": null
}
4.2 修改接口
| 接口名称 | 请求方式 | 路径 | 说明 |
|---|
| 接口A | POST | /api/xxx | 参数调整 |
5. 涉及的代码变更
5.1 新增文件
5.2 修改文件
| 文件路径 | 修改内容 |
|---|
| xxx.java | 方法A新增、方法B修改 |
5.3 删除文件
6. 非功能需求
6.1 性能要求
- 响应时间:< xxx ms
- 并发能力:xxx TPS
6.2 安全要求
6.3 兼容性要求
- 向前兼容:是/否
- 多数据库支持:MySQL/Oracle/PostgreSQL
7. 测试要点
7.1 功能测试
7.2 异常测试
7.3 边界测试
7.4 回归测试
8. 上线注意点
9. 变更记录
| 版本 | 日期 | 变更内容 | 作者 |
|---|
| v2.4.0.0 | 2026-04-30 | 初始版本 | xxx |
---
## 第4步:代码检测(P0/P1快速扫描)
在进入细粒度审查前,先快速扫描严重缺陷和代码缺陷。
### P0严重缺陷
| 检查项 | 检测模式 | 扣分 |
|--------|----------|------|
| 空指针 | `$OBJ.$METHOD()` obj未检查 | -10 |
| SQL注入 | `"SELECT " + $TABLE` 直接拼接 | -10 |
| 密钥泄露 | `password/token = "xxx"` | -10 |
| 事务缺失 | @Transactional 关键方法无事务 | -10 |
### P1代码缺陷
| 检查项 | 检测模式 | 扣分 |
|--------|----------|------|
| 资源泄漏 | new FileInputStream 未关闭 | -5 |
| 线程安全 | private static 共享变量 | -5 |
| 空catch | catch块为空或仅打印日志 | -5 |
| 循环查询 | for循环内数据库操作 | -5 |
### P2代码规范(快速扫描)
以下为不与第5步细粒度审查清单重叠的独立检查项:
| 检查项 | 检测模式 | 扣分 |
|--------|----------|------|
| 参数过多 | 方法参数超过3个 | -2 |
| 魔法数字 | 字面量未定义为常量 | -2 |
| 原始泛型 | List/Map 未指定类型参数 | -2 |
> **注意**:Streams滥用、Boolean参数、Optional.get()、equals缺hashCode、catch Exception 等 P2 检查项已整合到第5步对应分类中,此处不再重复。
---
## 第5步:细粒度代码审查清单 (Detailed Review Checklist)
### 审查策略
1. **Quick scan** - 理解变更意图,确定审查范围
2. **Checklist pass** - 按以下分类逐项检查
3. **Summary** - 按严重度汇总(Critical → Improvement → Minor)
### A. Null 安全
```java
// ❌ NPE 风险:链式调用不检查中间null
String name = user.getName().toUpperCase();
// ✅ 安全:Optional + map
String name = Optional.ofNullable(user.getName())
.map(String::toUpperCase)
.orElse("");
// ✅ 也可以:提前返回
if (user.getName() == null) {
return "";
}
return user.getName().toUpperCase();
grep: Optional\.get\(\) → 检查是否有 isPresent() 先导
ast_grep_search: $OBJ.$METHOD() pattern 查找链式调用中缺少 null 守卫
lsp_find_references: 追踪方法返回 null 的调用方
- 返回值可能为空时,使用
Optional<T> 替代 null
- 构造/方法入参使用
Objects.requireNonNull()
- 返回空集合用
Collections.emptyList() 替代 null
B. 异常处理
try {
process();
} catch (Exception e) {
}
catch (Exception e) { }
catch (Throwable t) { }
catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
catch (IOException e) {
log.error("处理文件失败: {}", filename, e);
throw new ProcessingException("文件处理失败", e);
}
ast_grep_search: catch (Exception 和 catch (Throwable → 宽泛捕获
grep: catch\s*\( 带上下文行查找空 catch 块
grep: throw new.*getMessage\(\) → 丢失原始异常栈
- 日志同时记录上下文 + 完整栈信息
- 使用具体的异常子类
- 领域错误使用自定义异常
C. Streams & 集合操作
for (Item item : items) {
if (item.isExpired()) {
items.remove(item);
}
}
items.removeIf(Item::isExpired);
list.stream().forEach(System.out::println);
for (Item item : list) {
System.out.println(item);
}
List<String> names = users.stream()
.map(User::getName)
.collect(Collectors.toList());
names.add("extra");
List<String> names = users.stream()
.map(User::getName)
.collect(Collectors.toCollection(ArrayList::new));
ast_grep_search: .stream().forEach → 可能的滥用模式
grep: \.remove\( 在 for\s*\( 块内 → 遍历时修改
grep: \.collect\(Collectors\.toList\(\)\) → 检查后续是否有 add/remove 操作
- 防御性拷贝用
List.copyOf()
- Stream 用于数据转换,循环用于副作用操作
- 简单逻辑(1-2行映射)用Stream,复杂逻辑用for循环
D. 并发安全
private Map<String, User> cache = new HashMap<>();
private Map<String, User> cache = new ConcurrentHashMap<>();
if (!map.containsKey(key)) {
map.put(key, computeValue());
}
map.computeIfAbsent(key, k -> computeValue());
if (instance == null) {
synchronized(this) {
if (instance == null) {
instance = new Instance();
}
}
}
private volatile Instance instance;
grep: private static.*Map|List|Set → 静态共享集合
ast_grep_search: synchronized\( → 检查同步对象是否为 final
grep: if \(.*== null\) 在 synchronized 块内 → 双重检查锁
- 优先使用不可变对象
- 优先用
java.util.concurrent 并发集合类
- 简单场景用
AtomicReference, AtomicInteger
- 考虑添加
@ThreadSafe / @NotThreadSafe 注解
E. Java 惯用法 (equals/hashCode/toString/Builder)
@Override
public boolean equals(Object o) { ... }
@Override
public int hashCode() {
return Objects.hash(id, mutableField);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User user)) return false;
return Objects.equals(id, user.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
return "User{password='" + password + "'}";
return "User{id=" + id + ", name='" + name + "'}";
User user = User.builder()
.name("张三")
.email("zhangsan@example.com")
.build();
ast_grep_search: public boolean equals → 检查同文件是否有 public int hashCode
grep: Objects\.hash\(.*this\. → hashCode 使用了实例字段(可能可变)
grep: password|secret|token 在 toString\(\) 方法内 → 敏感数据泄露
F. 资源管理 (Try-with-resources)
FileInputStream fis = new FileInputStream(file);
try (FileInputStream fis = new FileInputStream(file)) {
}
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
}
try (FileWriter fw = new FileWriter(file);
BufferedWriter writer = new BufferedWriter(fw)) {
}
grep: new (File|Input|Output|Reader|Writer|Connection|Statement) → 检查是否在 try-with-resources 内
ast_grep_search: new $CLOSEABLE($$$) 不在 try ( 块内 → 资源泄漏风险
强制规则:任何实现了 Closeable/AutoCloseable 的资源,必须使用 try-with-resources。
G. API 设计
process(data, true, false);
process(data, ProcessMode.ASYNC, ErrorHandling.STRICT);
public User findById(Long id) {
return users.get(id);
}
public Optional<User> findById(Long id) {
return Optional.ofNullable(users.get(id));
}
public void process(List<Item> items) {
if (items == null) items = Collections.emptyList();
}
public void process(List<Item> items) {
Objects.requireNonNull(items, "items must not be null");
}
ast_grep_search: $VISIBILITY $RET $NAME(boolean $PARAM → Boolean 参数
grep: public.*\(.*,.*,.*,.*, → 参数超过3个的方法签名
grep: Objects\.requireNonNull → 检查公共方法是否都有入参校验
H. 性能注意事项
String result = "";
for (String s : strings) {
result += s;
}
StringBuilder sb = new StringBuilder();
for (String s : strings) {
sb.append(s);
}
for (String line : lines) {
if (line.matches("pattern.*")) { }
}
private static final Pattern PATTERN = Pattern.compile("pattern.*");
for (String line : lines) {
if (PATTERN.matcher(line).matches()) { }
}
for (User user : users) {
List<Order> orders = orderRepo.findByUserId(user.getId());
}
Map<Long, List<Order>> ordersByUser = orderRepo.findByUserIds(userIds);
grep: \+= 在 for\s*\( 块内 → 循环内 String 拼接
grep: \.matches\( 在 for\s*\( 块内 → 循环内正则编译
ast_grep_search: for.*\{.*\.(select|find|query) → N+1 查询模式
I. 测试提示
glob: **/src/test/**/*Test*.java → 检查是否有对应测试文件
grep: @Test → 统计测试方法数量 vs 变更方法数量
J. MyBatis/ORM 检查
for (Order order : orders) {
List<OrderItem> items = orderItemMapper.selectByOrderId(order.getId());
order.setItems(items);
}
List<Long> orderIds = orders.stream().map(Order::getId).collect(Collectors.toList());
List<OrderItem> allItems = orderItemMapper.selectByOrderIds(orderIds);
Map<Long, List<OrderItem>> itemsMap = allItems.stream()
.collect(Collectors.groupingBy(OrderItem::getOrderId));
orders.forEach(o -> o.setItems(itemsMap.getOrDefault(o.getId(), Collections.emptyList())));
List<User> allUsers = userMapper.selectAll();
List<User> page = allUsers.subList(offset, offset + limit);
PageHelper.startPage(pageNum, pageSize);
List<User> users = userMapper.selectByCondition(condition);
grep: <select|<update|<insert|<delete 在 *.xml → 检查 id 命名是否与方法名一致
ast_grep_search: for.*\{.*Mapper\.|for.*\{.*mapper\. → N+1 查询模式
grep: PageHelper\.startPage → 检查是否紧跟 Mapper 调用(分页生效)
grep: \$\{ 在 *.xml → SQL 注入风险(应使用 #{})
K. 事务边界检查
@Transactional(propagation = Propagation.REQUIRED)
public void processOrder(Order order) {
orderMapper.update(order);
paymentService.pay(order);
}
public void batchProcess(List<Order> orders) {
for (Order order : orders) {
this.processSingle(order);
}
}
@Transactional
public void processSingle(Order order) { ... }
@Transactional
public void exportReport() {
List<Data> data = dataMapper.selectAll();
File file = generateExcel(data);
emailService.send(file);
}
grep: @Transactional → 检查 propagation 属性
grep: REQUIRES_NEW → 嵌套事务回滚边界
grep: @Transactional 在非 public 方法上 → 事务不生效
ast_grep_search: @Transactional.*\{.*(?:send|http|file|sleep) → 长事务嫌疑
L. SQL/DDL 质量检查
CREATE TABLE t_order (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL,
order_no VARCHAR(64) NOT NULL,
status TINYINT,
create_time DATETIME
) ENGINE=InnoDB;
CREATE TABLE t_order (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL,
order_no VARCHAR(64) NOT NULL,
status TINYINT DEFAULT 0,
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_user_id (user_id),
UNIQUE KEY uk_order_no (order_no),
KEY idx_status_create (status, create_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
ALTER TABLE t_order ADD COLUMN amount VARCHAR(32);
ALTER TABLE t_order ADD COLUMN amount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '订单金额';
grep: CREATE TABLE 无 COMMENT → 缺表注释
grep: ALTER TABLE → 检查是否有对应回滚脚本
grep: VARCHAR\( → 检查长度是否合理(如 VARCHAR(1) 或 VARCHAR(5000))
grep: amount|price|money.*VARCHAR → 金额字段类型不当
严重度分级参考
| 严重度 | 标准 | 对应评分 |
|---|
| Critical | 安全漏洞、可能丢失数据、生产环境必崩 | P0 (-10) |
| High | 大概率Bug、严重性能问题、破坏API契约 | P1 (-5) |
| Medium | 代码坏味、可维护性问题、缺少最佳实践 | P2 (-2) |
| Low | 风格问题、微优化、建议性 | P2 (-2) |
第6步:多维度评分系统
评分维度
| 维度 | 权重 | 计算方式 |
|---|
| 代码质量 | 20% | (100 - 扣分) * 权重 |
| 安全性 | 25% | (100 - P0问题*10) * 权重 |
| 性能 | 20% | (100 - 性能问题*8) * 权重 |
| 可维护性 | 15% | (100 - 规范问题*5) * 权重 |
| 业务风险 | 20% | (100 - 风险问题*10) * 权重 |
扣分规则
| 问题类型 | 扣分 |
|---|
| P0问题 | -10分/个 |
| P1问题 | -5分/个 |
| P2建议 | -2分/个 |
最终评级
| 等级 | 分数 | 颜色 | 行动 |
|---|
| S | 90-100 | 🟢 绿 | 可合并 |
| A | 80-89 | 🟢 绿 | 可合并 |
| B | 70-79 | 🟡 黄 | 需要确认 |
| C | 60-69 | 🟠 橙 | 需要修改 |
| D | <60 | 🔴 红 | 拒绝合并 |
第7步:Review报告生成
# 代码评审报告
## 基本信息
- 项目名称:xxx
- 评审范围:xxx → xxx
- 变更文件数:N
- 变更行数:+X / -Y
## 📊 质量评分
| 维度 | 得分 | 评级 |
|------|------|------|
| 代码质量 | 85 | A |
| 安全性 | 90 | S |
| 性能 | 80 | A |
| 可维护性 | 75 | B |
| 业务风险 | 70 | B |
| **总分** | **82** | **A** |
## 📋 需求汇总
### 需求1:[功能点A]
- 涉及文件:XxxService.java (新增100行)
- 变更类型:新增功能
- 入口:XxxController.create() (POST /api/xxx)
- 核心链路:
[入口] XxxController.create()
↓ XxxService.process()
[核心] XxxHandler.handle() ← 变更点
↓ XxxRepository.save()
[终点] 数据库持久化
- 风险等级:🟡 中
### 需求2:[功能点B]
- 涉及文件:XxxServiceImpl.java, XxxController.java
- 变更类型:新增功能
- 入口:POST /api/xxx/action
- 核心链路:
[入口] XxxController.action()
[核心] XxxServiceImpl.action() ← 变更点
↓ 逻辑处理
[终点] 数据库更新
- 风险等级:🟡 中
## 🔴 严重问题 (P0)
- [ ] 问题1
- 文件:xxx.java
- 行号:xxx
- 修复方案
## 🟡 中等问题 (P1)
- [ ] 问题1
- 文件:xxx.java
- 优化方案
## 🟢 建议优化 (P2)
- [ ] 优化1
## 评审结论
- 总体评级:S/A/B/C/D
- 是否可以合并:是/需修改/拒绝
输出
- Review报告 →
code-review-report.md(含评分 + 业务分析 + 细粒度代码检查)
- PRD文档 →
prd-{版本号}.md
- 控制台摘要 → 评分+问题统计
Review 执行流程总结
Trigger: "review代码" / "检查PR" / "代码评审"
Step 1: git diff 获取变更
├─ 确定基准分支(询问用户 / 自动检测)
├─ 支持 --cached(仅暂存区)/ 分支对比
├─ 统计变更文件和行数
└─ 识别变更类型(新增/修改/删除)
Step 2: 上下文分析
├─ lsp_find_references 追踪调用链
├─ 确定业务入口(Controller/MQ/定时任务/Feign)
└─ 推断业务逻辑
Step 3: PRD文档生成(覆盖所有变更点)
├─ 功能清单(含文件+行号)
├─ 核心链路图
├─ 数据库变更
└─ 接口设计
Step 4: 代码检测(P0/P1快速扫描)
├─ P0严重缺陷(NPE/SQL注入/密钥/事务)
├─ P1代码缺陷(资源泄漏/线程安全/空catch/循环查询)
└─ P2代码规范(参数过多/魔法数字/原始泛型)
Step 5: 细粒度审查清单(12类深度检查)
├─ A. Null安全
├─ B. 异常处理
├─ C. Streams & 集合
├─ D. 并发安全
├─ E. Java惯用法 (equals/hashCode)
├─ F. 资源管理 (try-with-resources)
├─ G. API设计
├─ H. 性能
├─ I. 测试提示
├─ J. MyBatis/ORM 检查
├─ K. 事务边界检查
└─ L. SQL/DDL 质量检查
Step 6: 多维度评分
├─ 代码质量 20%
├─ 安全性 25%
├─ 性能 20%
├─ 可维护性 15%
└─ 业务风险 20%
Step 7: 生成Review报告
├─ 基本信息
├─ 质量评分(含维度拆分)
├─ 需求汇总(含调用链路)
├─ 问题清单(Critical/High/Medium/Low)
└─ 评审结论
PRD生成 Checklist