본문 바로가기
AWS

스프링부트로 s3에 이미지 업로드 하기

by notcherry 2023. 11. 29.

 

 

 

++열심히 삽질하고 영상도 찾아보고 구글도 찾아보다가 415에러의 늪에 빠져 허우적 거리다 찾은 쏫아날 구멍입니다! 저는 스프링 부트3에서 작업했습니다.

 

저의 상황부터 말씀드리자면, 유저가 게시글을 등록하려고 하면 text부분은 reqeustDto로 post service에서 save 되고, 이미지 파일은 MultiPartFile로 s3에 저장합니다. s3에서 저장하면 이미지에 접근할 수 있는 고유 url을 주는데 그것을 postId와 함께 이미지 entity에 저장합니다. 저는 모놀리식이 아닌 msa로 진행해서 이미지 entity에 저장할 때, 게시물에 접근하면 해당 이미지를 postId로 조회하기 때문에 postId와 이미지 url을 함께 저장하는 것입니다! 

 

그리고 저는 백엔드를 맡았기 때문에 프론트 코드는 작성하지 않고, 포스트맨으로만 결과를 확인했습니다.

 

 

먼저 config 클래스 하나를 만들어 주어야 합니다!

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class S3Config {
    @Value("${cloud.aws.credentials.access-key}")
    private String accessKey;
    @Value("${cloud.aws.credentials.secret-key}")
    private String secretKey;
    @Value("${cloud.aws.region.static}")
    private String region;

    @Bean
    public AmazonS3 amazonS3() {
        AWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);
        return AmazonS3ClientBuilder.standard()
                .withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
                .build();
    }
}

 

이 코드는 어느 글을 참고하나 비슷할 거에요

 

 

 

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.wesell.dealservice.domain.entity.Image;
import com.wesell.dealservice.domain.repository.ImageRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.UUID;

@Service
@RequiredArgsConstructor
public class FileUploadService {
    @Value("${cloud.aws.s3.bucket}")
    private String bucket;
    private final AmazonS3 amazonS3;
    private final ImageRepository imageRepository;

    public void saveImageUrl(Long postId, MultipartFile file) throws IOException {
        Image userImage = Image.builder()
                .postId(postId)
                .imageUrl(uploadAndGetUrl(file))
                .build();
        imageRepository.save(userImage);
    }

    public String uploadAndGetUrl(MultipartFile multipartFile) throws IOException {
        String s3FileName = UUID.randomUUID() + "-" + multipartFile.getOriginalFilename();

        ObjectMetadata objMeta = new ObjectMetadata();
        objMeta.setContentLength(multipartFile.getInputStream().available());
        amazonS3.putObject(bucket, s3FileName, multipartFile.getInputStream(), objMeta);

        return amazonS3.getUrl(bucket, s3FileName).toString();
    }

}

 

uploadAndGetUrl은 말그대로 s3에 이미지를 보내고, s3에서 반환해주는 url 값을 받아오는 메소드입니다.

objectMetadata를 사용해서 amazons3에 보내는 코드입니다.

 

그리고 saveImageUrl은 image entity에 저장하는 거에요! 

 

 

저는 이렇게 게시글 만들어줘~ 하면 이미지를 제외한 정보를 저장하고 게시글의 id값을 프론트에 반환합니다. 그럼 프론트에서 받은 id값과 이미지를 전송해서 저장하는 거죠.

 

컨트롤러 코드는 아래와 같습니다.

    /**
     *
     * @param postId & file
     * @return postId와 이미지 url 저장
     * @throws IOException
     */
    @PostMapping("/upload")
    public ResponseEntity<?> uploadFile(@RequestParam("postId") Long postId, @RequestParam("file") MultipartFile file) throws IOException {
        uploadService.saveImageUrl(postId, file);
        return new ResponseEntity<>(HttpStatus.CREATED);
    }

 

 

포스트맨으로 요청 보낼 때도 저는,, 너무 고생을 많이 했는데요.. 지원하지 않는 content type 이라며ㅜㅜ 오만가지 방법을 해도 성사되지 않았고, RequestPart 사용을 포기하고  RequestParam을 사용하니 포스트맨에서 잘 잡더라구요!

안 되는 건 과감하게 포기하세요!

 

 

key값으로 file도 받을 수 있습니다. 저도 이번에 처음 알았는데요. file이라는 key값 보이시죠? file 칸 맨 왼쪽에 커서를 가져다대면 text/file 선택할 수 있더라구요! 

제 글이 도움이 됐으면 좋겠습니다. 궁금증은 댓글 달아주세요~

'AWS' 카테고리의 다른 글

s3 랑 스프링부트랑 연동하기  (0) 2023.11.21