AgentSkillsCN

java-review

Java/Spring Boot 代码审查规范。 使用场景:当用户要求对 Java 代码进行 review、检查、审查时调用。 典型触发词:review、检查代码、审查、对照规范、code review、检查一下、java review 功能:对照 Java/Spring Boot 编码规范,逐项检查代码质量,输出问题清单和修复建议。 规范来源:基于 java-spring-guidelines SKILL 的规范内容

SKILL.md
--- frontmatter
name: java-review
description: |
  Java/Spring Boot 代码审查规范。

  使用场景:当用户要求对 Java 代码进行 review、检查、审查时调用。
  典型触发词:review、检查代码、审查、对照规范、code review、检查一下、java review

  功能:对照 Java/Spring Boot 编码规范,逐项检查代码质量,输出问题清单和修复建议。

  规范来源:基于 java-spring-guidelines SKILL 的规范内容
allowed-tools: Read, Grep, Glob, Edit, Write
user-invocable: true
metadata:
  version: "8.0"
  compatibility: Spring Boot 2.7+ / 3.x, MyBatis Plus 3.5+
  based-on: java-spring-guidelines v5.0

Java/Spring Boot 代码审查规范

版本: 8.0 | 模式: Code Review | 检查项: 25 | 更新: 2026-01-28

本规范基于 java-spring-guidelines v5.0 编写


使用方式

用户在代码编写完成后,输入以下命令触发审查:

code
/java-review

或自然语言:

  • "对照规范检查一下"
  • "review 刚才写的代码"
  • "帮我审查这些修改"
  • "java review"
  • "检查代码质量"

审查流程

第一步:识别审查范围

确定需要审查的代码:

  • 本次会话新增/修改的文件
  • 用户指定的文件或目录
  • 最近 git 变更的文件
  • 用户粘贴的代码片段

第二步:逐项检查

按以下检查清单逐项审查,输出格式:

code
## 审查结果

### ✅ 通过项
- [检查项]: 通过

### ❌ 问题项
- [检查项]: 问题描述
  - 位置: `文件路径:行号`
  - 问题: 具体问题
  - 修复: 建议的修改

第三步:提供修复

对于问题项,直接提供修复代码或询问用户是否自动修复。


检查清单

1. 命名规范检查

检查项规则严重度
Controller 类必须以 Controller 结尾⚠️ 中
Service 接口必须以 I*Service 命名⚠️ 中
Service 实现必须以 *ServiceImpl 结尾⚠️ 中
Mapper 接口必须以 *Mapper 结尾⚠️ 中
实体类驼峰命名,与表名对应⚠️ 中
DTO 类必须以 *DTO 结尾⚠️ 中
请求对象必须以 *Req 结尾⚠️ 中
响应对象必须以 *Rsp 结尾⚠️ 中
枚举类必须以 *Enum 结尾⚠️ 中
方法/字段lowerCamelCase⚠️ 中
常量UPPER_SNAKE_CASE⚠️ 中
接口路径kebab-case(如 /product-catalog/page⚠️ 中

检查示例

java
// ❌ 问题
class ProductCtrl { }
class ProductImpl { }
interface IProduct { }

// ✅ 正确
class ProductController { }
class ProductServiceImpl implements IProductService { }
interface IProductService { }

2. Import 规范检查

检查项规则严重度
全限定类名禁止使用(如 java.util.List),必须先 import⚠️ 中
静态导入常量和静态方法使用 import static⚡ 低
通配符导入禁止 import xxx.*⚠️ 中

检查示例

java
// ❌ 问题
public java.util.List<String> getList() {
    return new java.util.ArrayList<>();
}
import com.dsl.service.*;

// ✅ 正确
import java.util.List;
import java.util.ArrayList;
import static com.dsl.base.exception.util.ServiceExceptionUtil.exception;

3. 类结构检查

检查项规则严重度适用范围
Controller 类注解建议有 @Validated(视业务需求)⚡ 低新建类
Service 类注解必须有 @Slf4j + @RequiredArgsConstructor⚠️ 中新建类
依赖注入方式新建类必须构造器注入,存量类不强制修改⚠️ 中新建类
类命名Controller/Service/Mapper/DTO 等后缀正确⚠️ 中所有

注意:存量代码中的 @Autowired 字段注入无需修改,只对新建类做要求。

检查示例

java
// ✅ 新建类应该这样写
@Service
@Slf4j
@RequiredArgsConstructor
public class ProductServiceImpl implements IProductService {
    private final ProductMapper productMapper;
}

// ⚠️ 存量代码(不强制修改)
@Service
public class ProductService {
    @Autowired
    private ProductMapper productMapper;
}

4. Controller 层检查

检查项规则严重度说明
职责边界禁止在 Controller 写业务逻辑🔴 高只接收参数、调用 Service、返回结果
返回类型必须是 CommonResult<T>,禁止返回 Entity🔴 高强制
直接注入 Mapper禁止在 Controller 直接注入 Mapper🔴 高必须通过 Service
参数校验建议有 @Valid @RequestBody(视业务需求)⚡ 低建议
嵌套校验嵌套对象必须加 @Valid 触发内部校验🔴 高强制

检查示例

java
// ❌ 问题:Controller 包含业务逻辑
@PostMapping("/add")
public CommonResult<Long> add(@RequestBody ProductAddReq req) {
    Product product = new Product();
    BeanUtils.copyProperties(req, product);
    productMapper.insert(product);  // ❌ 业务逻辑
    return CommonResult.success(product.getId());
}

// ✅ 正确
@PostMapping("/add")
public CommonResult<Long> add(@Valid @RequestBody ProductAddReq req) {
    return CommonResult.success(productService.add(req));
}

5. Service 层检查

检查项规则严重度
方法行数不超过 50 行⚠️ 中
if-else 嵌套不超过 2 层⚠️ 中
分支数量超过 3 个考虑策略模式⚡ 低
卫语句使用卫语句减少嵌套⚠️ 中

检查示例

java
// ❌ 问题:嵌套过深
if (order != null) {
    if (order.getStatus() == 1) {
        if (order.getAmount() > 0) {
            process(order);
        }
    }
}

// ✅ 正确:卫语句
if (order == null) {
    throw exception(ORDER_NOT_EXISTS);
}
if (order.getStatus() != 1) {
    throw exception(INVALID_STATUS);
}
process(order);

6. DTO/Req/Rsp 类检查

检查项规则严重度
Lombok 注解必须有 @NoArgsConstructor(MyBatis 映射需要)🔴 高
字段校验Req 类必须有校验注解⚠️ 中
嵌套对象校验嵌套对象必须加 @Valid 触发内部校验🔴 高
继承字段子类必须显式声明所有需映射的字段🔴 高

嵌套对象校验示例

java
// ❌ 问题:嵌套对象未加 @Valid
@Data
public class OrderReq {
    @NotNull(message = "用户信息不能为空")
    private UserInfo userInfo;  // 内部校验不会触发
}

// ✅ 正确:嵌套对象必须加 @Valid
@Data
public class OrderReq {
    @NotNull(message = "用户信息不能为空")
    @Valid  // 必须加
    private UserInfo userInfo;
}

7. 日志规范检查

检查项规则严重度
日志格式必须使用 [业务名称] 前缀 + {} 占位符⚠️ 中
字符串拼接禁止 log.info("ID: " + id)⚠️ 中
敏感信息phone/idCard/password/token 等必须脱敏🔴 高
异常日志catch 块必须 log.error + 异常堆栈🔴 高
业务方法入口必须打印关键参数⚠️ 中
外部系统调用调用前后必须打印日志⚠️ 中

敏感字段识别模式

  • *phone*, *mobile*, *tel* → 必须脱敏
  • *idCard*, *idNo* → 必须脱敏
  • *password*, *pwd*, *secret* → 禁止打印
  • *token*, *apiKey* → 禁止打印

检查示例

java
// ❌ 问题
log.info("用户手机号: " + phone);

// ✅ 正确
log.info("[用户注册],手机号: {}", DesensitizeUtil.mobile(phone));

8. 异常处理检查

检查项规则严重度
业务异常必须使用 ServiceExceptionUtil.exception()🔴 高
异常信息禁止直接 throw new RuntimeException()🔴 高
catch 块禁止空 catch,必须处理或重抛🔴 高
异常日志catch 中必须 log.error 并包含异常堆栈🔴 高

检查示例

java
// ❌ 问题:原生异常
if (user == null) {
    throw new RuntimeException("用户不存在");
}

// ✅ 正确:使用 ServiceExceptionUtil
import static com.dsl.base.exception.util.ServiceExceptionUtil.exception;

if (user == null) {
    throw exception(USER_NOT_FOUND);
}

9. 事务检查

检查项规则严重度
多表写操作必须有 @Transactional(rollbackFor = Exception.class)🔴 高
事务方法修饰符必须是 public🔴 高
多数据源冲突禁止事务方法中混用多个数据源🔴 高
同类调用禁止同类内部调用事务方法(代理失效)🔴 高
异常捕获catch 块不能吞掉异常🔴 高

多数据源事务限制

@Transactional 只对主数据源生效,事务方法中 ❌ 禁止混用 MySQL 和 Doris。

java
// ❌ 问题:事务中混用 MySQL 和 Doris
@Transactional(rollbackFor = Exception.class)
public void syncData() {
    List<Data> dorisData = dorisMapper.selectList();
    mysqlMapper.saveBatch(dorisData);
}

// ✅ 正确:拆分方法
public void syncData() {
    List<Data> dorisData = queryFromDoris();
    saveToMysql(dorisData);
}

@Transactional(rollbackFor = Exception.class)
public void saveToMysql(List<Data> data) {
    mysqlMapper.saveBatch(data);
}

10. Mapper 层检查

检查项规则严重度
复杂查询方式多表JOIN/动态条件≥3个 必须用 XML⚠️ 中
SQL 注入禁止 ${} 拼接,必须用 #{}🔴 高
XML 与 DTO 同步新增字段必须同步更新 DTO🔴 高
动态排序使用 <choose> 白名单,禁止直接拼接字段名🔴 高

动态排序安全写法

xml
<!-- ✅ 正确:白名单方式 -->
ORDER BY
<choose>
    <when test="orderColumn == 'create_time'">create_time</when>
    <when test="orderColumn == 'update_time'">update_time</when>
    <otherwise>id</otherwise>
</choose>

11. 性能检查

检查项规则严重度
N+1 查询禁止循环查询数据库,必须批量查询 + 内存关联🔴 高
深度分页大偏移量使用游标分页(WHERE id > lastId)⚠️ 中
批量处理超过 1000 条必须分批⚠️ 中
大数据量导出使用流式查询 @Options(fetchSize = 1000)⚠️ 中

N+1 查询示例

java
// ❌ 问题:循环查询
for (Order order : orders) {
    User user = userMapper.selectById(order.getUserId());  // N 次查询
}

// ✅ 正确:批量查询 + 内存关联
Set<Long> userIds = orders.stream().map(Order::getUserId).collect(Collectors.toSet());
Map<Long, User> userMap = userMapper.selectBatchIds(userIds).stream()
    .collect(Collectors.toMap(User::getId, u -> u));

12. 缓存检查

检查项规则严重度
Key 命名必须 {业务}:{模块}:{标识} 格式⚠️ 中
TTL 设置禁止永不过期⚠️ 中
缓存穿透空值也缓存(短 TTL 如 5 分钟)⚠️ 中
缓存更新先更新数据库,再删除缓存⚠️ 中

TTL 参考值

数据类型建议 TTL
热点数据1-5 分钟
普通数据30 分钟
配置数据1 小时

13. 并发控制检查

检查项规则严重度
幂等性写接口必须考虑重复调用⚠️ 中
乐观锁更新操作需考虑并发,优先使用 version 字段⚠️ 中
分布式锁跨实例操作必须使用分布式锁🔴 高
锁粒度锁 Key 必须精确到业务主键⚠️ 中
锁释放只释放自己持有的锁 lock.isHeldByCurrentThread()🔴 高

14. 安全规范检查

检查项规则严重度
SQL 注入MyBatis 禁止 ${} 拼接用户输入🔴 高
XSS 过滤用户输入必须过滤或转义🔴 高
文件上传类型白名单 + 大小限制 + UUID重命名🔴 高
数据权限查询/修改必须校验数据归属🔴 高
配置安全数据库密码、API Key 等禁止明文提交🔴 高

数据权限校验示例

java
// ❌ 典型漏洞:水平越权
@GetMapping("/orders/{id}")
public CommonResult<OrderDetailRsp> getOrder(@PathVariable Long id) {
    return CommonResult.success(orderService.getById(id));  // 未校验归属
}

// ✅ 正确:校验数据归属
@GetMapping("/orders/{id}")
public CommonResult<OrderDetailRsp> getOrder(@PathVariable Long id) {
    Order order = orderService.getById(id);
    if (order == null) {
        throw exception(ORDER_NOT_FOUND);
    }
    if (!order.getUserId().equals(SecurityUtils.getUserId())) {
        throw exception(NO_PERMISSION);
    }
    return CommonResult.success(convert(order));
}

15. 异步处理检查

检查项规则严重度
线程池指定必须使用 @Async("线程池名") 指定线程池🔴 高
默认线程池禁止使用默认 SimpleAsyncTaskExecutor🔴 高
同类调用禁止在同类中调用 @Async 方法(代理失效)🔴 高
事务冲突禁止在 @Async 方法中使用 @Transactional🔴 高

16. 微服务调用检查

检查项规则严重度
Feign 超时必须显式配置超时时间🔴 高
Feign 异常必须捕获处理 FeignException🔴 高
服务调用日志调用前后必须打印日志⚠️ 中

Feign 异常处理示例

java
// ✅ 正确:捕获并转换为业务异常
public UserDTO getUser(Long userId) {
    try {
        log.info("[用户查询],调用用户服务,userId: {}", userId);
        UserDTO user = userClient.getById(userId);
        log.info("[用户查询],调用成功,userId: {}", userId);
        return user;
    } catch (FeignException.NotFound e) {
        log.warn("[用户查询],用户不存在,userId: {}", userId);
        return null;
    } catch (FeignException e) {
        log.error("[用户查询],调用失败,userId: {},status: {},异常:",
            userId, e.status(), e);
        throw exception(USER_SERVICE_ERROR);
    }
}

17. MQ 消费检查

检查项规则严重度
消费幂等必须保证幂等消费(Redis 或数据库去重)🔴 高
消息确认业务成功后再 ACK🔴 高
死信处理配置死信队列 + 告警⚠️ 中
事务消息分布式事务使用 RocketMQ 事务消息🔴 高

18. 数据库设计检查

检查项规则严重度
基础字段必须包含 id, create_time, update_time, creator, updater, deleted⚠️ 中
字段类型金额使用 decimal,禁止 float/double🔴 高
字段命名使用 snake_case,全小写⚠️ 中
索引命名唯一索引 uk_,普通索引 idx_⚠️ 中
字符集使用 utf8mb4⚠️ 中

19. 接口文档检查(Apifox)

检查项规则严重度
Controller 类注释必须有类级别 Javadoc 描述模块功能⚠️ 中
方法注释必须有 @param 和 @return 说明⚠️ 中
字段注释DTO/Req/Rsp 字段必须有 Javadoc 注释⚠️ 中
Mock 值使用 @mock 标签提供示例值⚡ 低

20. 代码风格检查

检查项规则严重度
集合判空使用 CollectionUtils.isEmpty()⚡ 低
字符串判空使用 StringUtils.isBlank()⚡ 低
Optional 使用链式调用防空⚡ 低
对象比较使用 Objects.equals()⚡ 低

输出模板

审查完成后,按以下格式输出:

报告头部

markdown
## Java/Spring 代码审查报告

> 📋 审查范围: X 个文件 | 🕐 YYYY-MM-DD HH:mm

### 问题汇总

| 严重度 | 数量 | 可自动修复 |
|--------|------|-----------|
| 🔴 高   | X    | X         |
| ⚠️ 中   | X    | X         |
| ⚡ 低   | X    | X         |

问题详情(diff 格式)

每个问题使用编号和 diff 格式:

markdown
### 🔴 高严重度问题

#### #1 [问题标题]
📍 `文件路径:行号`

```diff
- // 原代码(红色删除)
+ // 修复代码(绿色新增)

🔧 可自动修复 - 回复 fix #1 应用修复


#2 [问题标题]

📍 文件路径:行号

diff
  // 上下文代码
- // 问题代码
+ // 修复代码

⚠️ 需手动修复 - [原因说明]

code

### 通过项汇总(折叠显示)

```markdown
### ✅ 审查通过

**X/20 项检查通过**(命名规范、Import规范、Mapper层、异常处理...)

后续操作提示

markdown
### 📌 后续操作

| 命令 | 说明 |
|------|------|
| `fix all` | 自动修复所有可修复问题 |
| `fix #1` | 修复指定问题 |
| `fix #1,#3,#5` | 批量修复多个问题 |
| `详细 #2` | 查看问题详细说明 |

快速参考

必须的注解组合

java
// Controller(新建类)
@RestController
@RequiredArgsConstructor
// @Validated 视业务需求,不强制

// Service(新建类)
@Service
@Slf4j
@RequiredArgsConstructor

// DTO
@Data
@NoArgsConstructor

日志格式

java
log.info("[业务名称],动作描述,参数: {}", value);
log.error("[业务名称],错误描述,参数: {},异常:", value, e);

敏感字段脱敏

java
DesensitizeUtil.mobile(phone)     // 138****1234
DesensitizeUtil.idCard(idCard)    // 310***********1234
// password/token 禁止打印

事务注解

java
@Transactional(rollbackFor = Exception.class)

异常抛出

java
import static com.dsl.base.exception.util.ServiceExceptionUtil.exception;

throw exception(ERROR_CODE_CONSTANT);

缓存 Key 格式

java
String key = "{业务}:{模块}:{id}";
// 示例: "order:detail:12345"

分布式锁模板

java
RLock lock = redisson.getLock("业务:操作:" + bizId);
try {
    if (lock.tryLock(3, 30, TimeUnit.SECONDS)) {
        // 业务逻辑
    }
} finally {
    if (lock.isHeldByCurrentThread()) {
        lock.unlock();
    }
}

审查报告示例

markdown
## Java/Spring 代码审查报告

> 📋 审查范围: 3 个文件 | 🕐 2026-01-28 14:30

### 问题汇总

| 严重度 | 数量 | 可自动修复 |
|--------|------|-----------|
| 🔴 高   | 2    | 1         |
| ⚠️ 中   | 3    | 2         |
| ⚡ 低   | 1    | 0         |

---

### 🔴 高严重度问题

#### #1 Controller 包含业务逻辑
📍 `ProductController.java:45`

```diff
- @PostMapping("/add")
- public CommonResult<Long> add(@RequestBody ProductAddReq req) {
-     Product product = new Product();
-     BeanUtils.copyProperties(req, product);
-     productMapper.insert(product);
-     return CommonResult.success(product.getId());
- }

+ @PostMapping("/add")
+ public CommonResult<Long> add(@Valid @RequestBody ProductAddReq req) {
+     return CommonResult.success(productService.add(req));
+ }

🔧 可自动修复 - 回复 fix #1 应用修复


#2 事务方法混用多数据源

📍 DataSyncServiceImpl.java:78

diff
  @Transactional(rollbackFor = Exception.class)
  public void syncData() {
-     List<Data> dorisData = dorisMapper.selectList();
-     mysqlMapper.saveBatch(dorisData);
+     List<Data> dorisData = queryFromDoris();
+     saveToMysql(dorisData);
  }

⚠️ 需手动修复 - 涉及方法拆分,需人工确认


⚠️ 中严重度问题

#3 日志缺少业务标识

📍 OrderServiceImpl.java:23

diff
- log.info("订单创建成功,orderId: {}", orderId);
+ log.info("[订单创建],创建成功,orderId: {}", orderId);

🔧 可自动修复

#4 嵌套对象缺少 @Valid

📍 OrderReq.java:15

diff
  @NotNull(message = "用户信息不能为空")
+ @Valid
  private UserInfo userInfo;

🔧 可自动修复

#5 方法超过50行

📍 ReportServiceImpl.java:120-185

⚠️ 需手动修复 - 建议拆分为多个私有方法


⚡ 低严重度问题

#6 缺少 @mock 注释

📍 ProductReq.java:12

diff
+ /**
+  * 商品名称
+  * @mock 阿莫西林
+  */
  private String name;

💡 建议修复 - 可提升接口文档质量


✅ 审查通过

14/20 项检查通过(命名规范、Import规范、Mapper层、异常处理、缓存规范...)


📌 后续操作

命令说明
fix all自动修复 #1, #3, #4(3个问题)
fix #1仅修复 Controller 业务逻辑问题
fix #3,#4批量修复日志和校验问题
详细 #2查看多数据源事务的详细说明
code

---

## 规范来源

本审查规范基于以下规范文档编写:

- [命名规范](../java/references/naming.md)
- [代码风格](../java/references/coding-style.md)
- [日志规范](../java/references/logging.md)
- [异常处理](../java/references/exception.md)
- [Controller 层](../java/references/controller.md)
- [Service 层](../java/references/service.md)
- [Mapper 层](../java/references/mapper.md)
- [事务管理](../java/references/transaction.md)
- [性能优化](../java/references/performance.md)
- [缓存规范](../java/references/cache.md)
- [并发控制](../java/references/concurrency.md)
- [安全规范](../java/references/security.md)
- [异步与消息](../java/references/async-mq.md)
- [数据库设计](../java/references/database.md)
- [接口文档](../java/references/api-doc.md)