テスト済みのソリューション!
このソリューションは、実際にここに既に投稿されているアイデアを取得します (特に @gyan から)。
- zip するサーブレットを作成する
(これにもフィルターを使用できます。たとえば、ZipFilter があるとします。すべての *.zip にフィルターをマップし、そのフィルターをそれぞれの .jsf URL の URLRewrite フィルターでチェーンすることができます)。
public class ZipServlet
extends HttpServlet {
@Override
public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException,
IOException {
ZipEntry zipEntry = new ZipEntry("helloWorld.html");
ZipHttpServletResponseWrapper respWrapper = new ZipHttpServletResponseWrapper(response, zipEntry);
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/helloWorld.jsf");
dispatcher.forward(request, respWrapper);
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "inline; filename=output.zip;");
response.flushBuffer();
respWrapper.getOutputStream().close();
}
}
それについて言うことはあまりありません。Java 7 から、ネイティブ クラスを使用して zip ファイルを適切に作成できます。response.getOutputStream() の上に ZipOutputStream を指定してDecorator パターンを使用することをお勧めします。
HttpServletResponseWrapper はデコレーターであることを思い出してください。ターゲットの「サーブレット」出力を直接再利用したくない場合は、これを使用しないでください (HttpServletResponseWrapper を使用する代わりに、スタント HttpServletResponse を使用できます)。
public class ZipHttpServletResponseWrapper
extends HttpServletResponseWrapper {
private ZipEntry entry;
private ZipServletOutputStreamWrapper streamWrapper;
private ZipOutputStream outputStream;
private PrintWriter printWriter;
public ZipHttpServletResponseWrapper(HttpServletResponse response, ZipEntry entry) {
super(response);
this.entry = entry;
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
if (streamWrapper == null) {
outputStream = new ZipOutputStream(this.getResponse().getOutputStream());
outputStream.putNextEntry(entry);
streamWrapper = new ZipServletOutputStreamWrapper(outputStream);
}
return streamWrapper;
}
@Override
public PrintWriter getWriter() throws IOException {
if (printWriter == null) {
printWriter = new PrintWriter(getOutputStream());
}
return printWriter;
}
private class ZipServletOutputStreamWrapper
extends ServletOutputStream {
private ZipOutputStream outputStream;
public ZipServletOutputStreamWrapper(ZipOutputStream outputStream) {
this.outputStream = outputStream;
}
@Override
public void close() throws IOException {
outputStream.closeEntry();
outputStream.finish();
}
@Override
public void write(int b) throws IOException {
outputStream.write(b);
}
}
}
- さて、その秘訣は、賢くマッピングすることです!
JSF のいくつかの重要な部分はフィルター チェーンを使用できます (たとえば、Apache の myfaces はいくつかの拡張機能を使用して、いくつかの JSF コンポーネントを提供します)。この場合、これらのフィルターでダイジェスト FORWARD および REQUEST を指定する必要があります。
<filter-mapping>
<filter-name>extensionsFilter</filter-name>
<url-pattern>*.jsf</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>