feat:处理OSS图片包

pull/1121/head
梁宇奇 2025-03-26 18:15:22 +08:00
parent 11f9815d2a
commit bd8f1bbedc
6 changed files with 331 additions and 1 deletions

View File

@ -0,0 +1,85 @@
package com.ruoyi.common.utils;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.lang.Assert;
import lombok.extern.slf4j.Slf4j;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
/**
* @author liangyq
* @date 2025-03-26 09:24
*/
@Slf4j
public class ImgExtUtil extends ImgUtil {
private static final byte[] JPEG_HEADER = new byte[]{(byte) 0xFF, (byte) 0xD8, (byte) 0xFF};
private static final byte[] PNG_HEADER = new byte[]{(byte) 0x89, 0x50, 0x4E, 0x47};
private static final byte[] GIF_HEADER = new byte[]{0x47, 0x49, 0x46, 0x38};
private static final byte[] BMP_HEADER = new byte[]{0x42, 0x4D};
/**
* <br>
* jpeg
*
* @param image
* @param destStream
* @param width
* @param height
* @param fixedColor {@code null}
* @throws IORuntimeException IO
*/
public static void scale(BufferedImage image, OutputStream destStream, int width, int height, Color fixedColor) throws IORuntimeException {
Assert.notNull(image, "图片不能为空");
try {
scale(image, getImageOutputStream(destStream), width, height, fixedColor);
} finally {
flush(image);
}
}
/**
* jpegpngbmpgif
*
* @param file
* @return
* @throws IOException
*/
public static boolean isImageByMagicNumber(File file) {
if (file == null || !file.exists() || file.isDirectory()) {
return false;
}
byte[] header = new byte[4];
try (InputStream is = new FileInputStream(file)) {
int readBytes = is.read(header);
if (readBytes == -1) return false;
} catch (Exception e) {
log.error("判断文件是否图片失败", e);
return false;
}
// 常见图片格式的魔数
if (bytesStartWith(header, JPEG_HEADER)) { // JPEG
return true;
} else if (bytesStartWith(header, PNG_HEADER)) { // PNG
return true;
} else if (bytesStartWith(header, GIF_HEADER)) { // GIF
return true;
} else if (bytesStartWith(header, BMP_HEADER)) { // BMP
return true;
}
return false;
}
private static boolean bytesStartWith(byte[] source, byte[] target) {
if (source.length < target.length) return false;
for (int i = 0; i < target.length; i++) {
if (source[i] != target[i]) return false;
}
return true;
}
}

View File

@ -250,7 +250,7 @@ public class OSSClientWrapper {
/**
*
*/
public void download(OSSClient client, String key, String filename)
public void download(String key, String filename)
throws OSSException, ClientException {
client.getObject(new GetObjectRequest(configuration.getBucketName(), key), new File(filename));
}

View File

@ -0,0 +1,25 @@
package com.ruoyi.xkt.dto.picture;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author liangyq
* @date 2025-03-26 15:51
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class DownloadResultDTO {
private String fileName;
private String filePath;
private String tempDirName;
private String tempDirPath;
}

View File

@ -0,0 +1,27 @@
package com.ruoyi.xkt.dto.picture;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author liangyq
* @date 2025-03-26 16:35
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PicZipDTO {
/**
* key
*/
private String key;
/**
* 450key
*/
private String keyOf450;
/**
* 750key
*/
private String keyOf750;
}

View File

@ -0,0 +1,18 @@
package com.ruoyi.xkt.service;
import com.ruoyi.xkt.dto.picture.PicZipDTO;
/**
* @author liangyq
* @date 2025-03-26 15:42
*/
public interface IPictureService {
/**
*
* @param key
* @return
*/
PicZipDTO processPicZip(String key);
}

View File

@ -0,0 +1,175 @@
package com.ruoyi.xkt.service.impl;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import com.ruoyi.common.core.text.CharsetKit;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.ImgExtUtil;
import com.ruoyi.framework.config.properties.OSSProperties;
import com.ruoyi.framework.oss.OSSClientWrapper;
import com.ruoyi.xkt.dto.picture.DownloadResultDTO;
import com.ruoyi.xkt.dto.picture.PicZipDTO;
import com.ruoyi.xkt.service.IPictureService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.List;
/**
* @author liangyq
* @date 2025-03-26 15:43
*/
@Slf4j
@Service
public class PictureServiceImpl implements IPictureService {
@Autowired
private OSSClientWrapper ossClient;
@Autowired
private OSSProperties ossProperties;
@Override
public PicZipDTO processPicZip(String key) {
checkProcessAccess(key);
//下载至系统临时文件夹
DownloadResultDTO downloadResult = downloadFile2TempDir(key);
String tempDirPath = downloadResult.getTempDirPath();
try {
String midDirName = "unzip_" + downloadResult.getTempDirName();
//解压
File unzipFile = unzip(downloadResult.getFilePath(), tempDirPath + midDirName);
List<File> allFiles = FileUtil.loopFiles(unzipFile);
for (File file : allFiles) {
if (file == null || !file.exists() || file.isDirectory()) {
continue;
}
//处理图片
String new450Path = file.getPath().replace(midDirName, "450");
String new750Path = file.getPath().replace(midDirName, "750");
if (ImgExtUtil.isImageByMagicNumber(file)) {
FileUtil.mkParentDirs(new450Path);
FileUtil.mkParentDirs(new750Path);
//450p图片
try (InputStream is = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(new450Path)) {
BufferedImage in = ImageIO.read(is);
int height = in.getHeight();
int weight = in.getWidth();
int neww = 450;
int newh = (int) (NumberUtil.div(height, weight, 5) * neww);
ImgExtUtil.scale(in, fos, neww, newh, null);
}
//750p图片
try (InputStream is = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(new750Path)) {
BufferedImage in = ImageIO.read(is);
int height = in.getHeight();
int weight = in.getWidth();
int neww = 750;
int newh = (int) (NumberUtil.div(height, weight, 5) * neww);
ImgExtUtil.scale(in, fos, neww, newh, null);
}
} else {
//非图片
FileUtil.copy(file, new File(new450Path), true);
FileUtil.copy(file, new File(new750Path), true);
}
}
//打包
String nameOf450 = FileNameUtil.getPrefix(downloadResult.getFileName()) + "_450.zip";
String pathOf450 = tempDirPath + nameOf450;
String nameOf750 = FileNameUtil.getPrefix(downloadResult.getFileName()) + "_750.zip";
String pathOf750 = tempDirPath + nameOf750;
ZipUtil.zip(tempDirPath + "450", pathOf450, CharsetKit.CHARSET_GBK, false);
ZipUtil.zip(tempDirPath + "750", pathOf750, CharsetKit.CHARSET_GBK, false);
//上传
String keyOf450 = StrUtil.replaceLast(key, downloadResult.getFileName(), nameOf450);
String keyOf750 = StrUtil.replaceLast(key, downloadResult.getFileName(), nameOf750);
try (InputStream is = new FileInputStream(pathOf450)) {
ossClient.upload(keyOf450, is);
}
try (InputStream is = new FileInputStream(pathOf750)) {
ossClient.upload(keyOf750, is);
}
return new PicZipDTO(key, keyOf450, keyOf750);
} catch (Exception e) {
log.error("图片处理异常", e);
throw new ServiceException("图片处理失败");
} finally {
//删除临时文件夹
FileUtil.del(tempDirPath);
}
}
/**
*
* TODO zip
*
* @param source
* @param target
* @return
*/
private File unzip(String source, String target) {
Assert.notEmpty(source);
Assert.notEmpty(target);
File file = null;
try {
file = ZipUtil.unzip(source, target, CharsetKit.CHARSET_GBK);
} catch (IllegalArgumentException e) {
if (e.getMessage().equals("MALFORMED")) {
//尝试用UTF8编码
file = ZipUtil.unzip(source, target, CharsetKit.CHARSET_UTF_8);
}
}
return file;
}
/**
* OSS
*
* @param ossKey
* @return
*/
private DownloadResultDTO downloadFile2TempDir(String ossKey) {
Assert.notEmpty("ossKey不能为空");
try {
String baseTempDir = ossProperties.getTempDir();
String tempDirName = IdUtil.fastSimpleUUID();
String tempDirPath = baseTempDir + tempDirName + "/";
//创建临时文件夹
FileUtil.mkdir(tempDirPath);
String fileName = FileNameUtil.getName(ossKey);
String filePath = tempDirPath + fileName;
ossClient.download(ossKey, filePath);
return DownloadResultDTO
.builder()
.fileName(fileName)
.filePath(filePath)
.tempDirName(tempDirName)
.tempDirPath(tempDirPath)
.build();
} catch (Exception e) {
log.error("文件下载异常", e);
throw new ServiceException("文件下载失败");
}
}
private void checkProcessAccess(String key) {
if (!"zip".equals(FileNameUtil.getSuffix(key))) {
throw new IllegalArgumentException("非zip格式图包");
}
}
}