提交 da209647 作者: 方治民

feat: 优化文件上传的临时文件处理方式

上级 47dbe6cd
......@@ -5,11 +5,11 @@ import cn.hutool.core.io.FileUtil;
import com.yiring.common.config.EnvConfig;
import com.yiring.common.core.Minio;
import com.yiring.common.service.UploadProcessService;
import com.yiring.common.util.Commons;
import io.minio.ObjectWriteResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
......@@ -33,6 +33,7 @@ import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.context.annotation.Primary;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
/**
* @author Jim
......@@ -53,24 +54,26 @@ public class UploadProcessServiceImpl implements UploadProcessService {
@SneakyThrows
@Override
public String handle(String object, Path path) {
@Cleanup
FileInputStream is = new FileInputStream(path.toFile());
public String handle(String object, MultipartFile file) {
String suffix = FileUtil.getSuffix(object);
// Image: 在文件名上追加图片物理像素
if (isSupportiveImage(suffix)) {
@Cleanup
InputStream is = file.getInputStream();
object = handleImage(object, is);
}
// PDF: 在文件名上追加页数,同时在同目录生成 PDF 每一页的图片
if (isPdf(suffix)) {
@Cleanup
InputStream is = file.getInputStream();
object = handlePdf(object, is);
}
// Video/Audio: 在文件名上追加时长,视频生成封面图
if (isSupportiveMedia(suffix)) {
object = handleMedia(object, suffix, path);
object = handleMedia(object, suffix, file);
}
return object;
......@@ -84,6 +87,7 @@ public class UploadProcessServiceImpl implements UploadProcessService {
@SneakyThrows
public String handlePdf(String object, InputStream is) {
@Cleanup
PDDocument doc = PDDocument.load(is);
int pages = doc.getNumberOfPages();
......@@ -107,7 +111,7 @@ public class UploadProcessServiceImpl implements UploadProcessService {
}
@SneakyThrows
public String handleMedia(String object, String suffix, Path path) {
public String handleMedia(String object, String suffix, MultipartFile file) {
// 判断是否配置 ffmpeg 环境
FFmpeg ffmpeg = new FFmpeg();
FFprobe ffprobe = new FFprobe();
......@@ -115,8 +119,13 @@ public class UploadProcessServiceImpl implements UploadProcessService {
return object;
}
// 将上传的文件转存一份到本地临时目录
Path tempFile = Paths.get(FileUtil.getTmpDirPath(), "T_" + Commons.uuid(), file.getOriginalFilename());
FileUtil.mkParentDirs(tempFile);
file.transferTo(tempFile);
// 解析媒体文件
FFmpegProbeResult probeResult = ffprobe.probe(path.toString());
FFmpegProbeResult probeResult = ffprobe.probe(tempFile.toString());
FFmpegFormat format = probeResult.getFormat();
// 构建具有时长(秒)标记的存储地址
......@@ -126,33 +135,35 @@ public class UploadProcessServiceImpl implements UploadProcessService {
// 视频截取首帧可见画面作为封面
if (isSupportiveVideo(suffix)) {
// 使用 ffmpeg 截取视频首帧图片
Path tempFile = Paths.get(path.getParent().toString(), FileUtil.getName(filepath) + ".jpg");
Path path = Paths.get(tempFile.getParent().toString(), FileUtil.getName(filepath) + ".jpg");
FFmpegBuilder builder = new FFmpegBuilder()
.setInput(path.toString())
.setInput(tempFile.toString())
.overrideOutputFiles(true)
.addOutput(tempFile.toString())
.addOutput(path.toString())
.setFrames(1)
.done();
FFmpegExecutor executor = new FFmpegExecutor(ffmpeg, ffprobe);
executor.createJob(builder).run();
// 判断封面图是否生成
if (Files.exists(tempFile)) {
if (Files.exists(path)) {
// 上传封面图
minio.putObject(tempFile.toFile(), getObjectFolder(filepath));
minio.putObject(path.toFile(), getObjectFolder(filepath));
}
// 大视频文件切片上传(> 5s)
if (sec > 5) {
filepath = handleToHls(filepath, path, ffmpeg, ffprobe);
filepath = handleVideoToHls(filepath, tempFile, ffmpeg, ffprobe);
}
}
// 删除为本次上传进行本地处理所创建的整个临时文件夹目录
FileUtil.del(tempFile.getParent());
return filepath;
}
@SneakyThrows
public String handleToHls(String object, Path path, FFmpeg ffmpeg, FFprobe ffprobe) {
public String handleVideoToHls(String object, Path path, FFmpeg ffmpeg, FFprobe ffprobe) {
String originName = FileUtil.getName(object);
String objectFolder = object.replace("/" + originName, "");
String targetName = originName.replaceAll("^(.*)\\." + FileUtil.getSuffix(originName) + "$", "$1.m3u8");
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.common.service;
import java.nio.file.Path;
import org.springframework.web.multipart.MultipartFile;
/**
* 文件上传媒体文件预处理服务
......@@ -19,10 +19,10 @@ public interface UploadProcessService {
* 视频封面:haha.mp4 -> haha.mp4.jpg 截取视频封面
*
* @param object 上传文件存储地址
* @param path 文件地址
* @param file 上传的文件
* @return 预处理后的文件地址(可能对文件名追加了时长、页数、分辨率等标识)
*/
default String handle(String object, Path path) {
default String handle(String object, MultipartFile file) {
return object;
}
}
/* (C) 2023 YiRing, Inc. */
package com.yiring.common.service.impl;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.yiring.common.core.Minio;
import com.yiring.common.service.FileManageService;
import com.yiring.common.service.UploadProcessService;
import com.yiring.common.util.Commons;
import java.nio.file.Path;
import java.nio.file.Paths;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
......@@ -43,14 +39,8 @@ public class FileManageServiceImpl implements FileManageService {
String uuid = IdUtil.fastSimpleUUID();
String object = minio.buildUploadPath(filename, "", uuid);
// 将上传的文件转存一份到本地临时目录
Path tempFile = Paths.get(FileUtil.getTmpDirPath(), Commons.uuid(), filename);
FileUtil.mkParentDirs(tempFile);
file.transferTo(tempFile);
// 预处理(默认不做任何处理,具体逻辑需自行在外部实现)
object = service.handle(object, tempFile);
// 删除为本次上传进行本地处理所创建的整个临时文件夹目录
FileUtil.del(tempFile.getParent());
object = service.handle(object, file);
// 上传原文件(如果是转换成了 m3u8 hls 文件则不保存原文件)
String suffix = ".m3u8";
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论