file video ai idea

This commit is contained in:
ran.shang
2025-08-27 17:15:06 +08:00
parent 7c62035839
commit 59ef112929

View File

@@ -95,20 +95,148 @@ public class FileServiceImpl implements FileService {
if (Objects.nonNull(request) && StringUtils.isNotBlank(request.getParameter("filename"))) { if (Objects.nonNull(request) && StringUtils.isNotBlank(request.getParameter("filename"))) {
filename = URLDecoder.decode(request.getParameter("filename"),"utf-8"); filename = URLDecoder.decode(request.getParameter("filename"),"utf-8");
} }
response.setContentType(session.getServletContext().getMimeType(filename));
String mimeType = session.getServletContext().getMimeType(filename);
response.setContentType(mimeType);
String encodFilename = URLEncoder.encode(filename, "utf-8"); String encodFilename = URLEncoder.encode(filename, "utf-8");
response.setHeader("code", "200"); response.setHeader("code", "200");
response.setHeader("Cache-Control", "max-age=31556926"); response.setHeader("Cache-Control", "max-age=31556926");
// 检查是否为视频文件,如果是则支持Range请求
boolean isVideo = mimeType != null && mimeType.startsWith("video/");
if (!Boolean.TRUE.equals(display)) { if (!Boolean.TRUE.equals(display)) {
response.setHeader("Content-Disposition", response.setHeader("Content-Disposition",
String.format("attachment; filename=\"%1$s\"; filename*=utf-8''%1$s", encodFilename)); String.format("attachment; filename=\"%1$s\"; filename*=utf-8''%1$s", encodFilename));
} }
Long fileSize = fileRecord.getFileSize();
// 对于视频文件,支持Range请求
if (isVideo) {
handleVideoDownloadWithRange(fileRecord, request, response, fileSize);
} else {
// 普通文件下载
try (OutputStream outputStream = response.getOutputStream()) { try (OutputStream outputStream = response.getOutputStream()) {
fileStorage.download(fileRecord.getFilePath(), outputStream, fileRecord.getFileSize()); fileStorage.download(fileRecord.getFilePath(), outputStream, fileSize);
} catch (ClientAbortException e) { } catch (ClientAbortException e) {
log.warn("客户端主动断开连接: {}", e.getMessage()); log.warn("客户端主动断开连接: {}", e.getMessage());
} }
} }
}
/**
* 处理支持Range请求的视频文件下载
*/
private void handleVideoDownloadWithRange(FileRecord fileRecord, HttpServletRequest request,
HttpServletResponse response, Long fileSize) throws IOException {
// 设置支持Range请求的头部
response.setHeader("Accept-Ranges", "bytes");
if (fileSize != null) {
response.setHeader("Content-Length", String.valueOf(fileSize));
}
String rangeHeader = request.getHeader("Range");
if (rangeHeader != null && rangeHeader.startsWith("bytes=")) {
// 处理Range请求
handleRangeRequest(fileRecord, response, rangeHeader, fileSize);
} else {
// 普通请求,但设置正确的头部
if (fileSize != null) {
response.setContentLengthLong(fileSize);
}
try (OutputStream outputStream = response.getOutputStream()) {
fileStorage.download(fileRecord.getFilePath(), outputStream, fileSize);
} catch (ClientAbortException e) {
log.warn("客户端主动断开连接: {}", e.getMessage());
}
}
}
/**
* 处理HTTP Range请求
*/
private void handleRangeRequest(FileRecord fileRecord, HttpServletResponse response,
String rangeHeader, Long fileSize) throws IOException {
if (fileSize == null) {
// 如果没有文件大小信息,降级为普通下载
try (OutputStream outputStream = response.getOutputStream()) {
fileStorage.download(fileRecord.getFilePath(), outputStream, fileSize);
} catch (ClientAbortException e) {
log.warn("客户端主动断开连接: {}", e.getMessage());
}
return;
}
// 解析Range头部,格式:bytes=start-end
String range = rangeHeader.substring(6); // 去掉 "bytes="
String[] ranges = range.split("-");
long start = 0;
long end = fileSize - 1;
try {
if (ranges.length >= 1 && !ranges[0].isEmpty()) {
start = Long.parseLong(ranges[0]);
}
if (ranges.length >= 2 && !ranges[1].isEmpty()) {
end = Long.parseLong(ranges[1]);
}
// 确保范围有效
if (start < 0) start = 0;
if (end >= fileSize) end = fileSize - 1;
if (start > end) {
response.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
return;
}
long contentLength = end - start + 1;
// 设置206 Partial Content响应
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
response.setHeader("Content-Range", String.format("bytes %d-%d/%d", start, end, fileSize));
response.setHeader("Content-Length", String.valueOf(contentLength));
// 下载指定范围的内容
downloadRange(fileRecord.getFilePath(), response.getOutputStream(), start, contentLength);
} catch (NumberFormatException e) {
log.warn("无效的Range请求: {}", rangeHeader);
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
} catch (ClientAbortException e) {
log.warn("客户端主动断开连接: {}", e.getMessage());
}
}
/**
* 下载文件的指定范围
*/
private void downloadRange(String filePath, OutputStream outputStream, long start, long length) throws IOException {
try (InputStream inputStream = fileStorage.download(filePath)) {
// 跳过开始位置之前的字节
long skipped = inputStream.skip(start);
if (skipped != start) {
log.warn("跳过字节数不匹配,期望: {}, 实际: {}", start, skipped);
}
// 读取指定长度的数据
byte[] buffer = new byte[8192];
long remaining = length;
int bytesRead;
while (remaining > 0 && (bytesRead = inputStream.read(buffer, 0, (int) Math.min(buffer.length, remaining))) != -1) {
outputStream.write(buffer, 0, bytesRead);
remaining -= bytesRead;
}
outputStream.flush();
}
}