package com.rj.service.impl; import com.rj.entity.AudioManagement; import com.rj.service.IFileUploadService; import com.rj.service.IAudioManagementService; import com.rj.service.MinIOService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; import java.util.UUID; /** * 文件上传服务实现类 * * @author 李中华 ,spllzh * @since 2025-08-07 */ @Slf4j @Service public class FileUploadServiceImpl implements IFileUploadService { @Autowired private IAudioManagementService audioManagementService; @Autowired private MinIOService minIOService; @Value("${app.audio.upload.path:uploads/audio}") private String uploadPath; @Value("${app.audio.access.url:/api/audio/}") private String accessUrl; @Value("${app.audio.max.size:10MB}") private String maxFileSize; // 支持的音频格式 private static final String[] SUPPORTED_AUDIO_FORMATS = { "mp3", "wav", "m4a", "aac", "ogg", "flac", "wma" }; @Override public Map uploadAudioFile(MultipartFile file, String audioId) throws IOException { Map result = new HashMap<>(); try { // 验证文件 if (file == null || file.isEmpty()) { result.put("success", false); result.put("message", "文件不能为空"); return result; } // 验证文件大小 long maxSize = parseFileSize(maxFileSize); if (file.getSize() > maxSize) { result.put("success", false); result.put("message", "文件大小超过限制,最大允许 " + maxFileSize); return result; } // 验证文件格式 String originalFilename = file.getOriginalFilename(); if (!isValidAudioFormat(originalFilename)) { result.put("success", false); result.put("message", "不支持的音频格式,支持的格式:" + String.join(", ", SUPPORTED_AUDIO_FORMATS)); return result; } // 直接上传到MinIO,不保存到本地 log.info("开始上传文件到MinIO..."); String fileUrl = minIOService.uploadFile(file); log.info("文件上传成功,URL: {}", fileUrl); // 获取录音记录并更新 AudioManagement audio = audioManagementService.getById(audioId); if (audio != null) { // 更新录音记录的文件信息 String fileExtension = getFileExtension(originalFilename); audio.setAudioFileUrl(fileUrl); audio.setAudioFileSize(file.getSize()); audio.setAudioFileOriginalName(originalFilename); audio.setAudioFileExtension(fileExtension); audio.setUploadTime(java.time.LocalDateTime.now()); audio.setUpdateTime(java.time.LocalDateTime.now()); // 保存更新 audioManagementService.updateById(audio); log.info("录音记录更新成功:audioId={}", audioId); } else { log.warn("未找到对应的录音记录:audioId={}", audioId); } result.put("success", true); result.put("message", "文件上传成功"); result.put("fileUrl", fileUrl); result.put("fileSize", file.getSize()); result.put("originalName", originalFilename); log.info("音频文件上传成功:audioId={}, minioUrl={}, size={}", audioId, fileUrl, file.getSize()); } catch (Exception e) { log.error("音频文件上传失败:audioId={}, error={}", audioId, e.getMessage(), e); result.put("success", false); result.put("message", "文件上传失败:" + e.getMessage()); } return result; } @Override public Map uploadAudioFileAndUpdateRecord(MultipartFile file, String audioId) throws IOException { Map result = new HashMap<>(); try { // 先上传文件 Map uploadResult = uploadAudioFile(file, audioId); if (!(Boolean) uploadResult.get("success")) { return uploadResult; } // 获取录音记录 AudioManagement audio = audioManagementService.getById(audioId); if (audio == null) { result.put("success", false); result.put("message", "录音记录不存在"); return result; } // 更新录音记录的文件信息 String fileName = (String) uploadResult.get("fileName"); String fileUrl = (String) uploadResult.get("fileUrl"); Long fileSize = (Long) uploadResult.get("fileSize"); String originalName = (String) uploadResult.get("originalName"); String fileExtension = getFileExtension(originalName); audio.setAudioFilePath(uploadPath + "/" + fileName); audio.setAudioFileUrl(fileUrl); audio.setAudioFileSize(fileSize); audio.setAudioFileOriginalName(originalName); audio.setAudioFileExtension(fileExtension); audio.setUploadTime(java.time.LocalDateTime.now()); audio.setUpdateTime(java.time.LocalDateTime.now()); // 保存更新 boolean updated = audioManagementService.updateById(audio); if (updated) { result.put("success", true); result.put("message", "音频文件上传成功并更新录音记录"); result.put("data", uploadResult); result.put("audioRecord", audio); log.info("音频文件上传并更新录音记录成功:audioId={}, fileName={}", audioId, fileName); } else { result.put("success", false); result.put("message", "文件上传成功但更新录音记录失败"); result.put("data", uploadResult); } } catch (Exception e) { log.error("音频文件上传并更新录音记录失败:audioId={}, error={}", audioId, e.getMessage(), e); result.put("success", false); result.put("message", "文件上传并更新录音记录失败:" + e.getMessage()); } return result; } @Override public String getAudioFileUrl(String audioId) { if (StringUtils.isEmpty(audioId)) { return null; } Path uploadDir = Paths.get(uploadPath); File dir = uploadDir.toFile(); if (!dir.exists() || !dir.isDirectory()) { return null; } // 查找对应的音频文件 File[] files = dir.listFiles((d, name) -> name.startsWith(audioId + ".")); if (files != null && files.length > 0) { String fileName = files[0].getName(); return accessUrl + fileName; } return null; } @Override public boolean deleteAudioFile(String audioId) { if (StringUtils.isEmpty(audioId)) { return false; } try { Path uploadDir = Paths.get(uploadPath); File dir = uploadDir.toFile(); if (!dir.exists() || !dir.isDirectory()) { return false; } // 查找对应的音频文件 File[] files = dir.listFiles((d, name) -> name.startsWith(audioId + ".")); if (files != null && files.length > 0) { boolean deleted = files[0].delete(); if (deleted) { log.info("音频文件删除成功:audioId={}, fileName={}", audioId, files[0].getName()); } return deleted; } return false; } catch (Exception e) { log.error("音频文件删除失败:audioId={}, error={}", audioId, e.getMessage(), e); return false; } } @Override public boolean audioFileExists(String audioId) { if (StringUtils.isEmpty(audioId)) { return false; } Path uploadDir = Paths.get(uploadPath); File dir = uploadDir.toFile(); if (!dir.exists() || !dir.isDirectory()) { return false; } File[] files = dir.listFiles((d, name) -> name.startsWith(audioId + ".")); return files != null && files.length > 0; } @Override public Map uploadAudioFileToMinIO(MultipartFile file, String audioId) throws IOException { Map result = new HashMap<>(); try { // 验证文件 if (file == null || file.isEmpty()) { result.put("success", false); result.put("message", "文件不能为空"); return result; } // 验证文件大小 long maxSize = parseFileSize(maxFileSize); if (file.getSize() > maxSize) { result.put("success", false); result.put("message", "文件大小超过限制,最大允许 " + maxFileSize); return result; } // 验证文件格式 String originalFilename = file.getOriginalFilename(); if (!isValidAudioFormat(originalFilename)) { result.put("success", false); result.put("message", "不支持的音频格式,支持的格式:" + String.join(", ", SUPPORTED_AUDIO_FORMATS)); return result; } // 使用MinIO上传文件 String minioUrl = minIOService.uploadFile(file); result.put("success", true); result.put("message", "文件上传到MinIO成功"); result.put("fileUrl", minioUrl); result.put("fileSize", file.getSize()); result.put("originalName", originalFilename); result.put("audioId", audioId); log.info("音频文件上传到MinIO成功:audioId={}, minioUrl={}, size={}", audioId, minioUrl, file.getSize()); } catch (Exception e) { log.error("音频文件上传到MinIO失败:audioId={}, error={}", audioId, e.getMessage(), e); result.put("success", false); result.put("message", "文件上传到MinIO失败:" + e.getMessage()); } return result; } /** * 验证音频文件格式 */ private boolean isValidAudioFormat(String filename) { if (StringUtils.isEmpty(filename)) { return false; } String extension = getFileExtension(filename).toLowerCase(); for (String format : SUPPORTED_AUDIO_FORMATS) { if (format.equals(extension)) { return true; } } return false; } /** * 获取文件扩展名 */ private String getFileExtension(String filename) { if (StringUtils.isEmpty(filename)) { return ""; } int lastDotIndex = filename.lastIndexOf('.'); if (lastDotIndex > 0 && lastDotIndex < filename.length() - 1) { return filename.substring(lastDotIndex + 1); } return ""; } /** * 解析文件大小字符串 */ private long parseFileSize(String sizeStr) { if (StringUtils.isEmpty(sizeStr)) { return 100 * 1024 * 1024; // 默认100MB } sizeStr = sizeStr.trim().toUpperCase(); long multiplier = 1; if (sizeStr.endsWith("KB")) { multiplier = 1024; sizeStr = sizeStr.substring(0, sizeStr.length() - 2); } else if (sizeStr.endsWith("MB")) { multiplier = 1024 * 1024; sizeStr = sizeStr.substring(0, sizeStr.length() - 2); } else if (sizeStr.endsWith("GB")) { multiplier = 1024 * 1024 * 1024; sizeStr = sizeStr.substring(0, sizeStr.length() - 2); } try { return Long.parseLong(sizeStr) * multiplier; } catch (NumberFormatException e) { return 100 * 1024 * 1024; // 默认100MB } } }