|
|
@@ -72,24 +72,37 @@ public class FileTypeUtils {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 返回附件
|
|
|
+ * 返回附件(优化版:支持缓存和视频分片)
|
|
|
*
|
|
|
* @param response 响应
|
|
|
* @param filename 文件名
|
|
|
- * @param content 附件内容
|
|
|
+ * @param content 内容(完整或分片)
|
|
|
*/
|
|
|
public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException {
|
|
|
- // 设置 header 和 contentType
|
|
|
- response.setHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename));
|
|
|
+ // 1. 基础头设置
|
|
|
String contentType = getMineType(content, filename);
|
|
|
response.setContentType(contentType);
|
|
|
- // 针对 video 的特殊处理,解决视频地址在移动端播放的兼容性问题
|
|
|
+ response.setContentLength(content.length);
|
|
|
+
|
|
|
+ // 2. 缓存设置(核心:添加缓存头)
|
|
|
+ // 视频缓存30天,其他文件缓存7天(可按需调整)
|
|
|
+ long maxAge = StrUtil.containsIgnoreCase(contentType, "video") ? 30 * 24 * 60 * 60 : 7 * 24 * 60 * 60;
|
|
|
+ response.setHeader("Cache-Control", "public, max-age=" + maxAge); // 公共缓存,有效期30天
|
|
|
+ response.setHeader("Pragma", "public"); // 兼容老浏览器
|
|
|
+
|
|
|
+ // 3. 文件名处理(视频用 inline 播放,非视频用 attachment 下载)
|
|
|
+ String disposition = StrUtil.containsIgnoreCase(contentType, "video")
|
|
|
+ ? "inline;filename=" + HttpUtils.encodeUtf8(filename) // 视频:在线播放
|
|
|
+ : "attachment;filename=" + HttpUtils.encodeUtf8(filename); // 其他:下载
|
|
|
+ response.setHeader("Content-Disposition", disposition);
|
|
|
+
|
|
|
+ // 4. 视频特殊处理(修正原逻辑错误)
|
|
|
if (StrUtil.containsIgnoreCase(contentType, "video")) {
|
|
|
- response.setHeader("Content-Length", String.valueOf(content.length - 1));
|
|
|
- response.setHeader("Content-Range", String.valueOf(content.length - 1));
|
|
|
- response.setHeader("Accept-Ranges", "bytes");
|
|
|
+ response.setHeader("Accept-Ranges", "bytes"); // 支持分片
|
|
|
+ // 原代码的 Content-Range 格式错误,已在 getFileContent 中正确设置,此处无需重复
|
|
|
}
|
|
|
- // 输出附件
|
|
|
+
|
|
|
+ // 5. 输出内容
|
|
|
IoUtil.write(response.getOutputStream(), false, content);
|
|
|
}
|
|
|
|