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

純 Servlet 架構重思考:拋棄 JSP/MVC,用 Java 程式碼直出 HTML 視圖層

     編輯:Java 相關知識

前言

JSP 設計初衷是分離 Java 開發與前端設計,但現實中設計師難駕馭 JSTL/EL/標籤庫,導致 Java 開發者兼寫視圖邏輯,代碼混雜難維護。本文提出「純 Servlet + Helper 物件」架構:以 Java 程式碼直接產出 HTML,封裝重複結構為可復用方法,實測可將視圖層代碼量縮減 2/3,維護成本大幅降低。

核心痛點:JSP 的混合地獄

  • 單一檔案混雜 HTML、Java Scriptlet、JSTL、EL、JavaScript
  • 除錯困難:堆疊追蹤行號常指向編譯後 Servlet,非原始 JSP
  • 無法繼承基類,代碼復用靠 include/標籤庫,維護成本高
  • 嘗試以宣告式語法表達本質動態的輸出邏輯,導致 scriptlet 滋生

純 Servlet 視圖層架構

分層結構

HTMLConstants (介面)   ← HTML 字串常量集中管理
    ↑
HTMLWriter / HTMLFlexiWriter  ← 低階 HTML 標籤輸出方法
    ↑
MadnessWriter (專案專用)      ← 高階組件:頁首、選單、表單、表格、分頁...
    ↑
MadnessServlet (抽象基類)     ← 統一請求前處理、安全檢查、Writer 工廠
    ↑
具體 Servlet (Picks, PicksAction, Admin...)  ← 業務邏輯 + 視圖輸出

關鍵設計決策

  1. 視圖與控制器合一:HTTP 無狀態特性下,表單顯示與提交處理同屬同一 UI 組件,分離反而增加配置負擔。
  2. HTML 封裝為 Java 方法:if/for 原生表達流程控制,元件重構為方法,易讀易改。
  3. Writer 非執行緒安全、請求域:每請求新建,避免狀態洩漏。
  4. CSS 類名作為參數:結構與樣式分離,佈局 Bug 單點修復全站生效。

實戰範例:NCAA March Madness 計分系統

PicksServlet.doBoth() 核心流程

protected void doBoth(HttpServletRequest req, HttpServletResponse resp,
                      HttpSession session, MadnessWriter out) throws IOException {
    // 1. 取得業務物件 + 安全檢查
    Player player = playerMan.select(session.getAttribute(PLAYER_ID), true);
    boolean readOnly = isCutoffPassed() && !player.isAdmin();

    // 2. 準備下拉選單資料
    Team[] teams = teamMan.selectAll();
    Map selectTeams = getDropDownMap(teams);

    // 3. 輸出頁面骨架
    out.printPreContent(null, out.SCRIPTFile("/js/picks.js"));
    out.printMenu(URL_PICKS);
    out.printBeginBox();

    // 4. 成功提示
    if ("true".equals(req.getAttribute(SUCCESS)))
        out.printDIV("smallHeading", "球隊選擇已儲存。");
    out.printDIV("reminder", "(提醒:Pick 20 代表最看好冠軍)");

    // 5. 表單輸出:動態/唯讀自動切換
    for (int i = 1; i <= 20; i++) {
        String teamID = player.getPick(i);
        if (!readOnly)
            out.printSELECT(PICK + i, selectTeams, teamID);
        else
            out.print(selectTeams.getOrDefault(teamID, "(未選擇)"));
    }

    // 6. 右側球隊列表(委派私有方法)
    doRegionList(teams, out);

    // 7. 收尾
    out.printEndBox();
    out.printPostContent();
}

Writer 方法簽名範例

// 低階
void printDIV(String cssClass, String content);
void printSELECT(String name, Map options, String selectedKey);
String IMG(String src, int w, int h); // 回傳字串,可巢狀

// 高階
void printMenu(String currentUrl);      // 自動跳過當前頁連結
void printBeginBox() / printEndBox();   // 統一框架結構
void printPreContent(String title, String headExtras);
void printPostContent();

跨領域關注點優雅解決

安全性

頁面級權限用 request.isUserInRole() 或自訂介面,邏輯寫在 Servlet 內,動態靈活(如截止日期後開放檢視他人選擇)。

國際化

Writer 加入 printText(key) / text(key),支援缺失翻譯拋異常或回退預設語系,完全掌控行為。

換膚

子類化 MadnessWriter 覆寫樣式表路徑、結構性 HTML(Logo、邊框),Servlet 基類依條件實例化不同 Writer,業務 Servlet 零修改。

關於 HTML 縮排

輸出 HTML 不縮排不影響瀏覽器渲染。除錯時看 Java 代碼結構即可定位佈局問題,比在混雜 JSP 中找缺標籤高效得多。必要時僅在關鍵處加 NL(換行常量)提升可讀性。

單元測試優勢

  • Servlet 可直接實例化,傳入 Mock Request/Response/Writer 驗證輸出字串。
  • 無需啟動容器、解析 JSP、處理標籤庫依賴。
  • Writer 方法可獨立測試 HTML 片段正確性。

何時仍適合 JSP/模板引擎?

  • 專職前端設計師團隊,需獨立維護樣板
  • 極度偏向靜態內容、動態邏輯極少的行銷型頁面
  • 強制規範要求視圖技術中立(罕見)

結語

「簡單靈活的方法往往更好」。純 Servlet 視圖層以 Java 原生語法表達動態輸出,封裝復用單位為方法而非標籤,配合單一職責的 Writer 階層,實現高內聚、低耦合、易測試、易維護的 Web UI 架構。建議團隊在中小型專案、內部系統、Admin 後台優先嘗試,體驗「代碼即視圖」的掌控感。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved