프로젝트/Wedle

[AWS] AWS S3 이용한 파일 업로드 - 프로필사진 등록 📸

예롱메롱 2025. 3. 7. 23:38
728x90
반응형

프로필 이미지 설정 및 제거 기능을 구현하고, Amazon S3에 저장하는 기능을 구현하였습니다. 이 기능을 구현하려면, 프로필 이미지 업로드, 기존 이미지 삭제, 그리고 기본 이미지로의 복구가 필요합니다. 기본 이미지인 default.png 외에는 S3에서 이미지를 삭제하고 새 이미지를 업로드합니다.


📌 build.gralde 에 의존성 추가

프로젝트에 AWS S3 기능을 사용하기 위해 AWS Java SDK 의존성을 추가해야 합니다.

implementation 'software.amazon.awssdk:s3:2.21.5

📌 AppConfig 클래스 (S3 설정)

S3 연동을 위한 기본 설정을 AppConfig 클래스에서 처리합니다. 이 클래스는 AWS 자격 증명과 S3 클라이언트를 설정하는 역할을 합니다.

🛠️ 코드 설명

@Configuration
public class AppConfig {

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

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

    @Bean
    public S3Client s3Client() {
        AwsBasicCredentials credentials = AwsBasicCredentials.create(accessKeyId, secretAccessKey);
        AwsCredentialsProvider provider = StaticCredentialsProvider.create(credentials);
        return S3Client.builder()
                .region(Region.AP_NORTHEAST_2)
                .credentialsProvider(provider)
                .build();
    }
}

🔐 보안 정보 관리

  • accessKeyIdsecretAccessKey는 중요한 보안 정보이므로 프로퍼티 파일에 저장하여 외부에 노출되지 않도록 합니다.
  • @Value 어노테이션을 사용하여 프로퍼티에서 값을 불러옵니다.

📡 AWS S3 클라이언트 설정

  • AwsBasicCredentials: AWS 서비스에 접근하기 위한 기본 자격 증명 클래스입니다. accessKeyId와 secretAccessKey로 구성됩니다.
  • AwsCredentialsProvider: AWS 자격 증명을 제공하는 인터페이스로, 동적 자격 증명을 처리합니다. 보안, 재생성, 환경 설정 등을 고려한 자격 증명 제공을 지원합니다.

🌍 리전 설정

  • Region.AP_NORTHEAST_2: 아시아 태평양 북동부(서울) 리전을 사용하도록 설정합니다.

💡 S3 클라이언트 생성

  • S3Client를 생성하고, 위에서 설정한 자격 증명 공급자와 리전을 적용하여 반환합니다.
  • 이 클라이언트는 Spring 컨테이너에서 관리되며 다른 빈에서 주입 및 사용될 수 있습니다.

📌 application-oauth.yml

🗂️ 파일 업로드 크기 설정

spring:
  servlet:
    multipart:
      max-file-size: 10MB # 업로드할 파일의 최대 크기
      max-request-size: 20MB # 업로드 요청의 최대 크기
  • max-file-size: 파일 하나의 최대 업로드 크기를 10MB로 제한합니다.
  • max-request-size: 요청 전체의 최대 크기를 20MB로 설정합니다.

🌐 Tomcat 서버 설정

server:
  tomcat:
    max-swallow-size: 50MB  # Tomcat에서 허용하는 최대 요청 크기
  • max-swallow-size: Tomcat이 처리할 수 있는 최대 요청 크기를 50MB로 설정합니다. 이는 Tomcat이 요청을 처리하는 중에 무시할 수 있는 데이터의 최대 크기를 정의합니다.

📌 S3Service.class

S3Service 클래스는 AWS S3와 파일 업로드 및 삭제 기능을 처리하는 서비스 클래스입니다. 주로 프로필 이미지 업로드와 삭제 작업을 담당합니다.

🛠️ 코드 설명

@RequiredArgsConstructor
@Service
public class S3Service {

    private final S3Client s3Client;  // S3 클라이언트
    @Value("${cloud.aws.s3.bucket}")
    private String bucketName;  // S3 버킷 이름
    @Value("${cloud.aws.s3.url}")
    private String url;  // S3 URL

    // 프로필 이미지 업로드
    public String uploadProfileImage(MultipartFile file) {
        String fileName = "profileImage/" + UUID.randomUUID() + "_" + file.getOriginalFilename();
        String contentType = getContentType(file.getOriginalFilename());

        try {
            s3Client.putObject(PutObjectRequest.builder()
                            .bucket(bucketName)
                            .key(fileName)
                            .contentType(contentType)
                            .build(),
                    RequestBody.fromByteBuffer(ByteBuffer.wrap(file.getBytes())));
            return url + fileName;  // 업로드 후 파일 URL 반환
        } catch (IOException e) {
            throw new RuntimeException("Failed to upload profile image", e);  // 에러 처리
        }
    }

    // 프로필 이미지 삭제
    public void deleteFile(String profileImageUrl) {
        String fileName = profileImageUrl.replace(url, "");

        try {
            s3Client.deleteObject(builder -> builder.bucket(bucketName).key(fileName));
        } catch (Exception e) {
            throw new RuntimeException("Failed to delete profile image", e);  // 에러 처리
        }
    }

    // 파일 유형에 따른 콘텐츠 타입 반환
    private String getContentType(String fileName) {
        if (fileName.endsWith(".png") || fileName.endsWith(".PNG")) {
            return "image/png";  // PNG 파일
        } else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") || fileName.endsWith(".JPG")
                || fileName.endsWith(".JPEG")) {
            return "image/jpeg";  // JPG/JPEG 파일
        } else {
            throw new RuntimeException("Unsupported file type");  // 지원하지 않는 파일 형식
        }
    }
}

🧑‍💻 주요 기능

  1. 프로필 이미지 업로드
    • 파일 이름을 랜덤 UUID와 원본 파일명을 조합하여 생성.
    • S3에 파일을 업로드하고 파일 URL을 반환합니다.
  2. 프로필 이미지 삭제
    • S3에서 프로필 이미지를 삭제하는 기능입니다.
    • 파일의 URL을 기준으로 S3에서 해당 파일을 삭제합니다.
  3. 파일 형식 확인
    • 파일 이름에 따른 콘텐츠 타입을 설정합니다. (예: PNG, JPG/JPEG)
    • 지원되지 않는 파일 형식에 대해서는 예외를 발생시킵니다.

⚙️ 구성 요소

  • S3Client: AWS S3와 상호작용하는 클라이언트.
  • @Value: application.yml 파일에서 설정한 버킷 이름URL을 불러옵니다.
  • UUID: 고유한 파일 이름 생성을 위한 랜덤 값 생성.
  • MultipartFile: 파일 업로드를 처리하는 Spring의 인터페이스.

📌 Member.class

🛠️ 코드 설명

private String profileImageUrl;
  
public void setProfileImageUrl(String imageUrl) {
    this.profileImageUrl = imageUrl;
}

🧑‍💻 주요 기능

  • profileImageUrl: 사용자의 프로필 이미지를 저장하는 URL을 나타내는 변수입니다.
  • setProfileImageUrl(String imageUrl): 전달된 이미지 URL을 profileImageUrl 변수에 설정하는 setter 메소드입니다.

📌 MemberService.class

프로필 이미지 설정

public ProfileImageResponse setProfileImage(MultipartFile profileImageRequest) {
    String socialId = getCurrentUserId();
    Member member = memberRepository.findBySocialId(socialId)
            .orElseThrow(MemberNotFoundException::new);

    // 기존 프로필 이미지가 있으면 삭제
    if (member.getProfileImageUrl() != null && !member.getProfileImageUrl().equals(defaultImageUrl)) {
        s3Service.deleteFile(member.getProfileImageUrl());
    }

    // 새 이미지 업로드
    String imageUrl = s3Service.uploadProfileImage(profileImageRequest);
    member.setProfileImageUrl(imageUrl); // 새로운 이미지 URL 저장
    memberRepository.save(member); // 변경된 회원 정보 저장
    return new ProfileImageResponse(imageUrl); // 업로드된 이미지 URL 반환
}

 

🧑‍💻 주요 기능

  1. 기존 프로필 이미지 삭제
    • 기존 프로필 이미지가 기본 이미지가 아니면 해당 이미지를 S3에서 삭제합니다. (기존 이미지가 있을 경우)
  2. 새 프로필 이미지 업로드
    • 새 프로필 이미지를 S3에 업로드하고, 반환된 이미지 URL을 회원 정보에 저장합니다.
  3. 회원 정보 저장
    • 변경된 프로필 이미지 URL을 데이터베이스에 저장하여, 최신 정보를 반영합니다.
  4. 업로드된 이미지 URL 반환
    • ProfileImageResponse 객체를 통해 새로 업로드된 이미지 URL을 반환합니다.

프로필 이미지 제거

public void removeProfileImage() {
    String socialId = getCurrentUserId();
    Member member = memberRepository.findBySocialId(socialId)
            .orElseThrow(MemberNotFoundException::new);

    // 프로필 이미지가 있으면 삭제
    if (member.getProfileImageUrl() != null && !member.getProfileImageUrl().equals(defaultImageUrl)) {
        s3Service.deleteFile(member.getProfileImageUrl());
    }

    member.setProfileImageUrl(defaultImageUrl); // 기본 이미지로 설정
    memberRepository.save(member); // 변경된 회원 정보 저장
}

🧑‍💻 주요 기능

  1. 프로필 이미지 삭제
    • 만약 프로필 이미지기본 이미지가 아니라면, S3에서 해당 이미지를 삭제합니다.
  2. 기본 이미지 설정
    • 프로필 이미지 URL을 기본 이미지인 defaultImageUrl로 설정합니다.
  3. 회원 정보 저장
    • 변경된 프로필 정보를 데이터베이스에 저장하여, 기본 이미지로 업데이트된 정보를 반영합니다.

📌 MemberApiController.class

@Operation(summary = "프로필 사진 제거", description = "프로필 사진을 제거하고 기본 이미지로 설정합니다.")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "프로필 사진 제거 성공"),
            @ApiResponse(responseCode = "404", description = "회원을 찾을 수 없음")
    })
    @PutMapping("/profile-image/remove")
    public ResponseEntity<Void> removeProfileImage() {
        memberService.removeProfileImage();
        return ResponseEntity.ok().build();
    }

    @Operation(summary = "프로필 사진 변경", description = "프로필 사진을 변경합니다.")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "프로필 사진 변경 성공"),
            @ApiResponse(responseCode = "404", description = "회원을 찾을 수 없음")
    })
    @PutMapping("/profile-image/update")
    public ResponseEntity<ProfileImageResponse> updateProfileImage(
            @RequestPart("profileImage") MultipartFile profileImageRequest) {
        ProfileImageResponse profileImageResponse = memberService.setProfileImage(profileImageRequest);
        return ResponseEntity.ok(profileImageResponse);
    }
  • 기본 이미지 처리: default.png가 이미 설정되어 있기 때문에, 이미지 제거 후에도 자동으로 기본 이미지로 설정됩니다. 
    ➡️ POST가 아닌 PUT 방식으로 변경과 제거를 처리하고 있습니다.

 

 


Reference

 

[AWS] AWS S3 이용한 파일 업로드 하기

AWS S3 이용한 파일 업로드(JAVA, SPRING, MyBatis, MariaDB) 스프링 연동하기 1) build.gradle에 의존성 추가 AWS Java SDK(소프트웨어 개발 키트)를 사용합니다. java aws api 검색하여 SDK 다운로드 페이지로 접속합

night-east.tistory.com

 

 

728x90
반응형