原因:上传MultipartFile到第三方提示像素要在300*300以内
public com.alibaba.fastjson2.JSONObject upload(@RequestPart("file") MultipartFile file){
file = compressImageIfNeededNoTemp(file, 300, 300);
}
一:压缩方法不产生临时文件
private MultipartFile compressImageIfNeededNoTemp(MultipartFile file, int maxWidth, int maxHeight) {
try {
// 1. 先读取文件内容到内存(此时会占用 Tomcat 临时文件,但流会关闭)
byte[] fileBytes = file.getBytes();
// 2. 从内存中读取图片(不再依赖临时文件)
try (ByteArrayInputStream bais = new ByteArrayInputStream(fileBytes)) {
BufferedImage image = ImageIO.read(bais);
if (image == null) {
throw new RuntimeException("无法解析图片格式");
}
int width = image.getWidth();
int height = image.getHeight();
// 如果已经符合要求,返回基于内存的 MultipartFile
if (width <= maxWidth && height <= maxHeight) {
// 返回内存文件,不再持有原始 file 的引用
return new CustomMultipartFile(
file.getName(),
file.getOriginalFilename(),
file.getContentType(),
fileBytes
);
}
// 计算缩放比例
double scale = Math.min(
(double) maxWidth / width,
(double) maxHeight / height
);
int newWidth = (int) (width * scale);
int newHeight = (int) (height * scale);
int imageType = image.getType() == BufferedImage.TYPE_CUSTOM
? BufferedImage.TYPE_INT_RGB
: image.getType();
BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, imageType);
Graphics2D g = resizedImage.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(image, 0, 0, newWidth, newHeight, null);
g.dispose();
image.flush();
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
String format = getImageFormat(file.getOriginalFilename());
boolean written = ImageIO.write(resizedImage, format, baos);
if (!written) {
format = "jpg";
ImageIO.write(resizedImage, format, baos);
}
resizedImage.flush();
return new CustomMultipartFile(
file.getName(),
file.getOriginalFilename(),
file.getContentType(),
baos.toByteArray()
);
}
}
} catch (IOException e) {
throw new RuntimeException("图片压缩失败: " + e.getMessage(), e);
}
}
二:文件格式
private String getImageFormat(String filename) {
if (filename == null) return "jpg";
String ext = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
return "jpg".equals(ext) || "jpeg".equals(ext) ? "jpg" : ext;
}
三:返回工具类
package com.edu.service.util;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
/**
* 自定义 MultipartFile 实现,用于生产环境
*/
public class CustomMultipartFile implements MultipartFile {
private final String name;
private final String originalFilename;
private final String contentType;
private final byte[] content;
public CustomMultipartFile(String name, String originalFilename,
String contentType, byte[] content) {
this.name = name;
this.originalFilename = originalFilename;
this.contentType = contentType;
this.content = content != null ? content : new byte[0];
}
@Override
public String getName() {
return name;
}
@Override
public String getOriginalFilename() {
return originalFilename;
}
@Override
public String getContentType() {
return contentType;
}
@Override
public boolean isEmpty() {
return content.length == 0;
}
@Override
public long getSize() {
return content.length;
}
@Override
public byte[] getBytes() throws IOException {
return content;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(content);
}
@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
try (FileOutputStream fos = new FileOutputStream(dest)) {
fos.write(content);
}
}
}