java/spring

[Spring] AWS S3에서 Spring Boot로 파일 다운로드

danuri 2021. 8. 5. 22:33

 

프로젝트 중 AWS S3에서 특정 버킷의 파일을 다운로드 받아야 하는 상황이 생겨 기록을 한다.

 

build.gradle - 의존성 추가

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

spring boot와 aws를 연동시키기 위해 build.gradle에 spring-cloud-starter-aws를 추가한다.

 

 

application.yml - aws  자격 정보 입력

cloud:
  aws:
    credentials:
      instance-profile: false
      access-key: {IAM MY_ACCESS_KEY 입력}
      secret-key: {IAM MY_SECERT_KEY 입력}
    region:
      auto: false
      static: ap-northeast-2
    stack:
      auto: false

logging:
  level:
    com:
      amazonaws:
        util:
          EC2MetadataUtils: error

aws:
  s3:
    bucket: {버킷 이름}

aws 계정에 해당하는 access-key, secret-key를 입력하고

접근을 원하는 버킷을 입력한다.

 

 

AWS 계정 연결

@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
    @Primary
    public BasicAWSCredentials awsCredentialsProvider(){
        BasicAWSCredentials basicAWSCredentials = new BasicAWSCredentials(accessKey, secretKey);
        return basicAWSCredentials;
    }

    @Bean
    public AmazonS3 amazonS3() {
        AmazonS3 s3Builder = AmazonS3ClientBuilder.standard()
                .withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(awsCredentialsProvider()))
                .build();
        return s3Builder;
    }
}

Amazon IAM계정과 연결하기 위한 Config클래스를 생성한다.

 

 

S3 버킷에 있는 파일 다운로드하기

<Controller>

@Controller
@RequiredArgsConstructor
public class S3Controller {

    private final S3Service s3Service;

    @GetMapping("/csv_download/{fileName}")
    public ResponseEntity<byte[]> download(@PathVariable String fileName) throws IOException {
        return s3Service.getObject(fileName);
    }
}

경로에 입력한 {fileName}을 이름으로 갖는 파일을 로컬에 다운로드 받는다.

만약 해당 파일이 버킷에 없으면 에러가 발생한다.

 

<Service>

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class S3Service {

    private final AmazonS3 amazonS3;

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

    /**
     * S3 bucket 파일 다운로드
     */
    public ResponseEntity<byte[]> getObject(String storedFileName) throws IOException {
        S3Object o = amazonS3.getObject(new GetObjectRequest(bucket, storedFileName));
        S3ObjectInputStream objectInputStream = ((S3Object) o).getObjectContent();
        byte[] bytes = IOUtils.toByteArray(objectInputStream);

        String fileName = URLEncoder.encode(storedFileName, "UTF-8").replaceAll("\\+", "%20");
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        httpHeaders.setContentLength(bytes.length);
        httpHeaders.setContentDispositionFormData("attachment", fileName);

        return new ResponseEntity<>(bytes, httpHeaders, HttpStatus.OK);

    }
}

컨트롤러에서 호출한 getObject()메서드가 있는 서비스 계층

부분적으로 간단히 살펴보자.

 

S3Object o = amazonS3.getObject(new GetObjectRequest(bucket, storedFileName));

aws s3의 버킷과 파일 이름(bucket, storedFileName)을 전달하고 매칭이 되면 S3Object를 반환한다.

 

httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);

전송하는 파일의 종류에 따라 Content-Type을 지정해준다.

이미지는 "image/jpeg" 같은 형식으로, 기타 파일은 "application/octet-stream"을 넣어준다.

나는 CSV 파일을 받기 위해 "application/octet-stream"을 사용한다.

 

 

파일 다운로드

이제 URL을 입력하면 파일을 다운로드 받을 수 있다.