Spring MVCで画像/メディアデータを返す

Spring MVCで画像/メディアデータを返す

1. 概要

このチュートリアルでは、SpringMVCフレームワークを使用して画像やその他のメディアを返す方法を説明します。

Message ConversionContent Negotiation、およびSpringのResource抽象化の恩恵を受けるアプローチに移行するのではなく、HttpServletResponseを直接操作することから始まるいくつかのアプローチについて説明します。 それぞれを詳しく見て、長所と短所について説明します。

2. HttpServletResponseの使用

イメージダウンロードの最も基本的なアプローチは、responseオブジェクトに対して直接作業し、純粋なServlet実装を模倣することです。これは、次のスニペットを使用して示されます。

@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/spring-mvc-xml/image-manual-response.jpg

org.apache.commons.ioパッケージのIOUtilsにより、実装はかなり単純で単純です。 ただし、このアプローチの欠点は、潜在的な変更に対して堅牢ではないことです。 MIMEタイプはハードコーディングされており、変換ロジックの変更またはイメージの場所の外部化には、コードの変更が必要です。

次のセクションでは、より柔軟なアプローチについて説明します。

3. Using the *HttpMessageConverter *

前のセクションでは、Spring MVCフレームワークのMessage ConversionおよびContent Negotiation機能を利用しない基本的なアプローチについて説明しました。 これらの機能をブートストラップするには、次のことが必要です。

  • コントローラメソッドに@ResponseBodyアノテーションを付けます

  • コントローラメソッドの戻り値の型に基づいて適切なメッセージコンバータを登録します(たとえば、バイト配列を画像ファイルに正しく変換するために必要なByteArrayHttpMessageConverter

3.1. 設定

コンバーターの構成を紹介するために、メソッドがbyte[]タイプを返すたびにメッセージを変換する組み込みのByteArrayHttpMessageConverterを使用します。

ByteArrayHttpMessageConverterはデフォルトで登録されますが、構成は他の組み込みまたはカスタムコンバーターと同様です。

メッセージコンバータBeanを適用するには、Spring MVCコンテキスト内に適切なMessageConverter Beanを登録し、処理する必要のあるメディアタイプを設定する必要があります。 <mvc:message-converters>タグを使用して、XMLで定義できます。

このタグは、次の例のように、<mvc:annotation-driven>タグ内で定義する必要があります。


    
        
            
                
                    image/jpeg
                    image/png
                
            
        
    

前述の構成部分は、image/jpegおよびimage/pngの応答コンテンツタイプに対してByteArrayHttpMessageConverterを登録します。 <mvc:message-converters>タグがmvc構成に存在しない場合、コンバーターのデフォルトセットが登録されます。

また、メッセージコンバータusing Java configurationを登録することもできます。

@Override
public void configureMessageConverters(List> converters) {
    converters.add(byteArrayHttpMessageConverter());
}

@Bean
public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() {
    ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
    arrayHttpMessageConverter.setSupportedMediaTypes(getSupportedMediaTypes());
    return arrayHttpMessageConverter;
}

private List getSupportedMediaTypes() {
    List list = new ArrayList();
    list.add(MediaType.IMAGE_JPEG);
    list.add(MediaType.IMAGE_PNG);
    list.add(MediaType.APPLICATION_OCTET_STREAM);
    return list;
}

3.2. 実装

これで、メディアのリクエストを処理するメソッドを実装できます。 上で述べたように、コントローラーメソッドに@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/spring-mvc-xml/image-byte-array.jpg

利点として、このメソッドは、使用可能なコンバーターの使用からカスタムコンバーターの指定まで、変換プロセスが高度に構成可能なHttpServletResponse,について何も知りません。 応答のコンテンツタイプはハードコーディングする必要はなく、要求パスのサフィックス.jpgに基づいてnegotiatedになります。

このアプローチの欠点は、データソース(ローカルファイル、外部ストレージなど)から画像を取得するためのロジックを明示的に実装する必要があり、応答のヘッダーやステータスコードを制御できないことです。

4. ResponseEntityクラスの使用

Response Entityでラップされたbyte[]として画像を返すことができます。 Spring MVCResponseEntityを使用すると、HTTP応答の本文だけでなく、ヘッダーとresposeステータスコードも制御できます。 このアプローチに従って、メソッドの戻り値の型をResponseEntity<byte[]>として定義し、メソッド本体に戻り値のResponseEntityオブジェクトを作成する必要があります。

@RequestMapping(value = "/image-response-entity", method = RequestMethod.GET)
public ResponseEntity 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 responseEntity = new ResponseEntity<>(media, headers, HttpStatus.OK);
    return responseEntity;
}

ResponseEntityを使用すると、特定の要求の応答コードを構成できます。

応答コードを明示的に設定することは、例外的なイベントが発生した場合に特に役立ちます。 イメージが見つからなかった場合(FileNotFoundException)または破損している場合(IOException))。 これらの場合、必要なのは応答コードの設定だけです。 適切なキャッチブロック内のnew ResponseEntity<>(null, headers, HttpStatus.NOT_FOUND),

さらに、応答に特定のヘッダーを設定する必要がある場合、このアプローチは、メソッドによってパラメーターとして受け入れられるHttpServletResponseオブジェクトを使用してヘッダーを設定するよりも簡単です。 これにより、メソッドの署名が明確になり、焦点が絞られます。

5. Resourceクラスを使用して画像を返す

最後に、Resourceオブジェクトの形式で画像を返すことができます。

Resourceインターフェースは、低レベルのリソースへのアクセスを抽象化するためのインターフェースです。 これは、標準のjava.net.URLクラスのより有能な代替品としてSpringに導入されました。 明示的に取得するコードを記述することなく、さまざまな種類のリソース(ローカルファイル、リモートファイル、クラスパスリソース)に簡単にアクセスできます。

このアプローチを使用するには、メソッドの戻り値の型をResourceに設定し、メソッドに@ResponseBodyアノテーションを付ける必要があります。

5.1. 実装

@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 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が画像の読み込み場所を決定します。

これは、構成を使用してイメージの場所を制御する一般的なアプローチを提供し、ファイル読み込みコードを作成する必要を排除します。

6. 結論

前述のアプローチの中で、フレームワークのメッセージ変換機能の恩恵を受けるアプローチを使用するよりも、基本的なアプローチから始めました。 また、応答オブジェクトを直接渡さずに応答コードと応答ヘッダーを設定する方法についても説明しました。

最後に、画像の場所の観点から柔軟性を追加しました。これは、画像を取得する場所が、その場で変更しやすい構成で定義されているためです。

チュートリアルに続くサンプルコードは、GitHubで入手できます。