-
최종 프로젝트 개발5엘리스트랙 2024. 5. 5. 22:40728x90
유저, 모임, 챌린지에서 이미지 업로드를 해주어야 돼서 이미지 업로드 기능을 구현하였다.
https://innovation123.tistory.com/197
[Spring / S3] SpringBoot 프로젝트 - S3 이미지 업로드
이전 글에서 S3 bucket과 IAM을 생성하고 SpringBoot project에서 S3 접근에 사용할 accessKey와 secretKey를 얻는 것까지 다뤘다. 2024.01.21 - [DevOps] - [AWS/S3] Spring boot project 이미지 업로드를 위해 S3 버켓 만들기 [
innovation123.tistory.com
이 블로그를 참고했는데 큰 도움이 되었다.
@Slf4j @RequiredArgsConstructor @Component public class S3ImageService { private final AmazonS3 amazonS3; @Value("${cloud.aws.s3.bucketName}") private String bucketName; public String upload(MultipartFile image) { if(image.isEmpty() || Objects.isNull(image.getOriginalFilename())){ throw new ServiceLogicException(ExceptionCode.EMPTY_FILE); } return this.uploadImage(image); } private String uploadImage(MultipartFile image) { this.validateImageFileExtention(image.getOriginalFilename()); try { return this.uploadImageToS3(image); } catch (IOException e) { throw new ServiceLogicException(ExceptionCode.IO_EXCEPTION_ON_IMAGE_UPLOAD); } } private void validateImageFileExtention(String filename) { int lastDotIndex = filename.lastIndexOf("."); if (lastDotIndex == -1) { throw new ServiceLogicException(ExceptionCode.NO_FILE_EXTENTION); } String extention = filename.substring(lastDotIndex + 1).toLowerCase(); List<String> allowedExtentionList = Arrays.asList("jpg", "jpeg", "png", "gif"); if (!allowedExtentionList.contains(extention)) { throw new ServiceLogicException(ExceptionCode.INVALID_FILE_EXTENTION); } } private String uploadImageToS3(MultipartFile image) throws IOException { String originalFilename = image.getOriginalFilename(); //원본 파일 명 String extention = originalFilename.substring(originalFilename.lastIndexOf(".")); //확장자 명 String s3FileName = UUID.randomUUID().toString().substring(0, 10) + originalFilename; //변경된 파일 명 InputStream is = image.getInputStream(); byte[] bytes = IOUtils.toByteArray(is); ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentType("image/" + extention); metadata.setContentLength(bytes.length); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); try{ PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, s3FileName, byteArrayInputStream, metadata); //.withCannedAcl(CannedAccessControlList.PublicRead); amazonS3.putObject(putObjectRequest); // put image to S3 }catch (Exception e){ log.error("S3 이미지 업로드 중 에러 발생", e); throw new ServiceLogicException(ExceptionCode.PUT_OBJECT_EXCEPTION); }finally { byteArrayInputStream.close(); is.close(); } return amazonS3.getUrl(bucketName, s3FileName).toString(); } public void deleteImageFromS3(String imageAddress){ String key = getKeyFromImageAddress(imageAddress); try{ amazonS3.deleteObject(new DeleteObjectRequest(bucketName, key)); }catch (Exception e){ throw new ServiceLogicException(ExceptionCode.IO_EXCEPTION_ON_IMAGE_DELETE); } } private String getKeyFromImageAddress(String imageAddress){ try{ URL url = new URL(imageAddress); String decodingKey = URLDecoder.decode(url.getPath(), "UTF-8"); return decodingKey.substring(1); // 맨 앞의 '/' 제거 }catch (MalformedURLException | UnsupportedEncodingException e){ throw new ServiceLogicException(ExceptionCode.IO_EXCEPTION_ON_IMAGE_DELETE); } } }
이미지를 업로드하는 서비스를 구현하고 기존 컨트롤러와 서비스에 적용을 해주었다.
@Operation(summary = "모임 생성 기능", description = "모임 생성") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "성공", content = @Content(schema = @Schema(implementation = MeetingResponseDto.class))) }) @PostMapping public ResponseEntity<MeetingResponseDto> createMeeting(@AuthenticationPrincipal String email, @ModelAttribute @Valid MeetingDto meetingDto){ meetingDto.setUserEmail(email); return ResponseEntity.ok(meetingService.createMeeting(meetingDto)); }
@RequestBody로 프론트에서 받아오던 부분을 @ModelAttribute로 받아왔다. 프론트는 JSON에서 form-data로 넘겨주는 차이가 있다.
MultipartFile imageFile = meetingDto.getImageFile(); String imageUrl = Constants.DEFAULT_URL + "meeting_default_image.png"; if (imageFile != null && !imageFile.isEmpty()) { imageUrl = s3ImageService.upload(imageFile); }
그리고 서비스에서 이미지 업로드를 하는 기능을 넣어주었다. S3에 이미지를 넣어주면 해당 이미지의 url을 반환해 주어 그걸 저장해 주었다.
db에 이미지 url이 잘 저장되었다.
728x90'엘리스트랙' 카테고리의 다른 글
엘리스 Cloud 트랙 수료 후기! (0) 2024.06.04 최종 프로젝트 후기! (0) 2024.05.12 최종 프로젝트 개발4 (0) 2024.05.05 최종 프로젝트 개발3 (1) 2024.04.28 최종 프로젝트 개발2 (1) 2024.04.28