JSP

**JSP**（全稱 **J**akarta **S**erver **P**ages，曾稱為 **J**ava**S**erver **P**ages）是由 Sun Microsystems 公司主導建立的一種動態網頁技術標準。JSP 部署於網路伺服器上，可以回應客戶端傳送的請求，並根據請求內容動態地生成 HTML、XML 或其他格式文件的 Web 網頁，然後返回給請求者。JSP 技術以 Java 語言作為手稿語言，為使用者的 HTTP 請求提供服務，並能與伺服器上的其它 Java 程式共同處理複雜的業務需求。

JSP 將 Java 程式碼和特定變動內容嵌入到靜態的頁面中，實現以靜態頁面為模板，動態生成其中的部分內容。JSP 引入了被稱為「JSP 動作」的 XML 標籤，用來呼叫內建功能。另外，可以建立 JSP 標籤庫，然後像使用標準 HTML 或 XML 標籤一樣使用它們。標籤庫能增強功能和伺服器效能，而且不受跨平台問題的限制。JSP 檔案在執行時會被其編譯器轉換成更原始的 Servlet 程式碼。JSP 編譯器可以把 JSP 檔案編譯成用 Java 程式碼寫的 Servlet，然後再由 Java 編譯器來編譯成能快速執行的二進位機器碼，也可以直接編譯成二進位碼。

## 綜述

JSP 從 2.0 版本開始，增加了表達式語言（EL），以提供更快更簡單的建立新標籤的方法，並允許開發者建立 Velocity 式模板。如舊版本代碼「`Hello, <%=request.getParameter("visitor")%>`」可簡化為「`Hello, ${param.visitor}”`。

## 特點

* 能以模板化的方式簡單、高效地添加動態網頁內容。
* 可利用 JavaBean 和標籤庫技術復用常用的功能代碼（設計好的組件容易實現重複利用，減少重複勞動）。標籤庫不僅帶有通用的內建標籤（JSTL)，而且支援可延伸功能的自訂標籤。
* 有良好的工具支援。
* 繼承了 Java 語言的相對易用性。
* 繼承了 Java 的跨平台優勢，實現「一次編寫，處處執行」。因為支援 Java 及其相關技術的開發平台多，網站開發人員可以選擇在最適合自己的系統平台上進行 JSP 開發；不同環境下開發的 JSP 專案，在所有客戶端上都能順利存取。
* 頁面中的動（控制變動內容的部分）／靜（內容不需變動的部分）區域以分散但又有序的形式組合在一起，能使人更直觀地看出頁面代碼的整體結構，也使得設計頁面效果和程式邏輯這 2 部分工作容易分離（外觀視圖與邏輯分離）。從而方便分配人員並行揮各自長處，實現高效地分工合作。
* 可與其它企業級 Java 技術相互配合。JSP 可以只專門負責頁面中的資料呈現，實現分層開發。

## 包含內容

### JSP 指令

JSP 指令控制 JSP 編譯器如何去生成 servlet，以下是可用的指令：

* 包含指令 include –包含指令通知 JSP 編譯器把另外一個檔案完全包含入當前檔案中。效果就好像被包含檔案的內容直接被貼上到當前檔案中一樣。這個功能和 C 預處理器所提供的很類似。被包含檔案的副檔名一般都是 "jspf"（即 JSP **Fragment**，JSP 片段）:

* 頁面指令 page –頁面指令有以下幾個選項：

**注意：**在同一個 JSP 檔案中只有「import」匯入頁面指令可以被多次使用。

* 標籤庫指令 taglib –標籤庫指令描述了要使用的 JSP 標籤庫。該指令需要指定一個字首 prefix（和 C++ 的命名空間很類似）和標籤庫的描述 URI:

### JSP 指令碼元素和變數

#### 標準指令碼變數

以下是永遠可用的指令碼變數：

* out：JSPWriter，用來寫入回應流的資料
* page：servlet 自身
* pageContext：一個 PageContext 實例包括和整個頁面相聯絡的資料，一個給定的 HTML 頁面可以在多個 JSP 之間傳遞。
* request：HTTP request（請求）物件
* response：HTTP response（回應）物件
* session：HTTP session（伺服器端對談）物件

#### 指令碼元素

有三個基本的指令碼元素，作用是使 JAVA 代碼可以直接插入 servlet.

* 一種是聲明標籤，在 JAVA SERVLET 的類體中放入一個變數的定義。靜態的資料成員也可以如此定義。

　
:
* 一種是指令碼標籤，在 JAVA SERVLET 的類的 \_jspService () 方法中放入所包含的語句。

　
:
* 一種是表達式標籤，在 JAVA SERVLET 的類中放入待賦值的表達式，表達式注意不能以分號結尾。

　
:

### JSP 動作

JSP 動作是一系列可以呼叫內建於網路伺服器中的功能的 XML 標籤。JSP 提供了以下動作：

#### 標籤樣例

##### jsp:include

##### jsp:forward

在本例中，請求被傳遞到 "subpage.jsp"，而且請求的處理權不會再返回前者。

##### jsp:useBean

scope 屬性可以是 request, page, session or application，它有以下用意：

* request— 該屬性在請求的生命周期內有效，一旦請求被所有的 JSP 頁處理完後，那麼該屬性就不可參照。
* page— 該屬性只是當前頁中有效。
* session— 該屬性在使用者對談的生命周期內有效。
* application— 該屬性在各種情況下都有效，並且永遠不會被變為不可參照，和全域變數 global variable 相同。

上述例子將會用一個建立一個類別的實例，並且把該實例儲存在屬性中，該屬性將在該請求的生命周期內有效。它可以在所有被包含或者從首頁面（最先接收請求的頁面）轉向到的 JSP 頁之間共享。

### JSP 標籤庫

除了 JSP 預定義動作之外，開發者還可以使用 JSP 標籤擴充 API 添加他們自訂的_動作_。開發者寫一種實現一個標籤的介面和一個標籤庫的 XML 描述檔案的 JAVA 類，這就能指定標籤和實現標籤的 JAVA 類
請看如下 JSP：

JSP 編譯器將會載入 mytaglib.tld 這個 XML 檔案，然後可以看到標籤 _myaction_ 由 JAVA 類 _MyActionTag_ 實現。當該標籤首次在檔案中使用時，將會建立一個 MyActionTag 的實例。然後（而且當每次該標籤被使用時），當出現開始標籤時，將會呼叫 doStartTag () 方法，根據開始標籤的結果，來決定如何處理標籤的主體。主體是指開始標籤和結束標籤之間的文字。這個 doStartTag () 方法將會返回如下之一：

* SKIP\_BODY - 標籤之間不做處理。
* EVAL\_BODY\_INCLUDE - 對標籤之內主體進行賦值。
* EVAL\_BODY\_TAG - 對標籤之內主體進行賦值並把結果輸出到流（儲存在標籤的主體內容屬性中）。

　
: **注意：**如果標籤擴充了 BodyTagSupport 類，當主體被執行時會在呼叫 doEndTag () 之前呼叫 doAfterBody () 方法。該方法用於實現迴圈結構。

當結束標籤出現時，它會呼叫 doEndTag () 方法，該方法會返回如下兩做之一：

* EVAL\_PAGE - 表示 JSP 檔案的剩餘部份將會被執行。this indicates that the rest of the JSP file should be processed.
* SKIP\_PAGE - 表示將不會再有更多執行操作。當前 JSP 頁交出控制權。就象在轉發動作中的作用一樣。

上述 myaction 標籤 tag 會有一個類似下面例子的用於實現的類：

## 在地化

JSP 的在地化是通過和 JAVA 應用程式相同的方式完成的，即使用資源包。

## 模型 - 視圖 - 控制器 模式

為了把表現層（presentation）從請求處理（request processing）和資料儲存（data storage）中分離開來（這樣更利於開發、查錯和功能擴充），昇陽公司推薦在 JSP 檔案中使用一種稱作模型 - 視圖 - 控制器（MVC）的架構模式。按照此設計，當使用者存取網站上的特定網址時，使用者的處理請求會先由網站伺服器取得到，然後先交由網站的控制器程式作初步處理。使用者的存取請求可能多種多樣，比如查詢資訊或進行資料計算都是常見的網站業務。控制器程式會初步判斷使用者請求的種類，然後把使用者請求轉發給與特定業務對應的 Servlet 程式或者另一個獨立的 JSP 檔案進行業務處理。當請求處理完後，再通過一個專門負責輸出資訊的 JSP 頁以清晰、美觀的方式向使用者的瀏覽器輸出結果。簡而言之，先由控制器攔截使用者請求並做初步判斷，再由業務處理程式存取資料（從資料庫中存取）和處理業務，最後由視圖組件生成結果頁面並行送結果給使用者。其中 JSP 一般用作展示輸出結果，可以用於展示經 Servlet 查詢或處理後的結果；也可以用一個 JSP 檔案處理業務邏輯，再用另一個 JSP 檔案展示結果。按功能做這樣的檔案拆分（而非由一個臃腫的 JSP 頁面包攬所有功能）是為了便於團隊分工。MVC 本身是一種由來已久的設計思想，基於 JSP 的技術只是實現 MVC 架構的流行方案之一。Struts 和 Spring 框架等好幾種流行的網站建設框架都是基於 MVC 模式設計的。

## JSP 和 Servlets

從架構上說，JSP 可以被看作是從 Servlets 進階提煉而作為 JAVA Servlet 2.1 API 的擴充而應用。Servlets 和 JSP 最早都是由 Sun Microsystems（太陽公司）開發的。從 JSP1.2 版本以來，JSP 處於 Java Community Process（有人譯為：Java 社群組織）開發模式下。JSR-53 規定了 JSP 1.2 和 Servlet 2.4 的規範，JSR-152 規定了 JSP 2.0 的規範。2006 年 5 月，JSP 2.1 的規範作為 Java EE 5 的一部份，在 JSR-245 中發布。

靜態資料在輸入檔案中的內容和輸出給 HTTP 回應的內容完全一致。此時，該 JSP 輸入檔案會是一個沒有內嵌 JAVA 或動作的 HTML 頁面。而且，客戶端每次請求都會得到相同的回應內容。

### 樣例

不管 JSP 編譯器是生成 SERVLET 的 JAVA 原始碼，或者是直接發布二進位碼，了解一下 JSP 編譯器是如何把檔案轉換成一個 JAVA SERVLET，都是很有幫助的。例如，看一下如下輸入 JSP 和它最後生成的 JAVA SERVLET：

**Input JSP**

**Resulting servlet**

## 參見

* JSTL
* Java 企業版
* JavaServer Faces
* Java Servlet
* SSJS
* WAR (file format)
* EAR (file format)
* JAR (file format)
* Tomcat 伺服器

## 參考資料

### 文內參照

### 書目

* Kin-man Chung. JavaServer Pages Specification (pdf) 2.3. 甲骨文公司. 2013 [2018 年 3 月 16 日].
* Hans Bergsten. JavaServer Pages 3. Sebastopol, California: O'Reilly. 2003 [2006-07-20]. ISBN0-596-00563-6. （原始內容存檔於 2019-10-17）.

 

## 外部連結

* Sun's JSP product description（頁面存檔備份，存於網際網路檔案館）
* JSR 245（頁面存檔備份，存於網際網路檔案館） (JSP 2.1)
* JSR 152（頁面存檔備份，存於網際網路檔案館） (JSP 2.0)
* JSR 53（頁面存檔備份，存於網際網路檔案館） (JSP 1.2)