JavaServer Page它不是Servlet

前言

      Servlet有兩個缺點是無法克服的:首先,寫在Servlet中的所有HTML標籤必須包含Java字符串,這使得處理HTTP響應報文的工作十分繁瑣;第二,所有的文本和HTML標記是硬編碼,導致即使是表現層的微小變化,如改變背景顏色,也需要重新編譯。
      JavaServer Pages(JSP)解決了上述兩個問題。同時,JSP不會取代Servlet,相反,它們具有互補性。現代的Java Web應用會同時使用Servlet和JSP頁面。

1.JSP概述

      JSP頁面本質上是一個Servlet。然而,用JSP頁面開發比使用Servlet更容易,主要有兩個原因。首先,不必編譯JSP頁面;其次,JSP頁面時一個已.jsp爲擴展名的文本文件,可以使用任何文本編輯器來編寫它們。JSP頁面在JSP容器中運行,一個Servlet容器通常也是JSP容器。例如,Tomcat就是一個Servlet/JSP容器。
      當一個JSP頁面第一次被請求時,Servlet/JSP容器主要做以下兩件事情:
      (1)轉換JSP頁面到JSP頁面實現類,該實現類是一個實現javax.servlet.jsp.JspPage接口或子接口javax.servlet.jsp.HttpJspPage的Java類。JspPage是javax.servlet.Servlet的子接口,這使得每一個JSP頁面都是一個Servlet。該實現類的類名由Servlet/JSP容器生成。如果出現轉換錯誤,則相關錯誤信息將被髮送到客戶端。
      (2)如果轉換成功,Servlet/JSP容器隨後編譯該Servlet類,並裝載和實例化該類,像其他正常的Servlet一樣執行生命週期操作。
      對於同一個JSP頁面的後續請求,Servlet/JSP容器會先檢查JSP頁面是否被修改過。如果是,則該JSP頁面會被重新翻譯、編譯並執行。如果不是,則執行已經在內存中的JSP Servlet。這樣一來,一個JSP頁面的第一次調用的實際花費總比後來的花費多,因爲它涉及翻譯和編譯。爲了解決這個問題,可以執行下列動作之一:

  • 配置應用程序,使所有的JSP頁面在應用程序啓動時被調用(實際上也可視爲翻譯和編譯),而不是在第一次請求時調用。
  • 預編譯JSP頁面,並將其部署爲Servlet。

      JSP頁面可以包含模板數據和語法元素。這裏,語法元素是一些具有特殊意義的JSP轉換符。例如,“<%”是一個元素,因爲它表示在JSP頁面中的Java代碼塊的開始。“%>”也是一個元素,因爲它是Java代碼塊的結束符。除去語法元素外的一切是模板數據。模板數據會原樣發送給瀏覽器。例如,JSP頁面中的HTML標記和文字都是模板數據。
      下圖所示代碼爲welcome.jsp的JSP頁面。它是發送一個客戶問候的簡單頁面。注意,同Servlet相比,JSP頁面時如何更簡單地完成同樣的事情的。
在這裏插入圖片描述
      一個JSP頁面不同於一個Servlet的另一方面是是,前者不需要添加註解或在部署描述符中配置映射URL。在應用程序目錄中的每一個JSP頁面可以直接在瀏覽器中輸入路徑頁面訪問。下圖給出了該應用程序的目錄結構。
在這裏插入圖片描述
      應用程序的結構非常簡單,由一個WEB-INF目錄和welcome.jsp頁面構成。可以通過URL訪問welcome.jsp頁面:

http://localhost:8080/JSPtest_war_exploded/welcome.jsp

在這裏插入圖片描述
      說明:添加新的JSP頁面後,無須重啓Tomcat。
      下圖展示瞭如何在JSP頁面中使用Java代碼來生成動態頁面。顯示了今天的日期。
在這裏插入圖片描述
在這裏插入圖片描述
      請注意兩件事情。首先,Java代碼可以出現在JSP頁面中的任何位置,並通過“<%”和“%>”包括起來。其次,可以使用page指令的import屬性導入在JSP頁面中使用的Java類型,如果沒有導入的類型,必須在代碼中寫Java類的全路徑名稱。

2.註釋

      在瀏覽器中爲JSP頁面添加註釋是一個良好的習慣。JSP支持兩種不同的註釋格式:
(1)JSP註釋。該註釋記錄頁面中做了什麼。
(2)HTML/XHTML註釋。這些註釋將會發送到瀏覽器上。
      JSP註釋以“<%–”開始,以“–%>”結束。下面是一個例子:

<%-- retrieve products to display --%>

JSP註釋不會被髮送到瀏覽器端,也不會被嵌套。
HTML/XHTML註釋語法如下:

<!-- [comments here] -->

一個HTML/XHTML註釋不會被容器處理,會發原樣發送給瀏覽器。HTML/XHTML註釋的一個用途是用來確定JSP頁面本身。

3.隱式對象

      Servlet容器會傳遞幾個對象給它運行的Servlet。例如,可以通過Servlet的service方法拿到HttpServletRequest和HttpServletResponse對象,以及可以通過init方法訪問到ServletConfig對象。此外,可以通過調用HttpServletRequest對象的getSession方法訪問到HttpSession對象。
      在JSP中,可以通過使用隱式對象來訪問上述對象。下標所示爲JSP隱式對象(九大內置對象)。
在這裏插入圖片描述
      以request對象爲例,該隱式對象代表Servlet/JSP容器傳遞給Servlet服務方法的HttpServletRequest對象。可以將request理解爲一個指向HttpServletRequest對象的引用變量。下面的代碼示例,從HttpServletRequest對象中返回username參數值:

<%
  String username=request.getParameter("userName"); 
%>

      pageContext用於javax.servlet.jsp.PageContext。它提供了有用的上下文信息,並通過其自說明的方法類訪問各種Servlet相關對象,如getRequest、getResponse、getServletContext、getServletConfig和getSession。當然,這些方法在腳本中不是非常有用的,因爲可以更直接地通過隱式對象來訪問request、response、session和application。
      此外,PageContext中提供了另一組有趣的方法:用於獲取和設置屬性的方法,即getAttribute方法和setAttribute方法。屬性值可被存儲在4個範圍之一:頁面、請求、會話和應用程序。頁面範圍是是最小範圍,這裏存儲的屬性只在同一個JSP頁面可用。請求範圍是指當前的ServletRequest中。會話範圍是指當前的HttpSession中。應用程序範圍指應用的ServletContext中。
pageContext的setAttribute方法簽名如下:

public abstract void setAttribute(java.lang.String name,java.lang.Object value,int scope)

      其中,scope的取值範圍爲PageContext對象的最終靜態int值:PAGE_SCOPE、REQUEST_SCOPE、SESSION_SCOPE和APPLICATION_SCOPE。
      若要保存一個屬性到頁面範圍,可以直接使用setAttribute重載方法:

public abstract void setAttribute(java.lang.String name,java.lang.Object value)

      如下腳本將一個屬性保存到ServletRequest中:

<%
pageContext.setAttribute("product",product,PageContext.REQUEST_SCOPE);
%>
同樣效果的代碼如下:
<%
request.setAttribute("product",product);
%>

      隱式對象out引用了一個javax.servlet.jsp.JspWriter對象,這類似於你在調用HttpServletResponse的getWriter方法時得到java.io.PrintWriter。可以通過調用它的print方法將消息發送到瀏覽器。例如:

out.println("Welcome");

      下圖中的implicitObjects.jsp頁面展示了部分隱式對象的使用。
在這裏插入圖片描述
在這裏插入圖片描述

4.指令

      指令是JSP語法元素的第一種類型。它們指示JSP轉換器如何翻譯JSP頁面爲Servlet。page和include指令尤爲重要。
(1)page指令
      page指令的語法如下:

<%@ page attribute1="value1" attribute2="value2"...%>

      @和page間的空格不是必須的,attribute1、attribute2等式page指令的屬性。如下是幾個比較常用的page指令屬性列表:

  • import:定義一個或多個本頁面中被導入和使用的java類型。例如:import="java.util.List"將導入List接口。可以使用通配符“*”來引入整個包。可以通過在兩個類型間加入“,”分隔符來導入多個類型,如import=“java.util.ArrayList,java.util.Calendar”。此外,JSP默認導入如下包:java.lang、javax.servlet、javax.servlet.http、javax.servlet.jsp。
  • session:值爲True,本頁面會加入會話管理;值爲False則相反。
  • errorPage:定義當時出錯是用來處理錯誤的頁面。
  • isErrorPage:標識本頁面是一個錯誤處理頁面。
  • contentType:定義本頁面隱式對象response的內容類型,默認是text/html。
  • pageEncoding:定義本頁面的字符編碼,默認是ISO-8859-1。

(2)include指令
      可以使用include指令將其他文件中的內容包含到當前JSP頁面。一個頁面中可以有多個include指令。若存在一個內容會在多個不同頁面中使用或一個頁面不同位置使用的場景,則將該內容模塊化到一個include文件非常有用。
      include指令的語法如下:

<%@ include file="url" %>

      其中,@和include間的空格不是必須的,URL爲被包含文件的相對路徑,若URL以一個斜杆(/)開始,則該URL爲文件在服務器上的絕對路徑,否則爲當前JSP頁面的相對路徑。

5.腳本元素

      一個腳本程序是一個Java代碼塊,以<%符號開始,以%>符號結束。以下圖所示的scriptletTest.jsp頁面爲例。
在這裏插入圖片描述
在這裏插入圖片描述
      在上述頁面中有兩個腳本程序,需要注意的是定義在一個腳本程序中的變量可以被其後續的腳本程序使用。
      腳本程序第一行代碼可以緊接<%標記,最後一行代碼也可以緊接%>標記,不過,這會降低代碼的可讀性。
(1)表達式
      每個表達式都會被JSP容器執行,並使用隱式對象out的打印方法輸出結果。表達式一“<%=”開始,並以“%>”結束。舉例如下:

Today is<%=java.util.Calendar.getInstance().getTime()%>

      注意,表達式無須分號結尾。
      JSP容易首先執行java.util.Calendar.getInstance().getTime(),並將計算結果傳遞給out.print(),這與如下腳本程序的效果一樣:

Today is
<%
  out.print(java.util.Calendar.getInstance().getTime());
%>

(2)聲明
      可以聲明能在JSP頁面中使用的變量和方法。聲明以“<%!”開始,並“%>”結束。例如下圖的declarationTest.jsp頁面展示了一個JSP頁面,該頁面聲明瞭一個名爲getTodayDate的方法。
在這裏插入圖片描述
在這裏插入圖片描述
      在JSP頁面中,一個聲明可以出現在任何地方,並且一個頁面可以有多個聲明。

6.錯誤處理

      JSP提供了很好的錯誤處理能力。除了在Java代碼中可以使用try語句,還可以指定一個特殊頁面。當應用頁面遇到未捕獲的異常時,用戶將看到一個精心設計的網頁解釋發生了什麼,而不是一個用戶無法理解的錯誤信息。
      請使用page指令的isErrorPage屬性(屬性值必須爲True)來標識一個JSP頁面是錯誤頁面,下圖errorHandler.jsp展示了一個錯誤處理程序。
在這裏插入圖片描述在這裏插入圖片描述
      其它需要防止未捕獲的異常的頁面使用page指令的errorPage屬性來指向錯誤處理頁面,例如,下圖的buggy.jsp頁面
在這裏插入圖片描述在這裏插入圖片描述
      運行的buggy.jsp頁面會拋出一個異常。不過,我們不會看到由Servlet/JSP容器生成錯誤消息。相反,會看到errorHandler.jsp頁面的內容。

7.小結

      JSP是構建在Java Web應用程序上的第二種技術,是Servlet技術的補充,而不是取代Servlet技術。一個精心設計的Java Web應用程序會同時使用Servlet和JSP。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章