ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 최종 프로젝트 개발5
    엘리스트랙 2024. 5. 5. 22:40
    728x90

     

     

     

     

     

    유저, 모임, 챌린지에서 이미지 업로드를 해주어야 돼서 이미지 업로드 기능을 구현하였다.

    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
Designed by Tistory.