69 lines
5.2 KiB
Markdown
69 lines
5.2 KiB
Markdown
# 代码审查报告
|
|
|
|
**文件:** `data\demo-pmd\src\com\demo\performance\extra\FileItemDemo.java`
|
|
**语言:** java
|
|
**耗时:** 170.1s
|
|
**分析工具:** pmd
|
|
|
|
---
|
|
|
|
总计: 16 | 错误: 3 | 警告: 12 | 建议: 1
|
|
|
|
静态分析 · 12 个问题
|
|
|
|
- 🔴 `pmd:SystemPrintln` L14
|
|
L14:使用了 System.out/err 输出。
|
|
建议: 使用 java.util.logging 或 SLF4J/Log4j2 输出,便于统一日志级别和格式。
|
|
- 🔴 `pmd:SystemPrintln` L19
|
|
L19:使用了 System.out/err 输出。
|
|
建议: 用日志记录器替换 System.out.println。
|
|
- 🔴 `pmd:SystemPrintln` L25
|
|
L25:使用了 System.out/err 输出。
|
|
建议: 在入口类中使用日志记录器输出,或确认该输出仅用于命令行演示且不会被生产使用。
|
|
- 🟡 `pmd:AtLeastOneConstructor` L11
|
|
L11:每个类应至少声明一个构造器。
|
|
建议: 为 UseIOStreamFileItem 添加显式默认构造器;如果不希望外部实例化,可将构造器声明为 private。
|
|
- 🟡 `pmd:CommentDefaultAccessModifier` L12
|
|
L12:方法 process(FileItem) 缺少默认访问修饰符的注释。
|
|
建议: 为包级私有方法添加 /* default */ 注释,或显式改为 public/private/protected,以明确访问意图。
|
|
- 🟡 `pmd:MethodArgumentCouldBeFinal` L12
|
|
L12:参数 item 未被重新赋值,可以声明为 final。
|
|
建议: 将方法签名中的 FileItem item 改为 final FileItem item,避免方法体内意外重新赋值。
|
|
- 🟡 `pmd:LocalVariableCouldBeFinal` L13
|
|
L13:局部变量 data 未被重新赋值,可以声明为 final。
|
|
建议: 将 byte[] data 改为 final byte[] data,表达只读引用的意图。
|
|
- 🟡 `pmd:UseIOStreamsWithApacheCommonsFileItem` L13
|
|
L13:应避免调用高内存占用的 FileItem.get() 或 FileItem.getString()。
|
|
建议: 如果只需要文件大小,使用 item.getSize();如果需要内容,使用 item.getInputStream() 配合 try-with-resources 流式读取,避免将整个文件载入内存。
|
|
- 🟡 `pmd:CommentDefaultAccessModifier` L17
|
|
L17:方法 processString(FileItem) 缺少默认访问修饰符的注释。
|
|
建议: 与 process 一致,添加 /* default */ 注释或使用显式访问修饰符。
|
|
- 🟡 `pmd:MethodArgumentCouldBeFinal` L17
|
|
L17:参数 item 未被重新赋值,可以声明为 final。
|
|
建议: 将方法签名中的 FileItem item 改为 final FileItem item。
|
|
- 🟡 `pmd:LocalVariableCouldBeFinal` L18
|
|
L18:局部变量 s 未被重新赋值,可以声明为 final。
|
|
建议: 将 String s 改为 final String s。
|
|
- 🟡 `pmd:UseIOStreamsWithApacheCommonsFileItem` L18
|
|
L18:应避免调用高内存占用的 FileItem.get() 或 FileItem.getString()。
|
|
建议: 改为读取输入流并显式指定 UTF-8 字符集,使用 try-with-resources 关闭输入流;避免 FileItem.getString() 使用默认字符集。
|
|
|
|
AI 审查 · 4 条建议
|
|
|
|
- 🟡 [AI] [performance] `use-getsize-for-length-only` L13
|
|
**process() 只需要文件长度时却把整个文件读入内存**
|
|
process(FileItem) 中仅用 data.length 获取字节数,但 FileItem.get() 会一次把整个上传文件载入 byte[]。当文件很大时会造成不必要的内存占用,甚至导致 OOM。FileItem.getSize() 可以在不读取内容的情况下返回文件大小。
|
|
建议: 将 byte[] data = item.get() 改为 long size = item.getSize(),并把 data.length 改为 size。若后续需要内容,再使用 item.getInputStream() 配合 try-with-resources 流式读取。
|
|
- 🟡 [AI] [security] `enforce-upload-size-limits` L13
|
|
**未限制上传文件大小,存在内存耗尽风险**
|
|
代码直接对 FileItem 调用 get()/getString() 将完整内容读入内存。若 FileItem 来自不受信任的 HTTP multipart 上传,攻击者可提交超大文件,导致 JVM 堆内存被耗尽。虽然静态分析建议改用 getInputStream(),但流式读取仍应配合上传大小上限。
|
|
建议: 在解析上传时配置 ServletFileUpload.setFileSizeMax()/setSizeMax(),或将 DiskFileItemFactory 的阈值调低使大文件写入临时文件;读取前检查 item.getSize()。
|
|
- 🟡 [AI] [bug] `explicit-charset-for-fileitem-read` L18
|
|
**FileItem.getString() 使用平台默认字符集,导致编码不一致**
|
|
FileItem.getString() 未指定字符集时会使用运行平台的默认字符集。开发环境与生产环境字符集不同(如本地 GBK、服务器 UTF-8)时,读取同一表单字段或文件内容会得到不同结果。应显式指定 UTF-8 或与业务约定的编码。
|
|
建议: 调用 item.getString(StandardCharsets.UTF_8.name());若按静态分析改为 getInputStream() 流式读取,也要使用显式字符集的 Reader,并在 try-with-resources 中关闭流。
|
|
- 🔵 [AI] [design] `explicit-access-modifiers` L12
|
|
**类及方法使用隐式包级私有访问权限**
|
|
UseIOStreamFileItem 的 process/processString 没有显式访问修饰符,默认为包级私有。当前代码中这两个方法未被类内部调用,也未声明为 private;如果实际需要外部访问,包级私有会限制可见性;如果仅是辅助方法,应缩小为 private。
|
|
建议: 若方法仅类内部使用,添加 private 修饰符;若需对外提供,请将 UseIOStreamFileItem 放入以类名命名的独立文件并声明 public,同时为方法添加 public。
|