ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring Boot] URL 이미지 반환하기
    개발/Java 2022. 4. 25. 17:14

    스프링부트를 활용해서 API 서버를 만들면서 이미지가 담긴 URL을 반환해주는 기능이 필요했다.

    클라이언트가 서버의 URL로 접근해서 이미지를 요청하면 외부 API의 정적 이미지를 담은 URL을 내 쪽으로 끌고와서 해당 URL의 이미지를 내 서버의 URL로 접근할 수 있도록 해야했다.

     

    외부 API에 직접 접근하면서 생기는 두 가지 문제점을 해결하고 싶었다.

    • API키가 노출되는 점
    • URL 길이가 길어지는 점

    위 두 개의 문제점을 해결하기 위해서 다음과 같은 방법을 생각했다.

    1. 외부 API URL에 접근해서 이미지만 객체 또는 바이트 배열로 받아오기
    2. 해당 이미지 객체를 바이트 배열로 반환하기

     

    우선 아래와 같은 클래스와 함수를 만들었다.

    파라미터로 전달되는 값들을 통해 URL을 구성하고 이를 통해서 URL 객체를 생성한다.

    ImageIO를 통해서 URL에 접근하게 되면 해당 URL 이미지를 BufferedImage로 반환하게 된다.

    public class SmsImageAPI {
    
        public BufferedImage getPickup(String paramForUrl, String key) {
            try{
                String URL = "___URL___";
    
                URL url = new URL(URL); //URL 객체 생성
    
                return ImageIO.read(url); //URL의 이미지를 BufferedImage로 반환
            }
            catch(IOException e){
                e.printStackTrace();
                return null;
            }
        }
    }

    여기서 Image 클래스를 사용하지 않고 BufferedImage 클래스를 사용한 이유는 다음과 같다.

    Image 클래스는 BufferedImage의 부모 클래스로 정적인 이미지를 표현할 수는 있지만 이를 직접 접근해서 수정할 수는 없다.

    따라서 BufferedImage로 변환해서 접근해야한다.

    만일 외부 API URL을 그대로 반환한다면 상관이 없었지만 나의 서버를 통해 이미지가 바이트 배열로 변환되어야하기 때문에 이를 사용했다.

     

     

     

    BufferedImage를 ByteArray로 변환하고 반환하는 코드를 작성했다.

    이렇게 되면 아래의 URI로 접근하게 되면 외부로부터 받아온 이미지를 반환하게 된다.

        @GetMapping(value = "/", produces = MediaType.IMAGE_PNG_VALUE)
        public @ResponseBody byte[] getPickUpLocation(
            @RequestParam(required = true) String parameter ) throws IOException {
            try{
                SmsImageAPI sms = new SmsImageAPI();
    
                BufferedImage bufferedImg = sms.getPickup(parameter, key); //위의 함수
                ByteArrayOutputStream bArr = new ByteArrayOutputStream();
                ImageIO.write(bufferedImg, "png", bArr); //BufferedImage를 ByteArray로 변환
                return bArr.toByteArray();
    
            }catch(Exception e){
                e.printStackTrace();
                return null;
            }
        }

     

     

    BufferedImage를 직접 반환해도 될거란 생각이 들었었지만 아래와 같은 에러가 발생했다.

    No converter for [class java.awt.image.BufferedImage] with preset Content-Type 'null'
    org.springframework.http.converter.HttpMessageNotWritableException: 
    No converter for [class java.awt.image.BufferedImage] with preset Content-Type 'null'

    여러 검색을 통해서 원인을 생각해보았다.

    Content-Type은 우리가 image/png로 함께 반환해준다면 문제가 없었을 것 같다.

    하지만 이를 지정하지 않고 BufferedImage를 반환했기에 문제가 생긴 것 같다.

     

    반대로 ByteArray는 결국 형태가 지정되지 않은 값이기에 Content-Type과 상관없이 브라우저에서 해석하면 되기에 에러가 나지 않는다고 생각했다.

     

     

    이 기능을 사용하려는 이유는 AWS S3 버킷과 같이 이미지를 직접 반환할 수 있는 API가 필요했고 직접 구현해보고자 했기 때문이다.

    현재는 외부 API에서 이미지를 그대로 반환하지만 Redis와 연동해서 캐시 성격의 디비를 통해 접근하는 것으로 개선하고자 한다.

    댓글

Designed by Tistory.