본문 바로가기
TIL/AWS

23.08.02

by J1-H00N 2023. 8. 2.

S3 이미지 업로드를 복습해보자.

 

일단 S3에서 버킷을 생성한다.

객체 소유권 > ACL 활성화됨 > 모든 퍼블릭 엑세스 차단 헤제

 

그리고 이 S3를 사용하기 위한 전용 IAM 사용자를 추가해야한다.

사용자 추가 > console 사용자 액세스 권한 제공 > IAM 사용자를 생성하고 싶음 > 나머지는 기본 설정 > 권한 옵션 > 직접 정책 연결 > AmazonS3FullAccess 선택 > 생성

IAM > 사용자 > 보안 자격 증명 > 액세스 키 만들기 > csv 파일 저장

 

# application.properties
spring.servlet.multipart.enabled=true
spring.servlet.multipart.max-file-size=10MB

cloud.aws.credentials.access-key=${AWS_S3_ACCESS_KEY}
cloud.aws.credentials.secret-key=${AWS_S3_SECRET_KEY}
cloud.aws.region.static=ap-northeast-2
cloud.aws.stack.auto=false
cloud.aws.s3.bucket= S3 버킷 이름
// build.gradle

// AWS
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
@Configuration
public class AwsS3Config {

    @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 AmazonS3Client amazonS3Client() {
        BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
        return (AmazonS3Client) AmazonS3ClientBuilder.standard()
                .withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(awsCreds))
                .build();
    }
}
@Slf4j
@RequiredArgsConstructor    // final 멤버변수가 있으면 생성자 항목에 포함시킴
@Service
public class S3Uploader {

    private final AmazonS3Client amazonS3Client;

    @Value("${cloud.aws.s3.bucket}")
    private String bucket;

    // MultipartFile을 전달받아 File로 전환한 후 S3에 업로드
    public String upload(MultipartFile multipartFile, String dirName) throws IOException {
        if (multipartFile.isEmpty()) {
            return "https://dtogram.s3.ap-northeast-2.amazonaws.com/postFile/%EA%B8%B0%EB%B3%B8%20%EC%9D%B4%EB%AF%B8%EC%A7%80.png";
        } else {
            File uploadFile = convert(multipartFile)
                    .orElseThrow(() -> new IllegalArgumentException("MultipartFile -> File 전환 실패"));
            return upload(uploadFile, dirName);
        }
    }

    private String upload(File uploadFile, String dirName) {
        String fileName = dirName + "/" + uploadFile.getName();
        String uploadImageUrl = putS3(uploadFile, fileName);

        removeNewFile(uploadFile);  // 로컬에 생성된 File 삭제 (MultipartFile -> File 전환 하며 로컬에 파일 생성됨)

        return uploadImageUrl;      // 업로드된 파일의 S3 URL 주소 반환
    }

    private String putS3(File uploadFile, String fileName) {
        amazonS3Client.putObject(
                new PutObjectRequest(bucket, fileName, uploadFile)
                        .withCannedAcl(CannedAccessControlList.PublicRead)	// PublicRead 권한으로 업로드 됨
        );
        return amazonS3Client.getUrl(bucket, fileName).toString();
    }

    private void removeNewFile(File targetFile) {
        if(targetFile.delete()) {
            log.info("파일이 삭제되었습니다.");
        }else {
            log.info("파일이 삭제되지 못했습니다.");
        }
    }

    private Optional<File> convert(MultipartFile file) throws  IOException {
        File convertFile = new File(file.getOriginalFilename());
        if(convertFile.createNewFile()) {
            try (FileOutputStream fos = new FileOutputStream(convertFile)) {
                fos.write(file.getBytes());
            }
            return Optional.of(convertFile);
        }
        return Optional.empty();
    }

}

 

테스트를 위해 postman에서 지난 프로젝트와 동일한 방식으로 진행했으나 postman에서 다음과 같은 오류메시지가 출력됐다.

{
    "type""about:blank",
    "title""Unsupported Media Type",
    "status"415,
    "detail""Content-Type 'application/octet-stream' is not supported.",
    "instance""/api/blog"
}

구글링을 해보니

@RequestPart("requestDto") BlogRequestDto requestDto

이와 같이 request형식이 아니라 

@RequestPart String title, @Request String contents

처럼 각 요소를 따로 분리하면 해결된다고 한다. 하지만 이렇게 하면 controller부터 service, serviceImpl, Blog까지 전부 수정사항이 생겨 다른 방법을 알아보려고 한다.

 

에러가 났던 이유는 postman에서 requestDto의 content type을 application/json로 지정하는 것을 깜빡해서 생긴 이슈였다.

하지만 이렇게 고친 뒤에도 어째선지 RuntimeError가 발생했다.

 

log를 추가하며 확인한 결과 디렉토리 문제임을 알게 됐다. S3 버킷을 새로 만들어서 해결했다.

 

참고한 블로그

https://velog.io/@chaeri93/SpringBoot-AWS-S3%EB%A1%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%97%85%EB%A1%9C%EB%93%9C%ED%95%98%EA%B8%B0

'TIL > AWS' 카테고리의 다른 글

23.08.01  (0) 2023.08.01
23.07.31  (0) 2023.07.31