cmvr-wms/ruoyi-system/src/main/java/com/ruoyi/warehouse/util/WarehouseFileUtils.java

145 lines
4.4 KiB
Java
Raw Normal View History

package com.ruoyi.warehouse.util;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
public final class WarehouseFileUtils
{
private static final long MAX_IMAGE_PIXELS = 40_000_000L;
private WarehouseFileUtils()
{
}
public static String validateUpload(MultipartFile file, long maxFileSize, Set<String> allowedExtensions)
{
if (file == null || file.isEmpty())
{
throw new ServiceException("请选择要上传的文件");
}
if (file.getSize() > maxFileSize)
{
throw new ServiceException("文件不能超过" + (maxFileSize / 1024 / 1024) + "MB");
}
String extension = StringUtils.defaultString(FilenameUtils.getExtension(file.getOriginalFilename()))
.toLowerCase(Locale.ROOT);
if (!allowedExtensions.contains(extension))
{
throw new ServiceException("不支持的文件类型");
}
try
{
byte[] header;
try (InputStream input = file.getInputStream())
{
header = input.readNBytes(12);
}
if ("xls".equals(extension) && !startsWith(header, 0xD0, 0xCF, 0x11, 0xE0))
{
throw new ServiceException("文件内容不是有效的Excel文件");
}
if ("xlsx".equals(extension) && !startsWith(header, 0x50, 0x4B))
{
throw new ServiceException("文件内容不是有效的Excel文件");
}
if (isImage(extension))
{
validateImage(file, extension, header);
}
return extension;
}
catch (ServiceException e)
{
throw e;
}
catch (Exception e)
{
throw new ServiceException("无法读取上传文件,请确认文件未损坏");
}
}
private static void validateImage(MultipartFile file, String extension, byte[] header) throws Exception
{
if ("webp".equals(extension))
{
if (!matchesAscii(header, 0, "RIFF") || !matchesAscii(header, 8, "WEBP"))
{
throw new ServiceException("文件内容不是有效的WebP图片");
}
return;
}
try (ImageInputStream input = ImageIO.createImageInputStream(file.getInputStream()))
{
if (input == null)
{
throw new ServiceException("文件内容不是有效图片");
}
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
if (!readers.hasNext())
{
throw new ServiceException("文件内容不是有效图片");
}
ImageReader reader = readers.next();
try
{
reader.setInput(input, true, true);
long pixels = (long) reader.getWidth(0) * reader.getHeight(0);
if (pixels <= 0 || pixels > MAX_IMAGE_PIXELS)
{
throw new ServiceException("图片尺寸过大,最大支持4000万像素");
}
}
finally
{
reader.dispose();
}
}
}
private static boolean isImage(String extension)
{
return Set.of("jpg", "jpeg", "png", "bmp", "webp").contains(extension);
}
private static boolean startsWith(byte[] source, int... prefix)
{
if (source.length < prefix.length)
{
return false;
}
for (int i = 0; i < prefix.length; i++)
{
if ((source[i] & 0xFF) != prefix[i])
{
return false;
}
}
return true;
}
private static boolean matchesAscii(byte[] source, int offset, String expected)
{
if (source.length < offset + expected.length())
{
return false;
}
for (int i = 0; i < expected.length(); i++)
{
if (source[offset + i] != (byte) expected.charAt(i))
{
return false;
}
}
return true;
}
}