当前位置: 首页 > news >正文

java 上传文件和下载/预览文件 包括音频调进度条

话不多说,直上代码

包括knife4j 3.0文档展示使用

一:Controller

   // 接口排序@ApiOperationSupport(order = 1)// 接口名称@Operation(summary = "上传文件")// 接口返回示例@ApiResponses({@ApiResponse(responseCode = "200",description = "成功",content = @Content(mediaType = "application/json",schema = @Schema(implementation = TempFile .class)))})@PostMapping("/upload")public AjaxResult upload(@Parameter(name = "files", description = "文件s", required = true, schema = @Schema(type = "array", implementation = MultipartFile.class))@RequestPart("files") MultipartFile[] files,@Parameter(name = "meetingId", description = "会议ID")@RequestParam("meetingId") Long meetingId, {
List<TempFile> list = new ArrayList<>();for (MultipartFile file : files) {try {// 防止文件名中文乱码String dbName = URLDecoder.decode(file.getOriginalFilename(), "UTF-8");// 文件名前面加了时间戳,防止重复上传替换了String name = DateUtils.getTimeNew() + "_" + dbName;// 保存路径 global是yml拿的;String path = global.getFilePath()  + "/" + meetingId;// 进行上传FileUtils.upload(path, name, file);// 获取文件后缀名(格式)String fileFormat = "";if (dbName != null && dbName.contains(".")) {fileFormat = dbName.substring(dbName.lastIndexOf(".") + 1).toLowerCase();}// 获取文件大小(转换为MB,保留两位小数)String fileSize = FileUtils.formatFileSize(file.getSize());// 根据文件后缀判断文件类型String fileType = FileUtils.getFileType(fileFormat);// 保存数据库TempFile tempFile = TempFile.builder().fileName(dbName).fileFormat(fileFormat).fileType(fileType).fileSize(fileSize).filePath(path + "/" + name).build();mapper.addTempFile(tempFile);} catch (Exception e) {e.printStackTrace();} finally {list.add(tempFile);}return AjaxResult.success(list);}}// 默认是下载,inline是在线预览,支持音频调整进度条@ApiOperationSupport(order = 2)@Operation(summary = "下载或预览文件")@GetMapping("/download")public void download(@RequestParam(name = "fileId") Long fileId,@Parameter(name = "disposition", description = "attachment(默认下载)、inline(在线预览)")@RequestParam(name = "disposition", required = false, defaultValue = "attachment") String disposition,HttpServletRequest request,HttpServletResponse response) throws IOException {TempFile tempFile= meetingFileService.selectTempFile (fileId);if (null == tempFile) {throw new RuntimeException("资源不存在!");}FileUtils.download(request, response, tempFile.getVoiceName(), tempFile.getVoicePath(), disposition);}

二:FileUtils

package org.example.common.utils;import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;/*** 文件上传工具类** @author lt*/
@Slf4j
public class FileUtils {public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.]+";// 文档类型public static String[] documentFormats = {"doc", "docx", "pdf", "txt", "xls", "xlsx", "ppt", "pptx", "rtf", "odt"};// 图片类型public static String[] imageFormats = {"jpg", "jpeg", "png", "gif", "bmp", "webp", "tiff", "svg"};// 视频类型public static String[] videoFormats = {"mp4", "avi", "mov", "wmv", "flv", "mkv", "webm", "mpeg", "3gp"};/*** 文件名称验证** @param filename 文件名称* @return true 正常 false 非法*/public static boolean isValidFilename(String filename) {return filename.matches(FILENAME_PATTERN);}/*** 根据文件路径上传** @param baseDir 相对应用的基目录* @param file    上传的文件* @return 文件名称* @throws IOException*/public static void upload(String baseDir, MultipartFile file) throws IOException {try {// 获取后缀名称String fileName = file.getOriginalFilename();String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();file.transferTo(Paths.get(absPath));} catch (Exception e) {throw new IOException(e.getMessage(), e);}}public static void upload(String baseDir, String fileName, MultipartFile file) throws IOException {try {// 获取后缀名称String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();file.transferTo(Paths.get(absPath));} catch (Exception e) {throw new IOException(e.getMessage(), e);}}public static File getAbsoluteFile(String uploadDir, String fileName) throws IOException {File desc = new File(uploadDir + File.separator + fileName);if (!desc.exists()) {if (!desc.getParentFile().exists()) {desc.getParentFile().mkdirs();}}return desc;}// 动态检测内容类型public static String detectContentType(String fileName) {String ext = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();switch (ext) {case "mp3":return "audio/mpeg";case "wav":return "audio/wav";case "flac":return "audio/flac";case "mp4":return "video/mp4";case "pdf":return "application/pdf";case "jpg":case "jpeg":return "image/jpeg";case "png":return "image/png";case "gif":return "image/gif";case "txt":return "text/plain";case "css":return "text/css";case "js":return "application/javascript";case "json":return "application/json";case "xml":return "application/xml";default:return "application/octet-stream";}}/*** 类型(默认0其他 1文档 2图片 3视频)** @param fileFormat 后缀格式* @return 类型*/public static String getFileType(String fileFormat) {String fileType = "0"; // 默认其他类型// 检查文件类型for (String format : documentFormats) {if (format.equals(fileFormat)) {fileType = "1";break;}}for (String format : imageFormats) {if (format.equals(fileFormat)) {fileType = "2";break;}}for (String format : videoFormats) {if (format.equals(fileFormat)) {fileType = "3";break;}}return fileType;}/*** 更准确的文件大小格式化方法*/public static String formatFileSize(long size) {try {if (size <= 0) return "0 B";final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};int digitGroups = (int) (Math.log10(size) / Math.log10(1024));// 确保不会超出数组范围digitGroups = Math.min(digitGroups, units.length - 1);return String.format("%.2f%s", size / Math.pow(1024, digitGroups), units[digitGroups]);}catch (Exception e){return "";}}/*** 下载或预览文件*  支持音频调进度条* @param response 响应对象* @param fileName 文件名* @param filePath  文件路径* @param disposition attachment(默认下载)、inline(在线预览)*/public static void download(HttpServletRequest request,HttpServletResponse response, String fileName, String filePath, String disposition) {Path basePath = Paths.get(filePath).toAbsolutePath().normalize();if (!Files.exists(basePath)) {throw new RuntimeException("文件不存在");}try {response.setCharacterEncoding("utf-8");response.setContentType(detectContentType(fileName));String safeFilename = URLEncoder.encode(fileName, "UTF-8").replace("+", "%20");String contentDispositionValue = disposition + "; filename=\"" + safeFilename + "\"";response.setHeader("Content-Disposition", contentDispositionValue);response.setHeader("Accept-Ranges", "bytes");response.setHeader("Cache-Control", "no-cache");long fileSize = Files.size(basePath);String rangeHeader = request.getHeader("Range");// 如果没有Range头,发送整个文件if (rangeHeader == null) {response.setHeader("Content-Length", String.valueOf(fileSize));response.setStatus(HttpServletResponse.SC_OK);Files.copy(basePath, response.getOutputStream());//FileUtils.writeBytes(voice.getVoicePath(), response.getOutputStream());return;}// 解析Range头String[] ranges = rangeHeader.substring(6).split("-");long start = Long.parseLong(ranges[0]);long end = ranges.length > 1 ? Long.parseLong(ranges[1]) : fileSize - 1;// 验证范围有效性if (start < 0 || end >= fileSize || start > end) {response.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);response.setHeader("Content-Range", "bytes */" + fileSize);return;}long contentLength = end - start + 1;response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);response.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + fileSize);response.setHeader("Content-Length", String.valueOf(contentLength));// 使用RandomAccessFile读取文件的指定部分try (RandomAccessFile randomAccessFile = new RandomAccessFile(basePath.toFile(), "r")) {randomAccessFile.seek(start);byte[] buffer = new byte[4096];long remaining = contentLength;while (remaining > 0) {int read = randomAccessFile.read(buffer, 0, (int) Math.min(buffer.length, remaining));if (read == -1) {break;}response.getOutputStream().write(buffer, 0, read);remaining -= read;}}} catch (Exception e) {log.error("下载或预览文件" + e.getMessage());if (!response.isCommitted()) {response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);}}}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
—音频选择进度条是重新发送 request的Range字段,FileUtils.download方法已经处理了。

http://www.dtcms.com/a/391316.html

相关文章:

  • 部署你的 Next.js 应用:Vercel、Netlify 和自托管选项
  • 从产品经理视角:小智AI的产品介绍与分析
  • 解决:导包红色波浪线但正常运行及其后续问题
  • webrtc弱网-LinkCapacityEstimator类源码分析与算法原理
  • vue el-autocomplete输入框自动匹配优化,建议项按高度相似降序
  • 十分钟了解@Version注解
  • vue3+ts+uniapp H5微信小程序app有截止日期的日期date-pcicker组件
  • 设计模式-观察者模式详解
  • centos7--安装海量数据库Vastbase M100
  • Apache Commons DBCP连接池生产环境配置推荐
  • 【11/20】实时数据基础:WebSocket 在 Express 和 Vue 中的整合,实现简单聊天功能
  • 五传输层-TCP UDP慢启动-真题
  • ARM基础知识
  • 从零开始的指针(5)
  • TDMQ CKafka 版客户端实战指南系列之二:消费消息最佳实践
  • Comcast 没有对比就没有伤害
  • AI悬浮窗 1.0 | 快捷提取文字,总结信息,支持提取文字、理解屏幕上的图案、总结分析信息
  • MySQL、PostgreSQL、MongoDB和Redis全面对比
  • 隐私保护与数据安全合规(七)
  • 登录 双层拦截器+redis
  • TM56M152A (SOP16) HITENX海速芯 8位微控制器MCU 芯片深度解析
  • 理解元学习器 - 如何使用机器学习估计异质处理效应(四)
  • [数据结构] Map和Set
  • [Go类库分享]Go template模版库
  • 辅助搜题系统-基于模糊搜索,上传word题库后,可搜索答案
  • 【完整源码+数据集+部署教程】遥感农田森林岩石图像分割系统: yolov8-seg-C2f-DCNV2
  • RTX 4090助力深度学习:从PyTorch到生产环境的完整实践指南
  • AWS中国云中的调用链监控(EC2版)
  • CI/CD到底是什么?
  • 3dmax三维动画渲染很慢怎么办?