S3 이미지 업로드

보트·2023년 8월 14일
0

AWS

목록 보기
1/1

준비

1. AWS 설정

S3 버킷 생성 > IAM 사용자 생성

2. 로컬 환경 설정

Spring Boot 연결

build.gradle

//  aws s3
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

application.properties
: 배포하지 않을 예정이기 때문에 application.properties에 한꺼번에 적어둠
: IAM 사용자의 access key를 발급받아 붙이기

#S3
cloud.aws.credentials.accessKey={IAM-access-key}
cloud.aws.credentials.secretKey={IAM-secret-key}
cloud.aws.s3.bucket={bucket-name}
cloud.aws.region.static={region}
cloud.aws.s3.bucket.url=https://s3.ap-northeast-2.amazonaws.com/{bucket-name}
cloud.aws.stack.auto=false

AmazonS3Config.java

@Configuration
public class AmazonS3Config {

    @Value("${cloud.aws.credentials.accessKey}")
    private String accessKey;

    @Value("${cloud.aws.credentials.secretKey}")
    private String secretKey;

    @Value("${cloud.aws.region.static}")
    private String region;

    // S3 버킷에 접근할 수 있는 client 객체
    @Bean
    public AmazonS3Client amazonS3Client() {
        BasicAWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);

        return (AmazonS3Client) AmazonS3ClientBuilder.standard()
                .withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
                .build();
    }

}

구현

업로드 기능

AwsS3FileUpload.java

@Slf4j(topic = "AwsS3Service")
@RequiredArgsConstructor
@Component
public class AwsS3FileUploadImpl implements AwsS3FileUpload {

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

    private final AmazonS3Client amazonS3Client;

    @Override
    public String upload(MultipartFile multipartFile, String dirName) throws IOException {
        File uploadFile = convert(multipartFile)
                .orElseThrow(() -> new IllegalArgumentException("MultipartFile -> File로 전환이 실패했습니다."));

        // 현재 dirName 은 profile 만 받을 예정
        String fileName = dirName + "/" + uploadFile.getName();
        String uploadImageUrl = putS3(uploadFile, fileName);
        removeNewFile(uploadFile);
        return uploadImageUrl;
    }

    @Override
    public String putS3(File uploadFile, String fileName) {
        // bucket 권한때 설정한 것 중 하나
        amazonS3Client.putObject(
                new PutObjectRequest(bucket, fileName, uploadFile)
                        .withCannedAcl(CannedAccessControlList.PublicRead)
        );
        return amazonS3Client.getUrl(bucket, fileName).toString();
    }

    @Override
    public void removeNewFile(File localSavedFile) {
        if (localSavedFile.delete()) {
            log.info("로컬에 저장된 파일 삭제");
        } else {
            log.info("로컬에 저장된 파일 삭제 실패");
        }
    }

    @Override
    public Optional<File> convert(MultipartFile file) throws IOException {
        File convertFile = new File(file.getOriginalFilename());
        log.info("convertFile = " + convertFile);

        if (convertFile.createNewFile()) {
            try (FileOutputStream fos = new FileOutputStream(convertFile)) {
                fos.write(file.getBytes());
            }
            return Optional.of(convertFile);
        }
        return Optional.empty();
    }
}

UserService.java

    @Override
    public void uploadProfileImage(MultipartFile multipartFile, User user) throws IOException {
        fileUpload.upload(multipartFile, "profile");
    }

UserController.java

    @PostMapping("/profileImg")
    public ResponseEntity<ApiResponseDto> uploadProfileImage(
            @RequestPart (required = false) MultipartFile multipartFile,
            @AuthenticationPrincipal UserDetailsImpl userDetails
            ) throws IOException {
        userService.uploadProfileImage(multipartFile, userDetails.getUser());
        return ResponseEntity.status(201).body(new ApiResponseDto("프로필 사진이 업로드 되었습니다.", HttpStatus.CREATED.value()));
    }

프로필 이미지를 변경할 때 이미지 파일과 요청한 사용자 정보만 필요하기 때문에 위와 같이 작성함

테스트

API 에서 content type을 Image/{확장자명} 으로 설정해야함
-> 설정하지 않는다면 415 Unsupported MediaType ERROR 발생


profile 폴더에 들어간 것을 확인할 수 있음

profile
일주일에 한 번

0개의 댓글