我们经常遇到图片上传的功能,如何不进行图片压缩就会导致在前端展示的时候,就像拉窗帘一样缓慢
在 Java 项目中实现用户上传图片的宽高校验和压缩存储,可以通过以下步骤完成:
确保项目中包含图片处理库,推荐使用 Thumbnailator
(简化图片操作)和 ImageIO
(Java 原生库):
<dependency>
<groupId>net.coobirdgroupId>
<artifactId>thumbnailatorartifactId>
<version>0.4.14version>
dependency>
使用 BufferedImage
读取图片尺寸并校验:
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
public class ImageUtils {
/**
* 校验图片宽度是否大于高度
* @param imageFile 上传的图片文件
* @return true=符合横向要求,false=不符合
*/
public static boolean isWidthGreaterThanHeight(File imageFile) throws IOException {
BufferedImage image = ImageIO.read(imageFile);
int width = image.getWidth();
int height = image.getHeight();
return width > height;
}
}
通过逐步降低质量或调整尺寸实现压缩目标:
import net.coobird.thumbnailator.Thumbnails;
import java.io.File;
import java.io.IOException;
public class ImageUtils {
/**
* 压缩图片到指定大小(300KB)以下
* @param sourceFile 原始图片文件
* @param targetFile 压缩后的文件
* @param maxSizeKB 目标最大大小(单位:KB)
*/
public static void compressImage(File sourceFile, File targetFile, int maxSizeKB) throws IOException {
long maxSizeBytes = maxSizeKB * 1024;
float quality = 0.9f; // 初始压缩质量
do {
Thumbnails.of(sourceFile)
.scale(1.0) // 保持原始尺寸
.outputQuality(quality)
.toFile(targetFile);
quality -= 0.1f; // 逐步降低质量
} while (targetFile.length() > maxSizeBytes && quality > 0.1f);
// 如果仍然不满足,调整尺寸
if (targetFile.length() > maxSizeBytes) {
Thumbnails.of(sourceFile)
.scale(0.5) // 缩小尺寸为50%
.outputQuality(0.7f)
.toFile(targetFile);
}
}
}
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import java.awt.image.BufferedImage;
import java.io.*;
public class ImageUtils {
/**
* 动态调整 JPEG 压缩质量
*/
public static void compressJPEG(File source, File target, float maxQuality) throws IOException {
BufferedImage image = ImageIO.read(source);
try (OutputStream os = new FileOutputStream(target)) {
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(maxQuality); // 0.0~1.0
writer.setOutput(ImageIO.createImageOutputStream(os));
writer.write(null, new IIOImage(image, null, null), param);
writer.dispose();
}
}
}
生成唯一文件名并存储,避免覆盖:
import java.io.File;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.UUID;
public class ImageStorage {
/**
* 保存图片到本地目录
* @param uploadFile 用户上传的文件
* @param targetDir 存储目录(如 /var/images/)
* @return 存储后的文件名
*/
public static String saveToDisk(File uploadFile, String targetDir) throws IOException {
String uniqueFileName = UUID.randomUUID() + ".jpg"; // 生成唯一文件名
File targetFile = new File(targetDir, uniqueFileName);
// 创建目录(如果不存在)
if (!targetFile.getParentFile().exists()) {
targetFile.getParentFile().mkdirs();
}
// 复制文件到目标路径
Files.copy(uploadFile.toPath(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
return uniqueFileName;
}
}
结合校验、压缩和存储:
public class ImageUploadService {
public static void processUpload(File uploadedImage, String savePath) throws IOException {
// 1. 校验宽高
if (!ImageUtils.isWidthGreaterThanHeight(uploadedImage)) {
throw new IllegalArgumentException("图片宽度必须大于高度!");
}
// 2. 压缩到 300KB 以下
File compressedFile = File.createTempFile("compressed-", ".jpg");
ImageUtils.compressImage(uploadedImage, compressedFile, 300);
// 3. 保存到硬盘
String savedFileName = ImageStorage.saveToDisk(compressedFile, savePath);
System.out.println("图片已保存为:" + savedFileName);
// 清理临时文件
compressedFile.delete();
}
}
格式兼容性:
性能优化:
BufferedInputStream
避免内存溢出。CompletableFuture
)提升响应速度。安全性:
MultipartFile
配置)。存储路径:
/data/images/
)而非相对路径。Thumbnails.of(sourceFile)
.size(1024, 768) // 调整到指定宽高
.outputQuality(0.8f)
.toFile(targetFile);
通过以上代码和流程,可以高效实现图片宽高校验、压缩存储功能,确保系统稳定性和用户体验。