diff --git a/src/main/java/com/server/running_handai/domain/course/service/CourseDataService.java b/src/main/java/com/server/running_handai/domain/course/service/CourseDataService.java index cce2e68..893614b 100644 --- a/src/main/java/com/server/running_handai/domain/course/service/CourseDataService.java +++ b/src/main/java/com/server/running_handai/domain/course/service/CourseDataService.java @@ -448,7 +448,7 @@ public void updateCourseImage(Long courseId, MultipartFile courseImageFile) { Course course = courseRepository.findById(courseId).orElseThrow(() -> new BusinessException(COURSE_NOT_FOUND)); // 새 파일을 S3에 먼저 업로드 - String newImageUrl = fileService.uploadFile(courseImageFile, "course"); + String newImageUrl = fileService.uploadFile(courseImageFile, "image"); log.info("[코스 이미지 수정] S3 버킷에 이미지 업로드 완료: newImageUrl={}", newImageUrl); // 삭제할 기존 파일 URL을 임시 변수에 저장 diff --git a/src/main/java/com/server/running_handai/domain/course/service/FileService.java b/src/main/java/com/server/running_handai/domain/course/service/FileService.java index 35aee78..e5d3ae7 100644 --- a/src/main/java/com/server/running_handai/domain/course/service/FileService.java +++ b/src/main/java/com/server/running_handai/domain/course/service/FileService.java @@ -44,6 +44,8 @@ public FileService(S3Client s3Client) { this.s3Client = s3Client; } + private static final String FILENAME_PATTERN = "[^A-Za-z0-9_-]"; + /** * MultipartFile을 S3 버킷에 업로드하고, 업로드된 파일의 URL을 반환합니다. * 파일에 따라 디렉토리로 구분하여 저장합니다. (예: gpx, image) @@ -54,17 +56,18 @@ public FileService(S3Client s3Client) { */ public String uploadFile(MultipartFile multipartFile, String directory) { String originalFileName = multipartFile.getOriginalFilename(); + if (originalFileName == null || originalFileName.isBlank()) { - originalFileName = "no-name"; + log.warn("[S3 파일 업로드] 파일명을 찾을 수 없어 기본값 제공"); + originalFileName = "file"; } - String fileName = directory + "/" + UUID.randomUUID() + "_" + originalFileName; - String contentType = multipartFile.getContentType(); - if (contentType == null || contentType.isBlank()) { - contentType = guessContentType(originalFileName); - } + String contentType = guessContentType(originalFileName); validateFileType(originalFileName); + String newFileName = changeFileName(originalFileName); + String fileName = directory + "/" + UUID.randomUUID() + "_" + newFileName; + try { return uploadToS3(fileName, contentType, multipartFile.getInputStream(), multipartFile.getSize()); } catch (IOException e) { @@ -86,14 +89,18 @@ public String uploadFileByUrl(String fileUrl, String directory) { URL url = new URL(fileUrl); String path = url.getPath(); String originalFileName = path.substring(path.lastIndexOf('/') + 1); - if (originalFileName == null || originalFileName.isBlank()) { - originalFileName = "no-name"; + + if (originalFileName.isBlank()) { + log.warn("[S3 파일 업로드] 파일명을 찾을 수 없어 기본값 제공"); + originalFileName = "file"; } - String fileName = directory + "/" + UUID.randomUUID() + "_" + originalFileName; String contentType = guessContentType(originalFileName); validateFileType(originalFileName); + String newFileName = changeFileName(originalFileName); + String fileName = directory + "/" + UUID.randomUUID() + "_" + newFileName; + HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); httpURLConnection.setRequestMethod("GET"); httpURLConnection.connect(); @@ -222,6 +229,31 @@ private void validateFileType(String fileName) { } } + /** + * 저장 시 UTF-8 인코딩이 필요없는 영문으로 파일명을 바꿉니다. + * 확장자는 보존하고, 파일명이 비어있으면 기본값(file)을 사용합니다. + * + * @param originalFileName 원본 파일명 + * @return 허용된 문자로 이루어진 파일명 + */ + private String changeFileName(String originalFileName) { + // 확장자 분리 + int dotIndex = originalFileName.lastIndexOf('.'); + String name = (dotIndex == -1) ? originalFileName : originalFileName.substring(0, dotIndex); + String extension = (dotIndex == -1) ? "" : originalFileName.substring(dotIndex).toLowerCase(); + + // 영문, 숫자, 하이픈, 언더스코어만 허용 + String newFileName = name.replaceAll(FILENAME_PATTERN, ""); + + // 원본 파일명에 허용된 문자가 없어 빈 파일명일 경우 기본값 사용 + if (newFileName.isBlank()) { + log.warn("[S3 파일 업로드] 원본 파일명에 허용된 문자가 없어 기본값 사용: originalFilName={}", originalFileName); + newFileName = "file"; + } + + return newFileName + extension; + } + /** * InputStream을 받아 S3에 업로드하고 업로드된 파일 URL을 반환합니다. *