From 1e20e93ea384b994de2767f3ce03e333eac47dd0 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Wed, 14 Jan 2026 11:51:24 +0800
Subject: [PATCH] fix(video): 修复视频播放器MIME类型设置问题

---
 src/main/java/cc/mrbird/febs/ai/controller/fileUpload/FileUploadController.java |  143 ++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 127 insertions(+), 16 deletions(-)

diff --git a/src/main/java/cc/mrbird/febs/ai/controller/fileUpload/FileUploadController.java b/src/main/java/cc/mrbird/febs/ai/controller/fileUpload/FileUploadController.java
index 1f1c849..97171f2 100644
--- a/src/main/java/cc/mrbird/febs/ai/controller/fileUpload/FileUploadController.java
+++ b/src/main/java/cc/mrbird/febs/ai/controller/fileUpload/FileUploadController.java
@@ -8,6 +8,7 @@
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.*;
 import java.nio.file.Files;
@@ -28,11 +29,11 @@
 @RequestMapping(value = "/fileUpload")
 public class FileUploadController extends BaseController {
 
-    // @Value("${file.upload.dir}")
-    private String uploadDir = "d:/upload/files";
+    // 基础上传目录
+    private String baseUploadDir = "/home/javaweb/webresource/ai/file";
 
-    // @Value("${file.chunk.dir}")
-    private String chunkDir = "d:/upload/chunks";
+    // 分片存储目录
+    private String baseChunkDir = "/home/javaweb/webresource/ai/file/chunks";
 
     /**
      * 上传文件分片
@@ -44,6 +45,9 @@
                                     @RequestParam("chunks") int chunks,
                                     @RequestParam("fileMd5") String fileMd5) {
         try {
+            String companyId = getCurrentUserCompanyId();
+            // 构建公司专属分片目录
+            String chunkDir = baseChunkDir + "/" + companyId;
             // 确保分片目录存在
             Path chunkPath = Paths.get(chunkDir, fileMd5);
             if (!Files.exists(chunkPath)) {
@@ -69,6 +73,10 @@
                                     @RequestParam("fileMd5") String fileMd5,
                                     @RequestParam("chunks") int chunks) {
         try {
+
+            String companyId = getCurrentUserCompanyId();
+            // 构建公司专属上传目录
+            String uploadDir = baseUploadDir + "/" + companyId;
             // 确保上传目录存在
             Path uploadPath = Paths.get(uploadDir);
             if (!Files.exists(uploadPath)) {
@@ -79,6 +87,8 @@
             String uniqueFileName = UUID.randomUUID().toString() + "_" + fileName;
             Path targetFilePath = uploadPath.resolve(uniqueFileName);
 
+            // 构建公司专属分片目录
+            String chunkDir = baseChunkDir + "/" + companyId;
             // 确保分片目录存在
             Path chunkPath = Paths.get(chunkDir, fileMd5);
             if (!Files.exists(chunkPath)) {
@@ -116,26 +126,87 @@
      * 播放视频文件
      */
     @GetMapping("/play/{fileName}")
-    public void playVideo(@PathVariable("fileName") String fileName, HttpServletResponse response) {
+    public void playVideo(@PathVariable("fileName") String fileName, HttpServletRequest request, HttpServletResponse response) {
         try {
+            String companyId = getCurrentUserCompanyId();
+            String uploadDir = baseUploadDir + "/" + companyId;
             Path filePath = Paths.get(uploadDir, fileName);
             if (!Files.exists(filePath)) {
                 response.setStatus(HttpStatus.NOT_FOUND.value());
                 return;
             }
 
-            // 设置响应头
-            response.setContentType("video/mp4");
-            response.setContentLengthLong(Files.size(filePath));
-            response.setHeader("Content-Disposition", "inline; filename=\"" + fileName + "\"");
+            // 获取文件大小
+            long fileSize = Files.size(filePath);
+            
+            // 检查是否有Range请求头
+            String rangeHeader = request.getHeader("Range");
+            if (rangeHeader != null) {
+                // 解析Range头,格式为"bytes=start-end"
+                String[] ranges = rangeHeader.replace("bytes=", "").split("-");
+                long start = 0, end = fileSize - 1;
+                
+                if (!ranges[0].isEmpty()) {
+                    start = Long.parseLong(ranges[0]);
+                }
+                if (ranges.length > 1 && !ranges[1].isEmpty()) {
+                    end = Long.parseLong(ranges[1]);
+                } else {
+                    end = fileSize - 1;
+                }
+                
+                // 确保范围有效
+                if (start > end || start >= fileSize) {
+                    response.setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value());
+                    return;
+                }
+                
+                // 限制结束位置不超过文件大小
+                if (end >= fileSize) {
+                    end = fileSize - 1;
+                }
+                
+                // 计算内容长度
+                long contentLength = end - start + 1;
+                
+                // 设置响应状态和头部信息
+                response.setStatus(HttpStatus.PARTIAL_CONTENT.value());
+                response.setContentType(getContentTypeByExtension(fileName));
+                response.setContentLengthLong(contentLength);
+                response.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + fileSize);
+                response.setHeader("Accept-Ranges", "bytes");
+                response.setHeader("Content-Disposition", "inline; filename=\"" + fileName + "\"");
+                
+                // 从指定位置开始读取文件
+                try (RandomAccessFile randomAccessFile = new RandomAccessFile(filePath.toFile(), "r");
+                     OutputStream outputStream = response.getOutputStream()) {
+                    
+                    randomAccessFile.seek(start);
+                    byte[] buffer = new byte[8192];
+                    long remaining = contentLength;
+                    int bytesRead;
+                    
+                    while (remaining > 0 && (bytesRead = randomAccessFile.read(buffer, 0, (int) Math.min(buffer.length, remaining))) != -1) {
+                        outputStream.write(buffer, 0, bytesRead);
+                        remaining -= bytesRead;
+                    }
+                }
+            } else {
+                // 没有Range头,返回完整文件
+                response.setStatus(HttpStatus.OK.value());
+                response.setContentType(getContentTypeByExtension(fileName));
+                response.setContentLengthLong(fileSize);
+                response.setHeader("Accept-Ranges", "bytes");
+                response.setHeader("Content-Disposition", "inline; filename=\"" + fileName + "\"");
 
-            // 流式传输文件
-            try (InputStream inputStream = Files.newInputStream(filePath);
-                 OutputStream outputStream = response.getOutputStream()) {
-                byte[] buffer = new byte[8192];
-                int bytesRead;
-                while ((bytesRead = inputStream.read(buffer)) != -1) {
-                    outputStream.write(buffer, 0, bytesRead);
+                // 流式传输文件
+                try (InputStream inputStream = Files.newInputStream(filePath);
+                     OutputStream outputStream = response.getOutputStream()) {
+                    byte[] buffer = new byte[8192];
+                    int bytesRead;
+                    while ((bytesRead = inputStream.read(buffer)) != -1) {
+                        outputStream.write(buffer, 0, bytesRead);
+                    }
                 }
             }
         } catch (Exception e) {
@@ -145,11 +216,48 @@
     }
 
     /**
+     * 根据文件扩展名获取MIME类型
+     */
+    private String getContentTypeByExtension(String fileName) {
+        String extension = "";
+        int lastDotIndex = fileName.lastIndexOf('.');
+        if (lastDotIndex > 0) {
+            extension = fileName.substring(lastDotIndex).toLowerCase();
+        }
+        
+        switch (extension) {
+            case ".mp4":
+                return "video/mp4";
+            case ".avi":
+                return "video/x-msvideo";
+            case ".mov":
+                return "video/quicktime";
+            case ".wmv":
+                return "video/x-ms-wmv";
+            case ".flv":
+                return "video/x-flv";
+            case ".webm":
+                return "video/webm";
+            case ".mkv":
+                return "video/x-matroska";
+            case ".m3u8":
+                return "application/vnd.apple.mpegurl";
+            case ".ts":
+                return "video/MP2T";
+            default:
+                return "application/octet-stream";
+        }
+    }
+
+    /**
      * 获取文件列表
      */
     @GetMapping("/list")
     public FebsResponse getFileList() {
         try {
+
+            String companyId = getCurrentUserCompanyId();
+            String uploadDir = baseUploadDir + "/" + companyId;
             Path uploadPath = Paths.get(uploadDir);
             if (!Files.exists(uploadPath)) {
                 return new FebsResponse().data(new ArrayList<>());
@@ -183,6 +291,9 @@
     @PostMapping("/delete")
     public FebsResponse deleteFile(@RequestParam("fileName") String fileName) {
         try {
+
+            String companyId = getCurrentUserCompanyId();
+            String uploadDir = baseUploadDir + "/" + companyId;
             Path filePath = Paths.get(uploadDir, fileName);
             if (Files.exists(filePath)) {
                 Files.delete(filePath);

--
Gitblit v1.9.1