JSP

JSP（全稱 Jakarta Server Pages，曾稱為 JavaServer Pages）是由昇陽電腦公司主導建立的一種動態網頁技術標準。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,” 可簡化為 “Hello, ${param.visitor}”。

特點

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

包含內容

3.1 JSP 指令

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

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

//example import 匯入樣例

//example contentType 頁面型別樣例

//example for non error page 無錯誤頁面樣例

//example for a thread safe JSP 執行序安全 JSP 樣例

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

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

3.2 JSP 指令碼元素和變數

3.2.1 標準指令碼變數

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

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

3.2.2 指令碼元素

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

一種是宣告標籤，在 JAVA SERVLET 的類體中放入一個變數或方法的定義。靜態的資料成員也可以如此定義。
:
一種是指令碼標籤，在 JAVA SERVLET 的類的_jspService 方法中放入所包含的語句。
:
一種是表示式標籤，在 JAVA SERVLET 的類中放入待賦值的表示式，表示式注意不能以分號結尾。
:

3.3 JSP 動作

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

3.3.1 標籤樣例

3.3.1.1 jsp:include

name:

3.3.1.2 jsp:forward

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

3.3.1.3 jsp:useBean

" />

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

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

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

3.4 JSP 標籤庫

除了 JSP 預定義動作之外，開發者還可以使用 JSP 標籤擴充套件 API 新增他們自定義的動作。開發者寫一種實現一個標籤的介面和一個標籤庫的 XML 描述檔案的 JAVA 類，這就能指定標籤和實現標籤的 JAVA 類

請看如下 JSP：

...

...

...

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

SKIP_BODY - 標籤之間不做處理。
EVALBODYINCLUDE - 對標籤之內主體進行賦值。
EVALBODYTAG - 對標籤之內主體進行賦值並把結果輸出到流（儲存在標籤的主體內容屬性中）。

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

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

EVAL_PAGE - 表示 JSP 檔案的剩餘部份將會被執行。this indicates that the rest of the JSP file should be processed.

SKIP_PAGE - 表示將不會再有更多執行操作。當前 JSP 頁交出控制權。就象在轉發動作中的作用一樣。

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

public class MyActionTag extends TagSupport {

//Releases all instance variables.

public void release {...}

public MyActionTag { ...}

//called for the start tag

public int doStartTag { ...}

//called at the end 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 最早都是由昇陽電腦開發的。從 JSP1.2 版本以來，JSP 處於 JCP 開發模式下。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 頁面。而且，客戶端每次請求都會得到相同的響應內容。

6.1 樣例

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

輸入 JSP

...

...

最後生成的 JAVA SERVLET

package jsp_servlet;

import java.util.*;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

import javax.servlet.jsp.*;

import javax.servlet.jsp.tagext.*;

import com.foo.bar; //imported as a result of

import ...

class _myserlvet implements javax.servlet.Servlet, javax.servlet.jsp.HttpJspPage {

//inserted as a

//result of

int serverInstanceVariable = 1;

...

public void _jspService ( javax.servlet.http.HttpServletRequest request,

javax.servlet.http.HttpServletResponse response )

throws javax.servlet.ServletException,

java.io.IOException

{

javax.servlet.ServletConfig config = ...;//get the servlet config

Object page = this;

PageContext pageContext = ...;//get the page context for this request

javax.servlet.jsp.JspWriter out = pageContext.getOut ;

HttpSession session = request.getSession (true);

try {out.print ( "\r\n");

out.print ("\r\n");

...

//from

int localStackBasedVariable = 1;

...

out.print ("\r\n");

out.print (" ");

//note, toStringOrBlank converts the expression into a string or if

//the expression is null, it uses the empty string.

//from

out.print (toStringOrBlank ( "expanded inline data" + 1) );

out.print ("\r\n");

...

} catch (Exception _exception) {//clean up and redirect to error page in}

}

}