JSP 開發中,頁面頭部、導航欄、腳部、JS/CSS 引入常需跨頁復用。本文對比三種主流復用方案的原理、優劣與適用場景,助你選型最適合專案的佈局策略。
| 方案 | 指令/標簽 | 編譯階段 | 運行機制 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|---|---|---|
| 靜態包含 | <%@ include file="header.jsp" %> | **翻譯階段**合併為單一 Servlet | 無額外請求,變量共享同一作用域 | 效能最高、變量直接可用 | 修改被包含頁需重新編譯主頁、易導致類體積過大 | 極少變動的公共片段(版權聲明、通用常量) |
| 動態包含 | <jsp:include page="header.jsp" flush="true" /> | **獨立編譯**為各自 Servlet | 運行時 `RequestDispatcher.include()` 合併響應 | 修改即時生效、邏輯解耦、參數可傳遞 | 額外 include 開銷、變量隔離需用 request.setAttribute | 頻繁變動的頁頭/頁尾/側邊欄 |
| 模板引擎 | FreeMarker / Thymeleaf / Velocity | 模板編譯 | 引擎渲染合併 | 功能強大(繼承、塊、宏)、前後端分離友好 | 引入依賴、學習成本 | 中大型專案、追求可維護性 |
<script src="${pageContext.request.contextPath}/js/common.js"></script>
<!-- 渲染為 /myapp/js/common.js,部署上下文變更自動適配 -->
等價 JS 寫法(動態注入):
<script id="commonJS"></script>
<script>
document.getElementById('commonJS').src = '${pageContext.request.contextPath}/js/common.js';
</script>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<%
String ctx = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + ctx + "/";
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><c:out value="${pageTitle}"/></title>
<script>var basePath = "<%=basePath%>";</script>
<!-- 統一引入 jQuery、Bootstrap、bsgrid 等 -->
</head>
<body>
<jsp:include page="/fragments/header.jsp" flush="true"/>
<div id="main-content"></div>
<jsp:include page="/fragments/footer.jsp" flush="true"/>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<jsp:include page="/base.jsp" flush="true">
<jsp:param name="pageTitle" value="學生成績信息"/>
</jsp:include>
<script>
// 頁面專屬 JS,可直接用 basePath 變量
console.log('ctx=' + '${pageContext.request.contextPath}');
</script>
JSP 佈局復用核心在於**「靜態包含求快、動態包含求柔、模板引擎求強」**。理解 `pageContext.request.contextPath` 統一路徑、掌握 `base.jsp` + `jsp:include` + `jsp:param` 經典模式,即可構建清晰可維護的頁面結構。新專案建議直接拥抱現代模板引擎或前端框架。