エクセルをダウンロードするサーブレットのサンプル。


エクセルがダウンロードできるサーブレットを作成する機会があり、なかなかにはまったので、そのサンプルを残しておきたいと思います。なおJavaからエクセルを操作するにあたってはApache POIを利用していますが、その導入方法や使用方法については省略しています。

まずはServletクラスを以下のように作成します。

package servlet;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

/**
 * エクセルをダウンロードするサーブレット。
 * @author nekoTheShadow
 *
 */
@WebServlet("/download")
public class ExcelDownloadServlet extends HttpServlet {

    /**
     * ダウンロードページを表示する。
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getRequestDispatcher("/WEB-INF/jsp/download.jsp").forward(request, response);
    }

    /**
     * POSTされたフォームデータに基づきエクセルを生成し、ダウンロードさせる。
     * @throws UnsupportedEncodingException
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {

        // リクエストの文字コードをUTF-8に変換する。
        request.setCharacterEncoding("UTF-8");

        // リクエストクエリを取得する。
        String param1 = (String) request.getParameter("param1");
        String param2 = (String) request.getParameter("param2");
        String param3 = (String) request.getParameter("param3");

        // ファイル名を生成する: ファイル名はダウンロード日付とする。
        SimpleDateFormat simpleDataFormat = new SimpleDateFormat("yyyy-MM-dd");
        String filename = simpleDataFormat.format(new Date()) + ".xlsx";

        // レスポンスヘッダを設定する。
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("content-disposition", String.format("attachment; filename=\"%s\"", filename));
        response.setCharacterEncoding("UTF-8");

        // ワークブックとバイトストリーム(レスポンス)を生成する。
        // このふたつはcloseが必ず必要 => try-with-resource文を活用する、
        try (Workbook workbook = new XSSFWorkbook();
             OutputStream outputStream = response.getOutputStream()) {

            // シートを生成する: 実際は複雑なロジックを用いるが、今回はサンプルなのでシンプルなものにとどめておく。
            Sheet sheet = workbook.createSheet();
            sheet.createRow(1).createCell(1).setCellValue(param1);
            sheet.createRow(2).createCell(1).setCellValue(param2);
            sheet.createRow(3).createCell(1).setCellValue(param3);

            // ワークブックをレスポンスに出力する。
            workbook.write(outputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


}

次にdownloadにアクセスした際に表示されるdownload.jspは次の通りです。これは/WEB-INF/jspディレクトリの直下に配置します。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
    <h1>Excel Download</h1>
    <form method="post" action="/excel/download">
        <p><label>パラメタ1:</label><input type="text" name="param1" /></p>
        <p><label>パラメタ2:</label><input type="text" name="param2" /></p>
        <p><label>パラメタ3:</label><input type="text" name="param3" /></p>

        <p><input type="submit" value="Download Excel" /></p>
    </form>
</body>
</html>

必要なファイルを準備した後はデプロイし、/downloadにアクセスすると次のようなページが現れるはずです。

あとはパラメタを入力してDownload Excelを押下すると、タイトルが日付となったエクセルファイルがダウンロードされます。

そして実際にダウンロードしたエクセルファイルを開いてみると、とりわけ壊れたりなどせず、ちゃんとエクセルファイルが作られていることがわかります。

今回特に重要なのはレスポンスヘッダの設定でしょうか。content-typeに指定したapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetは正直なところあまり見かけないものですし、そもそもcontent-dispositionという属性自体が個人的にはなじみが薄く、はまったポイントでした。

// レスポンスヘッダを設定する。
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("content-disposition", String.format("attachment; filename=\"%s\"", filename));
response.setCharacterEncoding("UTF-8");