利用 RequestDispatcher.include() 捕獲 JSP 輸出流,寫入文件系統,實現頁面靜態化。本文提供一個可直接使用的 Servlet 完整實現,支持參數化輸入 JSP、輸出路徑、文件名,並處理編碼與流轉換。
file_name(目標 JSP)、build_name(生成文件名)、path(JSP 相對路徑)、real_path(輸出相對路徑)。url 與輸出物理路徑 name。HttpServletResponseWrapper,重寫 getOutputStream()/getWriter() 將輸出導向 ByteArrayOutputStream。dispatcher.include(request, wrappedResponse) 執行 JSP,內容落入字節數組。FileOutputStream 持久化到磁盤,返回「發布成功」。public class ToHtmlPath extends HttpServlet {
@Override
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
ServletContext servletContext = getServletContext();
final String CONTEXT_PATH = servletContext.getRealPath("/");
// 1. 解析參數
String file_name = request.getParameter("file_name") + ".jsp";
String build_name = request.getParameter("build_name");
String path = request.getParameter("path");
String real_path = request.getParameter("real_path");
// 2. 默認 build_name 取 file_name 參數值
if (build_name == null || build_name.equals("")) {
int a = file_name.indexOf("=") + 1;
build_name = file_name.substring(a);
if (build_name.indexOf(".") > 0) build_name = build_name.substring(0, build_name.indexOf("."));
}
// 3. 構造訪問 URL
String url = (path == null || path.equals("")) ? "/" + file_name : "/" + path + File.separator + file_name;
// 4. 構造輸出路徑
String name;
if (real_path == null || real_path.equals("")) {
if (path == null || path.equals("")) name = CONTEXT_PATH + File.separator + build_name + ".html";
else name = CONTEXT_PATH + File.separator + path + File.separator + build_name + ".html";
} else {
name = CONTEXT_PATH + File.separator + real_path + File.separator + build_name + ".html";
}
// 5. 捕獲 JSP 輸出
RequestDispatcher dispatcher = servletContext.getRequestDispatcher(url);
final ByteArrayOutputStream byteos = new ByteArrayOutputStream();
final ServletOutputStream stream = new ServletOutputStream() {
@Override public void write(byte[] data, int offset, int length) { byteos.write(data, offset, length); }
@Override public void write(int b) throws IOException { byteos.write(b); }
};
final PrintWriter printw = new PrintWriter(new OutputStreamWriter(byteos, "UTF-8"));
HttpServletResponse rep = new HttpServletResponseWrapper(response) {
@Override public ServletOutputStream getOutputStream() { return stream; }
@Override public PrintWriter getWriter() { return printw; }
};
dispatcher.include(request, rep);
printw.flush();
// 6. 寫入文件
FileOutputStream fileos = new FileOutputStream(name);
byteos.writeTo(fileos);
fileos.close();
out.print("發布成功!");
}
}
https://host:port/app/ToHtmlPath?file_name=newsDetail.jspx&build_name=news_123&path=news&real_path=html-news
將訪問 /news/newsDetail.jspx,生成 {webapp}/html-news/news_123.html。
request.getContextPath() 生成的鏈接在靜態頁失效 → 改用相對路徑或配置 base 標簽。include 時 Session/Request 屬性不傳遞 → 需在 JSP 所需屬性預先放入 Request。