AWS

[S3] AWS - SpringBoot 설정

공부 기록장 2025. 3. 2. 16:25

- application.properties 파일 설정

cloud.aws.s3.bucket=[생성한 버킷 이름]
cloud.aws.stack.auto=false
cloud.aws.region.static=ap-northeast-2
cloud.aws.credentials.access-key=[액세스 키]
cloud.aws.credentials.secret-key=[비밀 액세스 키]

 

 

 

- build.gradle 에 의존성 추가

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

 

 

 

 

- S3Config 파일 설정

@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 AmazonS3Client amazonS3Client(){
        BasicAWSCredentials credentials = new BasicAWSCredentials(this.accessKey, this.secretKey);
        return (AmazonS3Client) AmazonS3ClientBuilder
                .standard()
                .withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(credentials))
                .build();
    }
}

 

 

 

 

- S3Service 파일 설정

@Service
@RequiredArgsConstructor
public class S3Service {
    private final S3Config s3Config;


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

    public String uploadPostImage(MultipartFile file) {
        // 파일명 설정 (UUID + 원본 파일명)
        String post_folderName = "post_image/";
        String fileName = post_folderName + UUID.randomUUID();

        // 메타데이터 설정 (파일 크기 및 타입)
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(file.getSize());
        metadata.setContentType(file.getContentType());

        try {
            // S3에 파일 업로드
            s3Config.amazonS3Client().putObject(new PutObjectRequest(bucketName, fileName, file.getInputStream(), metadata)
                    .withCannedAcl(CannedAccessControlList.PublicRead));

            // 업로드된 이미지의 URL 반환
            return s3Config.amazonS3Client().getUrl(bucketName, fileName).toString();
        } catch (IOException e) {
            throw new RuntimeException("게시글 이미지 업로드 실패", e);
        }
    }

 

 

 

 

 

 

- 프론트로부터 이미지를 받는 컨트롤러 작성

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/posts")
public class PostController {
    private final PostService postService;
    private final S3Service s3Service;

    @PreAuthorize("isAuthenticated()")
    @PostMapping("/create")
    public ResponseEntity<?> createPost(@RequestPart("postData") PostCreateRequest request,
                                        @RequestPart(value="image", required = false) MultipartFile file,
                                        @AuthenticationPrincipal CustomUserDetails customUserDetails,
                                        @AuthenticationPrincipal CustomOAuth2User customOAuth2User) throws IOException {


        if (customUserDetails == null && customOAuth2User == null) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                    .body("accessToken 재발급 요청");
        }

        if (request.getContent()== null || request.getContent().trim().isEmpty()) {
            return ResponseEntity.badRequest().body("게시글 내용은 필수입니다.");
        }
        try {
            String imagePath = null;
            if(file != null){
                imagePath = s3Service.uploadPostImage(file);
                log.info("S3 에 이미지 업로드 완료 : " + imagePath);
            }
            if(customUserDetails != null){
                postService.create(request, customUserDetails, imagePath);
            }
            if(customOAuth2User != null){
                postService.create(request, customOAuth2User, imagePath);
            }
            return ResponseEntity.status(200).build();
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("게시글 작성 중 서버 오류가 발생했습니다.");
        }
    }
}