ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring MVC로 이미지/미디어 데이터 변환하기
    개발 일지/Back-end 2022. 1. 26. 16:31
    반응형

    출처: https://www.baeldung.com/spring-mvc-image-media-data

     

    1. Overview

    본 포스트에서는 Spring MVC 프레임워크를 사용하여 이미지 및 기타 미디어를 리턴하는 방법을 살펴봅니다.

     

    Message Conversion, Content Negotiation 및 Spring의 리소스 추상화로부터 이점을 얻는 접근 방식으로 이동하는 것보다 HttpServletResponse를 직접 조작하는 것부터 시작하여 여러 접근 방식에 대해 알아보겠습니다.

     

    2. HttpServletResponse 사용하기

    이미지 다운로드의 가장 기본적인 접근 방식은 response 객체에 대해 직접 작업하고 순수한 Servlet 구현(implement)을 모방하는 것 입니다.

    @RequestMapping(value = "/image-manual-response", method = RequestMethod.GET)
    public void getImageAsByteArray(HttpServletResponse response) throws IOException {
        InputStream in = servletContext.getResourceAsStream("/WEB-INF/images/image-example.jpg");
        response.setContentType(MediaType.IMAGE_JPEG_VALUE);
        IOUtils.copy(in, response.getOutputStream());
    }

     

    다음과 요청하면 브라우저에서 이미지가 렌더링 됩니다.

    http://localhost:8080/image-manual-response.jpg

    이 방식은 org.apache.commons.io 패키지의 IOUtils를 사용하여 직관적이고 간단합니다.

    그러나 이 접근 방식의 단점은 잠재적인 변경 사항에 대해 강력하지 않다는 것입니다.

    MIME 유형은 하드 코딩되어 있으며 변환 논리를 변경하거나 이미지 위치를 외부화하려면 코드를 변경해야 합니다.

     

     

    아래에서는 좀 더 유연한 접근법을 살펴보겠습니다.

    3. HttpMessageConverter 사용하기

    위에서는 Spring MVC 프레임워크의 메시지 변환(Message Conversion) 및 콘텐츠 협상(Content Negotiation) 기능을 활용하지 않는 기본적인 접근 방법이었습니다.

    • 컨트롤러 메소드에 @ResponseBody 를 어노테이트 합니다.
    • 컨트롤러 메소드의 리턴 유형에 따라 적절한 메시지 컨버터를 등록합니다.
      (예를 들면, 바이트 배열을 이미지 파일로 변환하려면 ByteArrayHttpMessageConverter가 필요합니다.)

    3.1. 구성(Configuration)

    컨버터의 구성을 살펴보기 위해, 메소드가 byte[]를 리턴할 때마다 베시지를 변환하는 빌트-인 ByteArrayHttpMessageConverter를 사용합니다.

     

    메시지 컨버터 빈을 적용하려면 Spring MVC 컨텍스트 내에 적절한 MessageConverter 빈을 등록하고 처리해야 하는 미디어 유형을 설정해야 합니다.

     

    <mvc:message-converters> 태그를 사용하여 XML을 통해 정의할 수 있습니다.

    이 태그는 <mvc:annotation-driven> 태그 안에 정의되어야 합니다.

    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>image/jpeg</value>
                        <value>image/png</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

    앞서 언급한 구성 부분은 image/jpeg 및 image/png 응답 콘텐츠 유형에 대해 ByteArrayHttpMessageConverter를 등록합니다.

    <mvc:message-converters> 태그가 mvc 구성에 없으면 기본 컨버터 세트가 등록됩니다.

     

    또한 Java 구성을 사용하여 메시지 변환기를 등록할 수도 있습니다.

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(byteArrayHttpMessageConverter());
    }
    
    @Bean
    public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() {
        ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
        arrayHttpMessageConverter.setSupportedMediaTypes(getSupportedMediaTypes());
        return arrayHttpMessageConverter;
    }
    
    private List<MediaType> getSupportedMediaTypes() {
        List<MediaType> list = new ArrayList<MediaType>();
        list.add(MediaType.IMAGE_JPEG);
        list.add(MediaType.IMAGE_PNG);
        list.add(MediaType.APPLICATION_OCTET_STREAM);
        return list;
    }

    3.2. 구현(Implementation)

    이제 미디어 요청을 처리할 메소드를 구현할 수 있습니다.

    위에서 언급했듯이 @ResponseBody 어노테이션으로 컨트롤러 메소드를 표시하고 리턴 타입으로 byte[]를 사용합니다.

    @RequestMapping(value = "/image-byte-array", method = RequestMethod.GET)
    public @ResponseBody byte[] getImageAsByteArray() throws IOException {
        InputStream in = servletContext.getResourceAsStream("/WEB-INF/images/image-example.jpg");
        return IOUtils.toByteArray(in);
    }

     

    아래와 같이 브라우저에서 테스트할 수 있습니다.

    http://localhost:8080/image-byte-array.jpg

     

    장점은 HttpServletResponse에 대해 몰라도, 사용 가능한 컨버터 사용에서 커스텀 컨버터 지정에 이르기까지 변환 프로세스를 세팅으로 해결할 수 있습니다.

    response의 콘텐츠 유형을 하드코딩할 필요가 없고 request 경로의 접미사 .jpg를 기반으로 협상됩니다.

     

    이 접근 방식의 단점은 데이터 소스(로컬 파일, 외부 저장소 등)에서 이미지를 검색하기 위한 로직을 명시적으로 구현해야 하고 response 헤더나 상태 코드를 제어할 수 없다는 것입니다.

    4. ResponseEntity 클래스 사용하기

    Response 엔티티에 래핑된 byte[]로 이미지를 반환할 수 있습니다.

    Spring MVC ResponseEntity는 HTTP Response의 본문뿐만 아니라 헤더와 응답 상태 코드에 대한 제어를 가능하게 해줍니다.

    메서드의 반환 유형을 ResponseEntity<byte[]>로 정의하고 메서드 본문에 반환하는 ResponseEntity 개체를 만듭니다.

    @RequestMapping(value = "/image-response-entity", method = RequestMethod.GET)
    public ResponseEntity<byte[]> getImageAsResponseEntity() {
        HttpHeaders headers = new HttpHeaders();
        InputStream in = servletContext.getResourceAsStream("/WEB-INF/images/image-example.jpg");
        byte[] media = IOUtils.toByteArray(in);
        headers.setCacheControl(CacheControl.noCache().getHeaderValue());
        
        ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(media, headers, HttpStatus.OK);
        return responseEntity;
    }

    ResponseEntity를 사용하면 주어진 요청에 대한 응답 코드를 구성할 수 있습니다.

     

    응답 코드를 명시적으로 설정하는 것은 예외적인 이벤트에 직면했을 때 특히 유용합니다.

    (이미지를 찾을 수 없거나: FileNotFoundException 또는 IOException에 직면하는 경우)

    이 경우 응답 코드를 설정하기만 하면 됩니다. 적절한 catch 블록에서 new ResponseEntity<>(null, headers, HttpStatus.NOT_FOUND).

     

    또한 응답에 특정 헤더를 설정해야 하는 경우 메서드에서 매개변수로 허용하는 HttpServletResponse 개체를 사용하여 헤더를 설정하는 것보다 이 방법이 더 간단합니다.

     

    5. Resource 클래스를 사용하여 이미지 반환하기

    마지막으로 Resource 객체의 형태로 이미지를 반환할 수 있습니다.

     

    Resource 인터페이스는 저수준(low-level) 리소스에 대한 액세스를 추상화하기 위한 인터페이스입니다.

    이것은 표준 java.net.URL 클래스에 대한 보다 쓸만한 대체물로 Spring에 도입되었습니다.

    이를 통해 명시적으로 검색하는 코드를 작성할 필요 없이 다양한 유형의 리소스(로컬 파일, 원격 파일, 클래스 경로 리소스)에 쉽게 액세스할 수 있습니다.

     

    메소드의 리턴 타입을 Resource로 설정하고 @ResponseBody 어노테이션으로 메소드를 표시합니다.

    5.1. 구현(Implementation)

    @ResponseBody
    @RequestMapping(value = "/image-resource", method = RequestMethod.GET)
    public Resource getImageAsResource() {
       return new ServletContextResource(servletContext, "/WEB-INF/images/image-example.jpg");
    }

     

    또는 응답 헤더에 더 많은 제어를 원할 때는 아래와 같이 작성합니다.

    @RequestMapping(value = "/image-resource", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<Resource> getImageAsResource() {
        HttpHeaders headers = new HttpHeaders();
        Resource resource = 
          new ServletContextResource(servletContext, "/WEB-INF/images/image-example.jpg");
        return new ResponseEntity<>(resource, headers, HttpStatus.OK);
    }

    이 접근 방식을 사용하면 이미지를 ResourceLoader 인터페이스 구현을 사용하여 로드할 수 있는 리소스로 처리합니다.

    이러한 경우 이미지의 정확한 위치에서 추상화하고 ResourceLoader는 이미지가 로드되는 위치를 결정합니다.

     

    구성(Configuration)을 사용하여 이미지 위치를 제어하고 파일 로드 코드를 작성할 필요가 없도록 하는 일반적인 접근 방식을 제공합니다.

    반응형
Designed by Tistory.