JSPの出力結果をZIPにまとめて出力
仕事で利用している独自フレームワークの都合上
「JSPの出力結果をZIPで固めてダウンロード」
する必要がでてきたので、サンプルを作ってみました。
まず、サーブレットの処理はこんな感じ。
public class TestServlet extends HttpServlet {@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
}@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {resp.setContentType("application/zip;charset=Shift_JIS");
resp.setHeader( "Content-Disposition"," attachment;filename=\"data.zip\"");ZipOutputStream zos = new ZipOutputStream(resp.getOutputStream());
RequestDispatcher dispatcher = req.getRequestDispatcher("/WEB-INF/jsp/testres.jsp");// 何回か処理実行(結果のレスポンスはJSPの出力結果)
for (int i = 0; i < 5; i++) {
TestResponseWrapper wrapper = new TestResponseWrapper(resp);
dispatcher.include(req, wrapper);
ZipEntry entry = new ZipEntry("test" + i + ".txt");
zos.putNextEntry(entry);
zos.write(wrapper.getWriteDataByJsp().getBytes());
zos.closeEntry();
wrapper.clearStream();
}
zos.close();
}
}
次に、レスポンスを横取りするResponseWrapperはこんな感じ。
※手抜きです
public class TestResponseWrapper extends HttpServletResponseWrapper {private TestServletOutputStream os;
private CharArrayWriter writer;public TestResponseWrapper(HttpServletResponse resp) {
super(resp);
os = new TestServletOutputStream();
writer = new CharArrayWriter();
}@Override
public ServletOutputStream getOutputStream() throws IOException {
return os;
}@Override
public PrintWriter getWriter() throws IOException {
return new PrintWriter(writer);
}
public String getWriteDataByJsp() {
return writer.toString();
}public void clearStream() {
os = new TestServletOutputStream();
writer = new CharArrayWriter();
}/** ※こいつはオマケに近い */
class TestServletOutputStream extends ServletOutputStream {private ByteArrayOutputStream baos;
public TestServletOutputStream() {
baos = new ByteArrayOutputStream();
}@Override
public void write(int b) throws IOException {
baos.write(b);
}public byte[] getWriteData() {
return baos.toByteArray();
}
}
}
今回詰まったのは以下の点。
・Tomcatの場合、JSPの出力は#getWriter()経由で出力される。
※最初ずっと#getOutputStream()が呼ばれる前提で色々やっていたので見事にハマッた。
※コンテナの実装依存部分ですかね?JspWriterで出力してるから依存ではないような気もするけど…中まで追ってないからよくわかりません。
・フレームワークが、RequestDispatcher#forward固定になっており、それをincludeと切り替えれるようにするのに
ものすごく時間がかかった。(※HttpServletを何回も継承[縦の階層が深い]するのはやめてほしいなぁ…)
本当はServletじゃなくて、Filterで実装しようとしてましたけど、邪魔くさくなったので途中でやめ。
上のコードで期待する動作にはなっているので、今回はよしとします。。