エクセルがダウンロードできるサーブレットを作成する機会があり、なかなかにはまったので、そのサンプルを残しておきたいと思います。なお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");


