[Spring] Naver Cloud Object Storage 연동 방법 정리

NameJM·2024년 3월 5일

Spring Boot 2.7.10, JDK 1.8 기준

dependency

implementation platform('com.amazonaws:aws-java-sdk-bom:1.11.238')
implementation 'com.amazonaws:aws-java-sdk-s3'

property

app:
  ncloud:
    accessKey: {accessKey}
    secretKey: {secretKey}
    objectStorage:
      endPoint: "https://kr.object.ncloudstorage.com"
      regionName: "{regionName}"
      bucketName: "{bucketName}"

source

vo, dto

@Data
class FileInfoVO {
    private String fileUrl;
    private String fileName;
}

service

@Slf4j
public class FileService {
    @Value("${app.ncloud.accessKey}")
    private String accessKey;
    @Value("${app.ncloud.secretKey}")
    private String secretKey;
    @Value("${app.ncloud.objectStorage.endPoint}")
    private String endPoint;
    @Value("${app.ncloud.objectStorage.regionName}")
    private String regionName;
    @Value("${app.ncloud.objectStorage.bucketName}")
    private String bucketName;

    /**
     * object storage에서 파일 다운로드
     * @param param 다운로드할 객체 정보
     */
    public ResponseEntity<byte[]> fileDownload(FileInfoVO param) throws AmazonS3Exception, IOException {
        byte[] bytes = null;
        HttpHeaders httpHeaders = null;
        try {
            final AmazonS3 s3 = AmazonS3ClientBuilder.standard()
                        .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, regionName))
                        .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey)))
                        .build();

            S3Object s3Object = null;

            s3Object = s3.getObject(bucketName, param.getFileUrl());

            S3ObjectInputStream s3ObjectInputStream = s3Object.getObjectContent();
            bytes = IOUtils.toByteArray(s3ObjectInputStream);

            httpHeaders = new HttpHeaders();
            httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            httpHeaders.setContentLength(bytes.length);

            String encFileName = URLEncoder.encode(param.getFileName(), "UTF-8").replaceAll("\\+", "%20");
            httpHeaders.setContentDispositionFormData("attachment", encFileName);

            s3ObjectInputStream.close();
        }catch (Exception e){
            throw e;
        }
        return new ResponseEntity<>(bytes, httpHeaders, HttpStatus.OK);
    }
    
    /**
     * object storage에서 파일 다운로드 (zip 형태로 압축해서 내려줌)
     * 하드에 저장하는 방식이 아니라 빠른 속도 및 파일관리 불필요
     * @param param 다운로드할 객체 정보들
     */
    public ResponseEntity<byte[]> fileDownloadAll(List<FileInfoVO> param) throws AmazonS3Exception, IOException {
        List<byte[]> bytes = new ArrayList<>();
        try {
            final AmazonS3 s3 = AmazonS3ClientBuilder.standard()
                        .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, regionName))
                        .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey)))
                        .build();

            if(param.size() <= 0) {
                throw new NullPointerException();
            }

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ZipOutputStream zos = new ZipOutputStream(baos);
            for(int i = 0; i < param.size(); i++) {
                S3Object s3Object = s3.getObject(bucketName, param.get(i).getFileUrl());
                S3ObjectInputStream s3ObjectInputStream = s3Object.getObjectContent();
                byte[] a = IOUtils.toByteArray(s3ObjectInputStream);
                bytes.add(a);

                s3ObjectInputStream.close();

                String fileName = param.get(i).fileName;

                ZipEntry entry = new ZipEntry(fileName);
                entry.setSize(bytes.get(i).length);
                entry.setTime(System.currentTimeMillis());
                zos.putNextEntry(entry);
                zos.write(bytes.get(i));
                zos.closeEntry();
            }
            try {
                zos.finish();
                zos.flush();
                zos.close();
            } catch(Exception e) {
                log.error(StringUtils.getStackTrace(e));
            }finally {
                if(zos != null){
                    zos.close();
                }
            }

            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"download.zip\"")
                    .contentLength(baos.size())
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .body(baos.toByteArray());
        }catch (IOException e){
            throw e;
        }catch (Exception e){
            throw e;
        }
    }
    
    /**
     *  파일 업로드
     * @param files MultipartFile
     */
    public boolean fileUpload(MultipartFile[] files) throws Exception {
        final AmazonS3 s3 = AmazonS3ClientBuilder.standard()
                            .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, regionName))
                            .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey)))
                            .build();

        String folderName = "{서버에 저장할 파일 경로}";

        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(0L);
        objectMetadata.setContentType("application/x-directory");
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, folderName, new ByteArrayInputStream(new byte[0]), objectMetadata);

        try {
            s3.putObject(putObjectRequest);
        } catch (AmazonS3Exception e) {
            log.error("Error : {}", e.getMessage());
        } catch(SdkClientException e) {
            log.error("Error : {}", e.getMessage());
        }

        for(MultipartFile file : files) {
            String fileName = folderName + "{파일 이름}";

            try {
                s3.putObject(new PutObjectRequest(bucketName, fileName, file.getInputStream(), null));
            }catch (IOException e){
                log.error(e.getMessage());
                return false;
            }catch (Exception e){
                log.error(e.getMessage());
                return false;
            }
        }
        return true;
    }
    
    /**
     * 업로드된 파일 삭제
     * @param param 파일정보
     */
    public boolean deleteFile(FileInfoVO param) throws Exception {
        final AmazonS3 s3 = AmazonS3ClientBuilder.standard()
                            .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, regionName))
                            .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey)))
                            .build();
        try {
            s3.deleteObject(bucketName, param.getFileUrl()); // 물리파일삭제
            return true;
        } catch (AmazonS3Exception e) {
            log.error("Error : {}", e.getMessage());
            return false;
        } catch(SdkClientException e) {
            log.error("Error : {}", e.getMessage());
            return false;
        }
    }
    
}

0개의 댓글