diff --git a/src/main/java/org/cotato/csquiz/common/S3/S3Uploader.java b/src/main/java/org/cotato/csquiz/common/S3/S3Uploader.java index 7d3b8816..f750e52d 100644 --- a/src/main/java/org/cotato/csquiz/common/S3/S3Uploader.java +++ b/src/main/java/org/cotato/csquiz/common/S3/S3Uploader.java @@ -1,11 +1,11 @@ package org.cotato.csquiz.common.S3; -import static org.cotato.csquiz.common.util.FileUtil.checkAllowedImageFileExtension; import static org.cotato.csquiz.common.util.FileUtil.extractFileExtension; +import static org.cotato.csquiz.common.util.FileUtil.isImageFileExtension; -import com.amazonaws.SdkClientException; import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.services.s3.model.CannedAccessControlList; +import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.PutObjectRequest; import org.cotato.csquiz.common.entity.S3Info; import org.cotato.csquiz.common.error.ErrorCode; @@ -20,27 +20,29 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.util.Optional; @Slf4j @RequiredArgsConstructor @Component public class S3Uploader { + private static final String CONTENT_TYPE = "multipart/formed-data"; private final AmazonS3Client amazonS3; @Value("${cloud.aws.s3.bucket}") private String bucket; public S3Info uploadFiles(MultipartFile multipartFile, String folderName) throws ImageException { - log.info("upload Files {}", multipartFile); - File uploadFile = convert(multipartFile) - .orElseThrow(() -> new ImageException(ErrorCode.IMAGE_PROCESSING_FAIL)); - String uploadUrl = upload(uploadFile, folderName); + log.info("{} 사진 업로드", multipartFile.getOriginalFilename()); + File localUploadFile = convert(multipartFile); + + String fileName = folderName + "/" + localUploadFile.getName(); + String uploadUrl = putS3(localUploadFile, fileName); + localUploadFile.delete(); return S3Info.builder() .folderName(folderName) - .fileName(uploadFile.getName()) + .fileName(localUploadFile.getName()) .url(uploadUrl) .build(); } @@ -48,57 +50,43 @@ public S3Info uploadFiles(MultipartFile multipartFile, String folderName) throws public void deleteFile(S3Info s3Info) { String fileName = s3Info.getFolderName() + "/" + s3Info.getFileName(); - log.info("deleteFile fileName = {}", fileName); - try { - amazonS3.deleteObject(bucket, fileName); - } catch (SdkClientException e) { - log.error("Failed to delete file: {}", s3Info.getUrl(), e); - } + log.info("{} 사진 삭제", fileName); + amazonS3.deleteObject(bucket, fileName); } - private String upload(File uploadFile, String dirName) { - String fileName = dirName + "/" + uploadFile.getName(); - String uploadUrl = putS3(uploadFile, fileName); - removeNewFile(uploadFile); - log.info(uploadUrl); - return uploadUrl; - } + private String putS3(File uploadFile, String fileName) { + PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, fileName, uploadFile) + .withCannedAcl(CannedAccessControlList.PublicRead); - private void removeNewFile(File targetFile) { - if (targetFile.delete()) { - log.info("삭제 완료"); - } else { - log.error("삭제 에러"); + if (isImageFile(uploadFile)) { + ObjectMetadata objMeta = new ObjectMetadata(); + objMeta.setContentType(CONTENT_TYPE); } - } - private String putS3(File uploadFile, String fileName) { - amazonS3.putObject( - new PutObjectRequest(bucket, fileName, uploadFile).withCannedAcl(CannedAccessControlList.PublicRead)); + amazonS3.putObject(putObjectRequest); + return amazonS3.getUrl(bucket, fileName).toString(); } - private Optional convert(MultipartFile file) throws ImageException { - String fileExtension = extractFileExtension(file); - checkAllowedImageFileExtension(fileExtension); + private boolean isImageFile(File file) { + String fileName = file.getName(); + String extension = fileName.substring(fileName.lastIndexOf(".") + 1); + + return isImageFileExtension(extension); + } + private File convert(MultipartFile file) throws ImageException { + String fileExtension = extractFileExtension(file); File convertFile = new File(System.getProperty("user.dir") + "/" + UUID.randomUUID() + "." + fileExtension); - log.info("converted file name: {}", convertFile.getName()); try { - log.info("convert try start"); - if (convertFile.createNewFile()) { // 바로 위에서 지정한 경로에 File이 생성됨 (경로가 잘못되었다면 생성 불가능) - FileOutputStream fos = new FileOutputStream(convertFile); // FileOutputStream 데이터를 파일에 바이트 스트림으로 저장하기 위함 - fos.write(file.getBytes()); - fos.close(); - log.info("convert to " + convertFile); - return Optional.of(convertFile); - } + FileOutputStream fos = new FileOutputStream(convertFile); + fos.write(file.getBytes()); + fos.close(); + + return convertFile; } catch (IOException e) { - log.error("convert 실패", e); throw new ImageException(ErrorCode.IMAGE_PROCESSING_FAIL); } - log.info("convert empty"); - return Optional.empty(); } } diff --git a/src/main/java/org/cotato/csquiz/common/error/handler/GlobalExceptionHandler.java b/src/main/java/org/cotato/csquiz/common/error/handler/GlobalExceptionHandler.java index c9a0d35d..28517304 100644 --- a/src/main/java/org/cotato/csquiz/common/error/handler/GlobalExceptionHandler.java +++ b/src/main/java/org/cotato/csquiz/common/error/handler/GlobalExceptionHandler.java @@ -1,5 +1,6 @@ package org.cotato.csquiz.common.error.handler; +import com.amazonaws.services.s3.model.AmazonS3Exception; import org.cotato.csquiz.common.error.exception.AppException; import org.cotato.csquiz.common.error.exception.ImageException; import org.cotato.csquiz.common.error.response.ErrorResponse; @@ -84,4 +85,13 @@ public ResponseEntity handleSQLException(SQLException e, HttpServ ErrorResponse errorResponse = ErrorResponse.of(ErrorCode.INTERNAL_SQL_ERROR, request); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); } + + @ExceptionHandler(AmazonS3Exception.class) + public ResponseEntity handleAmazonS3Exception(AmazonS3Exception e, HttpServletRequest request) { + log.error("발생한 에러: {}", e.getErrorCode()); + log.error("에러가 발생한 지점 {}, {}", request.getMethod(), request.getRequestURI()); + ErrorResponse errorResponse = ErrorResponse.of(ErrorCode.FILE_EXTENSION_FAULT, request); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse); + } } + diff --git a/src/main/java/org/cotato/csquiz/common/util/FileUtil.java b/src/main/java/org/cotato/csquiz/common/util/FileUtil.java index 34c06e22..9ee7099a 100644 --- a/src/main/java/org/cotato/csquiz/common/util/FileUtil.java +++ b/src/main/java/org/cotato/csquiz/common/util/FileUtil.java @@ -1,13 +1,13 @@ package org.cotato.csquiz.common.util; -import java.util.Arrays; +import java.util.List; import org.cotato.csquiz.common.error.ErrorCode; import org.cotato.csquiz.common.error.exception.ImageException; import org.springframework.web.multipart.MultipartFile; public class FileUtil { - private static final String[] ALLOWED_IMAGE_FILE_EXTENSIONS = {"png", "jpg", "jpeg", "heif"}; + private static final List ALLOWED_IMAGE_FILE_EXTENSIONS = List.of("png", "jpg", "jpeg", "heif"); public static String extractFileExtension(MultipartFile file) throws ImageException { String originalFilename = file.getOriginalFilename(); @@ -18,9 +18,7 @@ public static String extractFileExtension(MultipartFile file) throws ImageExcept return originalFilename.substring(originalFilename.lastIndexOf(".") + 1); } - public static void checkAllowedImageFileExtension(String fileExtension) throws ImageException { - if (!Arrays.asList(ALLOWED_IMAGE_FILE_EXTENSIONS).contains(fileExtension)) { - throw new ImageException(ErrorCode.FILE_EXTENSION_FAULT); - } + public static boolean isImageFileExtension(String fileExtension) { + return ALLOWED_IMAGE_FILE_EXTENSIONS.contains(fileExtension); } }