ファイルをダウンロードする

このページでは、ファイルをダウンロードする方法について説明します。

ファイルのダウンロード処理は、AbstractView を継承したカスタムViewクラスで実施します。 AbstractViewを継承したクラスをSpringのDIコンテナに登録しておくと、 BeanNameViewResolver が Controllerから返却されたBean名と一致する場合に、Viewとして選択してくれます。

Tip

Spring Web MVCやThymeleafでは、Controllerから返却された値に対応するViewを解決するため、いくつかのViewResolverが提供されています。Spring Bootを使用する場合、これらのViewResolverは自動で構成され、優先度の高いViewResolverから使用されます。Spring Web MVCが提供しているものについては View Resolution を、Thymeleafが提供しているものについては Views and View Resolvers を参照してください。

以下のサンプルコードの動作確認環境については、 動作確認環境と依存ライブラリについて を参照してください。

処理フロー

  1. Controllerはファイルのダウンロード処理を実施するカスタムViewクラスのBean名を返却します。(このサンプルではテキストファイルのダウンロード処理を実施するBean名を返却します。)

  2. BeanNameViewResolverは、Controllerから返却されたBean名に一致するカスタムViewクラスを選択します。

  3. カスタムViewクラスは、レスポンスヘッダを設定してダウンロードファイルをレスポンスボディに書込みます。

実装例

Controller
@GetMapping("/download")
public String download(Model model) {

    // Viewで使用するダウンロードファイルパスをModelに設定します
    // (もしユーザが画面で入力したファイルパス等を使用する場合は、ディレクトリトラバーサル攻撃への対策も考慮してください)
    model.addAttribute(TextFileDownloadView.DOWNLOAD_FILE_INFO_KEY,
            new FileDownloadAttributes(targetFilePath, "ダウンロード.txt"));

    // ViewのBean名を返します
    return "textFileDownloadView";
}
TextFileDownloadView
// @Componentを設定して、コンポーネントスキャン対象にします
@Component
public class TextFileDownloadView extends AbstractView {

    public static final String DOWNLOAD_FILE_INFO_KEY = "fileInfo";

    private final ResourceLoader resourceLoader;

    public TextFileDownloadView(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Override
    protected void renderMergedOutputModel(Map<String, Object> model,
                                           HttpServletRequest request, HttpServletResponse response) throws Exception {
        FileDownloadAttributes attributes = (FileDownloadAttributes) model.get(DOWNLOAD_FILE_INFO_KEY);

        // レスポンスヘッダを設定します
        response.setContentType("text/plain");
        // 日本語のファイル名に対応するため、Content-DispositionはRFC6266の形式に沿って設定する
        ContentDisposition contentDisposition = ContentDisposition
                .attachment()
                .filename(attributes.getDownloadFileName(), StandardCharsets.UTF_8)
                .build();
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString());

        // ダウンロード対象のファイルを読込み、レスポンスボディに書込みます
        try (InputStream in = resourceLoader.getResource(attributes.getTargetFilePath()).getInputStream()) {
            in.transferTo(response.getOutputStream());
        }
    }
}

サンプル全体は file-download を参照してください。