feat:处理OSS图片包
parent
11f9815d2a
commit
bd8f1bbedc
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断文件是否是图片(jpeg、png、bmp、gif)
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
/**
|
||||
* 450图包key
|
||||
*/
|
||||
private String keyOf450;
|
||||
/**
|
||||
* 750图包key
|
||||
*/
|
||||
private String keyOf750;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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格式图包");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue