ファイルダウンロード用のViewを自作する
Springでファイルダウンロードを実装する方法はいろいろあるが、今回はViewを自作する方向でやってみたい。
利点
- レスポンスヘッダーの設定など、冗長になりがちなコードをコントローラーに書かなくて済む。
- 戻り値の型を文字列で統一できるので、条件によってダウンロードか画面表示かに分岐するようなコントローラーが作れる。
環境
Spring Boot 1.4
やり方
ファイルの種類ごとにViewを作成する。以下はPDFの例。
View
ファイルダウンロードの体裁を整えるクラス。コントローラーとのデータの受け渡しはModelを通して行う。ここではファイルデータをcontents
、ファイル名をfileName
という名前で受け取ることにしている。
import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.util.FileCopyUtils; import org.springframework.web.servlet.view.AbstractView; public class PdfView extends AbstractView { @Override protected boolean generatesDownloadContent() { return true; } @Override protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { byte[] pdf = (byte[]) model.get("contents"); String fileName = (String) model.get("fileName"); response.setHeader("Content-Disposition", "attachment; filename*=utf-8''" + java.net.URLEncoder.encode(fileName, "UTF-8")); response.setContentLength(pdf.length); response.setContentType("application/pdf"); FileCopyUtils.copy(pdf, response.getOutputStream()); } }
設定
自作したViewとBeanNameViewResolver
をBean定義する。
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.BeanNameViewResolver; @Configuration public class WebMvcConfig extends WebMvcConfigurerAdapter { @Bean public BeanNameViewResolver fileDownloadViewResolver() { BeanNameViewResolver resolver = new BeanNameViewResolver(); resolver.setOrder(0); return resolver; } @Bean public PdfView pdfView() { return new PdfView(); } }
Controller
先に書いた通り、ファイルデータをcontents
、ファイル名をfileName
という名前でModelにセットした後、自作したViewのBean名、pdfView
を戻り値として返す。
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @Controller public class RootController { @GetMapping("pdf") public String pdf(Model model) { // PDFファイルの取得 byte[] contents = getPdf(); model.addAttribute("contents", contents); model.addAttribute("fileName", "テスト.pdf"); return "pdfView"; } }