MinIO Object Storage II - JAVA Sample
업데이트:
개요
지난 번 MinIO를 설명하면서 S3와 완벽히 호환한다고 이야기 하였으므로, 이에 대해 AWS S3 JAVA SDK v2를 이용한 샘플 코드를 설명한다.
설정
- S3의 CredentialsProvider는 여러 가지가 존재하지만 application.properties를 활용한 설정을 사용하는 방법과 DefaultProvider 사용하는 방법을 유연하게 전환할 수 있는 샘플 코드를 설명한다.
S3Properties.java
@Data
@Configuration
@ConfigurationProperties(prefix = "s3")
public class S3Properties {
private String endpointUrl;
private String accessKeyId;
private String secretAccessKey;
private String region;
}
- ConfigurationProperties를 이용하여 “application.properties”에 설정한 아래의 설정들을 가져와 설정한다.
- s3.endpoint-url : S3 API URL을 설정한다.
- s3.access-key-id : S3에서 발급한 Access Key를 설정한다.
- s3.secret-access-key : 위의 Access key의 Secrey Key를 설정한다.
- s3.region : S3 연결 리전 명칭을 설정한다.
S3Config.java
private AwsCredentialsProvider getAwsCredentialsProvider() {
if (StringUtils.isNotBlank(this.s3Properties.getAccessKeyId()) && StringUtils.isNotBlank(this.s3Properties.getSecretAccessKey())) {
return StaticCredentialsProvider.create(
AwsBasicCredentials.create(this.s3Properties.getAccessKeyId(), this.s3Properties.getSecretAccessKey()));
} else {
return DefaultCredentialsProvider.create();
}
}
- S3Properties에서 설정한 정보를 이용하여 CredentialsProvider를 동적으로 설정한다.
- “AccessKeyId”와 “SecretAccessKey”를 설정한 경우, AwsBasicCredentials를 이용한 설정을 사용하도록한다.
- DefaultCredentialsProvider는 SDK 내에서 동적으로 어떤 CredentialsProvider를 사용할지 아래의 순서대로 확인하여 인증 가능하도록 한다.
- SystemPropertyCredentialsProvider : JAVA 시스템 설정 내 “aws.accessKeyId”와 “aws.secretAccessKey”를 이용한다.
- EnvironmentVariableCredentialsProvider : 환경 변수로 설정된 “AWS_ACCESS_KEY_ID”와 “AWS_SECRET_ACCESS_KEY”를 사용한다.
- WebIdentityTokenFileCredentialsProvider : JAVA 시스템 설정 내 혹은 환경 변수에 존재하는 Web ID 토큰을 사용한다.
- ProfileCredentialsProvider : AWS 인증 정보를 저장하는 기본 파일인 ‘~/.aws/credentials’를 이용해 AWS SDK와 CLI와 설정을 공유한다.
- ContainerCredentialsProvider : security manager가 해당 변수에 접근할 권한을 가진 경우, Amazon EC2 컨테이너 서비스에 “AWS_CONTAINER_CREDENTIALS_RELATIVE_URI” 환경 변수가 설정하여 사용한다.
- InstanceProfileCredentialsProvider : Amazon EC2 메타 서비스를 이용하여 인스턴스 프로필을 가져온다.
public S3Client s3Client() {
S3ClientBuilder s3ClientBuilder = S3Client.builder().credentialsProvider(this.getAwsCredentialsProvider());
if (StringUtils.isNotBlank(this.s3Properties.getEndpointUrl())) {
s3ClientBuilder.endpointOverride(URI.create(this.s3Properties.getEndpointUrl()));
}
if (StringUtils.isNotBlank(this.s3Properties.getRegion())) {
s3ClientBuilder.region(Region.of(this.s3Properties.getRegion()));
}
return s3ClientBuilder.build();
}
- S3ClientBuilder를 이용하여 위에서 사용된 기본 방법을 이용하여 CredentialsProvider를 설정한다.
- “application.properties” 내 “EndpointUrl”, “Region” 정보가 있을 때는 해당 정보를 보도록 하고 없으면 위에서 설명한 DefaultCredentialsProvider에서 제공하는 방법으로 주입 받도록 처리한다.
- “EndpointUrl”을 설정하지 않으면 “Region” 내 “EndpointUrl” 사용하기 때문에 “Region”은 반드시 설정해야 하며, 설정되지 않은 경우 오류가 발생한다.
실행
S3Service.java
listObjects
public List<S3Object> listObjects(String bucket, int size) {
try {
return this.s3Client.listObjects(ListObjectsRequest.builder().bucket(bucket).maxKeys(size).build())
.contents();
} catch (Exception e) {
e.printStackTrace();
return Collections.emptyList();
}
}
- S3의 특정 bucket에 존재하는 Object 정보 size 단위로 페이징 처리하여 가져오는 listObjects를 이용한 샘플 코드이다.
getObject
public ResponseEntity<ByteArrayResource> getObject(String bucket, String key) {
try {
ResponseInputStream<GetObjectResponse> responseInputStream = this.s3Client.getObject(GetObjectRequest.builder().bucket(bucket).key(key).build());
GetObjectResponse getObjectResponse = responseInputStream.response();
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + key)
.contentType(MediaType.valueOf(responseInputStream.response().contentType()))
.contentLength(getObjectResponse.contentLength())
.lastModified(getObjectResponse.lastModified())
.body(new ByteArrayResource(responseInputStream.readAllBytes()));
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.internalServerError().build();
}
}
- S3에 생성된 bucket 내 key에 해당하는 Object 정보를 가져와서 Reponse로 해당 파일을 반환하는 getObject를 활용한 샘플 코드이다.
- GetObjectResponse를 반환하여 Object 정보를 여러 방법거나, OutputStream을 이용해 파일 생성 등 다양하게 활용 가능하다.
putObject
public boolean putObject(String bucket, String key, String path) {
try {
return this.s3Client.putObject(PutObjectRequest.builder().bucket(bucket).key(key).build(), Paths.get(path))
.sdkHttpResponse()
.isSuccessful();
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
- S3에 생성된 bucket 내 key에 해당하는 Object를 시스템 내 path에 위치한 파일로 덮어쓰는 putObject를 이용한 샘플 코드이다.
- S3는 기본적으로 key에 Object를 설정하므로, Versioning 설정을 하지 않은 상태라면 기존 파일 정보를 백업하지 않고 덮어써진다.
copyObject
public boolean copyObject(String sourceBucket, String sourceKey, String destinationBucket, String destinationKey) {
try {
return this.s3Client
.copyObject(CopyObjectRequest.builder()
.sourceBucket(sourceBucket).sourceKey(sourceKey)
.destinationBucket(destinationBucket).destinationKey(destinationKey).build())
.sdkHttpResponse()
.isSuccessful();
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
- S3에 생성된 sourceBucket 내 sourceKey에 해당하는 Object를 destinationBucket의 destinationKey로 복사하는 putObject를 이용한 샘플 코드이다.
deleteObject
public boolean deleteObject(String bucket, String key) {
try {
return this.s3Client.deleteObject(DeleteObjectRequest.builder().bucket(bucket).key(key).build())
.sdkHttpResponse()
.isSuccessful();
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
- S3에 생성된 bucket 내 key에 해당하는 Object를 삭제하는 deleteObject를 이용한 샘플 코드이다.
여담
- Spring Boot 3.2 버전에서는 Spring Framework 6.1 버전을 도입하여 “@RequestMapping”과 관련한 어노테이션들에서 “@PathVariable” 어노테이션을 사용할 때, “name”과 “value”으로 어느 값을 변수에 할당할지 명시하지 않으면 “Ensure that the compiler uses the ‘-parameters’ flag.” 오류가 발생한다.
- Spring Framework가 5에서 6으로 버전이 올라가면서 “LocalVariableTableParameterNameDiscoverer”가 삭제되어 컴파일 단계에서 매개 변수 이름을 추론하는 기능을 기본적으로 제공하지 않으므로, 사용하고자 하는 경우 컴파일 설정에 Java 8 이상에서는 ‘-parameters’, Kotlin은 ‘-java-parameters’ 플래그를 추가하여 해당 기능을 사용할 수 있도록 변경되었다.
소스
Sample Code는 여기에서 확인 가능합니다.
댓글남기기