Spring:ファイルダウンロードでファイル名を設定するのに便利なクラス

Springフレームワークを利用している場合にファイルのダウンロードでContent-Dispositionヘッダーに日本語が含まれるファイル名を設定するのにContentDispositionクラスが便利です。

サンプルコード

以下はファイルをダウンロードするコントローラのサンプルです。

SampleController.java
package com.example;

import java.nio.charset.StandardCharsets;

import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

@Controller
public class SampleController {

  @GetMapping(path = "/download")
  public ResponseEntity<StreamingResponseBody> download(
      @RequestParam(name = "filename") String filename) {

    return ResponseEntity.ok()
        .contentType(MediaType.APPLICATION_OCTET_STREAM)
        .header(
            HttpHeaders.CONTENT_DISPOSITION,
            ContentDisposition.attachment()
                .filename(filename + ".txt", StandardCharsets.UTF_8)
                .build().toString())
        .body(os -> os.write("Hello World!\n".getBytes()));
  }
}

このサンプルはリクエストパラメータのfilenameに設定されたファイル名をContent-Dispositionレスポンスヘッダーに設定してテキストファイルをダウンロードします。

Content-Dispositionとは

Content-DispositionはRFC 6266で定義されていてコンテンツをブラウザーに表示させるかダウンロードさせるかを示すためのレスポンスヘッダーです。

Content-Disposionヘッダーに以下のようにattachmentと組み合わせてファイル名を指定することでブラウザに表示される「名前を付けて保存」ダイアログのデフォルトのファイル名を指定することができます。

Content-Disposition: attachment; filename="download.html"

ただし日本語のようにUS-ASCII以外の文字が含まれるファイル名をfilenameに指定した場合は正しくファイル名が設定されません。

例えば文字コードがUTF-8でファイル名が「ダウンロード.txt」の場合は以下のように指定する必要があります。

Content-Disposition: attachment; filename*=UTF-8''%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89.txt

この場合のファイル名のエンコードの方法はRFC 5987で定義されています。

ContentDispositionクラスの利用

SpringフレームワークではRFC6266で定義されているContent-Dispositionを表現するクラスが用意されています。

このクラスには目的ごとにビルダーを取得するビルダーメソッドが用意されています。今回のサンプルではこのクラスのattachmentビルダーを利用してContent-Dispositionヘッダーにファイル名を設定しました。

.header(
    HttpHeaders.CONTENT_DISPOSITION,
    ContentDisposition.attachment()
        .filename(filename + ".txt", StandardCharsets.UTF_8)
        .build().toString())

ブラウザでの実行結果は以下です。

Chromeでの実行結果

まとめ

Springフレームワークを利用していて日本語を含むファイル名のファイルをダウンロードする処理を作成する場合にContentDispositionクラスを利用すると便利です。