Java Server Pages(JSP)規範用於組合Java代碼和HTML,以提供網頁的動態內容。當創建動態內容時,編寫JSP比編寫HTTP Servlet更方便,因爲JSP允許將Java代碼直接嵌入到HTML頁,而對於HTTPServlet,則需要將HTML嵌入到Java代碼中。JSP還可以調用一種稱爲標記庫(taglib)的自定義Java 類(使用類似於HTML的標記)。
通過JSP,可以將網頁的動態內容及靜態演示內容分開。它可以滿足兩種不同類型的開發人員:負責網頁圖形設計的HTML開發人員和負責軟件開發以創建動態內容的Java開發人員。
BES應用服務器支持JSP 1.1規範、JSP標記庫、JSTL和JSP預編譯。
1.1.2.1 標記
表2‑3 JSP標記
JSP標記 |
語法 |
描述 |
Scriptlet |
嵌入Java源代碼Scriptlet。Java代碼會被執行,其輸出也會按順序插入該頁的其餘HTML中。 |
|
指令 |
<%@ dir-type dir-attr %> |
指令包含嚮應用程序服務器發出的消息。 |
聲明 |
<%! declaration %> |
對頁中其它聲明、Scriptlet或表達式引用的變量或方法進行聲明。 |
表達式 |
<%= expression %> |
定義一個Java表達式,該表達式在請求頁面時進行計算,並會轉換爲字符串,然後內聯發送到JSP響應的輸出流。 |
操作 |
<jsp:useBean ... > <jsp:setProperty ...> <jsp:getProperty ...> <jsp:include ...> <jsp:forward ...> <jsp:plugin ... > |
提供對JSP高級功能的訪問,並且僅僅使用XML語法。 |
註釋 |
<%/* comment */%> |
通過僅使用JSP註釋標記,確保註釋會從可查看的HTML文件源代碼中刪除。當用戶在瀏覽器中選擇“查看源文件”時,HTML註釋保持可見狀態。 |
JSP規範中定義了一些隱式Java對象,爲JSP頁提供有用的方法和信息。隱式對象僅在Scriptlet或表達式中纔可以使用,在聲明裏定義的方法中使用這些關鍵字會導致轉換時發生編譯錯誤。
request代表HttpServletRequest對象。它包含有關來自瀏覽器的請求的信息,並具有若干可用於獲取Cookie、頭和會話數據的有用方法。
response代表HttpServletResponse對象。它提供用於設置從JSP頁發回到瀏覽器的響應信息的方法。這些響應的信息包含Cookie和其它頭信息。
但不能在JSP頁內部使用response.getWriter()方法;如果這樣做,會引發運行時異常。要將JSP 響應發送回瀏覽器,請在Scriptlet代碼中直接使用out對象。
out是javax.jsp.JspWriter的實例,具有幾個可用於將輸出發送回瀏覽器的方法。
pageContext代表javax.servlet.jsp.PageContext對象。便於訪問各種作用域的名稱空間和與Servlet相關的對象,並且它爲與Servlet相關的常用功能提供包裝方法。
session代表請求的javax.servlet.http.HttpSession對象。默認情況下,session指令設置爲true,因此在默認情況下,session是有效的。JSP2.1 規範聲明,如果session指令設置爲false,使用session關鍵字則會導致致命轉換錯誤。
application代表javax.servlet.ServletContext對象。使用它可找到有關Servlet引擎和Servlet環境的信息。
要轉發或包含請求,可使用ServletContext訪問Servlet requestDispatcher,也可使用JSPforward指令將請求轉發至其它Servlet,以及使用JSP include指令來包含來自其它Servlet的輸出。
config代表javax.servlet.ServletConfig對象,並提供對Servlet實例初始化參數的訪問。
page代表從此JSP頁生成的Servlet實例。在Scriptlet代碼中使用時,它與Java關鍵字this同義。
要使用page,必須將其轉換爲實現JSP頁的Servlet的類類型,因爲它被定義爲java.lang.Object的實例。默認情況下,Servlet類是按JSP文件名命名的。爲方便起見,建議使用Java關鍵字this(而不是使用page)引用Servlet實例和獲得對初始化參數的訪問。
指令可指示JSP執行特定功能,或以特殊方式解釋JSP頁。指令由某個指令類型和該類型的一個或多個特性組成。指令可以放置在JSP頁的任何位置,位置通常是無關的(除了include指令);並且可以在一個JSP頁中使用多個指令標記。
指令的語法爲<%@dir_type dir_attr %>,dir_type表示指令類型,dir_attr表示使用該指令類型的一個或多個指令特性的列表。指令的類型有三種:page、taglib或include。其中使用page指令可以設置字符編碼;使用taglib指令可聲明JSP頁使用的自定義JSP標記擴展。
使用聲明可在生成的JSP Servlet的類作用域級別定義變量和方法。在JSP標記之間做出的聲明可從JSP頁中的其它聲明和Scriptlet進行訪問。例如:
int i=0;
String foo="Hello";
private void bar(){
……
}
%>
JSP Scriptlet組成JSP Servlet的HTTP響應的Java正文。要將Scriptlet包含在JSP頁中,請使用此處顯示的標記:
// Java代碼
%>
1. 可將多個Scriptlet Java代碼塊與純HTML混合在一起。
2. 可在任何位置(甚至在Java構造塊中)切換HTML和Java代碼。
3. 可使用預定義的變量out將HTML文本從Java代碼直接輸出到Servlet輸出流。
表達式經常用於返回用戶以前提供的數據,表達式可以讓HTML在JSP頁中更具可讀性。要將表達式包含在JSP文件中,請使用以下標記:
使用JSP操作可以創建、使用、修改由JavaBean代表的對象,也可以轉發或包含其它請求,或包含Applet。
通過<jsp:useBean>操作標記,可以實例化符合JavaBean規範的Java對象,並可以從JSP頁引用這些對象。
<jsp:useBean>標記會從特定作用域檢索現有的指定Java對象,如果找不到現有對象,它會實例化新對象,並將其與由id特性給定的名稱相關聯。對象存儲在由scope特性給定的位置中,該特性確定該對象的可用性。例如,以下標記會嘗試從HTTP會話檢索類型爲examples.jsp.ShoppingCart、名爲cart的Java對象。
<jsp:useBeanid="cart" class="examples.jsp.ShoppingCart"scope="session"/>
如果當前不存在這樣的對象,則JSP會嘗試新建一個對象,並將其命名爲cart,存儲在HTTP會話中。
<jsp:useBean>標記語法具有另一種格式,通過該格式,可以在首次實例化對象時設置某些屬性。例如:
<jsp:useBeanid="cart" class="examples.jsp.ShoppingCart"scope=session>
<jsp:setPropertyname="cart" property="cartName"value="music"/>
</jsp:useBean>
實例化JavaBean對象之後,可通過其id名稱,在JSP文件中將其作爲Java對象進行引用。可在Scriptlet標記和表達式計算器標記中使用它,並可分別使用<jsp:setProperty>和<jsp:getProperty>標記調用其setXxx()或getXxx()方法。
使用scope特性可指定JavaBean對象的可用性和生命週期。作用域可以是下列隱式對象之一:page、request、session、application。
可使用<jsp:include>標記將其它資源包含在JSP中。
JSF2.0和JSTL1.2包是WEB應用通用的庫,BES應用服務器默認提供了JSF實現(BES_HOME\framework\components\javax.faces.jar)和JSTL(BES_HOME\framework\components\javax.servlet.jsp.jstl.jar),使用JSF或JSTL功能的所有標準WEB應用都可以直接使用JSF和JSTL。
JSF技術簡化了爲JavaServer應用生成用戶界面的過程。利用JSF快速生成WEB應用的步驟是:
1. 將可重用的UI組件裝配到頁面中;
2. 將組裝進來的UI組件連接到應用數據源;
3. 將客戶端生成的事件綁定到服務器端事件處理程序。
1.1.3.2 JavaServerPage標準標記庫(JSTL)
JSP標準標記庫(JSTL)將許多WEB應用中常見的核心功能作爲簡單的標記進行封裝。JSTL可支持常見的、結構化的任務,例如迭代和條件、用於操作XML文檔的標記、國際化標記以及SQL標記。它還提供了一個框架,用於將現有自定義標記與JSTL標記集成。
1.1.4 自定義標記庫(Taglib)
JSP標記能封裝Java邏輯或功能,從而將Java邏輯和頁面展現分離開來、簡化JSP頁面的開發和維護。JSP除了使用JSP標準標記庫(JSTL)之外,也可以自定義標記。
一組相關的自定義標記可以以標記庫(TagLibrary)的形式發佈。每個Taglib都包含一個標記庫描述符(TLD)文件,以及各個標記的處理實現類和輔助類。標記庫的結構如下圖所示:
圖1‑1 標記庫結構
開發自定義標記庫的步驟爲:
1.1.4.1 開發標記處理類
當使用了自定義標記的JSP頁面被調用時,WEB容器會調用標記處理類。
標記處理類必須實現javax.servlet.jsp.tagext.Tag或javax.servlet.jsp.tagext.BodyTag接口,或者繼承javax.servlet.jsp.tagext.TagSupport或javax.servlet.jsp.tagext.BodyTagSupport。
標記處理類的簡單示例如下:
package com.bes.demo;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
importjavax.servlet.jsp.tagext.BodyTagSupport;
public class SimpleTag extendsBodyTagSupport {
// 遇到開始標記時調用,此處接收JSP頁面傳遞過來的name屬性,並打印歡迎語句
public intdoStartTag() throws JspException {
try{
pageContext.getOut().print("Hello," + this.name + "!");
}catch (Exception ex) {
thrownew JspTagException("SimpleTag: " + ex.getMessage());
}
returnSKIP_BODY;
}
// 遇到結束標記時調用
public intdoEndTag() {
returnEVAL_PAGE;
}
// 標記的每個屬性都需定義getter、setter方法
private Stringname = null;
public StringgetName() {
return(this.name);
}
public voidsetName(String name) {
this.name= name;
}
}
1.1.4.2 編寫標記庫描述符
標記庫描述符(TLD)是描述標記庫的XML文檔,包含了標記庫的整體信息和每個標記的信息。WEB容器使用標記庫描述符校驗標記。標記庫描述符必須以.tld爲文件擴展名,存放在WEB應用的WEB-INF目錄或其子目錄中。
下面是一個簡單的TLD文件示例:
<?xml version="1.0"encoding="UTF-8"?>
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>bes-tags</short-name>
<!-- 定義Taglib的URI,JSP頁面使用taglib指令聲明該Taglib。taglib指令的uri需與此uri元素值保持一致 -->
<uri>/simpleTag</uri>
<tag>
<name>hello</name>
<tag-class>com.bes.demo.SimpleTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>name</name>
<required>yes</required>
<rtexprvalue>yes</rtexprvalue>
</attribute>
</tag>
</taglib>
1.1.4.3 使用自定義標記庫
WEB應用要使用標記庫,需要將標記處理類放在WEB應用的WEB-INF/lib或WEB-INF/classes目錄中,將TLD文件放在WEB應用的WEB-INF目錄或其子目錄中。
在JSP頁面中,使用taglib指令聲明標記庫。taglib指令的uri屬性需與TLD文件中的<uri>值保持一致;prefix屬性用來定義標記庫的前綴,編寫JSP時使用此前綴引用標記庫中的標記。JSP頁面示例如下:
<%@ taglib uri="/simpleTag"prefix="simple" %>
<simple:hello name="World"/>
該WEB應用部署後,訪問JSP時WEB容器會調用com.bes.demo.SimpleTag的setName方法將name賦值爲World,然後調用doStartTag()方法,在頁面上輸出如下內容:
Hello, World!