跳转到主要内容

使用AI进行code review

相关提示词


# 后端JAVA代码 Code Review 检查项



标签语义:

 - 【停用】:本条不检查,扫描时跳过
 - 【待改造】:本条仍然要检查,按目标态标准执行;发现的存量不合规项不报违规,归入清单管理



## 一、架构与设计类

1. **分层规范(Controller / Service / DAO 职责边界)**
    - Controller 只做参数接收校验、调 Service、组装响应,禁止写业务逻辑、禁止直接调 Mapper/DAO
    - Service 承担业务逻辑与事务边界,不出现 HttpServletRequest 等 Web 层对象
    - DAO/Mapper 只做数据存取,不写业务判断;禁止 Service 之间循环依赖

2. **面客端与管理端接口分离**
    - 面客端(网站 / APP / 小程序)和管理端(WEB / APP)的接口不得混在同一个 Controller 里,必须分开建 Controller。
    - URL 规范:
      - 【待改造】管理端接口路径规范:/api/<服务>/<路径>
      - 【待改造】面客端接口路径规范: /api/<服务>/client/<路径>,即路径必须含 /client/ 段
      - 接口归属判定:以 Controller 映射路径是否含 /client/ 段为准,**含 /client/ 段为面客端接口,无 /client/ 段一律视为管理端接口**;与前端源码(面客端 / 管理端分别提供)做交叉验证,面客端前端调用了但没有 /client/ 段的,列入改造清单;有 /client/ 段但没有被面客端前端调用的,列入清理清单。
    - 两端走各自的认证鉴权链和过滤器配置,互不复用;管理端接口不得挂在面客端路由下,反之亦然
      - 管理端网关:/api
      - 面客端网关:/c-api,不带 /client/ 段的路由一律拒绝(须在路由匹配前以 GlobalFilter 拦截)
    - 接口归属须与用户提供并标注的前端源码双向交叉验证:同一 Controller 被两端前端共同调用即违规;前端调用了但后端找不到对应 Controller
       的路径,按违规报告;接口既未被管理端前端调用、也未被面客端前端调用的,列为未归属接口报告,不得静默跳过(第 7 条的越权检查依赖本条的归类结果)

3. **接口设计**
    - RESTful 规范:所有接口统一使用 POST,参数一律通过 @RequestBody 从请求 body 中接收;禁止使用 GET / PUT / DELETE,禁止用 @RequestParam / @PathVariable / 表单形式接收参数。确有特殊情况(如第三方回调、文件下载等)必须使用其他方式的,须在代码注释中明确注明原因,未注明原因的按违规报告;统一返回格式 { code, message, data }
    
    - 写接口需幂等:重复调用不产生副作用
    - 禁止开启 Swagger / OpenAPI 文档端点,不管什么环境(项目未使用,发现依赖或配置开启即报告)
4. **第三方调用**
    - 调用外部服务必须设置超时(connect + read)
    - 必须有降级 / 重试策略(熔断器如 Sentinel / Resilience4j);重试设最大次数和退避间隔
    - 关键调用必须记录请求和响应日志(脱敏后)

## 二、安全类

5. **【停用】CVE 漏洞扫描**
    - 检查 pom.xml 中写死版本号的三方依赖,比对 NVD / Snyk / dependency-check 是否落在已知漏洞影响区间内   
    - 同一依赖出现多个版本并存的,报告中列出各模块使用的版本,建议收敛到父 pom 统一管理;扫描阶段只标记不修复
    - 命中漏洞的依赖:报告中列出所用版本、漏洞编号(CVE ID)、官方修复版本号;扫描阶段只标记不修复
6. **SQL 注入**
    - mapper XML 和注解 SQL(@Select 等)中,凡是接收外部输入的地方一律用 #{} 预编译,禁止 ${} 拼接和字符串拼接 SQL   
    - ORDER BY 排序字段:列名不能用 #{} 预编译,服务端必须用白名单映射(前端传别名,服务端换真实列名),方向只允许 asc / desc
    - 分页 limit:每页条数、页码等数值用 #{} 预编译传参,禁止 ${} 拼接(如 limit ${offset});每页条数设上限(最大 1000 条)防止一次拉全表    
    - MyBatis-Plus Wrapper 的 .last() / .apply() 中不允许拼接用户输入;IN 子句参数数量设置上限(最大 10个)
7. **没有增加权限标识(含越权)**
    - 每个接口都必须声明鉴权方式:方法上加权限注解(`@PreAuthorize` / `@RequiresPermissions` / 自定义注解),或在 SecurityConfig 中配置路径规则;没声明的就是缺权限标识   
    - 管理端接口(无 /client/ 段)权限注解必须全覆盖,写接口(新增/修改/删除)和接收身份参数的接口尤为重要。
    - 区分接口是面客端还是管理端,再定用户 ID 的来源:
      - 面客端接口(面客端网站 / APP / 小程序):查当前用户数据时,用户 ID 必须从登录 token 中获取,禁止直接接收前端传入的 userId 参数,防止横向越权
      - 管理端接口(管理端 WEB / APP):可以按传入的 userId 查询任意用户数据,但必须挂权限标识,登录 ≠ 有权限
      - 接口归属面客端还是管理端,按第 2 条的归类规则判定;同一接口被两端前端共同调用的,越权按"从严"(面客端)规则检查
    - 根据 ID 查询/修改/删除资源时,必须校验资源归属(用户 A 不能操作用户 B 的数据);普通用户不能调用管理员接口(垂直越权)    
    - 匿名放行的白名单逐条注明原因,写操作一律不允许匿名访问
8. **认证与会话安全(暴力破解、弱密码、短信轰炸防护)**
    - 防暴力破解:同一账号 / IP 连续登录失败 N 次(如 5 次)后锁定或要求验证码,失败计数要落库并可告警   
    - 密码强度:长度 ≥ 8 位且至少含 3 类字符(大小写 / 数字 / 符号),拒绝常见弱密码(123456、admin123)和与账号相同的密码
    - 密码存储用 BCrypt 等加盐慢哈希,禁止 MD5 / SHA / 明文    
    - 短信轰炸防护:验证码同一手机号 60 秒 1 条,发送前必须先过图形验证码等人机校验   
    - 会话与 token:必须有过期时间,退出登录、修改密码后旧 token 要立即失效
9. **XSS / CSRF**
    - XSS 过滤链必须启用(XssFilter 默认关闭,需配置 renren.xss.enabled=true 才生效);富文本内容入库前必须清洁
    - Cookie 会话的服务必须有 CSRF Token;Authorization 头传 token 的接口天然免疫,无需检查
    - 响应头正确设置 Content-Type,避免浏览器自动嗅探
10. **敏感信息泄露**
    - 日志中禁止出现密码、Token、身份证号、手机号、银行卡号;如需记录必须脱敏(如 138****1234)   
    - 【停用】配置文件禁止明文存储密码/密钥,使用加密配置或密钥管理服务
    - 异常堆栈不得直接返回给前端,统一包装为标准错误响应

## 三、代码质量类

11. **魔法变量**
    - 一个变量在生命周期内被不同代码块反复赋值、复用作不同用途(如 result / flag / temp 先后装多种东西),含义随位置漂移,极易误读误改   
    - 不同用途必须拆成各自独立命名的变量,做到见名知义
    - 缩小变量作用域:就近声明、尽量一次赋值,禁止在大方法里跨代码块共享一个变量
12. **非空验证**
    - 接口入参用 DTO + @Validated + JSR-303 注解校验,禁止用 Map 裸接参数   
    - 查询结果(getById、getOne、list.get(0) 等)必须先判空再取值;链式调用(user.getAddress().getCity())注意中间环节判空
    - 外部调用(RPC / HTTP / MQ)的返回值使用前必须判空;集合用 CollectionUtils.isEmpty() 判空,Map 取值用 getOrDefault
13. **异常处理**
    - 禁止空 catch 块、禁止 e.printStackTrace(),捕获后至少 log.error 带完整堆栈   
    - 统一走 @ControllerAdvice + @ExceptionHandler 全局捕获;自定义业务异常继承 RuntimeException 并携带错误码
    - 不要用异常做流程控制;finally 块中禁止 return(会覆盖 try 中的返回值)
14. **命名与方法设计**
    - 类名大驼峰、方法/变量小驼峰、常量全大写下划线;布尔以 is/has/can 开头
    - 单个方法不超过 200 行、参数不超过 20 个、嵌套不超过 5 层,用早返回优化
    - 【停用】方法名体现行为:get 查询 / save 新增 / update 修改 / remove 删除 / delete 删除

## 四、性能类

15. **数据库查询**
    - 禁止循环内查库(N+1 问题):改批量查询或 JOIN;批量插入用 INSERT VALUES (...),(...) 或 batch 模式
    - 禁止 SELECT *;大结果集必须分页;单表查询必须命中索引(EXPLAIN 确认执行计划)
    - LIKE '%keyword%' 左模糊无法走索引,考虑全文检索(ES)
    - @Transactional 范围尽量小,事务中不调外部接口

16. **【停用】缓存**
    - 高频读、低频写的数据加缓存
    - 缓存必须设置过期时间
    - 防缓存穿透(不存在的 key)、雪崩(同时过期)、击穿(热点 key);修改数据后必须同步更新/删除缓存

17. **【停用】并发与线程安全**
    - 线程池必须自定义配置,禁止 Executors.newFixedThreadPool() 无界队列;异步任务必须设置超时时间
    - SimpleDateFormat 非线程安全,用 DateTimeFormatter;Controller(单例)禁止用实例变量存请求状态
    - 余额扣减、库存扣减必须用乐观锁或悲观锁防超卖;定时任务多实例部署时加分布式锁防重复执行

18. **资源管理**
    - IO 流、数据库连接必须用 try-with-resources 或 finally 关闭
    - 文件上传限制大小;下载文件用流式传输,避免一次性加载到内存

## 五、日志与可观测性

19. **日志规范**
    - 使用 SLF4J + Logback / Log4j2,禁止 System.out.println;禁止在循环中打日志
    - 级别正确:ERROR 系统异常需人工介入 / WARN 可恢复问题 / INFO 关键业务节点 / DEBUG 生产环境关闭
    - 日志必须包含上下文(traceId / userId / 关键参数);异常日志打完整堆栈 log.error("msg", e)

20. **监控埋点(慢 SQL、线程池、GC)**
    - 慢 SQL:数据源开启慢 SQL 统计(如 Druid slowSqlMillis / p6spy),超阈值(如 500ms)记日志并告警
    - 【停用】线程池:自建线程池必须用 ThreadFactory 命名、暴露活跃线程数 / 队列积压指标,禁用 Executors 快捷方法
    - 【停用】GC 与链路:启动参数开启 GC 日志,接入 actuator / micrometer,核心接口有耗时打点(成功率、耗时、QPS)

21. **【停用】关键操作日志埋点(增加、修改、删除)**
    - 对数据库的新增、修改、删除操作,必须记录操作日志:操作人、操作时间、操作内容(含操作前后数据快照)