jinshihui 1 ヶ月 前
コミット
3798bfbcc2

+ 35 - 73
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/TbFileServiceImpl.java

@@ -11,6 +11,7 @@ import com.ylx.common.utils.file.FileUtils;
 import com.ylx.framework.config.ServerConfig;
 import com.ylx.massage.domain.TbFile;
 import com.ylx.massage.mapper.TbFileMapper;
+import com.ylx.massage.utils.MimeTypeUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -116,7 +117,7 @@ public class TbFileServiceImpl extends ServiceImpl<TbFileMapper, TbFile> impleme
             TbFile dbFile = this.getByMd5(md5);
             if (null != dbFile) {
                 // 文件已存在,直接返回已有文件的访问信息(秒传)
-                ajax.put("url",  dbFile.getFileUrl());
+                ajax.put("url", dbFile.getFileUrl());
                 ajax.put("newFileName", FileUtils.getName(dbFile.getFileUrl()));
                 ajax.put("originalFilename", dbFile.getFileName());
                 // 封面图URL路径(针对视频文件)
@@ -130,7 +131,7 @@ public class TbFileServiceImpl extends ServiceImpl<TbFileMapper, TbFile> impleme
             // 上传文件到服务器并返回新的文件名称
             String fileName = FileUploadUtils.upload(filePath, file);
             //获取新的文件子路径
-            String subFileName= fileName.substring(fileName.indexOf("/upload") + 7);
+            String subFileName = fileName.substring(fileName.indexOf("/upload") + 7);
             // 构建完整的文件访问路径
             subFileName = filePath + subFileName;
             log.info("上传文件的路径:{},返回的新文件路径:{}", filePath, subFileName);
@@ -146,7 +147,7 @@ public class TbFileServiceImpl extends ServiceImpl<TbFileMapper, TbFile> impleme
             ajax.put("newFileName", FileUtils.getName(fileName));
             ajax.put("originalFilename", file.getOriginalFilename());
             // 封面图URL路径(针对视频文件)
-            ajax.put("coverUrl",  substring);
+            ajax.put("coverUrl", substring);
 
             // 保存文件记录到数据库
             TbFile tbFile = new TbFile();
@@ -174,11 +175,11 @@ public class TbFileServiceImpl extends ServiceImpl<TbFileMapper, TbFile> impleme
      *
      * @param file 上传的文件对象
      * @return AjaxResult 包含文件访问信息的对象:
-     *         - url: 文件的完整访问 URL(包含域名)
-     *         - fileName: 服务器存储的文件路径
-     *         - newFileName: 文件名(不含路径)
-     *         - originalFilename: 原始上传文件名
-     *         如果上传失败,返回错误信息
+     * - url: 文件的完整访问 URL(包含域名)
+     * - fileName: 服务器存储的文件路径
+     * - newFileName: 文件名(不含路径)
+     * - originalFilename: 原始上传文件名
+     * 如果上传失败,返回错误信息
      */
     @Override
     public AjaxResult uploadFile(MultipartFile file) {
@@ -190,7 +191,7 @@ public class TbFileServiceImpl extends ServiceImpl<TbFileMapper, TbFile> impleme
             TbFile dbFile = this.getByMd5(md5);
             if (null != dbFile) {
                 // 文件已存在,直接返回已有文件的访问信息(秒传)
-                ajax.put("url",  dbFile.getFileUrl());
+                ajax.put("url", dbFile.getFileUrl());
                 ajax.put("fileName", dbFile.getFileUrl());
                 ajax.put("newFileName", FileUtils.getName(dbFile.getFileUrl()));
                 ajax.put("originalFilename", dbFile.getFileName());
@@ -204,7 +205,7 @@ public class TbFileServiceImpl extends ServiceImpl<TbFileMapper, TbFile> impleme
             String fileName = FileUploadUtils.upload(filePath, file);
             log.info("上传文件到服务器并返回新的文件名称:{}", fileName);
             //获取新的文件子路径
-            String subFileName= fileName.substring(fileName.indexOf("/upload") + 7);
+            String subFileName = fileName.substring(fileName.indexOf("/upload") + 7);
             // 构建完整的文件访问路径
             subFileName = filePath + subFileName;
             log.info("上传文件路径:{},返回的新文件路径:{}", filePath, subFileName);
@@ -237,10 +238,10 @@ public class TbFileServiceImpl extends ServiceImpl<TbFileMapper, TbFile> impleme
      * 4. 验证生成的图片文件有效性
      * </p>
      *
-     * @param videoPath 视频文件路径
+     * @param videoPath        视频文件路径
      * @param originalFilename 原始视频文件名(用于生成缩略图文件名)
      * @return String 生成的封面图片文件绝对路径
-     * @throws IOException 如果目录创建失败
+     * @throws IOException                                 如果目录创建失败
      * @throws VideoThumbnailService.VideoProcessException 如果封面生成失败或验证失败
      */
     private String generateThumbnailFilePath(String videoPath, String originalFilename) throws IOException, VideoThumbnailService.VideoProcessException {
@@ -287,14 +288,12 @@ public class TbFileServiceImpl extends ServiceImpl<TbFileMapper, TbFile> impleme
         if (hostPath == null || hostPath.isEmpty()) {
             return hostPath;
         }
+
         // 规范化路径分隔符(Windows风格转Linux风格)
         String normalizedPath = hostPath.replace("\\", "/");
         // 移除可能存在的重复斜杠
         normalizedPath = normalizedPath.replaceAll("/+", "/");
 
-        //添加指定的前缀
-        normalizedPath = "/usr/local/java" + normalizedPath;
-
         // 获取配置的宿主机映射路径(规范化)
         String normalizedVolumePath = hostVolumePath.replace("\\", "/").replaceAll("/+", "/");
         if (!normalizedVolumePath.endsWith("/")) {
@@ -306,6 +305,7 @@ public class TbFileServiceImpl extends ServiceImpl<TbFileMapper, TbFile> impleme
             String relativePath = normalizedPath.substring(normalizedVolumePath.length());
             return containerWorkDir + "/" + relativePath;
         }
+
         // 如果路径不匹配,直接返回原路径
         log.warn("路径 {} 不在Docker卷映射路径 {} 下,使用原路径", hostPath, hostVolumePath);
         return normalizedPath;
@@ -334,69 +334,30 @@ public class TbFileServiceImpl extends ServiceImpl<TbFileMapper, TbFile> impleme
      * 2. Docker模式:通过docker run命令调用容器内的FFmpeg
      * </p>
      *
-     * @param videoPath 视频文件路径(宿主机路径)
+     * @param videoPath     视频文件路径(宿主机路径)
      * @param thumbnailPath 封面图片保存路径(宿主机路径)
      */
     private void executeFfmpegCommand(String videoPath, String thumbnailPath) throws IOException, InterruptedException, VideoThumbnailService.VideoProcessException {
-        log.info("开始执行FFmpeg命令,Docker模式: {}, 视频文件路径: {}, 封面图片保存路径: {}", dockerEnabled, videoPath, thumbnailPath);
+        log.info("开始执行FFmpeg命令,视频文件路径: {}, 封面图片保存路径: {}", videoPath, thumbnailPath);
         List<String> command = new ArrayList<>();
-        if (dockerEnabled) {
-            // Docker模式:构建 docker run 命令
-            // 命令格式:docker run --rm -v /host/path:/data -w /data jrottenberg/ffmpeg -ss 1 -i /data/input.mp4 -vframes 1 -q:v 2 -y /data/output.jpg
-            command.add("docker");
-            command.add("run");
-            command.add("--rm");
-
-            // 添加volume映射:将宿主机路径映射到容器内
-            command.add("-v");
-            // 规范化路径(处理Windows风格的路径分隔符)
-            String normalizedVolumePath = hostVolumePath.replace("\\", "/");
-            if (!normalizedVolumePath.startsWith("/")) {
-                // Windows路径需要特殊处理,转换为 /host 形式或使用完整路径
-                normalizedVolumePath = "/" + normalizedVolumePath.replace(":", "").replace("\\", "/");
-            }
-            String volumeMapping = normalizedVolumePath + ":" + containerWorkDir;
-            command.add(volumeMapping);
-
-            // 设置工作目录
-            command.add("-w");
-            command.add(containerWorkDir);
-
-            // Docker镜像名称
-            command.add(dockerImage);
-
-            // 将宿主机路径转换为容器内路径
-            String containerVideoPath = convertToContainerPath(videoPath);
-            String containerThumbnailPath = convertToContainerPath(thumbnailPath);
-
-            // FFmpeg参数
-            command.add("-ss");
-            command.add(String.valueOf(CAPTURE_TIME_SECOND));
-            command.add("-i");
-            command.add(containerVideoPath);
-            command.add("-vframes");
-            command.add("1");
-            command.add("-q:v");
-            command.add("2");
-            command.add("-y");
-            command.add(containerThumbnailPath);
-        } else {
-            // 本地模式:直接调用FFmpeg可执行文件
-            command.add(FFMPEG_PATH);
-            command.add("-ss");
-            command.add(String.valueOf(CAPTURE_TIME_SECOND));
-            command.add("-i");
-            command.add(videoPath);
-            command.add("-vframes");
-            command.add("1");
-            command.add("-q:v");
-            command.add("2");
-            command.add("-y");
-            command.add(thumbnailPath);
-        }
+        //直接调用FFmpeg可执行文件
+        command.add(FFMPEG_PATH);
+        command.add("-ss");
+        command.add(String.valueOf(CAPTURE_TIME_SECOND));
+        command.add("-i");
+        command.add(videoPath);
+        command.add("-vframes");
+        command.add("1");
+        command.add("-q:v");
+        command.add("2");
+        command.add("-y");
+        command.add(thumbnailPath);
         log.info("执行命令: {}", String.join(" ", command));
+
         // 执行命令
         ProcessBuilder processBuilder = new ProcessBuilder(command);
+        // 设置工作目录
+        processBuilder.directory(new File("/nightFragrance/uploadPath"));
         processBuilder.redirectErrorStream(true);
         Process process = processBuilder.start();
         // 读取命令输出(用于日志和调试)
@@ -434,11 +395,12 @@ public class TbFileServiceImpl extends ServiceImpl<TbFileMapper, TbFile> impleme
         }
         // 可选:验证文件是否为有效的图片
         try {
-            String mimeType = Files.probeContentType(thumbnailFile.toPath());
+            String mimeType = MimeTypeUtil.getMimeType(thumbnailFile.toPath());
+            log.info("mimeType的值:{}", mimeType);
             if (mimeType == null || !mimeType.startsWith("image/")) {
                 throw new VideoThumbnailService.VideoProcessException("生成的文件不是有效的图片");
             }
-        } catch (IOException e) {
+        } catch (Exception e) {
             e.printStackTrace();
             log.info("无法验证文件 MIME 类型", e);
         }

+ 54 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/utils/MimeTypeUtil.java

@@ -0,0 +1,54 @@
+package com.ylx.massage.utils;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MimeTypeUtil {
+
+    private static final Map<String, String> MIME_TYPES = new HashMap<>();
+
+    static {
+        // 常见图片格式
+        MIME_TYPES.put("jpg", "image/jpeg");
+        MIME_TYPES.put("jpeg", "image/jpeg");
+        MIME_TYPES.put("png", "image/png");
+        MIME_TYPES.put("gif", "image/gif");
+        MIME_TYPES.put("bmp", "image/bmp");
+        MIME_TYPES.put("webp", "image/webp");
+        MIME_TYPES.put("svg", "image/svg+xml");
+
+        // 文档格式
+        MIME_TYPES.put("pdf", "application/pdf");
+        MIME_TYPES.put("doc", "application/msword");
+        MIME_TYPES.put("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+        MIME_TYPES.put("txt", "text/plain");
+
+        // 视频格式
+        MIME_TYPES.put("mp4", "video/mp4");
+        MIME_TYPES.put("avi", "video/x-msvideo");
+    }
+
+    public static String getMimeType(Path path) {
+        // 优先使用系统探测
+        try {
+            String mimeType = Files.probeContentType(path);
+            mimeType = null;
+            if (mimeType != null) {
+                return mimeType;
+            }
+        } catch (Exception e) {
+            // 忽略异常,使用备用方案
+        }
+
+        // 备用方案:根据扩展名
+        String fileName = path.getFileName().toString();
+        int dotIndex = fileName.lastIndexOf('.');
+        if (dotIndex > 0 && dotIndex < fileName.length() - 1) {
+            String extension = fileName.substring(dotIndex + 1).toLowerCase();
+            return MIME_TYPES.getOrDefault(extension, "application/octet-stream");
+        }
+        return "application/octet-stream"; // 默认二进制类型
+    }
+}