Spring

[Spring Boot] S3 이미지 업로드

JangJangYi 2021. 6. 2. 11:35

Spring Boot로 S3에 이미지 업로드 하기 Ver.1

의존성을 먼저 추가해주어야 합니다

// AWS S3
    compile group: 'org.springframework.cloud', name: 'spring-cloud-aws', version: '2.2.1.RELEASE', ext: 'pom'

    // https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-s3
    implementation group: 'com.amazonaws', name: 'aws-java-sdk-s3', version: '1.11.993'

MultipartFile로 이미지 파일을 주고 받기

  • 총 3가지의 방법이 있습니다.
    • @RequestParam MultipartFile 타입 사용
    • ServletRequest or MultipartHttpServletRequest 타입 사용
    • 사용자 정의 Class 사용

저는 여기서 첫 번째 방법인 @RequestParam 을 사용하겠습니다.

  • 이유는 Controller의 요청 파라미터 타입 중 MultipartFile 타입에 해당하는 한 가지를 직접 골라서, File 데이터를 직접 다룰 수 있습니다.

들어가기전에 유의할 점!

  • MultipartFile은 프론트에서 Form 데이터로 보내주기 때문에 HTTP Header에 Content-Type으로 multipart/form-data를 넣어주셔야합니다.
    2021-06-01-10-07-45.png

Controller.java

@PostMapping("/api/boards")
    public Boards createBoards(HttpServletRequest req,
                               @RequestParam(value = "files", required = false) List<MultipartFile> files,
                               @RequestParam("title") String title,
                               @RequestParam("contents") String contents,
                               @RequestParam("price") String price)
          ...
}
  • 인자를 보시면 @RequestParam(value = "files", required = false) List files 로 되어 있습니다. 여기서 프론트에서 파일 이름은 files로 보내야 한다는 점과 사용자가 이미지 파일을 안보낼 수 도 있기 때문에 required = false로 지정하였습니다. 또한 여기서 주의 할 점은 required = false 이런식으로 해놓으면 NULL값이 들어오기 때문에 NULL 값 처리를 해주어야 합니다.
  • 그리고 현재 저의 프로젝트에서는 List로 Multipart를 받고 있지만 이거는 단일로 받던지 다중으로 받던지 선택입니다!

S3Service.java

    @Value("AKIASMHMW5M2RB6R6NFB")
    private String accessKey;

    @Value("rmXhmQbSZUoNDs+e4RbkBiLdws4PFTErfPs9I7/k")
    private String secretKey;

    @Value("clonedanggeon")
    private String bucket;

    @Value("ap-northeast-2")
    private String region;
  • 현재는 Access Key와 Secret Key의 값을 직접 넣어주고 있는데 원래는 .yml or .properties에 데이터를 넣어서 받아와야한다! 이 부분은 다음편에 설명하겠습니다 :)
    1. @Value로 S3Service 빈을 생성할 때 , 설정 파일의 S3 관련 프로퍼티 값을 매핑한다.
@PostConstruct
public void setS3Client() {
    AWSCredentials credentials = new BasicAWSCredentials(this.accessKey, this.secretKey);

    s3Client = AmazonS3ClientBuilder.standard()
            .withCredentials(new AWSStaticCredentialsProvider(credentials))
            .withRegion(this.region)
            .build();
}
  • @PostContruct로, S3Service가 사용되기 이전에 AmazonS3Client 객체를 생성한다.
public String upload(MultipartFile file) throws IOException {
    String fileName = file.getOriginalFilename().replace(" ","");
    Date date_now = new Date(System.currentTimeMillis()); // 현재시간을 가져와 Date형으로 저장한다
    SimpleDateFormat fourteen_format = new SimpleDateFormat("yyyyMMddHHmmss");
    System.out.println(fourteen_format.format(date_now)); // 14자리 포멧으로 출력한다
    fileName = fourteen_format.format(date_now) + fileName;
    System.out.println(fileName);

    s3Client.putObject(new PutObjectRequest(bucket, fileName, file.getInputStream(), null)
            .withCannedAcl(CannedAccessControlList.PublicRead));
    return s3Client.getUrl(bucket, fileName).toString();
}
  • 간혹가다 파일명이 특수문자와 한글로 파일명이 된게 있기 때문에 파일명을 시간포맷으로 바꿔준다. 업로드는 S3에서 메서드를 따로 제공해주는데 코드에서 보면 putObject를 사용하면 된다
  • 업로드 시에는 파일 명과 경로는 직접 지정하는 경우와 그렇지 않은 경우를 나눠 오버로딩하고, 삭제 시에는 파일이 존재하는지 확인하기 위해서 AmazonS3Client의 doesObjectExist 메소드를 사용했다. 존재하는 파일인 경우에만 경로의 파일을 삭제한다.