Spring Boot/A-ger프로젝트 탄생의비화

[spring] MultipartFile을 Bufferimage로 받아서 S3에 업로드하기

뇌장하드 2022. 3. 3. 21:18

직접 만들어본 이미지

기존에는 MultipartFile을 파일로 저장을시킨후에 업로드를 하고 삭제하는 방식으로 진행을 하였습니다.

하지만 첫번째장을 썸네일로 만드는 작업을 하려고하면 잘 안되는 문제가 발생을 하여서 file저장 방식이 아닌 bufferimage로 받아서 파이프라인을 타게끔 변경을 하였습니다.

기존 방법이 궁금하신분은 이 곳을 보고 와주세요.

 

먼저 껀쮸롤러를 먼저 보겠습니다.

    @PostMapping
    public ResponseEntity<SingleResult<ProductResponse>> createProduct(
            @RequestHeader("Authorization") String accessToken,
            @RequestPart(value = "file") List<MultipartFile> multipartFile,
            @RequestPart(value = "product") @Valid ProductRequest productRequest, BindingResult bindingResult) throws IOException {

        productService.validateUploadForm(bindingResult);
        productService.validateFileExists(multipartFile);
        String[] splitToken = accessToken.split(" ");
        ProductResponse productResponse = productService.createProduct(splitToken[1], productRequest, multipartFile);

        return new ResponseEntity<>(responseService.getSingleResult
                (productResponse), HttpStatus.CREATED);
    }

productservice 에서 등록을 해주는 기능을 실행을 해줍니다.

써비스를 보겠습니다.

public ProductResponse createProduct(String accessToken,
                                     ProductRequest productRequest,
                                     List<MultipartFile> multipartFile) throws IOException {
    Account account = accountService.findAccountByAccessToken(accessToken);
    String thumbNailUrl = uploadService.makeThumbNail(multipartFile.get(0));
    List<String> uploadImagesUrl = uploadService.uploadImages(multipartFile);
    Product product = productRequest.toProduct(account, uploadImagesUrl, thumbNailUrl);
    productRepository.save(product);
    return ProductResponse.toProductResponse(product, account);
}

먼저 아거 로직인 토큰 검증을 해준다음 썸네일이터로 첫번째 장을 썸네일로만들어 주고 

들어온 파일들을 for문을 돌려서 순차적으로 업로드 시켜줍니다.

 

이제 핵심 로직을 보겠습니다.

public String uploadImg(MultipartFile multipartFile) throws IOException {
    String origName = multipartFile.getOriginalFilename();
    final String ext = origName.substring(origName.lastIndexOf('.'));
    if (ext.equals(".jpg") || ext.equals(".png") || ext.equals(".jpeg")) {
        final String saveFileName = getUuid() + ext;
        BufferedImage image = ImageIO.read(multipartFile.getInputStream());
        return uploadImgToS3(image, saveFileName, ext);
    } else throw new InvaildFileExtensionException();
}

먼저 일단 혹시 모르니 확장자를 걸러주고 그다음 Bufferimage로 읽어 오겠습니다.

그다음 uploadImgToS3에다가 이미지, 이름, 확장자를 던져줍니다.

 

public String uploadImgToS3(BufferedImage image, String Filename, String ext)
        throws IllegalStateException, IOException {
    String url;
    try {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        log.info("확장자는 :{}", ext.substring(1));
        ImageIO.write(image, ext.substring(1), os);
        byte[] bytes = os.toByteArray();
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(bytes.length);
        objectMetadata.setContentType(ext.substring(1));
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        final TransferManager transferManager = new TransferManager(this.amazonS3Client);
        final PutObjectRequest request = new PutObjectRequest(bucket, Filename, byteArrayInputStream, objectMetadata);
        final Upload upload = transferManager.upload(request);
        upload.waitForCompletion();
    } catch (AmazonServiceException | InterruptedException e) {
        e.printStackTrace();
    }
    url = defaultUrl + Filename;
    return url;
}

 

S3에서 제공하는 PutObjectRequest에서는 3가지 방식이 가능합니다.

이중에서 저는 가장 마지막 방법으로 inputStream형식으로 보내는 방식을 선택하였습니다.

요로코롬 버킷과 키 inputstream 메타데이터를 넣어주면 스무스 하게 프론트에서 넘어온 데이터가 쭈르르륵 s3로 흘러들어가는 기능을 구현을 할수 있습니다.

 

다음에는 사용자에게 이미지를 더 빨리 로드를 하기위해서 AWS에 Cloudfront서비스를 적용시키는 포스팅으로 돌아오겠습니다.