1. 概要

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

HttpServletResponse を直接操作することから始めて、メッセージ変換コンテンツネゴシエーション、およびSpringのの恩恵を受けるアプローチに移行することから始めて、いくつかのアプローチについて説明します。リソース抽象化。 それぞれについて詳しく見ていき、それぞれの長所と短所について説明します。

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. HttpMessageConverterの使用

前のセクションでは、SpringMVCフレームワークのメッセージ変換およびコンテンツネゴシエーション機能を利用しない基本的なアプローチについて説明しました。 これらの機能をブートストラップするには、次のことを行う必要があります。

  • コントローラメソッドに@ResponseBodyアノテーションを付けます
  • コントローラメソッドの戻りタイプに基づいて適切なメッセージコンバータを登録します(たとえば、バイト配列を画像ファイルに正しく変換するために必要な ByteArrayHttpMessageConverter )。

3.1. 構成

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

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

メッセージコンバータBeanを適用するには、適切な MessageConverter BeanをSpringMVCコンテキスト内に登録し、処理する必要のあるメディアタイプを設定する必要があります。 を使用して、XMLを介して定義できます鬼ごっこ。

このタグは内部で定義する必要があります次の例のように、タグを付けます。

<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構成に存在しない場合、デフォルトのコンバーターのセットが登録されます。

また、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. 実装

これで、メディアのリクエストを処理するメソッドを実装できます。 上で述べたように、コントローラーメソッドに @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に基づいてネゴシエートされます。

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

4. ResponseEntityクラスの使用

応答エンティティでラップされたbyte[]として画像を返すことができます。 Spring MVC ResponseEntity を使用すると、HTTP応答の本文だけでなく、ヘッダーと応答ステータスコードも制御できます。 このアプローチに従って、メソッドの戻り型を次のように定義する必要があります。 ResponseEntity リターンを作成します 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)。 このような場合、必要なのは応答コードを設定することだけです。 新しいResponseEntity<>(null、ヘッダー、HttpStatus.NOT_FOUND)、 適切なキャッチブロックで。

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

5. リソースクラスを使用して画像を返す

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

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

6. 結論

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

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

Springを使用してイメージまたはファイルをダウンロードするでは、SpringBootを使用して同じことを実現する方法について説明しています。

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