iFlyCode+SpecKit
项目背景
**需求来源:**业务上需要上传考生相片,支持历年存储,预期每年新增20w+,上传质量大小不一,除了大小判断外,需要对相片超过配置阈值(默认300KB)的照片进行智能压缩,还不能影响显示效果,同时考虑压缩性能,否则前端返回时间比较久,用户等待时间长。
核心特性
-
✅ 可配置阈值 : 通过系统配置
KsXpCompressSize动态调整压缩阈值 -
✅ 智能压缩: 质量递减压缩 + 尺寸缩放双重策略
-
✅ 大图优化: 超大图片预缩放,显著降低内存占用
-
✅ 透明通道支持: 智能识别图片类型,支持PNG/GIF透明背景
-
✅ 三重清理机制: 正常清理 + 异常清理 + JVM退出清理
-
✅ 详细日志: 完整的压缩过程日志记录
提问过程
将上述需求描述提交给iFlyCode,使用项目环境和设计智能体。
(执行片段如下图:)

技术架构
压缩流程图
核心方法调用链
scssreadXpFile() ├─ 判断文件大小 > KsXpCompressSize ├─ compressImage() │ ├─ 读取原始图片 │ ├─ 大图片检测与预缩放 │ │ ├─ 计算缩放比例 │ │ ├─ resizeImage() - 预缩放 │ │ └─ 释放原图内存 │ ├─ 质量压缩循环 │ │ └─ compressImageWithQuality() │ ├─ 尺寸缩放备选 │ │ └─ resizeImage() │ └─ 返回压缩文件 ├─ fileHandler.uploadFile() └─ 清理临时文件
核心代码实现
1. 主压缩逻辑(readXpFile方法集成)
位置 : BkKsxpServiceImpl.java 第822-849行
2. 智能压缩方法(compressImage)
位置 : BkKsxpServiceImpl.java 第1960-2090行
核心特性:
-
大图片预缩放优化(>2MB或>2000px)
-
二分查找压缩算法
(压缩次数减少50%)
-
尺寸缩放备选方案(80%)
-
完整的内存管理
-
三重临时文件清理
markdown
3. 质量压缩方法(compressImageWithQuality)
位置 : BkKsxpServiceImpl.java 第2096-2116行
java
privatevoidcompressImageWithQuality(BufferedImage image, File outputFile, float quality) throws IOException { javax.imageio.ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next(); javax.imageio.ImageWriteParam param = writer.getDefaultWriteParam(); if (param.canWriteCompressed()) { param.setCompressionMode(javax.imageio.ImageWriteParam.MODE_EXPLICIT); param.setCompressionQuality(quality); } try (FileOutputStream fos = new FileOutputStream(outputFile); javax.imageio.stream.ImageOutputStream ios = ImageIO.createImageOutputStream(fos)) { writer.setOutput(ios); writer.write(null, new javax.imageio.IIOImage(image, null, null), param); } finally { writer.dispose(); }}
4. 尺寸缩放方法(resizeImage)
位置 : BkKsxpServiceImpl.java 第2118-2141行
特性: 支持透明通道(ARGB)
perl
private BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight){ // 保持原图的图片类型,支持透明通道 int imageType = originalImage.getType(); if (imageType == 0) { imageType = originalImage.getTransparency() == BufferedImage.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB; } BufferedImage resizedImage = new BufferedImage(targetWidth, targetHeight, imageType); Graphics2D graphics = resizedImage.createGraphics(); // 设置高质量渲染 graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); graphics.drawImage(originalImage, 0, 0, targetWidth, targetHeight, null); graphics.dispose(); return resizedImage;}
配置说明
系统配置参数

配置方法
方法1: 数据库配置(推荐)
java
-- 插入配置(如果不存在)INSERT INTO basis_syscfg(syscfg_key, syscfg_value, syscfg_desc)VALUES('KsXpCompressSize', '300', '照片压缩阈值(KB)');-- 更新配置UPDATE basis_syscfg SET syscfg_value = '500'WHERE syscfg_key = 'KsXpCompressSize';
方法2: 系统管理界面
-
登录系统管理后台
-
进入"系统配置"模块
-
查找或添加
KsXpCompressSize配置项 -
设置期望的阈值(单位:KB)
-
保存配置
性能优化详解
1. 大图片预缩放策略
优化前后对比

预缩放触发条件
ruby
finallong LARGE_FILE_THRESHOLD = 2 * 1024 * 1024L; // 2MBfinalint LARGE_DIMENSION_THRESHOLD = 2000; // 2000像素// 满足以下任一条件触发预缩放:// 1. 文件大小 > 2MB// 2. 宽度 > 2000px// 3. 高度 > 2000px
缩放比例计算
erlang
printf("hello world!");// 策略1: 尺寸超标 - 等比例缩放到2000px以内if (width > 2000 || height > 2000) { scaleFactor = min(2000/width, 2000/height);}// 策略2: 文件超大但尺寸正常 - 缩小到70%if (fileSize > 2MB && scaleFactor == 1.0) { scaleFactor = 0.7;}
2. 内存管理优化
内存释放时机
代码示例
yaml
// 1. 预缩放后释放原图workingImage = resizeImage(originalImage, preScaledWidth, preScaledHeight);originalImage.flush(); // 立即释放originalImage = null;// 2. 压缩完成后释放工作图workingImage.flush();workingImage = null;// 3. finally块确保释放finally { if (workingImage != null) { workingImage.flush(); }}
3. 临时文件清理机制
三重保障

清理代码
vbnet
// 1. 创建时设置自动清理compressedFile = File.createTempFile("compressed_", ".jpg");compressedFile.deleteOnExit(); // JVM退出时自动删除// 2. 正常使用后清理if (fileToUpload != readFile && fileToUpload.exists()) { fileToUpload.delete();}// 3. 异常情况清理catch (Exception e) { if (compressedFile != null && compressedFile.exists()) { try { compressedFile.delete(); } catch (Exception deleteEx) { SysLogUtils.printLogger("删除临时文件失败"); } }}
单元测试
测试场景
1. 功能测试

2. 性能测试
shell
# 测试场景1: 单张大图片- 文件: 4000x3000, 2MB- 预期: 内存占用 < 20MB, 处理时间 < 3秒# 测试场景2: 批量上传- 文件: 100张混合大小照片- 预期: 无内存溢出, 总时间 < 30秒# 测试场景3: 极限测试- 文件: 8000x6000, 10MB- 预期: 成功压缩, 无崩溃
3. 边界测试
arduino
// 测试用例1. 损坏的图片文件 → 应返回null,使用原图2. 非JPG格式 → 应正常处理(PNG/GIF)3. 阈值为0 → 应使用默认值300KB4. 极小图片(10KB) → 不压缩5. 正方形图片 → 等比例缩放6. 极窄/极宽图片 → 正确计算缩放比例
测试步骤
准备工作
arduino
-- 1. 配置压缩阈值INSERT INTO basis_syscfg(syscfg_key, syscfg_value, syscfg_desc)VALUES('KsXpCompressSize', '300', '照片压缩阈值(KB)');
执行测试
shell
# 2. 准备测试照片- 小照片: 150KB (不压缩)- 中照片: 500KB (质量压缩)- 大照片: 2MB (预缩放+压缩)- PNG照片: 带透明背景# 3. 批量上传测试- 打包成ZIP文件- 通过系统上传- 检查日志输出- 验证存储结果# 4. 验证结果- 检查照片大小是否符合阈值- 检查照片质量是否可接受- 检查透明通道是否保留- 检查临时文件是否清理
日志示例
正常压缩日志
scss
照片 20240101001.jpg 从 450KB 压缩到 280KB (阈值: 300KB)
大图片预缩放日志
makefile
大图片预缩放: IMG_4000x3000.jpg, 原尺寸: 4000x3000, 预缩放到: 2000x1500 (比例: 0.50)压缩成功: IMG_4000x3000.jpg, 质量: 0.7, 大小: 285KB
尺寸缩放日志
makefile
通过缩小尺寸压缩: large_photo.jpg, 新尺寸: 1600x1200, 大小: 295KB
压缩失败日志
lua
压缩照片失败: corrupted.jpg, Cannot read input file!
性能指标
压缩效果统计

效果总结
1、原计划3个工作日完成,使用iFlyCode,省去寻找方案的时间,1天左右完成,提效66%;
2、经过生产验证,该压缩方案成功率100%,效果符合预期,即300k以上相片压缩至300k内,不影响打印效果呈现,满足业务需求,后期可以将本方法抽象成为通用方法进行复用。
--- END ---