ファイルダウンロード ================================================================================ .. only:: html .. contents:: 目次 :depth: 3 :local: Overview -------------------------------------------------------------------------------- | 本節では、Springでクライアントにサーバからファイルをダウンロードする機能について説明する。 | Spring MVCのViewで、ファイルのレンダリングを行うことを推奨する。 \ .. note:: コントローラクラスで、ファイルレンダリングのロジックを持たせることは推奨しない。 理由としては、コントローラの役割から逸脱するためである。 また、コントローラから分離することで、Viewの入れ替えが、容易にできる。 ファイルのダウンロード処理の概要を、以下に示す。 #. DispatchServletは、コントローラへファイルダウンロードのリクエストを送信する。 #. コントローラは、ファイル表示の情報を取得する。 #. コントローラは、Viewを選択する。 #. ファイルレンダリングは、Viewで行われる。 | SpringベースのWebアプリケーションで、ファイルをレンダリングするため、 | 本ガイドラインでは、カスタムビューを実装することを推奨する。 | Spring フレームワークでは、カスタムビューの実装に | ``org.springframework.web.servlet.View`` インタフェースを提供している。 | | **PDFファイルの場合** | Springから提供されている\ ``org.springframework.web.servlet.view.document.AbstractPdfView``\ | クラスは、modelの情報を用いてPDFファイルをレンダリングするときに、サブクラスとして利用するクラスである。 | | **Excelファイルの場合** | Springから提供されている\ ``org.springframework.web.servlet.view.document.AbstractXlsxView``\ | クラスは、modelの情報を用いてExcelファイルをレンダリングするときに、サブクラスとして利用するクラスである。 | | Spring では上記以外にも、いろいろなViewの実装を提供している。 | Viewの技術詳細は、\ `Spring Framework Documentation -View Technologies- `_\ を参照されたい。 | 共通ライブラリから提供している、\ ``org.terasoluna.gfw.web.download.AbstractFileDownloadView``\ は、 | 任意のファイルをダウンロードするために使用する抽象クラスである。 | PDFやExcel形式以外のファイルをレンダリングする際に、本クラスをサブクラスに定義する。 .. tip:: ファイルダウンロード機能を提供する際には、ディレクトリトラバーサル攻撃への対策が必要な場合がある。 ディレクトリトラバーサル攻撃については、\ :ref:`file-upload_security_related_warning_points_directory_traversal` \を参照すること。 | How to use -------------------------------------------------------------------------------- PDFファイルのダウンロード ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | PDFファイルのレンダリングには、Springから提供されている、 | \ ``org.springframework.web.servlet.view.document.AbstractPdfView``\ を継承したクラスを作成する必要がある。 | コントローラでPDFダウンロードを実装するための手順は、以下で説明する。 カスタムViewの実装 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" **AbstractPdfViewを継承したクラスの実装例** .. code-block:: java @Component // (1) public class SamplePdfView extends AbstractPdfView { // (2) @Override protected void buildPdfDocument(Map model, Document document, PdfWriter writer, HttpServletRequest request, HttpServletResponse response) throws Exception { // (3) document.add(new Paragraph((Date) model.get("serverTime")).toString()); } } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | 本例では、\ ``@Component``\ アノテーションを使用して、component-scanの対象としている。 | 後述する、\ ``org.springframework.web.servlet.view.BeanNameViewResolver``\ の対象とすることができる。 * - | (2) - | \ ``AbstractPdfView``\ を継承する。 * - | (3) - | \ ``buildPdfDocument``\ メソッドを実装する。 | \ ``AbstractPdfView``\ は、PDFのレンダリングに、\ `OpenPDF `_\ を利用している。 | そのため、Mavenのpom.xmlに OpenPDFの定義を追加する必要がある。 .. note:: TERASOLUNA Server Framework for Java 5.4.xではiText 2.1.7をサポートしていたが、後継のiText 5.0.0よりAGPLライセンスに変更されたため、TERASOLUNA Server Framework for Java 5.5.1.RELEASEからiTextからフォークされた\ `OpenPDF `_\ をサポートする。 OpenPDFでは、iText 2.1.7からいくつかのバグや脆弱性が修正されている。 .. code-block:: xml com.github.librepdf openpdf \ .. note:: 上記設定例は、依存ライブラリのバージョンを親プロジェクトである terasoluna-gfw-parent で管理する前提であるため、pom.xmlでのバージョンの指定は不要である。 .. note:: iText 2.1.7を利用する場合、日本語の出力を行うためにはiTextAsianを依存ライブラリに追加する必要があったが、OpenPDFはデフォルトで日本語に対応しているため、追加は不要である。 .. _viewresolver-label: ViewResolverの定義 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" \ ``org.springframework.web.servlet.view.BeanNameViewResolver``\ とは、 Springのコンテキストで管理されたbean名を用いて実行するViewを選択するクラスである。 \ ``BeanNameViewResolver``\ を使用する際は、通常使用する、 * JSP用の\ ``ViewResolver``\(\ ``InternalResourceViewResolver``\) * Tiles用の\ ``ViewResolver``\(\ ``TilesViewResolver``\) より先に\ ``BeanNameViewResolver``\が実行されるように定義する事を推奨する。 .. note:: Spring Frameworkはさまざまな\ ``ViewResolver``\ を提供しており、複数の\ ``ViewResolver``\をチェーンすることができる。 そのため、特定の状況では、意図しないViewが選択されてしまうことがある。 この動作は、\ ````\ 要素の子要素に、優先したい\ ``ViewResolver``\を上から順に定義する事で防ぐことができる。 | **bean定義ファイル** .. code-block:: xml :emphasize-lines: 2 .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | \ ````\ 要素を使用して、\ ``BeanNameViewResolver``\ を定義する。 * - | (2) - | \ ````\ 要素を先頭に定義し、通常使用する\ ``ViewResolver``\ (JSP用の\ ``ViewResolver``\ )より優先度を高くする。 | コントローラでのViewの指定 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" | \ ``BeanNameViewResolver``\ により、コントローラで"samplePdfView"を返却することで、 | Springのコンテキストで管理されたBeanIDにより、"samplePdfView"であるViewが使用される。 **Javaソースコード** .. code-block:: java @RequestMapping(value = "home", params= "pdf", method = RequestMethod.GET) public String homePdf(Model model) { model.addAttribute("serverTime", new Date()); return "samplePdfView"; // (1) } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | "samplePdfView" をメソッドの戻り値として返却することで、 | Springのコンテキストで管理された、\ ``SamplePdfView``\ クラスが実行される。 | 上記の手順を実行した後、以下に示すようなPDFを開くことができる。 .. figure:: ./images/file-download-pdf.png :alt: FILEDOWNLOAD PDF :width: 60% :align: center **Picture - FileDownload PDF** | .. _excelfiledownload-label: Excelファイルのダウンロード ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | EXCELファイルのレンダリングには、Springから提供されている、 | \ ``org.springframework.web.servlet.view.document.AbstractXlsxView``\ を継承したクラスを作成する必要がある。 | コントローラでEXCELファイルをダウンロードさせるための実装手順は、以下で説明する。 カスタムViewの実装 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" **AbstractXlsxViewを継承したクラスの実装例** .. code-block:: java @Component // (1) public class SampleExcelView extends AbstractXlsxView { // (2) @Override protected void buildExcelDocument(Map model, Workbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception { // (3) Sheet sheet; Cell cell; sheet = workbook.createSheet("Spring"); sheet.setDefaultColumnWidth(12); // write a text at A1 cell = getCell(sheet, 0, 0); setText(cell, "Spring-Excel test"); cell = getCell(sheet, 2, 0); setText(cell, ((Date) model.get("serverTime")).toString()); } private Cell getCell(Sheet sheet, int rowNumber, int cellNumber) { Row row = sheet.createRow(rowNumber); return row.createCell(cellNumber); } private void setText(Cell cell, String text) { cell.setCellValue(text); } } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | 本例では、\ ``@Component``\ アノテーションを使用して、component-scanの対象としている。 | 前述した、\ ``org.springframework.web.servlet.view.BeanNameViewResolver``\ の対象とすることができる。 * - | (2) - | \ ``AbstractXlsxView``\ を継承する。 * - | (3) - | \ ``buildExcelDocument``\ メソッドを実装する。 | \ ``AbstractXlsxView``\ は、EXCELのレンダリングに、\ `Apache POI `_\ を利用している。 | そのため、Mavenのpom.xmlに POIの定義を追加する必要がある。 .. code-block:: xml org.apache.poi poi-ooxml \ .. note:: 上記設定例は、依存ライブラリのバージョンを親プロジェクトである terasoluna-gfw-parent で管理する前提であるため、pom.xmlでのバージョンの指定は不要である。 \ .. note:: xlsファイル形式をサポートしたい場合は \ ``AbstractXlsView``\を使用されたい。 詳細は、\ `AbstractXlsViewのJavaDoc `_\ を参照されたい。 ViewResolverの定義 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 設定は、PDFファイルをレンダリングする場合と同様である。詳しくは、\ :ref:`viewresolver-label`\ を参照されたい。 コントローラでのViewの指定 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" | \ ``BeanNameViewResolver``\ により、コントローラで"sampleExcelView"を返却することで、 | Springのコンテキストで管理されたBeanIDにより、”sampleExcelView”であるViewが使用される。 **Javaソース** .. code-block:: java @RequestMapping(value = "home", params= "excel", method = RequestMethod.GET) public String homeExcel(Model model) { model.addAttribute("serverTime", new Date()); return "sampleExcelView"; // (1) } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | "sampleExcelView" をメソッドの戻り値として返却することで、 | Springのコンテキストで管理された、\ ``SampleExcelView``\ クラスが実行される。 | 上記の手順を実行した後、以下に示すようなEXCELを開くことができる。 .. figure:: ./images/file-download-excel.png :alt: FILEDOWNLOAD EXCEL :width: 60% :align: center **Picture - FileDownload EXCEL** 任意のファイルのダウンロード ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | 前述した、PDFやEXCELファイル以外のファイルのダウンロードを行う場合、 | 共通ライブラリが提供している、\ ``org.terasoluna.gfw.web.download.AbstractFileDownloadView``\ を継承したクラスを実装すればよい。 | 他の形式にファイルレンダリングするために、\ ``AbstractFileDownloadView``\では、以下を実装する必要がある。 1. レスポンスボディへの書き込むためのInputStreamを取得する。 2. HTTPヘッダに情報を設定する。 | コントローラでファイルダウンロードを実装するための手順は、以下で説明する。 カスタムViewの実装 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" | テキストファイルをダウンロードする例を用いて、説明を行う。 **AbstractFileDownloadViewを継承したクラスの実装例** .. code-block:: java @Component // (1) public class TextFileDownloadView extends AbstractFileDownloadView { // (2) @Override protected InputStream getInputStream(Map model, HttpServletRequest request) throws IOException { // (3) Resource resource = new ClassPathResource("abc.txt"); return resource.getInputStream(); } @Override protected void addResponseHeader(Map model, HttpServletRequest request, HttpServletResponse response) { // (4) response.setHeader("Content-Disposition", "attachment; filename=abc.txt"); response.setContentType("text/plain"); } } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | 本例では、\ ``@Component``\ アノテーションを使用して、component-scanの対象としている。 | 前述した、\ ``org.springframework.web.servlet.view.BeanNameViewResolver``\ の対象とすることができる。 * - | (2) - | \ ``AbstractFileDownloadView``\ を継承する。 * - | (3) - | \ ``getInputStream``\ メソッドを実装する。 | ダウンロード対象の、\ ``InputStream``\ を返却すること。 * - | (4) - | \ ``addResponseHeaderメソッド``\ を実装する。 | ダウンロードするファイルに合わせた、 Content-Dispositionや、ContentTypeを設定する。 ViewResolverの定義 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 設定は、PDFファイルをレンダリングする場合と同様である。詳しくは、\ :ref:`viewresolver-label`\ を参照されたい。 コントローラでのViewの指定 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" | \ ``BeanNameViewResolver``\ により、コントローラで"textFileDownloadView"を返却することで、 | Springのコンテキストで管理されたBeanIDにより、”textFileDownloadView”であるViewが使用される。 **Javaソース** .. code-block:: java @RequestMapping(value = "download", method = RequestMethod.GET) public String download() { return "textFileDownloadView"; // (1) } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | "textFileDownloadView" をメソッドの戻り値として返却することで、 | Springのコンテキストで管理された、\ ``TextFileDownloadView``\ クラスが実行される。 \ .. tip:: 前述してきたように、SpringはModelの情報をいろいろなViewにレンダリングすることができる。 Springでは、複数のレンダリングエンジンをサポートしており、さまざまなViewを返却することが可能である。 詳細は、Spring の公式ドキュメント\ `Spring Framework Documentation -View Technologies- `_\ を参照されたい。 .. raw:: latex \newpage