標籤:
Web 應用程式
Web應用是Web伺服器上組成一個完整應用的 servlets,HTML pages,classes 和其他資源的一個集合。Web應用可以被捆綁並運行在不同供應商的不同容器內。
10.1 Web伺服器中的Web應用?
Web伺服器裡的Web應用以一個特定的路徑為根。例如,catalog應用可能定位到http://www.mycorp.com/catalog。所有以此首碼為開始的請求會被路由到代表該 catalog 應用的 ServletContext。servlet 容器可以建立 Web應用的自動建置規則。例如 ~user/ 映射可以用來映射一個基於/home/user/public_html的 Web應用。預設情況下,在任何同一時間一個Web應用的執行個體必須運行在一個VM上。如果應用通過其部署描述符將其標記為“distributable(分布的)”,此行為可以被覆蓋。標記為分布的應用必須遵守比普通Web應用更嚴格的規則。本規範中設定了這些規則。
10.2 與ServletContext的關係 ?
servelt容器必須強制Web應用與 ServletContext 之間一一對應的。ServletContext 對象提供給 servlet 它的應用視圖。
10.3 Web應用的元素
Web應用可以由以下項目組成:
? Servlets ?
?JSP Pages1 ?
?工具類 ?
?靜態文檔(HTML,圖片,聲音,等等)?
?用戶端Java applets,beans,和類 ?
?將以上元素綁在一起的描述性元資訊
10.4 部署層次 ?
為部署和打包目的,本規範定義了一個可以存在於開放檔案系統,歸檔檔案或其它格式的階層。建議 servlet 容器支援該結構作為運行時表現形式,但不是必須的。
10.5 目錄結構 ?
Web 應用程式作為一個結構化層級目錄存在。此結構層級的根作為應用中檔案的文檔根。例如,Web容器中以 /catalog 作為上下文路徑的應用,Web應用程式層級根目錄下的 index.html 和 在WEB-INF/lib 下的JAR檔案中/META-INF/resources 目錄下包含的index.html 都滿足來自 /catalog/index.html 的請求。如果 index.html 同時存在於根上下文和 應用 WEB-INF/lib 目錄裡的JAR檔案 /META-INF/resources中,則必須使用根上下文中的index.html。匹配 URLs 到上下文路徑的規則在12章”映射請求到Servlets” 中給出。由於應用的上下文路徑決定了Web應用內容的 URL 命名空間,Web容器必須拒絕Web應用在此 URL 命名空間中定義可能造成潛在衝突的上下文路徑。比如嘗試部署相同上下文路徑的另外一個Web應用,就會發生衝突。由於請求匹配資源使用大小寫敏感的方式,潛在衝突的確定也必須以大小寫敏感的方式進行。
在應用程式層級結構中存在一個名為”WEB-INF”的特殊目錄。此目錄包含與應用相關的不在應用根文檔中的所有東西。大部分 WEB-INF 節點不是應用公用文檔樹的一部分。除了打包在位於 WEB-INF/lib 中的 JAR 檔案中 META-INF/resources 的靜態資源和JSP,包含在 WEB-INF 目錄中的其他檔案不能被容器提供給用戶端。但是 WEB-INF 目錄的內容對調用 ServletContext 的 getResource 和 getResourceAsStream 方法的 servlet 代碼是可見的,並且可以使用 RequestDispatcher 調用被公開。因此,如果應用開發人員需要從 servlet 代碼訪問他不想直接對Web用戶端直接公開的應用特殊配置資訊,可以將它放到該目錄下。由於請求匹配資源地圖使用大小寫敏感的方式,例如用戶端請求,‘/WEB-INF/foo’, ‘/WEb-iNf/foo’,不應該將位於 /WEB-INF 下的Web應用的內容返回,包括任何形式的目錄列表。
WEB-INF 目錄的內容:
? /WEB-INF/web.xml 部署描述符。 ?
? /WEB-INF/classes/ servlet和工具類的目錄。此目錄中的類必須對應用的類載入器可用。?
? /WEB-INF/lib/*.jar Java 歸檔檔案區。這些檔案包括打包在JAR檔案中的 servlets,benas,靜態資源和JSPs 和其他對Web應用有用的工具類。Web應用類載入器必須能從任何這些歸檔檔案中載入類。Web 應用程式必須首先從 WEB-INF/classes 目錄載入類,然後從 WEB-INF/lib 目錄下的庫 JARs載入。另外,任何來自用戶端訪問 WEB-INF/ 目錄裡資源的請求,除了靜態資源被打包進JAR檔案的情況外,必須返回一個SC_NOT_FOUND(404)響應。?
10.5.1 應用目錄結構樣本
下面是一個樣本Web應用中的所有檔案清單:
/index.html
/howto.jsp
/feedback.jsp
/images/banner.gif
/images/jumping.gif
/WEB-INF/web.xml
/WEB-INF/lib/jspbean.jar
/WEB-INF/lib/catalog.jar!/META-INF/resources/catalog/moreOffers/books.html
/WEB-INF/classes/com/mycorp/servlets/MyServlet.class
/WEB-INF/classes/com/mycorp/util/MyUtils.class
10.6 Web 應用程式歸檔檔案
使用標準Java歸檔工具,Web應用可以被打包並簽入一個Web歸檔格式(WAR)檔案。例如,一個用來“issue tracking(跟蹤問題)”的應用發行就緒在一個名為 issuetrack.war 的歸檔檔案中。
當打包成這種格式時,將產生一個包含對Java歸檔工具有用資訊的 META-INF 目錄。此目錄不能被容器作為內容直接提供給作為Web用戶端請求的響應,雖然它的內容對通過調用 ServletContext 的 getResource 和 getResourceAsStream 的 servlet 代碼是可見的。另外對任何訪問 META-INF 目錄下資源的請求必須返回 SC_NOT_FOUND(404) 響應。
10.7 Web 應用程式部署描述符
Web應用描述符(見14章:部署描述符)包括以下配置類型和部署資訊:
? ServletContext 初始化參數 ?
? Session 配置 ?
? Servlet/JSP 定義 ?
? Servlet/JSP 映射 ?
? MIME Type 映射 ?
? Welcome File 列表 ?
? Error Pages
? Security 安全?
10.7.1 擴充依賴 ?
當大量應用使用相同的代碼或資源時,他們通常會被作為庫檔案安裝進容器裡。這些檔案經常是通用和標準的API,可以在不犧牲移植性的情況下使用。僅被一個或少數應用使用的檔案將作為Web應用的一部分來訪問。容器必須為這些庫提供一個目錄。存放在這個目錄的檔案必須可以跨Web應用可用。這個目錄的位置是容器指定的。servlet容器用來載入這些庫檔案的類載入器必須與在同一JVM中的所有Web應用的類載入器相同。此類載入器執行個體必須位於Web應用類載入器的父載入器鏈中。為了保持移植性,應用開發人員需要知道Web容器上安裝了什麼擴充,並且容器需要知道 WAR 中的 servlets 依賴哪些庫。依賴這些擴充的應用開發人員必須在 WAR 檔案中提供一個 META-INF/MANIFEST.MF 條目列出WAR需要的所有擴充。這個 manifest 條目的格式必須遵循標準的 JAR manifest 格式。在 Web 應用程式的部署中,Web 容器必須使擴充的正確版本對[遵守“可選包版本識別”機制定義規則]的應用可用。Web容器必須能識別 WAR 包中 WEB-INF/lib 目錄下的任何 JAR 庫中 manifest 條目裡聲明的依賴。如果Web容器不能滿足以這種方式聲明的依賴,它應該使用一個有意義的錯誤資訊拒絕應用。
10.7.2 Web應用類載入器?
容器用來載入 WAR 中 servlet 的類載入器必須允許開發人員使用 getResource 來載入[遵循正常 Java SE 詞法的] WAR 中 JAR 庫中包含的任何資源。在 Java EE 許可協議描述中,servlet 容器不是 Java EE 產品的一部分,不應該允許應用去覆蓋 Java SE 平台類,比如 java.* 和 javax.* 中的類,Java SE 不允許被修改。容器不應該允許應用去覆蓋或者訪問容器的實作類別。建議應用的類載入器實現為:載入打包進WAR中的類和資源優先於載入容器範圍內的位於JAR庫中的類和資源。實現必須保證為容器中部署的每一個 web 應用調用 Thread.currentThread.getContextClassLoader() 必須返回一個實現了在本節中指定約定的 ClassLoader 執行個體。另外,每個部署的 web 應用的 ClassLoader 執行個體必須是一個獨立的執行個體。在讓任何回調(包括 listener 回調)進入 web 應用之前,容器必須按照上面的描述設定線程上下文 ClassLoader(?),一旦回調返回,將它設定回原來的 ClassLoader。
10.8 替換 Web 應用程式
伺服器應該能在不重啟容器的情況下使用新版本替換應用。當應用被替換時,容器應該提供一個穩健的方法保留應用中的會話(session)資料。
10.9 錯誤處理
10.9.1 請求屬性
當錯誤發生時,Web 應用程式必須能指定應用中用來提供錯誤響應內容體的其它資源。這些資源的規範在部署描述符中設定。
如果錯誤處理的位置(the location of the error handler)是一個 servlet 或 一個 JSP 頁面:
? 被容器建立的初始未封裝的請求和響應對象被傳遞給 servlet 或 JSP 頁面。
? 請求路徑和屬性被設定為:對錯誤資源的RequestDispatcher.forward 已經被執行一樣。(?)
? 表10-1中的請求屬性必須被設定:
表10-1 請求屬性和他們的類型
請求屬性 類型
javax.servlet.error.status_code java.lang.Integer
javax.servlet.error.exception_type java.lang.Class
javax.servlet.error.message java.lang.String
javax.servlet.error.exception java.lang.Throwable
javax.servlet.error.request_uri java.lang.String
javax.servlet.error.servlet_name java.lang.String
這些屬性允許 servlet 根據狀態代碼,異常類型,錯誤資訊,傳播的異常對象,錯誤產生在其中的 servlet 處理的請求URI(由 getRequestURI 調用確定)和錯誤產生的 servlet 的邏輯名來產生專門內容。
隨著本規範 2.3 版本中屬性列表中異常對象的引入,異常類型和異常資訊屬性變得多餘。保留它們是為了向後相容API的早期版本。
10.9.2 錯誤頁面
為了允許開發人員自訂 servlet 產生錯誤時返回 網頁用戶端的內容的外觀(呈現),部署描述符定義了一系列錯誤頁面說明。 當 servlet 或 filter 為特定狀態代碼調用 response 的 sendError 或如果 servlet 產生的異常或錯誤傳播到了該容器時,此文法允許容器返回資源的配置。
如果 response 的 sendError 方法被調用,容器查詢Web應用的錯誤頁面聲明,使用狀態代碼文法並嘗試匹配。如果有一個匹配,容器返回此位置(<location>)條目指示的資源。
容器或filter在處理請求期間可能會拋出下面的異常:
? runtime exceptions or errors 運行時異常或錯誤?
? ServletExceptions 或 它的子類 ?
? IOExceptions or 或它的子類?
Web應用可以使用 exception-type 元素宣告錯誤頁面。在此情況下,容器通過比較拋出的異常和使用 exception-type 元素定義的錯誤頁面(<error-page>)定義列表來匹配異常類型。匹配導致容器返回在位置(<location>)條目指示的資源。在類繼承層次最近的匹配勝出。
如果使用類層次匹配沒有包含合適的 exception-type 的 error-page 聲明,並且拋出的異常是 ServletException 或它的子類,容器使用 ServletException.getRootCause 方法提出被封裝的異常。使用被封裝的異常(ServletException 或其子類中封裝的),再次傳入錯誤頁面聲明,重新嘗試匹配錯誤頁面聲明。
在部署描述符中使用 exception-type 元素的錯誤頁面(<error-page>)聲明中 exception-type 的類名必須是唯一的。同樣,使用 status-code 元素的 error-page 聲明在部署描述符中 status code 也必須是唯一的。
如果部署描述符中的一個 error-page 元素沒有包含 exception-type 或 error-code 元素,此錯誤頁面是預設錯誤頁面。
當使用 RequestDispatcher 或 filter.doFilter 方法調用發生錯誤時,錯誤頁面機制不會幹預。在此種方式下,filter 或者 servlet 有機會使用 RequestDispatcher 處理產生的錯誤。(這段不知道對不對)
如果 servlet 產生的錯誤沒有被上面介紹的錯誤頁面機制處理,容器必須確保發送帶有狀態代碼 500 的響應。
預設 servlet 和 container 將使用 sendError 方法發送 4XX 和 5XX 狀態響應,以便調用錯誤機制。預設 servlet 和 container 將使用 sendError 方法發送 2XX 和 3XX 狀態響應,不會調用錯誤機制。
如果應用(程式)使用在2.3.3.3節描述的非同步作業,2-10頁的“非同步處理”,應用程式負責處理應用程式建立的線程上的錯誤。容器【可以】處理通過 AsyncContext.start 建立的線程產生的錯誤。參看2-16頁的幾節關於處理 AsyncContext.dispatch 期間產生的錯誤,“容器必須如下捕獲並處理 dispatch 方法執行期間可能產生的任何錯誤和異常”。
10.9.3 錯誤過濾器
錯誤頁面機製作用在容器產生的原始未封裝/未過濾的請求和響應對象上。此機制在 6.2.5 節描述,“過濾器和 RequestDispatcher”,在錯誤響應產生之前可以用來指定應用的過濾器。
10.10 歡迎檔案
Web應用開發人員可以在Web應用部署描述符中定義稱為歡迎檔案的[部分URI]有序列表。Web應用部署描述符 schema 中描述了此列表的部署描述符文法。
此機制的目的是允許開發人員為容器指定一個 部分的URIs 有序列表,當有對應 WAR 中一個目錄條目的 URI 的請求沒有映射到 Web 元件時,用來追加到這些 URI之後。這種類型的請求就是有名的 有效部分請求(a valid partial request)。
這種用法的好處通過下面的例子來搞清楚: 可以定義一個 ‘index.html’ 的歡迎檔案,以便對像 URL host:port/webapp/directory/ 的請求,’directory’ 是 WAR 裡一個沒有映射到 servlet 或 JSP page 的條目,返回給用戶端的是 ‘host:port/webapp/directory/index.html’。
如果Web容器接收到一個有效部分請求,Web容器必須檢查定義在部署描述符中的歡迎檔案。歡迎檔案清單是一個沒有前置和後導 / 的有順序的部分URL列表。Web 服務器必須按在部署描述符中指定的順序逐個添加歡迎檔案到部分請求,並且檢查在WAR是否有一個靜態資源映射到請求的URI。如果沒有找到匹配,Web 服務器必須重新按照部署描述符中指定的順序依次添加每個歡迎檔案到部分請求並檢查是否有一個 servlet 映射到請求URI。Web 容器必須將請求發送到 WAR中匹配的第一個資源。容器可以使用 forward,redirect 或容器指定的機制將請求發送到歡迎資源,與直接請求沒有什麼區別。
按照上面描述的方式如果沒有匹配的歡迎檔案,容器可以按照它能找到的合適方式來處理請求。對於某些配置可能意味著返回目錄列表,其它配置可能返回 404 響應。
考慮這樣的一個 Web 應用程式:
■ 部署描述符列出了下面的歡迎檔案。
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
■ WAR中的靜態檔案如下:
/foo/index.html
/foo/default.jsp
/foo/orderform.html
/foo/home.gif
/catalog/default.jsp
/catalog/products/shop.jsp
/catalog/products/register.jsp
? 請求URI /foo 將會重新導向到 URI /foo/。 ?
? 請求URI /foo/ 將返回 /foo/index.html 。?
? 請求URI /catalog 將會重新導向到 URI ?/catalog/。
? 請求URI /catalog/ 將會返回 /catalog/default.jsp 。?
? 請求URI /catalog/index.html 將會導致 404 NOT FOUND.
? 請求URI /catalog/products 將會重新導向到 URI ?/catalog/products/。
? 對URI /catalog/products/ 的請求將會傳遞到“預設”servlet, 如果有的話。如果沒有“預設”servlet 映射,此請求可能導致 404 not found , 可能導致包括 shop.jsp 和 register.jsp 的目錄列表,或者可能導致容器定義的其他行為。參見 12.2 節,“映射規範”中“預設” servlet 的定義。 ?
? 上面列出的所有靜態內容也可以與上面打包進 jar 檔案 META-INF/resources 目錄裡的內容一起打包進 JAR 檔案。此 JAR 檔案可以包含在 Web 應用程式的 WEB-INF/lib 目錄裡。 ?
10.11 Web應用環境
Servlet 容器不是 Java EE 技術標準的一部分,鼓勵實現但不必須,在 15.2.2 節“Web應用環境和Java EE規範”中描述了實現應用環境功能。如果它們(容器)沒有實現所需功能來支援[在上面部署應用所依賴]的環境,容器應該提供一個警告。
10.12 Web應用部署
當web應用被部署進容器,在web 應用開始處理用戶端的請求之前,必須按照下面的步驟依次執行:
? 執行個體化在部署描述符中通過<listener>元素標識的每個事件 listener 一個執行個體。
? 為每個實現 ServletContextListener 的已執行個體化 listener 執行個體,調用 contextInitialized() 方法。
? 執行個體化在部署描述符中通過 <filter> 元素標識的每個 filter 的一個執行個體,然後調用每個 filter 執行個體的 init() 方法。?
? 包含<load-on-startup> 元素的 <servlet> 元素標識的 servlet,按照 load-on- startup 元素值定義的(按由小到大)順序,每個 servlet 執行個體化一個執行個體,並且調用每個 servlet 的 init() 方法。 ?
10.13 包含web.xml部署描述符
如果web應用不包含任何 Servlet,Filter?或 Listener 組件,或者使用註解聲明了相同(就是使用了註解),不需要包含一個 web.xml 檔案。換句話說,一個僅包括靜態檔案或JSP頁面的應用不需要一個web.xml 來介紹。
第十章 Web Application(JavaTM Servlet 規範3.1 )