TIL

SpringBoot에서 첨부파일 처리하기 AWS S3

everyday-spring 2024. 10. 18. 13:30
cloud:
  aws:
    credentials:
      access-key: ${aws_access_key}
      secret-key: ${aws_secret_key}
    region:
      static: ${aws_region}

미리 만들어 둔 AWS S3와 연결하기 위해 필요한 값들을 지정했다

두개의 키는 IAM 계정의 정보

@PostMapping
    public ResponseEntity<ApiResponse<?>> createCard(
            @RequestPart("data") CreateCardDto.Request request,
            @RequestPart("file") MultipartFile file,
            @AuthenticationPrincipal AuthUser authUser)
            throws IOException {

        Card card = cardService.createCard(authUser, request, file);

        return ResponseEntity.ok(ApiResponse.success(new CreateCardDto.Response(card)));
    }

 

Controller 에서는 파일과 JSON 데이터를 동시에 처리할 수 있는 @RequestPart 를 사용

 

public String uploadFile(MultipartFile file) throws IOException {
        // 파일 검증 (크기와 형식)
        validateFile(file);

        // 고유한 파일 이름 생성
        String fileName = generateFileName(file);

        try {
            // S3에 파일 업로드
            s3Client.putObject(
                    PutObjectRequest.builder().bucket(bucketName).key(fileName).build(),
                    RequestBody.fromInputStream(file.getInputStream(), file.getSize()));
        } catch (S3Exception e) {
            throw new InvalidRequestException("Failed to upload the file to S3");
        }

        return fileName;
    }

 

입력받은 파일은  파일 업로드와 데이터 전송을 효율적으로 처리할 수 있는 MultipartFile로 처리

이미지, PDF, CSV 등 여러 종류의 파일을 처리할 수 있는 Spring에서 파일을 간편하게 처리할 수 있는 고수준의 유틸리티

 

이 외의 파일 업로드를 처리하기 위한 클래스는

  • Servlet API (HttpServletRequest 사용)
  • Apache Commons FileUpload
  • Standard InputStream/OutputStream
  • Spring WebFlux (Reactive Programming)
// 파일 검증 로직
    private void validateFile(MultipartFile file) {
        if (file.isEmpty()) {
            throw new InvalidRequestException("파일이 비어 있습니다.");
        }

        // 파일 크기 제한 (5MB 이하)
        if (file.getSize() > 5 * 1024 * 1024) { // 5MB 제한
            throw new InvalidRequestException("파일 크기는 최대 5MB입니다.");
        }

        // 지원되는 MIME 타입 목록
        String contentType = file.getContentType();
        if (!isSupportedContentType(contentType)) {
            throw new InvalidRequestException("지원되지 않는 파일 형식입니다.");
        }
    }

    // 지원되는 파일 형식 확인
    private boolean isSupportedContentType(String contentType) {
        return contentType.equals("image/jpeg")
                || contentType.equals("image/png")
                || contentType.equals("application/pdf")
                || contentType.equals("text/csv");
    }

파일 검증 메소드로 업로드 파일 크기와 형식을 검증

AWS의 기본 업로드 제한이 사실 1MB로 제한되어 있어서 최대 5MB는 아니다...

 

// 고유한 파일 이름 생성
    private String generateFileName(MultipartFile file) {
        return UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
    }

파일 이름 충돌과, 보안을 위한 파일 이름 생성 메소드

UUID와 원본 파일 이름을 조합하여 고유한 파일 이름을 생성

 

import java.io.IOException;
import java.util.UUID;

import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.sparta.springtrello.domain.common.exception.InvalidRequestException;

import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.S3Exception;

@Service
public class FileUploadService {

    private final S3Client s3Client;
    private final String bucketName = "버킷의이름을이곳에넣는다"; // S3 버킷 이름

    public FileUploadService(S3Client s3Client) {
        this.s3Client = s3Client;
    }

    public String uploadFile(MultipartFile file) throws IOException {
        // 파일 검증 (크기와 형식)
        validateFile(file);

        // 고유한 파일 이름 생성
        String fileName = generateFileName(file);

        try {
            // S3에 파일 업로드
            s3Client.putObject(
                    PutObjectRequest.builder().bucket(bucketName).key(fileName).build(),
                    RequestBody.fromInputStream(file.getInputStream(), file.getSize()));
        } catch (S3Exception e) {
            throw new InvalidRequestException("Failed to upload the file to S3");
        }

        return fileName;
    }

    // 파일 검증 로직
    private void validateFile(MultipartFile file) {
        if (file.isEmpty()) {
            throw new InvalidRequestException("파일이 비어 있습니다.");
        }

        // 파일 크기 제한 (5MB 이하)
        if (file.getSize() > 5 * 1024 * 1024) { // 5MB 제한
            throw new InvalidRequestException("파일 크기는 최대 5MB입니다.");
        }

        // 지원되는 MIME 타입 목록
        String contentType = file.getContentType();
        if (!isSupportedContentType(contentType)) {
            throw new InvalidRequestException("지원되지 않는 파일 형식입니다.");
        }
    }

    // 지원되는 파일 형식 확인
    private boolean isSupportedContentType(String contentType) {
        return contentType.equals("image/jpeg")
                || contentType.equals("image/png")
                || contentType.equals("application/pdf")
                || contentType.equals("text/csv");
    }

    // 고유한 파일 이름 생성
    private String generateFileName(MultipartFile file) {
        return UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
    }
}

전체 코드

String fileUrl = fileUploadService.uploadFile(file);

card.addFile(file.getOriginalFilename(), fileUrl);

Service에서는 파일 이름과 정상 업로드 후 출력된 url값을 DB에 저장한다

'TIL' 카테고리의 다른 글

Spring Boot AOP 사용하여 Slack 사용자 멘션하기  (0) 2024.10.18
QueryDSL  (0) 2024.10.17
Spring boot AWS S3 image, file upload  (0) 2024.10.15
git repository commit 기록 전부 삭제  (0) 2024.10.11
면접피드백  (1) 2024.10.10