본문 바로가기

AWS/S3

Springboot + MinIO + Docker로 구성한 파일 스토리지(2)

반응형

minio console 화면

지난 블로그

지난 편에서는 MinIO란 무엇인지, Docker로는 어떻게 컨테이너를 띄울 수 있는지 확인하였다.

이번 블로그에서는 실제로 springboot 와 연결하기 위한 방법을 소개하고자 합니다.

 

 

의존성 추가 minio vs spring-boot-starter-minio

 

본래 spring에 연결하기 위해 gradle에서는 기본 minio 의존성을 제공하고 있고,

아래가 gradle 기준으로 추가하는 의존성이다.

implementation "io.minio:minio:8.5.7"

 

 

한편 한 개발자가 minio 의존성의 불편함을 느끼고

간편하게 사용하기 위해 spring-boot-starter 버전의 의존성을 만든 것이 있다.

다음 블로그에서 참고할 수 있으니 확인해보면 쉽게 사용할 수 있을 것이다.

기본적으로는 아래의 의존성을 추가하면 사용할 수 있다.

implementation 'com.jlefebure:spring-boot-starter-minio:1.1'

 

그러나 springboot 3.0 이상의 버전에서는 해당 의존성 코드를 추가했을 때의 bean들이
만들고자 하는 프로젝트에서 반영이 되지 않는 문제가 있어 minio 기본 의존성을 추가한 다음
springboot 버전의 minio에서 사용한 코드를 참고하여 코드를 작성하였다.

 

 

1. Yaml 파일에 필요한 정보 정리

minio:
  url: // docker port
  bucket: // bucket name
  access-key: // username
  secret-key: // password

- 기본적으로 사용해야 하는 것은 어떤 포트로 연결되어 있는지 정보(url)

- 사용하고자 하는 bucket(bucket)

- 설정항 아이디와 비밀번호(access-key, secret-key)를 yaml파일에 추가해줘야 한다.

 

2. MinIO Config 작성

@Slf4j
@Getter
@Component
public class MiniOConfig {

    @Value("${minio.url}")
    private String url;

    @Value("${minio.access-key}")
    private String accessKey;

    @Value("${minio.secret-key}")
    private String accessSecret;

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

    @Bean
    public MinioClient minioClient() {
        MinioClient minioClient = MinioClient.builder()
                .endpoint(url)
                .credentials(accessKey, accessSecret)
                .build();
        try {
            boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
            if (!found) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
            }
        } catch (Exception e) {
            log.warn("bucketError found : {}", e.getMessage(), e);
        }
        return minioClient;
    }
    
}

- 설정 데이터를 바탕으로 @Value 를 통해 값을 넣고 MiniO에서 객체를 다룰 MinioClient 객체를 bean으로 등록한다.

- 만약 사용하고자 하는 bucket이 없다면 생성을 해준 후 해당 Minio에 넣어준다.

- 실제 아무 버켓이 없더라도 springboot를 띄우면 해당 빈이 생성되는 과정에서 MinIO에 localhost로 접속해보면 새롭게 버켓이 생성됨을 확인할 수 있다.

 

 

3. ImageService interface 작성

public interface ImageService {

    String uploadImage(MultipartFile file);

}

- 추후 S3로 변경할 수 있기 때문에 인터페이스를 생성한 후

 

 

4. MiniOImageServiceImpl 작성

@Slf4j
@Controller
@RequiredArgsConstructor
public class MiniOImageServiceImpl implements ImageService {

    private final MinioClient minioClient;
    private final MiniOConfig miniOConfig;
    private Path path;

    @Override
    public String uploadImage(MultipartFile file) {
        try {
            path = Path.of(file.getOriginalFilename());
            InputStream inputStream = file.getInputStream();
            String contentType = file.getContentType();
            PutObjectArgs args = PutObjectArgs.builder()
                    .bucket(miniOConfig.getBucket())
                    .object(path.toString())
                    .stream(inputStream, inputStream.available(), -1)
                    .contentType(contentType)
                    .build();
            minioClient.putObject(args);
        } catch (Exception e) {
            log.warn("Exception occurred while saving contents : {}", e.getMessage(), e);
        }
        return getUrl();
    }

    private String getUrl() {
        String url = null;
        try {
            url = minioClient.getPresignedObjectUrl(
                    GetPresignedObjectUrlArgs.builder()
                            .method(Method.GET)
                            .bucket(miniOConfig.getBucket())
                            .object(path.toString())
                            .expiry(12, TimeUnit.HOURS)
                            .build());
        } catch (Exception e) {
            log.warn("Exception Occurred while getting: {}", e.getMessage(), e);
        }
        return url;
    }

}

- client로부터 받아온 file로 파일 명 생성, InputStream 생성, Content-Type 을 생성한다.

- 그리고 저장할 데이터를 PutObjectArgs 객체로 생성한다. 이때, 위에서 생성한 파일 정보를 이용한다.

- 그리고 config파일에 저장한 버켓 이름을 사용한다.

- 생성된 파일을 저장한 후 minio의 저장된 url을 호출하는 로직을 호출한다.

- 이 url을 return 해주면 그 내용을 DB에 저장할 수 있게 로직을 만들었다.

 

 

5. ImageControllerTest

@RestController
@RequiredArgsConstructor
public class ImageTestController {

    private final ImageService imageService;

    @PostMapping("/api/v1/image")
    public ResponseEntity<String> uploadImage(@RequestPart("file")MultipartFile file){
        return ResponseEntity.ok(imageService.uploadImage(file));
    }

}

- 실제 이미지를 전송하고 해당 url을 클릭하면 이미지가 나오는지 확인하기 위한 controller를 만들었다.

- 해당 api를 만들고 포스트맨으로 테스트 하면 아래와 같은 결과가 나온다.

 

 

 

그리고 해당 url로 접속하면 내가 마지막 대학 과제를 위해 옛날에 받았던 이미지가 그대로 나오는 것을 확인할 수 있다.

 

 

 

그러나 아직 최대 url을 사용할 수 있는 유효시간이 12시간이라는 한계점과

url 자체에 정보가 많이 포함될 수 있다는 부담이 있다.

 

이 한계점들은 추후 보완해볼 예정이다.

반응형

'AWS > S3' 카테고리의 다른 글

Springboot + MinIO + Docker로 구성한 파일 스토리지(1)  (1) 2023.12.24