首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Servlet 動態生成靜態 HTML 頁面實現方案

     編輯:Java 相關知識

利用 RequestDispatcher.include() 捕獲 JSP 輸出流,寫入文件系統,實現頁面靜態化。本文提供一個可直接使用的 Servlet 完整實現,支持參數化輸入 JSP、輸出路徑、文件名,並處理編碼與流轉換。

核心原理

  1. 接收參數:file_name(目標 JSP)、build_name(生成文件名)、path(JSP 相對路徑)、real_path(輸出相對路徑)。
  2. 構造請求路徑 url 與輸出物理路徑 name。
  3. 自定義 HttpServletResponseWrapper,重寫 getOutputStream()/getWriter() 將輸出導向 ByteArrayOutputStream。
  4. dispatcher.include(request, wrappedResponse) 執行 JSP,內容落入字節數組。
  5. FileOutputStream 持久化到磁盤,返回「發布成功」。

完整 Servlet 代碼

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。

生產環境優化建議

  • 併發控制:大量靜態化時引入隊列(如 Disruptor)避免線程耗盡。
  • 模板引擎替代:FreeMarker/Velocity 直接生成文件,無需 Servlet 容器啟動,性能更高。
  • CDN 配合:生成後推送至對象存儲(OSS/S3)並刷新 CDN 緩存。
  • 增量更新:僅在數據變更時觸發重新生成,配合消息隊列解耦。
  • 編碼統一:全鏈路 UTF-8,避免中文亂碼。

常見問題

  • JSP 中使用 request.getContextPath() 生成的鏈接在靜態頁失效 → 改用相對路徑或配置 base 標簽。
  • include 時 Session/Request 屬性不傳遞 → 需在 JSP 所需屬性預先放入 Request。
  • 大文件導致 OOM → 分片寫入或改用流式模板引擎。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved