Spring Server 와 S3 연결하기

Spring Server 와 S3 연결하기

S3 버킷 생성이 완료되지 않았다면 S3 버킷 포스팅를 먼저 따라해주시면 됩니다.

S3 to EC2 포스팅에서는 SSH 를 통해 EC2 인스턴스에 접근해서 S3 와 연결해서 접근할 수 있었다면, 지금 작업은 백엔드 서버에서 접근하는 방법입니다.

IAM 사용자 세팅하기

image

검색창에 IAM 을 입력해서 IAM 메뉴를 클릭합니다.


액세스 관리 > 사용자 > 사용자 생성을 클릭합니다.


사용자 이름을 작성한 후 다음 버튼을 눌러줍니다.


직접 정책 연결 > AmazonS3FullAccess 체크 -> 다음

AmazoneS3FullAccess 는 모든 접근에 대해 열어두는 것입니다.

그러나 S3 bucket 정책을 설정했음으로 정해진 IP 주소에서만 업로드가 가능합니다.


이전에 작성한 것들을 보여주는 검토 및 생성 페이지에서는 사용자 생성 버튼을 눌러 사용자를 만들어줍니다.


사용자에서 해당 이름을 클릭하면 다음과 같이 뜨는데 여기서 액세스 키 만들기를 눌러줍니다.


액세스 키 모범 사례 및 대안이 나오는데 아무거나 체크하고 다음 눌러줍니다.

여기서는 선택했을때 사용 사례와 대안만 나타내는 기능이기 때문에 무엇을 선택하던지 상관없습니다.


태그를 작성하고 액세스 키 만들기 버튼을 클릭합니다.


엑세스 키가 나오게 되는데 이부분은 딱 한번만 나오는 부분이기 때문에 액세스키와 비밀 엑세스키를 저장을 잘해둬야 합니다.

( .csv 파일 다운로드도 같이 받아두는 것이 좋습니다. )




Spring 서버 세팅하기

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

먼저 Gradle 에 다음줄을 추가해줍니다.


## aws
cloud.aws.s3.bucket=test
cloud.aws.stack.auto=false
cloud.aws.region.static=ap-northeast-2
cloud.aws.credentials.access-key=아까 받은 access-key
cloud.aws.credentials.secret-key=아까 받은 secret-key

그다음 application-prod.properties 에 추가해줍니다.

  • cloud.aws.s3.bucket: 아까 설정한 bucket 이름
  • cloud.aws.stack.auto: false 를 하지 않으면 애플리케이션 시작시 자동으로 CloudFormation 스택을 생성하게 되는데 우리는 이미 위에서 수동으로 설정했기때문에 false 로 세팅합니다.
  • cloud.aws.region.static: ap-northeast-2 ( 한국 )

시크릿 정보가 들어가있음으로 application.properties 에 추가하면 안됩니다. ( git 저장 X )


@Configuration
@Profile("prod")
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
    public AmazonS3Client amazonS3Client() {
        BasicAWSCredentials awsCredentials= new BasicAWSCredentials(accessKey, secretKey);
        return (AmazonS3Client) AmazonS3ClientBuilder.standard()
                .withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
                .build();
    }
}

이후 코드에서 S3Config 를 세팅해줘야 합니다. 위 코드를 통해서 빈으로 S3 Client 를 등록해서 Service 단에서 사용할 수 있게 됩니다.

참고) profile 에 prod 를 설정해줘야 해당 설정이 들어가게 됩니다.

ex) nohup java -jar app-20240802.jar –spring.profiles.active=prod &


@RequiredArgsConstructor
@RequestMapping("/admin/file")
@RestController
public class S3Controller {
    private final FileService fileService;

//    @GetMapping("/download")
//    public ResponseEntity<byte[]> get(@RequestParam("fileName") String fileName) throws IOException {
//        S3Object s3Object = amazonS3.getObject(bucket, fileName);
//        S3ObjectInputStream objectInputStream = s3Object.getObjectContent();
//        byte[] bytes = IOUtils.toByteArray(objectInputStream);
//        HttpHeaders httpHeaders = new HttpHeaders();
//        httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
//        httpHeaders.setContentDispositionFormData("attachment", fileName);
//
//        return new ResponseEntity<>(bytes, httpHeaders, HttpStatus.OK);
//    }

    @PostMapping("/upload")
    public ApiResponse<String> upload(@RequestParam("file") MultipartFile file) {
        String url = fileService.upload(file);
        return ApiResponse.success(url);
    }

}

본인의 경우 upload 만 사용하고 있어서 download 는 주석처리해두었습니다.

또한 url 을 상황에 따라 바로 데이터 베이스에 저장하거나 저장 페이지로 url 을 돌려주어 파라미터 받아 저장하는 방법이 있는데 저는 후자를 선택하였습니다.


@Service
@RequiredArgsConstructor
public class FileService {
    private final AmazonS3 amazonS3;
    @Value("${cloud.aws.s3.bucket}")
    private String bucket;

    public String upload(MultipartFile file) {
        File uploadFile = convert(file);
        String url = uploadToS3(uploadFile);
        return url;
    }

    public File convert(MultipartFile multipartFile) {
        File file = new File(multipartFile.getOriginalFilename());
        try (FileOutputStream fos = new FileOutputStream(file)) {
            fos.write(multipartFile.getBytes());
        } catch (IOException e) {
            throw new RuntimeException();
        }
        return file;
    }

    private String uploadToS3(File uploadFile) {
        try {
            amazonS3.putObject(bucket, uploadFile.getName(), uploadFile);
            return amazonS3.getUrl(bucket, uploadFile.getName()).toString();
        } catch (SdkClientException e) {
            throw e;
        } finally {
            removeNewFile(uploadFile);
        }
    }

    private void removeNewFile(File uploadFile) {
        uploadFile.delete();
    }
}

서비스 코드이며, 해당 코드로 이미지를 업로드하고 URL 을 받아올 수 있습니다.




프로젝트 세팅하기 시리즈

프로젝트 세팅하기




참고

https://gaeggu.tistory.com/33

Leave a comment