본문 바로가기

개발/Java & Spring

[AWS/S3/Spring boot] Spring boot와 S3를 연동하여 이미지를 다운로드 받아보자

헬스일정예약관리 웹페이지를 제작할 때 트레이너의 사진을 업로드하고 별도 페이지에서 트레이너 스펙을 보여줄 때 노출시킬 수 있도록 할계획이다.

예전에 Aws 세미나 갔을 때 Node.js로 하긴 했는데 스프링은 또 다르더라 ㅠ__ㅠ


업로드는 폼도 만들어야하고, Ajax좀 공부하고 하고 싶어서 일단 연동+다운로딩만 구현해보았다.


S3버킷 생성은 다 되어있다는 가정 하에서 시작한다.

이때, 액세스키를 발급받아야 하는데 

https://console.aws.amazon.com/iam/home?region=ap-southeast-1#/security_credential 를 참고한다. 


build.gradle

compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.cloud:spring-cloud-aws-context:${springCloudVersion}")
compile("commons-io:commons-io:2.4")

에러의 굴레에 빠지지 않으려면 최신 버전을 넣어주는 것이 좋다.


application.yml 에 버킷 정보, 자격 정보를 입력한다.

amazonProperties:
     region: 리전
     accessKey: 액세스키
     secretKey: 보안액세스키
     bucketName: 버킷이름

리전은  https://docs.aws.amazon.com/ko_kr/general/latest/gr/rande.html를 참고한다



다음은 Configuration Class이다.

@Configuration 당연히 해주고


@Value("${amazonProperties.accessKey}")
    private String accessKey;
@Value("${amazonProperties.secretKey}")
    private String secretKey;
@Value("${amazonProperties.region}")
    private String region;
@Bean
    public BasicAWSCredentials basicAWSCredentials() {
        return new BasicAWSCredentials(accessKey, secretKey);
    }
@Bean
public AmazonS3 amazonS3Client(AWSCredentials awsCredentials) {
    AmazonS3 amazonS3Client = AmazonS3ClientBuilder.standard()
            .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
            .withRegion(region)
            .build();
    return amazonS3Client;
}


내가 본 예제는 AmazonS3Client를 이용한 것이었고 해당 클래스는 deprecated되었으며 AmazonS3 클래스를 사용하라는 권장사항이 있었다.

그래서 찾아본 결과 친절한 AWS 한글 가이드

https://docs.aws.amazon.com/ko_kr/sdk-for-java/v1/developer-guide/credentials.html
아주 쉽게 설명되어있다.

리전 설정을 안해주면 에러가 나니 꼭 해주도록 한다

이제 다운로드 기능을 구현해본다
@Service
public class S3Wrapper {
	@Autowired
      private AmazonS3 amazonS3Client;
	@Value("${amazonProperties.bucketName}")
      private String bucket;

	public ResponseEntity<byte[]> download(String key) throws IOException {
            GetObjectRequest getObjectRequest = new GetObjectRequest(bucket, key);
            S3Object s3Object = amazonS3Client.getObject(getObjectRequest);
            S3ObjectInputStream objectInputStream = s3Object.getObjectContent();
            byte[] bytes = IOUtils.toByteArray(objectInputStream);
            String fileName = URLEncoder.encode(key, "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);
      }
}


컨트롤러에 해당 경로 매핑을 해주고


@Autowired
 private S3Wrapper s3Wrapper;
@RequestMapping(value = "/download", method = RequestMethod.GET)
    public ResponseEntity<byte[]> download(@RequestParam String key) throws IOException {
        return s3Wrapper.download(key);

이제 잘 되나 확인을 해야하니까 자신의 버킷에 들어가서 아무 이미지를 업로드 한뒤,

ip:8080/download?key=파일명.확장자

를 입력하면 이상이 없는 한 이미지가 다운로드 될 것이다.

지금은 이렇게 하지만 실제 구현은 다운 받은걸 토대로 다시 출력해주어야겠지 갈길이 태산이군