第一章:
servlet2.3規范用到了一下的一些規范:J2EE、JSP1.1、JNDI
在14章中講述了規范中的所有的classes類或接口(改文中不講述)。對開發者而言以下的有些相關的協議:URI、URL、HTTP/1.0、MIME、HTCPCP/1.0、XML
1.1 什么是servlet?
servlet是一個基于java技術的web組件,該組件被容器管理,能被編譯成字節碼被web服務調用;容器也被稱之為引擎,是支持servlet功能的web服務的擴展。servlet之間的通信是通過客戶端請求被引擎執行成request/response對象進行的。
1.2 什么是servlet引擎?
servlet引擎是web服務器或應用服務器的一部分,服務器能夠支持網絡的請求/響應,基于請求解析MIME,基于響應格式化MIME。servlet引擎是一個servlet容器,也掌管著servlet的生命周期。
所有的servlet引擎都必須支持HTTP的請求/響應模式,但HTTPS的請求/響應模式也是被支持的。HTTP的版本最小要HTTP/1.0,最好是HTTP/1.1。servlet引擎也具有安全和權限的一些特性,這些特性其服務器應提供。
1.3 例子
一個典型的事件執行的順序是:
1) 客戶端向web服務器發起一個HTTP請求
2) HTTP請求被web服務器接受,并移交給servlet引擎,servlet引擎可以在主機的同一個進程、不同的進程或其他的web服務主機的進程中啟動。
3) servlet引擎根據servlet的配置檔確定調用的servlet,并把request對象、response對象傳給它。
4) 4.servlet通過request對象知道客戶端的使用者是誰,客戶的請求信息是什么和其他的一些信息。servlet處理完請求后把要返回的信息放入response對象返回到客戶端
5) 一旦servlet完成了請求的處理,servlet引擎就會刷新response,把控制權返回給web服務器
1.4與其它技術的比較
與其它服務相比servlet有以下的一些優點
1) 運行速度上比CGI快,因為使用了多線程
2) servlet使用了標準的api,可被許多web服務支持
3) 與系統無關性,一次編譯多次使用
第二章
servlet接口是servlet api核心部分,所有的servlet都是直接或間接的實現了這些接口。兩個最重要的servlet api 接口是GenericServlete 和 HttpServlet,更多的開發者都繼承HttpServlet去實現他們的servlet
2.1 Request 包含的方法
一個基本的servlet接口應該定義一個方法包含客戶端的信息,每次servlet引擎把一個request發送到一個servlet事例,這個方法都要被調用。
對于并發的請求,web應用需要設計者設計的servlet引擎能分配多個線程執行這個方法。
2.1.1 HTTP 請求處理的方法
HttpServlet是實現了Servlet接口的抽象類,增加了一些新的方法,這些方法在處理HTTP請求時會被service方法自動調用,這些方法是:
doGet 接受 HTTP 的GET請求
doPost 接受 HTTP 的POST請求
doPut 接受 HTTP的PUT請求
doDelete 接受 HTTP的DELETE請求
doHead 接受 接受 HTTP的HEAD請求
doOptions 接受 HTTP的OPTIONS請求
doTrace 接受 HTTP的TRACE請求
一個開發者只會涉及到doGet和doPost方法,其它的方法是為非常熟悉HTTP的設計師準備的
2.1.2
HTTP/1.0只定義了doGet,doHead,doPost方法,沒有定義PUT,DELETE,OPTIOONS和TRACE方法
2.1.3
HttpServlet接口定義了getLastModified方法
2.2 實例數
2.2.1
在分布式環境中servlet引擎為每個servlet只能聲明一個實例,當一個servlet實現了SingleThreadModel接口時,servlet引擎可以聲明多個實例去處理請求,servlet在應用服務的部署描述中定義發布.
2.2.2單線程servlet
SingleThreadModel接口保證了在同一時刻一個servlet實例的service方法只會被一個線程執行。這對于每個請求發送給每個實例是很重要的。引擎可以從對象池中選擇,對象池可以在同一時刻保持多個實例,如HttpSession可以被多個servlet在任何時候調用包括實現了SingleThreadModel接口的servlet
2.3 servlet的生命周期
一個好的生命周期的定義應該是servlet怎么被引入了,怎么實例化的,怎么初始化的?當請求從客戶端來的時候,是怎么從服務器中取出來的,這些在javax.servlet.Servlet的接口的init,service,destroy方法中都有明確的定義。
所有的servlet都必須實現GenericServlet或HttpServlet抽象類
2.3.1 servlet的引入和實例化
servlet引擎會可靠的引入和實例化servlet,當servlet引擎被啟動時servlet就被引入和實例化了,或者當一個servlet被請求時被引擎引入和實例化。
servlet引擎啟動時,需要裝載的類通過java的裝載類進行裝載,被裝載的類可以在本地文件系統、遠程文件系統或網絡服務中。在裝載完后,引擎就實例化它們。
2.3.2 初始化
在servlet對象實例化后,引擎必須在這個servlet接受客戶段請求之前初始化,在初始化中servlet可以讀取固定的配置信息,一些昂貴的資源如數據庫連接和一次性激活的資源,引擎通過調用servlet接口的init方法初始化。每個serlet對象都實現了Servlet接口和ServletConfig接口,ServletConfig接口允許servlet接受web應用配置檔中配置的參數,還向servlet中傳入了一個描述servlelt運行環境的類(ServletContext)
2.3.2.1 在初始化時發生錯誤
在初始化過程中,servlet實例能拋出UnavailableException 或ServletException異常。在這樣的情況下servlet不能被放入服務中,必須被引擎釋放,destroy方法沒有被調用。在初始化失敗后引擎可以在UnavailableException異常規定的最短無效時間后實例化新的一個實例,再初始化。
2.3.3 request
當servlet初始化完成后,引擎可以使用它去處理客戶端的請求了。請求被封裝在Servletrequest類型的對象中,響應信息被封裝在ServletResponse類型的對象中,這兩個對象以參數的形式傳給Servlet接口中的service方法。
2.3.3.1 多線程問題
servlet引擎可以發送并發的請求給servlet的service方法,servlet開發者必須提供足夠的線程來運行service方法。
對開發者來說一個可以選擇的方法是實現SingleThreadModel接口,以確保在同一時刻只有一個請求在service方法中。一個引擎要確保請求能夠在servlet中持續化,或維持在一個servlet實例池中,如果servlet是web應用服務的一部分,引擎可以在一個虛擬機中擁有一個servlet實例化的池。
對于沒有實現SingleThreadModel接口的servlet,如果service方法(或 doGet,doPost)被聲明為synchronized,引擎將不能用實例池的途徑,而必須持續化請求,強力建議開發者不能聲明synchronize service方法,這樣會嚴重影響系統的性能。
2.3.3.2 request中的異常
在處理請求時servlet可以拋出ServletException或UnavailableException異常,一個ServletException異常會在處理一個請求出現錯誤時拋出,引擎將清除這個異常。當servlet一時或永久地不能獲得一個請求時就會拋出UnavailableException異常,如果是一個永久性異常時引擎將調用它的destroy方法從服務器中消除servlet實例,如果是暫時性異常時引擎在異常期間不發送請求給servlet。如果返回SERVICE_UNAVAILABLE(503)響應,在這期間引擎將不接受任何請求,直到header中出現Retry-After。引擎可以不區分永久性還是暫時性的異常把所有的UnavailableException作為永久性處理。
2.3.3.3 線程安全
執行request和response對象不能保證是線程安全的,意思是說他們只能在請求的線程中使用,不能被其它線程中的對象使用。
2.3.4 結尾
servlet實例可能被引擎保存幾毫秒或和引擎一樣的生命時間或在這兩者之間。當引擎決定結束一個servlet時,調用它的destroy方法,在destroy中釋放任何長久固定的資源。
在引擎調用desroy方法之前,必須保證運行在service方法中的線程都完成處理,或者超過了服務定義的執行時間。
一旦servlet實例的destroy方法被調用,引擎不在發送任何請求給這個實例。如果引擎再次使用這個servlet就必須再建一個這個servlet的實例。
在destroy方法執行完成后,引擎將釋放這個servlet實例,于是就符合垃圾回收機制的條件了。
3.1 介紹ServletContext接口
ServletContext接口定義了servlet運行環境的信息。引擎提供商有義務在servlet引擎中提供一個實現了ServletContext接口的對象。通過這個對象servlet能夠獲得log事件,資源的URL,設置或存儲servlet之間通信的變量。ServletContext在web服務中確定了一個所有請求開始的路徑,是ServletContext的上下文路徑。
3.2 ServletContext 接口的作用范圍
每個web應用配置到容器中都會產生一個實現了ServvletContext接口的實例。如果是分布式的,將會在每個java虛擬機上產生一個ServletContext實例。容器中默認固有的web應用(不是發布上來的web應用)有一個默認的ServletContext,在分布式中這個默認的ServletContext只存在于一個虛擬機中,是不可分配的。
3.3 初始化參數
ServletContext接口的getInitParameter,getInitParameterNames方法接受部署描述文件中的初始化參數,這些參數可以是的安裝信息,或網站管理員的mail或名字或對系統的評論。
3.4 上下文屬性
servlet可以通過一個名稱把對象邦定到servletContext中,幫定到ServletContext中的對象都能被同一個web服務中的其它對象引用。ServletContext中的屬性方法有:
setAttribute
getAttribute
getAttributeNames
removeAttribute
3.4.1 在分布式系統中 上下文的屬性
上下文屬性是在本地的虛擬機中保存的,這防止了ServletContext屬性存在于分布式的內存中。當信息需要在一個分布式環境中共享的時候,信息應該被放在session中,或存在數據庫中,或存在一個實體bean中。
3.5 資源
ServletContext接口提供了獲取web服務中的靜態資源的方法:
getResource
getResourceAsStream
這些方法以一個“/”作為上下文的根目錄,后跟著資源路徑的路徑為參數。這些資源可以在本地服務系統中也可以在另個web應用中,或在一個遠程的文件系統中。
這些方法不能用于去獲得一個動態的資源,如要調用一個jsp頁面,getResource("/index.jsp")將返回index.jsp的原代碼,不能web顯示index.jsp。
要獲得資源列表可以用getResourcePaths(String path)方法
3.6 多主機 和 Servlet 上下文
web服務中可能在一個IP上有多個邏輯主機的情況。在這種情況下每個邏輯主機必須有自己單獨的servlet上下文,或者設置多個servlet 上下文,但在邏輯主機中不能共享這些servlet 上下文,一個主機只能單獨使用一個。
3.7
引擎提供類重新裝載機制是必須的,必須確認應用中所有的類和接口都可以在單類裝載器中裝載;在session綁定監聽事件中引擎會終止正在裝在的類。以前版本的裝載器,引擎創建一個新的裝載器裝載一個servlet或class和類裝載器裝載其他的servlet或類截然不同;這可能裝載一個未知的類或對象,產生不可預知的行為。這是新的類裝載器中是應該注意預防的問題。
3.7.1 臨時工作目錄
Servlet 上下文需要一個臨時存儲的目錄。servlet引擎必須為每個servlet 上下文提供一個私有臨時目錄,通過javax.servlet.context.tempdir的context屬性使目錄有效。與該屬性關聯的對象必須是java.io.File類型。
在許多servlet引擎實現中提供請求可以識別的通用的機制。
當servlet引擎重起始不必維護臨時目錄中的內容,但要確保臨時目錄中的該上下文內容對于運行在該servlet引擎中的其它web應用中的servlet 上下文是不可見的。
4 requeset
request對象包含了客戶端的所有請求信息。在HTTP協議中,客戶端發送到服務端的信息都包含在請求的HTTP 頭和消息體中
4.1 HTTP 協議的參數
客戶端發送給servlet引擎的參數是包含在請求中的,引擎從客戶端請求的URI字符串中或POST數據中解析出請求的參數。參數以name-value的形式存儲的。任何一個name可以對應多個value。在ServletRequest接口的方法中:
getParameter
getParameterNames
getParameterValues
getParameterValues方法返回關聯到一個name上的一個String對象的數組。getParameter返回name對應的values數組中的第一個value。URI和POST體中的參數都會放入請求參數的set對象中。URI中的參數會在POST體之前被引入,如URI中的參數“a=hello”post體中的參數是a=goodbye&a=world,則參數set中的內容是a=(hello,goodbye,world).以HTTP GET請求的參數是不隱蔽的,參數必須通過getRequestURI或getPathInfo方法獲得參數字串。
4.1.1 參數什么時候有效
在post form中的數據參數被放入參數set之前的情況是這樣的:
1)請求是一個HTTP或一個HTTPS
2)HTTP方法是POST
3)內容的類型是application/x-www-form-urlencoded
4)初始化過的servlet從request對象中調用getParameter方法(或getParameterNames,getParameterValues)。
Post form 中的數據符合條件的就放入參數set中,不符合的就放入request對象的輸入流中。
4.2 屬性
request的屬性是一個對象,引擎可以把API不能表達的信息放入屬性中,一個servlet也可以設置一個屬性信息用于servlet之間的通信。request對象中的屬性方法有:
getAttribute
getAttributeNames
setAttribute
一個屬性名稱只能關聯一個value。屬性名以“java.”或“javax.”為前綴的是規范保留的,類似的“sun.”“com.sun”是sun公司的保留字,這些保留的前綴是不能使用的。name建議使用統一的包命名規范名稱。
4.3 頭
servlet通過HttpServletRequest接口的方法獲得HTTP的包頭信息,這些方法是:
getHeader
getHeaders
getHeaderNames
getHeader 方法返回頭的名稱。一個名稱可以關聯多個頭信息,如果在這種情況下,getHeader方法返回第一個頭信息。
getHeaders返回與一個名稱關聯的所有頭信息存放在Enumeration對象中。HttpServletRequest提供了一些提取頭信息的類型轉換方法,如:
getIntHeader 把頭信息中的數據轉換成int型,如果轉換失敗會報NumberFormatException錯誤。
getDateHeader 把頭信息中日期的數據轉換成date型,如果轉換失敗會報IllealArgumentException錯誤
4.4 請求路徑
context路徑:這路徑是和ServletContext對象關聯的,在web服務中默認的上下文路徑是空的字符串,如果上下文路徑不是web服務的根目錄,則路徑以‘/’字符開始,但不能以‘/’結束。
Servlet 路徑:與該請求匹配的servlet的路徑。該路徑以‘/’字符開頭,或以‘/*’開頭但后面為空字串。
路徑信息:是請求路徑的一部分,但不是context路徑的一部分,也不是Servlet路徑的一部分,它既不為null也不是以‘/’開頭的字符串。
上一路徑在HttpServletRequest接口中對應的方法是:
getContextPath
getServletPath
getPathInfo
requestURI = contextPath + servletPath + pathInfo
上下文配置的例子:
Conteext Path /catalog
Servlet Mapping Pattern:/lawn/*
Servlet:LawnServlet
Servlet Mapping Pattern:/garden/*
Servlet:GardenServlet
Servlet Mapping Pattern:*.jsp
Servlet:JSPServlet
觀察下面的路徑
Request path path Elements
/catalog/lawn/index.htm ContextPath:/catalog
ServletPath:/lawn
PathInfo:/index.html
/catalog/garden/implements/
ContextPath:/catalog
ServletPath:/garden
PathInfo:/implements/
/catalog/help/feedback.jsp
ContextPath:/catalog
ServletPath:/help/feedback.jsp
PathInfo:null
4.5 路徑轉換
在API中有兩個簡單的方法允許開發者獲得文件系統的路徑:
ServletContext.getRealPath
HttpServletRequet.getPathTranslated
getRealPath(String aPath)方法返回本地文件系統的絕對路徑。getPathTranslated方法計算出請求pathInfo中的絕對路徑。
以上的兩個方法,servlet引擎不能辨認文件的路徑是否有效,當web應用調用一個不確定遠程文件系統,或數據庫路徑中的文件時,會返回null
4.6 Cookies
HttpServletRequest接口中提供了getCookies方法返回請求中的cookies數組,在每次客戶端請求時cookies數據就從客戶端發送給服務。客戶端返還的部分cookie信息是cookie的name和cookie的value。當cookie被送入瀏覽器時,cookie的其它信息就可以設置了。
4.7 SSL 屬性
如果一個請求被轉給一個安全的協議,如HTTPS,這些信息必須暴露給ServletRequest接口的isSecure方法。web引擎必須把下面的信息暴露給servlet開發者:
Attribute Attribute Name javaType
Cipher suite javax.servlet.request.cipher_suite String
bit size of the algo-rithm javax.servlet.request.key_size Integer
如果一個SSL證書伴隨著一個請求,servlet引擎必須把它作為一個數組對象暴露給servlet開發者,該數組中有
java.security.cert.X509Certificate對象和放在ServletRequest屬性中的javax.servlet.request.X509Certificate對象。
數組排列的順序是升序,在鏈中的證書的順序就是客戶端設置的順序。
4.8 國際化
ServletRequest接口的方法中提供了的方法:
getLocale
getLocales
getLocale方法將返回客戶端將從中獲得內容的首選的locale。要想知道更多的關于Accept-Language header 怎么解釋客戶端首選的語言的,請看14.4章
getLocales方法返回一個Locale objects的Enumeration,從首選的locale開始遞減。
如果客戶端沒有制定首選的locale,servlet引擎一定要提供一個默認的locale供getLocale方法返回,getLocales方法必須包含一個默認的locale的locale element
4.9 Request 數據的編碼
有許多web瀏覽器不能發送一個編碼的頭內容,所以把編碼留給解讀HTTP請求的Read去做。對于默認的請求編碼,引擎通常創建一個reader用“ISO-8859-1”去解析POST的數據,如果客戶端沒有指明編碼,或者客戶端發送失敗,getCharacterEncoding方法就返回null。
如果客戶端沒有設置編碼,而請求需被另外一種編碼,可用ServletRequest接口中的setCharacterEncoding(String enc) 方法。必須在解析post數據或讀取請求流之前調用這些方法。
4.10 Request對象的生命周期
每個request對象僅在servlet的service方法或filter中的doFilter方法中有效,引擎重用request對象是為了降低創建request對象的性能消耗。
開發者必須清楚request對象在給定的范圍外的一些不確定的行為。
第五章
response對象封裝著服務端送給客戶端的信息,從服務端傳回的信息可以包含在請求的頭和消息體重。
5.1 緩存
servlet引擎支持應答緩存,典型的servlet會默認的執行緩存,servlet可以指定緩存參數。
設置緩存信息的方法在ServletResponse接口中的方法有:
getBufferSize
setBufferSize
isCommitted
Reset
resetBuffer
flushBuffer
這些方法只有在servlet調用ServletOutputStream 或Writer之前有效。
getBufferSize返回緩存的大小,如果沒有緩存,該方法返回0。
setBufferSize可以設置緩存的大小,但不是必須的。servlet會根據請求放置適當的緩存大小。這方法必須在servlet調用ServletOutputStream 或Writer方法之前被調用。如果在之后調用就會拋出IllegalStateException錯誤。
isCommitted返回一個boolen值,標志是否有任何一個字節的數據被返回給客戶端了。flushBuffer方法強制把緩存中的信息寫到客戶端。
當response沒有提交緩存內容時調用reset方法就會清除緩存中的信息,包括頭信息和狀態碼。resetBuffer方法會清除緩存中的信息,但不會清除頭和狀態碼。在commit之后調用reset或resetBuffer都會拋出IllegalStateException錯誤,緩存中的內容不受影響。
使用緩存時,當緩存滿時response就必須立刻刷新把緩存中的內容發送給客戶端;只要第一個字節到了客戶端,commit的狀態就為true。
5.2 Headers
servlet能夠通過HttpServletResponse的一些方法設置HTTP響應的頭信息,這些方法有:
setHeader
addHeader
setHeader方法會把給定的一個name-values放到頭信息中,頭信息中只能有一個name-values,后面setHeader會覆蓋前面setHeader方法中的內容,一個name可以有多個value。
addHeader方法可以增加一個value到已有的name上,如果name不同就會新建一個name-values
頭可以包含一些信息,如日期或數字對象。
以下的一些方法用適當的數據類型設置頭信息:
setIntHeader
setDateHeader
addIntHeader
addDateHeader
在響應被發送到客戶端之前,頭信息是必須被設置的,如果沒有設置頭信息,servlet引擎將不會發送該請求到客戶端。HTTP1.1規范沒有規定必須設置響應的頭信息。當程序員沒有設置響應體的Content-Type時,servlet引擎也不需要設置一個默認的類型。
5.3 其他一些方法
HttpServletResonse接口中還有其他的一些方法:
sendRedirect
sendError
sendRedirect方法將設置合適的頭和體信息,用于重定向客戶端到另一個URL。如果sendRedirect參數是個相對路徑,則在底層servlet引擎中會把這相對路徑轉換成絕對路徑返回給客戶端的。
如果相對路徑不能被引擎轉換成絕對路徑就會拋出IllegalArgumentException錯誤。
sendError方法會把一條錯誤信息作為頭和體信息發送給客戶端。
如果在調用sendRedirect或sendError之前設置了頭和體信息,再調用sendRedirect或sendError時,之前的頭和體中的數據信息都將沒用,不會被發送到客戶端。如果使用了緩存,在調用sendRedirect或sendError時,之前的信息都將被清除。如果在commit之后調用sendRedirect或sendError就會拋出IllegalStateException錯誤。
5.4 國際化
當客戶端用一特殊的語言(或客戶端設置了語言)發出請求時,servlet會設置相應的響應語言信息,ServletResponse接口中設置響應語言的方法是setLocale。這個方法會設置一個合適的Content-Language到頭信息中。最好是開發者在調用getWriter方法之前調用setLocale方法,確保返回的PrintWriter已經被設置好了語言信息。如果在調用setLocale之后又調用了setContentType,setLocale中的內容將被setContentType中的字符集覆蓋。
response默認的編碼方式是“ISO-8859-1”。
5.5 response對象的關閉
當response被關閉時,引擎必須刷新該response緩存中的所有內容到客戶端。關閉的順序是:
1)關閉servlet的service方法
2)response 中setContentLength方法設置的指定數量的信息被寫入response
3)調用sendError方法
4)調用sendRedirect方法
5.6 response對象的生命周期
每個response對象僅在servlet的serrvice方法或filter的doFilter的方法中有效。引擎重復使用reponse對象,是為了降低創建response對象的開銷。開發者必須注意response對象在指定范圍外可能出現的一些意外的行為。
6 Filtering
Fileter是servlet2.3新增的部分。這一章介紹Filter類和方法,以及在web工程中的配置。
6.1什么是Fileter
Filter是重復使用的,用于變換HTTP請求和響應以及頭信息中的內容。Filter不能像servlet那樣創建response響應,但可以修改請求和響應的內容。
6.1.1例舉一些Filter
驗證Filter
登陸,審核Filter
圖像處理Filter
數據壓縮Filter
加密Filter
XSL/T Filter
MIME Filter
6.2 主要觀念
開發者通過創建實現javax.servlet.Filter接口的類,并提供一個沒有參數的構造函數來創建一個Filter。
在描述文件中Fileter用filter表示,調用方法用filter-mapping進行配置。
6.3 Filter生命周期
在web工程發布后,在請求使引擎訪問一個web資源之前,引擎必須定位Filter列表;引擎必須確保為列表中的每一個Filter建立了一個實例,并調用了他們的init(FilterConfig config)方法。在這過程中可以拋出異常。
部署描述文件中定義的所有filter,僅會在引擎中產生一個實例。
引擎為filter提供了一個FilterConfig類,該類附有ServletContext和一個帶有初始化參數的set。
當引擎接受一個請求時,引擎就會調用filter列表中第一個filter的doFilter方法,把ServletRequest,ServletResponse和FilterChain作為參數傳給它。
filter中doFilter方法典型的處理步驟是:
1)檢查請求頭信息
2)開發者創建一個實現了ServletRequest或HttpServletRequest的類,去包裝request對象,以便修改請求的頭信息或體數據。
3)開發者創建一個實現了ServletReqponse或HttpServletResponse的類,去包裝response對象,以便修改請求的頭信息或體數據。
4)filter可以調用鏈中的下一個實體,下一個實體是另一個filter,如果該filter是列表中最后的一個,則它的下一個實體就是一個目標web資源。如果要調用下一個filter的doFilter方法,把request,和response對象傳給FilterChain對象的doFilter方法中就可以了。
Filter chain 的doFilter方法是由引擎提供的,引擎在該方法中會定位filter列表中的下一個filter,調用它的doFilter方法,把傳來的request和response對象傳給它。
5)在調用chain.doFilter之后,filter可以檢測響應的頭信息
6)在這些過程中,filter可以拋出異常。當在調用doFilter過程中拋出UnavailableException異常時,引擎重復嘗試處理下面的filter chain的方法,如過時后還沒請求到filter chain 就會關閉對filter chain的請求。
當filter是列表中最后一個filter時,它的下一個實體是描述配置文件中filter后面的servlet或其它資源。
在引擎刪除一個Filter之前,引擎必須調用Filter的destroy方法,來釋放資源。
6.3.1 包裝Requests 和Responsees
過濾的中心觀念是對request或response的包裝,在這種模式下,開發者不僅可以改寫存在的方法,還可以創建自己的新方法,用于特殊的過濾任務,例如:開發者希望擴展response對象,希望有個更高層次的輸出流對象(writer)。
為了支持包裝模式,引擎不許保證在整個過濾鏈中,傳遞的request和response對象都是同一個對象。
6.3.2 Filter的環境
Filter的初始參數可以在描述配置文件中用init-params元素來配置,在運行時中,用FilterConfig的getInitParameter和getInitParamesterNames方法得到配置參數。
6.3.3 Filter在web工程中的配置
在部署描述文件中:
filter-name:filter名稱
filter-class:filter類路徑
init-params:用于初始化參數
如果開發者在部署描述中為一個filter類描述了兩個定義,則引擎會創建這個filter類的兩個實例。
下面是個配置的例子:
<filter>
<filter-name>Image Filter</filter-name>
<filter-class>com.acme.ImageServlet</fiflter-class>
</filter>
一旦filter在部署描述中定義,filter-mapping就可以被定義了,filter-mapping在web應用中是定義關聯filter的servlet和靜態資源的。
如:
<filter-mapping>
<filter-name>Image Filter</filter-name>
<servlet-name>ImageServlet</servlet-name>
</filter-mapping>
Image Filter 的 Filter就和ImageServlet 的Servlet建立了關聯。
Filter 可以和一群servlet和靜態資源關聯,用url-pattern。如:
<filter-mapping>
<filter-name>Loging Filter</filter-name>
<url-pattern>/*</url-pattern>
<filter-mapping>
引擎建立特殊請求URI的Filter鏈的順序是:
1)url-pattern映射fiter-mapping的順序和描述文件中定義的順序是一樣的。
2)servlet-name映射filter-mapping的順序和描述文件中定義的順序是一樣的。
這種需求要求引擎在接受請求時:
.識別符合SRV.11.2規則的web資源。
.如果一些filter是servlet和有servlet-name的web資源匹配的,引擎就會創建一個和描述文件中映射servlet-name的順序一樣的filter鏈。
.如果一些filter是rul-pattern關聯的,引擎就會創建一個和描述文件中映射url-pattern的順序一樣的efilter鏈。
一個高性能的web容器將會緩存filter鏈。
第七章 Sessions
超文本傳輸協議(HTTP)是無狀態的協議。要建立一個有效的web應用,客戶端之間的通信是需要的。有很多會話跟蹤的策略,
但是直接使用這些技術都很難使用。servlet規范中提供了一個簡單的HttpSession接口,不需要開發者關心會話跟蹤的具體細節。
7.1 會話跟蹤機制
下面描述了幾種會話的跟蹤機制
7.1.1 Cookies
HTTP cookies是最常用的會話跟蹤機制,所有的servlet引擎都應該支持這種方法。
引擎發送一個cookie到客戶端,客戶端就會在以后的請求中把這個cookie返回給服務器。用戶會話跟蹤的cookie的名字必須是JSESSIONID
7.1.2 SSL Sessions
在安全套接字層,加密技術用在了HTTPS協議,從一個客戶端來的多個請求允許用一個含糊的標識,servlet引擎就用這個數據定義一個Session。
7.1.3 URL重寫
URL重寫是最低性能的通用會話跟蹤方法。當一個客戶端不能接受cookie時,URL重寫就會作為基本的會話跟蹤方法;URL重寫包括一個附加的數據,一個session id,這樣的URL會被引擎解析和一個session相關聯。一個session id是作為URL的一個被編碼的參數傳輸的,這個參數名字必須是jsessionid.如下面的例子:
http://www.myserver.com/catalog/index.html;jsessionid=1234
7.1.4 會話的完整性
一個web容器必須支持HTTP 會話。而當cookies方法不被支持時,通常使用URL重寫方法。
7.2 創建一個會話
servlet設計者必須考慮到一個客戶端不能加入session的情況。
7.3 會話范圍
HttpSession對象只在應用程序級有效,通常用于session的cookie可以服務于不同的上下文,但一個HttpSession實例只服務于一個會話。舉個例子:如一個servlet A用RequestDispatcher去調用另一個web應用中的另一個servlet B,用于A和B的會話一定是兩個不同的會話。
7.4 Session屬性的邦定
一個servlet可以通過一個name邦定一個對象到HttpSession實例中;只要獲得包含同一個會話的請求對象,任何邦定到會話中的對象在同一個ServletContext中對于其它的servlet都是可用的。
當把一個對象放入session或從session刪除時可能要通知其它對象,這些信息能夠被實現了HttpSessionBindingListener接口的對象獲得,這個接口定義了一下的一些方法。
valueBound
valueUnbound
valueBound方法在HttpSession接口調用getAttribute方法獲得一個有效的對象之前調用。valueUnbound方法在HttpSession接口調用getAttribute方法獲得一個不再有效的對象后調用。
7.5 會話超時
在HTTP協議中,當客戶端不再有效時,沒有清楚的定義終止信號。這就意味著通常只能采用時間超時來表明客戶端不再有效。
默認的超時時間是servlet引擎定義的,通過HttpSession的getMaxInactiveInterval方法可以得到超時的時間;開發者可用用setMaxInactiveInterval方法來設置超時的時間,以秒定義的。如果一個session的超時時間被設置為-1,則這個session將永遠有效。
7.6 最后訪問時間
在當前的請求中用HttpSession接口的getLastAccessedTime可以獲得最后一次訪問session的時間。
7.7 重要session
7.7.1 線程問題
在一個可以配置的應用中,所有的請求都是一個會話的一部分,引擎一定能夠取出通過setAttribute或putValue放入HttpSession對象中的對象。注意以下的情況:
.引擎一定能夠訪問實現了Serializable接口的對象。
.引擎可以選擇存儲HttpSession對象中指定的對象,如EJB組件和事務。
.引擎能夠監聽到會話的變動。
如果放入session中的對象沒有被Seializable或沒有效,servlet可以拋出IllegalArgumentException;如果引擎不支持Session存儲對象的機制,引擎一定會拋出IllegalArgumentException。
這些限制意味著,在一個分布式引擎中,不會有額外的并發問題。
如果引擎為了service的品質持續化或遷移session,使用本地持續化的HttpSession或它的屬性是不受限制的,開發者要想確保放入session中的屬性對象能夠可用,最好對象實現Serializable接口。
在遷移一個session時引擎必須通知session中實現了HttpSessinActivationListener的屬性對象,必須通知在序列化前鈍化的或序列化后激活的session的監聽器。
開發分布式的開發者應該清楚的是,一旦引擎運行在超過一個JVM的時候,就不能用static 表明變量來存儲應用狀態,應該用EJB或數據庫賴存儲。
7.7.3客戶端
因為cookies或SSL證書都是被web瀏覽器訪問過程控制的,與任何特殊的window瀏覽器是沒有關系的。所以從所有window客戶端到一個servlet引擎的請求是同一個會話的一部分。最好是開發者總是設想所有的window客戶端是一起參與同一個會話的。
第八章 Dispatching Requests
當建立一個web應用時,把一個請求傳給另一個servlet或在response中包含另一個servlet的輸出是經常使用的。RequestDispatcher接口就提供了一些方法。
8.1 獲得RequestDispatcher
實現了接口RequesetDispatcher接口的對象可以在ServletContext的getRequestDispatcher或getNamedDispatchcer方法得到。
getRequestDispatcher的參數是一個以根目錄‘/’開始的一個路徑,該方法會查找路徑下的servlet,并把它封裝成RequestDispatchcer對象返回。
getNamedDispatcher方法把一個ServletContext知道的servlet名字作為參數,如果找到servlet,該servlet就被封裝成RequestDispatcher對象返回,如果沒有找到則返回null。
RequestDispatcher對象中使用相對路徑也是可以的。在ServletRequest中提供了getRequestDispatcher方法;這個方法和ServletContext中同名的方法功能類似。servlet引擎會用request的信息把相對路徑轉化成完整路徑的。如ServleltRequest.getRequestDispatcher("header.html")和ServletConext.getRequestDispatcher("/garden/headere.html")是等效的。
8.1.1 在Request Dispatcher 路徑中附加字符串
在ServletContext和ServletRequest創建RequestDispatcher方法中參數都可以帶字符串如:
Context.getRequestDispatcher("/raisons.jsp?orderno=5");
8.2 Request Dispatcher的使用
對于使用Request Dispatcher 而言就是一個servlet調用include或forward方法,這些方法的參數是Servlet接口傳來的request和response對象實例。引擎必須確保調用Request Dispatcher的處理過程是在同一個JVM的同一個線程中。
8.3 include 方法
RequestDispatcher接口的include方法可以在任何時候被調用;目標servlet可以包含所有外的request對象,不過response對象的使用是有限制的:
response只能寫信息到ServletOutputStream 或者Writer中,調用response對象的flushBuffer方法進行提交。不能夠設置頭信息,任何方法都不會影響到response的頭信息。
8.3.1 被包含的request參數
除了可以用getNamedDispatcher方法包含一個servlet外,以下的屬性可以被設置:
Java.servlet.include.request_uri
Java.servlet.include.context_path
Java.servlet.include.servlet_path
Java.servlet.include.path_info
Java.servlet.include.query_string
用request對象的getAttribute方法可以獲取被包含servlet的以上屬性。
如果被包含的servlet能后通過getNamedDispatcher方法找到就不必設置以上屬性了。
8.4 Forward 方法
RequestDispatcher接口中的forward方法,只有servlet沒有提交響應到客戶端時才可用;如果響應buffer中有數據還沒有提交,當調用forward方法中目標servlet的service方法前,buffer中的內容會被清空;如果buffer中的數據提交了,則發生IllegalStateException錯誤。
request對象的路徑必須放映獲取RequestDispatcher對象的路徑。
有個例外,如果RequestDispatcher是通過getNamedDispatcher方法得到的,request對象必須反映原始request的路徑。
在RequestDispatcher接口方法forward返回前,response的內容必須被提交,并由引擎關閉該servlet。
8.4.1 query String
在Request Dispatcher中創建的路徑是可以帶參數的。
8.5 錯誤
如果request Dispatcher的目標servlet拋出運行時錯誤或ServletException 或IOException,錯誤就會被傳給調用的servlet;在上傳之到調用的servlet之前,所有其他的exception都應該包裝成ServletExceptions。
第九章 web 應用
一個web應用是一堆servlet,html頁面,類和其他資源的集合。web應用可以被發布運行在很多服務提供商的多種引擎下。
9.1 web服務器
在web服務中一個web應用的根目錄是一個特殊的路徑,例如:一個網站目錄可以以http://www.mycorp.com/登錄,所有的請求都將以這個作為前綴發送到以這個前綴描述的servletContext環境中。
在任何時候一個web應用的實例只能運行在一個JVM中。
9.2 和servletContext的關系
servlet引擎會強迫web應用和ServletContext的通信,一個ServletContext對象提供了一個servlet使得該應用可見。
9.3 web應用中的元素
一個web應用包含以下的元素:
.Servlets
.JSP
.Utility Classes
.Static documents(html,images,sounds,etc)
.Client side Java applets,beans,and classes
.Descriptive meta informateion
9.4 部署層次
這個協議定義了一個層次結構,用于部署和打包,這個結構存在于一個文件中。
9.5 目錄結構
一個web應用存在一個目錄層次結構。文件根目錄是應用的一部分。例如:一個web應用的上下文路徑是/catalog,web應用的index.html文件就能被/catalog/index.html請求訪問。URL和上下文路徑的匹配規則將在11章討論。servlet引擎必須拒絕一個具有現在沖突的上下文路徑的web應用,這種情況是有的,如:兩個web應用發布在同一個上下文路徑中,或一個web應用的上下文路徑是另一個web應用上下文路徑的子路徑。
有一個特殊的目錄(“WEB-INF”)在應用中存在,這個目錄包含所有與應用相關,又不在根目錄中的事物。可以直接被引擎提供給客戶端的文件不放在WEB-INF中,但WEB-INF目錄對于調用ServletContext的getResource和getResourceAsStream方法的servlet 代碼是有效的。如果開發者想用servlet代碼調用一個不希望暴露給客戶端的一個配置信息,就可以把這個配置信息放在WEB-INF目錄下。請求都是和資源相匹配的;敏感的匹配如客戶端的請求是“/WEB-INF/foo”和“/Web-iNf/foo”,但不應該把定位于/WEB-INF下的內容作為結果返回。
WEB-INF目錄下的內容有:
./WEB-INF/web.xml 部署描述文件
./WEB-INF/classes/ 存放servlet class
./WEB-INF/lib/*.jar 是jar包的目錄
應用的classloader先load WEB-INF/classes目錄下的class后load WEB-INF/lib目錄下的jar包
9.5.1 目錄結構的一個例子
一個簡單web應用的目錄結構:
/index.html
/howto.jsp
/images/banner.gif
/images/jumping.gif
/WEB-INF/web.xml
/WEB-INF/lib/jspbean.jar
/WEB-INF/classes/com/mycorp/servlets/MyServlet.class
/WEB-INF/classes/com/util/MyUtils.class
9.6 web應用的存檔文件
一個web應用可以被java打包工具打包成war文件,當被打包后包中就會有一個額外META-INF目錄,該目錄下存放了打包工具的一些信息。
9.7 web應用部署描述
下面是web應用部署描述中的配置類型:
.ServletContext Init Parameters
.Session Configuration
.Servlet / JSP Definitions
.Servlet / JSP Mappings
.MIME Type Mappings
.Welcome File list
.Error Pages
.Security
9.7.1 可靠的擴展
web容器須提供一種機制使得web應用知道jar文件中包含的有用資源或代碼。
引擎因該提供編輯、配置庫文件的程序。
在WAR中提供一個MANIFEST.MF文件,描述擴展名列表是比較好的。標準的JAR是應該有的,這個文件描述的擴展名應該遵循Http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html中的規定。web容器應該能夠識別WEB-INF/lib文件夾中的任何文件的擴展名,如果不能夠識別就應該拒絕該應用程序,并報出錯誤。
9.7.2 web應用的classloader
引擎用于裝載war中的servlet的裝載器必須能夠讓開發者裝載jar庫中的任何資源。但裝載的資源禁止覆蓋j2se或servlet API中的類;通常建議的做法是裝載器不允許war中的servlet去訪問web引擎中的類。
還有一個被推薦的做法是實現應用類裝載器,war中被裝載的類或資源就會被放到container-wide JAR庫的特定類或資源中。
9.8 替換web應用
一個服務器可能會在不重新啟動引擎的情況下用一個新版本的應用替換原有的應用。當一個應用被替換時,引擎應提供一個robust方法去保存該應用中的session
9.9 錯誤句柄
9.9.1 request Attributes
web應用必須列出在使用中資源發生的錯誤,這些資源在部署描述中都有定義。
如果錯誤在一個servlet或一個jsp頁面中發生,則在第9.1章中的如下的請求屬性就會被設置:
Request Attributes Type
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版本中錯誤類型和錯誤信息屬性是多余的,他們被保留只是為了向下兼容以前的版本。
9.9.2 錯誤頁面
當一個servlet產生錯誤時,開發者可以訂制錯誤內容返回給客戶端。部署描述文件定義了一個錯誤頁面列表。servlet在response中設置錯誤狀態碼或產生的異常或錯誤被引擎支持時,引擎就會從部署描述文件中調用相應的配置的錯誤資源。
如果一個錯誤碼被設置在了response中,引擎在部署描述文件的錯誤頁面列表中用status-code方式匹配對應的資源,如果找到就調用本地的資源。
在一個請求被處理的過程中servlet可以拋出以下的異常:
.runtime exceptions or errors
.ServletExceptions or subclasses thereof
.IOException or subclasses thereof
web應用可以用exception-type元素來描述錯誤頁面,在這種情況下引擎會通過比較用exception-type元素定義的error-page列表中的異常來匹配產生的異常。匹配的結果是返回定義的與錯誤匹配的本地資源。在繼承類中,最近的類將被調用。
如果沒有一個error-page包含的exception-type與class-heirarchy相匹配。拋出的ServletException或其子類異常,被引擎通過ServletException.getRootCause方法獲得,獲得后用這個異常再去配置的error page列表中去匹配。
在部署描述文件中用exception-type元素定義的Error-page中exception-type的類名必須是唯一的。
當錯誤發生在servlet調用的RequestDispatcher中時error page機制是不能夠干預到的;這樣的情況如:一個servlet用RequestDispatcher去調用另一個有錯誤的servlet。
如果一個servlet產生的錯誤沒有被描述的錯誤頁面機制所抓到,引擎必須設置response的狀態碼為500
9.10 Welcome Files
web應用可以在部署描述文件中定義一個welcome files調用的URI列表,這個機制的目的是允許開發者定義自己的訪問首頁。
如果沒有在部署描述中配置welcome 文件,引擎將把局部請求(沒有指明具體訪問資源,如www.cacolg.com/index.html,請求訪問時用www.cacolg.com/訪問的)發送到適當的資源中,如:一個可能默認的servlet,或列出該目錄下的文件列表,或返回404響應錯誤。
一個例子:
1)在部署描述中定義index.html和default.jsp為welcome files
2)定義一個servlet的mapping路徑為/foo/
WAR中有的文件如下:
/foo/index.html
/foo/default.html
/foo/orderform.html
/foo/home.gif
/catalog/default.jsp
/catalog/products/shop.jsp
/catalog/products/register.jsp
3)請求的URI為 處理后的URI
/foo 或 /foo/ /foo/index.html
/catalog/ /catalog/default.jsp
/catalog/index.html 404 not found
/catalog/products/ 404 not found 也可能返回shop.jsp and /or register.jsp 列表。
9.11 web應用環境
j2EE定義的命名環境能夠使得應用在不需要知道外部信息怎么命名的情況下比較方便的訪問資源或外部信息。
servlet作為j2EE完整的一部分,使web應用部署描述文件提供了一個servlet可以訪問資源和EJB,這些部署描述元素有:
.env-entry
.ejb-ref
.ejb-local-ref
.resource-ref
.resource-env-ref
開發者使用這些元素描述web應用中需要用到的對象,這些對象都要在web容器運行時注冊到JNDI命名空間。
在J2EE1.3版本j2EE的環境需求中,servlet引擎不是J2EE技術的一部分,web環境要提供的功能在J2EE規范中有描述。如果沒有實現支持環境所要提供的功能,在發布應用時,web容器就會拋出警告。
實現servlet引擎在J2EE中是需要的,應該被納入J2EE1.3中。J2EE1.3應該提供更多的內容。
servlet引擎必須支持對象的lookup方法,查找對象并在引擎控制的線程中實例化。
servlet引擎應該支持開發者創建的線程,因為應用創建的線程不是很輕便,開開發者不得不依賴于這些功能有限的線程。這些需求將被加入到下一個版本的servlet規范中。
第十章 應用周期事件
10.1 介紹
事件是servlet2.3種新添的內容。應用事件使得web開發者能夠控制ServletContext和HttpSession對象的信息交互,使得管理web使用的資源更有效,方便。
10.2 事件監聽器
事件監聽器是實現了servlet事件監聽接口的類。在web發布是這些監聽類就被實例化和注冊在web容器中。
servlet事件監聽器提供了在ServletContext和HttpSerssion對象狀態發生改變時觸發的事件。Servlet cotext監聽器用于管理應用的資源或虛擬機的狀態。HTTP session監聽器管理與會話關聯的資源。
可以有多個監聽器監聽每一個事件類型。開發者可以指定引擎調用監聽類的順序。
10.2.1 事件類型和監聽接口
Event Type ListenerInterface 說明
Lifecycle javax.servlet.ServletContextListener 當servlet context被創建并有效的接受第一個請求
或servlet context銷毀前
Changes to attributees javax.servlet.ServletContextAttributesListener 當servlet context中的屬性發生added,removed,replaced
Lifecycle javax.servlet.http.HttpSessionListener 當HttpSession被創建,無效或超時
Changes to attributes javax.servlet.HttpSessionAttributesListener 當屬性added,removed或replaced時
10.2.2 一個使用監聽的例子
一個簡單的web應用中有servlet要訪問數據庫,開發者提供一個context 監聽類管理數據庫連接。
1)web應用啟動時,監聽類被裝載,登陸數據庫,在servlet context中保存數據庫連接。
2)servlet訪問數據庫連接
3)當web服務銷毀時,或應用從web服務中刪除時,關閉數據庫連接。
10.3 監聽類的配置
10.3.1 對監聽類的規定
web開發者提供實現了以上監聽接口的類,每個類應該有一個沒有參數的構造器函數。監聽類放在WEB-INF/classes下或以一個jar文件放在WEB-INF/lib下都可以。
10.3.2 部署描述
web容器對每個監聽類只會創建一個實例,在第一個請求到來之前實例化并注冊。web容器注冊監聽類的順序根據他們實現的接口和在部署描述文件中定義的順序。web應用調用監聽實例的順序按照他們注冊的順序。
10.3.4 在銷毀時的事件
當應用銷毀時監聽事件的執行順序按部署描述中的順序,先執行session中的監聽事件再執行context中的監聽事件。session的無效事件必須在context的銷毀事件之前被調用。
10.4 部署描述的例子
下面給出注冊兩個servlet cocntext lifecycle監聽器和一個HttpSession監聽器的例子。
Com.acme.MyconnectionManager和com.acme.MyLoggingMoudule都實現了javax.servletServletContextListener接口,com.acme.MyloggingModule另外還實現了javax.servlet.HttpSessionListener接口。開發者希望com.acme.MyConnectionManager在com.acme.MyLoggingModule之前管理者servlet context 的生命周期事件。部署描述文件如下:
<web-app>
<display-name>MyListeningApplication</display-name>
<listener>
<listener-class>com.acme.MyConnectionManager</listener-class>
</listenrer>
<listenrer>
<listenrer-class>com.acme.MyLoggingModele</listener-class>
</listener>
<sevlet>
<display-name>RegistrationServlet</display-name>
..etc
</servlet>
</web-app>
10.5 監聽器的實例和線程
在第一個請求被web容器接受之前實例化并注冊好監聽器類是必須的。監聽器在整個web應用生命周期中都要使用。
ServletContext和HttpSession對象屬性的改變可能會同時產生,引擎不需要同步這些屬性類的事件。
10.6 分布式容器組
在分布式web容器組中,HttpSession和ServletContext實例只活動與它們本地的JVM中。在分布式web容器中,監聽實例會在每一個web容器中創建實例。
10.7 session事件
監聽器使得開發者可以跟蹤web應用中的session。知道session是否變得無效是經常被用到的,因為session超時時引擎會使session變得無效,或應用會調用invalidate方法。
第十一章 請求到servlet的映射
11.1 URI的使用
web容器根據客戶端的請求決定要調用的資源。
URL路徑映射規則是第一個匹配成功就不再匹配了。
1)引擎將盡力為每一個請求一個servlet的路徑匹配一個servlet
2)引擎將遞歸的匹配最長的路徑前綴(在一個目錄樹中)
3)如果在URL路徑中的最后一節有擴展名(例如:.jsp),則servlet引擎將會匹配一個適當的servlet獲取請求對象
4)如果沒有一個servlet能夠匹配請求,引擎將用一個適當的資源來處理該請求。如:在應用中配置了默認的servlet,就會被用來處理匹配不到資源的請求。
11.2 匹配規則
在web應用描述文件中,匹配的定義如下:
.以'/'開始,以'/*'為結尾的字符串,用作路徑匹配
.以'*.'開始的字符串,用作擴展名匹配
.包含'/'字符串,定義一個默認的servlet。如匹配的servlet路徑是請求URI路徑的最小上下文路徑,路經的info為空。
.其它的字符串用作精確的匹配。
11.2.1 絕對匹配
servlet引擎能夠匹配任何精確的資源,如后綴為*.jsp的匹配,引擎中有JSP引擎的話,就會把所有的JSP頁面和與之對象的資源相匹配。
11.2.2 匹配的例子:
path pattern servlet
/foo/bar/* servlet1
/baz/* servlet2
/catalog servlet3
*.bop servlet4
incoming path servlet handling request
/foo/bar/index.html servlet1
/foo/bar/index.bop servlet1
/baz servlet2
/baz/index.html servlet2
/catalog servlet3
/catalog/racecar.bop servlet4
/index.bop servlet4
第十二章 安全
12.1介紹
web應用的資源能夠被很多的用戶訪問,這些資源經常沒有保護的暴露在網絡中,因此一個穩定的web應用需要一個安全的環境。
提高安全性有以下的幾個方面:
.認證:訪問一個實例前需要一個特殊的ID進行授權認證后才能訪問該實例
.資源的訪問控制:一些機密資源或局部資源只限制給某些用戶或程序使用。
.數據完整性:在傳輸過程中數據不能被意外的改變。
.機密性:確定信息只能被授權過的用戶使用。
12.2 公共安全
安全性聲明是指表明應用是有安全結構的;包括權限、訪問控制、認證。在web應用中部署描述是安全聲明的主要工具。
開發者應該為應用運行時配一個邏輯安全策略,在運行時中,servlet引擎用這個安全策略去驗證授權請求。
安全模塊應該適用web應用的靜態內容,當servlet用RequestDispatcher調用一個靜態資源或servlet用forward或include,時安全模塊不適用。
12.3 程序級安全
當應用的安全模塊不能充分的表明安全時程序安全就可以被使用。
程序安全有以下部分組成:
HttpServletRequest接口:
.getRemoteUser
.isUserInRole
.getUserPrincipal
getRemoteUser方法返回客戶端用戶的名稱,用于授權。
isUserInRole方法判斷遠程用戶是否在一個安全的角色內。
getUserPrincipal方法返回一個java.security.Principal對象,表明當前用戶的主要名稱。這個API允許servlet根據這個信息處理一些業務邏輯。
如果用戶沒有授權,getRemoteUser返回null,isUserInRole返回false,getUserPrincipal返回null。
isUserInRole以一個role-name為參數。一個security-role-ref元素為在部署描述文件中定義,role-name子元素包含角色名稱。Security-role包含一個子元素role-link,role-link的value值是客戶端用戶將匹配的安全角色。當用isUserInRole時引擎將調用security-role-ref到security-role的匹配。
舉個例子:
<security-role-ref>
<role-name>FOO</role-name>
<role-link>manager</role-link>
</security-role-ref>
當一個用戶屬于“manager”角色是調用isUsesrInRole("FOO")返回true
如果匹配一個security-role元素的security-role-ref沒有被定義,引擎必須找出一個與security-role列表不同的roel-name元素作為web應用默認的安全角色。但默認的安全角色限制了變換角色名稱不需要重新編譯的機動性。
12.4 角色
一個安全角色是一組用戶的邏輯名稱。當應用發布時,角色就部署在web應用的運行時環境中了。在基于安全屬性的請求到來時,servlet引擎就會執行公共安全或程序級安全。安全請求在以下的一些情況中會產生:
1)開發者給用戶群配置了一個安全角色。
2)開發者把一個安全角色配置給一個安全域中的一個主要名稱。
12.5 驗證
web客戶端可以用以下的一些機制驗證用戶:
.HTTP Basic Authentication
.HTTP Digest Authentication
.HTTPS Client Authentication
.Form Based Authentication
12.5.1 HTTP Basic Authentication
HTTP Basic Authentication是基于用戶名和密碼的驗證機制,是在HTTP/1.0規范中定義的。web服務要求客戶端驗證用戶,web服務用一個realm字符串作為請求的一部分,用戶通過這個realm字符串被驗證。realm字符串不會和任何安全域相關聯。客戶端獲得用戶名稱和密碼發送到服務端。然后服務端用一個特殊的realm去驗證該用戶。
Basic Authentication 不是安全的驗證協議。用戶的密碼是用base64編碼的,服務端是不能夠識別的。一些附加的安全措施可以被使用,這些協議有:HTTPS安全傳輸協議或網絡安全標準(如IPSEC協議、VPN策略)。
12.5.2 HTTP Digest Authentication
和HTTP Basic Authentication一樣,HTTP Digest Authentication 也是驗證用戶名和密碼的。然而這種驗證是把密碼加密傳輸的,要比Basic Authentication的base64編碼要安全的多。Digest Authentication 沒有被廣泛的運用,建議servlet引擎支持這種驗證,但不是必須的。
12.5.3 Form Based Authentication
web應用部署描述文件包含登陸表單和錯誤頁面。登陸表單必須包含用戶名和用戶密碼字段,這兩個字段必須以j_username和j_password命名。當一個用戶要訪問一個被保護的資源時,引擎就會驗證該用戶信息,如果該用戶驗證通過就會調用保護的資源,如果沒有驗證通過,以下的步驟就會發生:
1)登陸表單被送到客戶端,啟動這個驗證的URL路徑將被引擎保存。
2)用戶被要求填寫用戶名和密碼
3)客戶端重新post表單到服務端
4)引擎嘗試著重新去驗證該用戶的信息
5)如果驗證有失敗,響應被設置為401的錯誤頁面將被返回
6)如果驗證成功,如果該訪問的資源在一個授權角色中,將進一步驗證。
7)如果用戶是授權用戶,客戶端將用保存的URL路徑重新定向到訪問的資源。
發送到驗證失敗的用戶的錯誤頁面包含了失敗的信息。
Form Based Authentication 和 Basic Authentication 有一樣的弊端,密碼是用簡單的文本傳輸的,不能夠被服務端驗證。附加的一些協議可以增強這部分功能。如HTTPS傳輸協議,或網路安全標準(如IPSEC協議或VPN策略)。
12.5.3.1 登陸表單的一些注意事項
登陸的表單和跟蹤session的URL實現上是有限制的。
登陸表單只能在cookies或SSL跟蹤session的方式下才能使用。
登陸表單要進行驗證的話,表單的action就必須為j_security_check。這個約束使得登陸表單訪問的資源沒有問題,也避免了把表單外的字段提交進請求中。
在HTML頁面中登陸表單的一個例子如下:
<form method="POST" action="j_security_check" >
<input type="text" name="j_username">
<input type="password" name="j_password">
</form>
當登陸表單因為HTTP請求被調用時,原始的請求參數必須被引擎存儲,在驗證成功后重新定向請求的資源。
如果用登陸表單的用戶被驗證通過,創建了一個session,當session超時或調用了失效方法,使得登陸者推出了。后續來的請求就必須重新對用戶進行驗證。
12.5.4 HTTPS Client Authentication
用HTTPS驗證用戶是很強的驗證機制。這個驗證需要用戶擁有一個公共鑰匙(PKC)。servlet引擎不需要支持HTTPS協議。
12.6 驗證信息的跟蹤
基本的身份驗證實在運行時環境中進行的:
1)確認一個登陸驗證機制或策略已經配置在web應用中。
2)把需驗證的信息發往一個容器中的所有應用。
3)當一個安全域被刪除時,用戶的請求就需要重新驗證。
第十三章 部署描述文件
13.1 部署描述元素
部署描述文件中的所有元素都要被所有的servlet引擎支持。配置類型有下面的幾種:
.ServletContext Init Parameteres
.Session Configuration
.Servlet Declaration
.Servlet Mapping
.Application Lifecycle Listener classes
.Filter Dfinitions and Filter Mappings
.MIME Type Mappings
.Error Pages
當servlet 引擎是實現了J2EE規范的一部分的時候,安全信息才有必要在部署描述文件中定義。
部署描述文件不光光只支持servlet規范,在部署描述文件為了適應web應用的需求增加了其他的部屬描述元素。如:
.taglib
.用于查找JNDI對象的一些元素(env-entry,ejb-ref,ejb-local-ref,resource-ref,resource-env-ref)
13.2 處理部屬描述文件的規則
本節主要講一下web容器訪問部屬描述文件的幾種規則。
.web容器應該忽略部屬描述文件中數據的開始空字符和最后的空字符。
.web容器應該有一個廣泛的選項用戶檢查web應用的有效性。如檢查web應用是否包含部署描述文件,部屬描述文件結構是否正確。部署描述中應該有語義檢查,如:安全規則有同樣的名字,應該報錯等等。
.部署描述中的URI是假定在URL解碼表單中的
.引擎必須正確解釋部屬文件中的路徑,如:路徑'/a/../b'必須解釋為'/b',因為路徑是以'..'開始的路徑在部署描述中是無效的。
.調用資源的URI與WAR的根目錄關聯,以‘/’開頭
.在一個元素中,如果它的顯示值是一個列表,則這個列表將可能會報錯
13.2.1 DOCTYPE
所有2.3版本的部屬描述文件的DOCTYPE必須是:
<!DOCTYPE web-app PUBLIC "-//sun Microsystems, inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
13.3 DTD
web應用的部署描述文件DTD如下:
<!--
web-app 元素是部署描述的根元素
-->
<!ELEMENT web-app(icon?,display-name?,description?,distributable?,context-param*,filter*,filter-mapping*,listener*,servlet*,servlet-mapping*,session-config?,mime-mapping*,welcome-file-list?,error-page*,taglib*,resource-env-ref*,resource-ref*,security-constraint*,login-config?,security-role*,env-entry*,ejb-ref*,ejb-local-ref*)>
<!--
Auth-constraint 元素定義了可以訪問資源列表的用戶角色。Role-name可以作為security-role元素的子元素出現也可以以role-name"*"出現表示所有的角色,如果*和role-name都出現了,引擎將解釋這個資源可以被所有角色使用。如果沒有定義角色,用戶就不能夠訪問定義的資源。
Used in :security-constraint
-->
<!ELEMENT auth-constraint (description?,role-name*)>
<!--
Auth-method 元素是配置web應用的安全機制的,是訪問被保護資源的先決條件。用戶必須用這個驗證機制驗證。這個元素Value值有“BASIC”,“DIGEST”,“FORM”或“CLIENT-CERT”
Userd in : login-config
-->
<!ELEMENT auth-method(#PCDATA)>
<!--
Context-param元素包含了servlet context初始化的參數
Used in :web-app
-->
<!ELEMENT context-param(param-name,param-value,description?)>
<!--
description元素用于對父元素進行說明,description元素可以包含任何說明信息。當父元素被工具訪問時這些說明就會顯示。
Used in :auth-contraint,context-param,ejb-local-ref,ejb-ref,env-entry,filter,init-param,resource-env-ref,resource-ref,ren-as,security-role,security-role-ref,servlet,user-data-constraint,web-app,web-resource-collection
-->
<!ELEMENT description(#PCDATA)>
<!--
Display-name元素是一個簡稱,被調用的工具顯示,這個簡稱不必是唯一的
Used in: filter,security-constraint,sevlet,web-app
例如:
<display-name>Employee self Service </display-name>
-->
<!ELEMENT display-name(#PCDATA)>
<!--
Distributable 元素,這個元素出現在部署描述中,說明該應用可以部署在分布式servlet引擎中。
Used in :web-app
-->
<!ELEMENT distributable EMPTY>
<!--
Ejb-link 元素用在ejb-ref 或ejb-local-ref元素中,去指定EJB關聯的一個enterprise bean.
Ejb-link中的名字是一個關聯著enterprise bean的路徑 或者是目標bean+一個以“#”開頭的路徑。一個ejb-name可以對應多個enterprise beans。
Used in : ejb-local-ref,ejb-ref
例如:
<ejb-link>EmployeeRecord</ejb-link>
<ejb-link>../products/product.jar#ProductEJB</ejb-link>
-->
<!ELEMENT ejb-link (#PCDAATA)>
<!--
ejb-local-ref 元素用于描述本地enterprise bean的home接口,描述由下面的部分組成:
一個可選的描述
與enterprise bean 相關的EJB名稱
Enterprise bean 的類型
Enterprise bean 的本地接口
可選的ejb-link信息
Used in: web-app
-->
<!ELEMENT ejb-local-ref (description?,ejb-ref-name,ejb-ref-type,local-home,local,ejb-link?)>
<!--
Ejb-ref 元素用于描述enterprise bean的home接口。描述由下面組成:
一個可選描述
與enterprise bean 相關的EJB名稱
Enterprise bean 的類型
Enterprise bean 的本地接口
可選的ejb-link信息
Used in:web-app
-->
<!ELEMENT ejb-ref(description?,ejb-ref-name,ejb-ref,type,home,remote,ejb-link?)>
<!--
Ejb-ref-name 元素包含一個EJB的名字,這個名字必須是唯一的;這個EJB是web應用環境和關聯的java:comp/env context的入口。建議名字以“ejb/”開頭。
Used in : ejb-local-ref,ejb-ref
例如:
<ejb-ref-name>ejb/Payroll</ejb-ref-name>
-->
<!ELEMENT ejb-ref-name(#PCDATA)>
<!--
Ejb-ref-type 元素包含enterprise bean的類型。Ejb-ref-type元素必須是下面的一種:
<ejb-ref-type>Entity</ejb-ref-type>
<ejb-ref-type>Session</ejb-ref-type>
Used in :ejb-local-ref,ejb-ref
-->
<!ELEMENT ejb-ref-type(#PCDATA)>
<!--
Env-entry 元素包含了web應用的環境入口的描述。描述包含一個可選的描述,一個環境入口的名稱,一個可選的value,如果value沒有被指定,在部署中必須提供。
-->
<!ELEMENT env-entry (description?,env-entry-name,env-entry-value?,env-entry-type)>
<!--
env-entry-name元素包含了web應用環境入口的名稱,這個名稱是一個java:comp/env context關聯的JNDI名稱。名字必須是唯一的。
例如:
<env-entry-name>minAmount</env-entry-name>
Used in: env-entry
-->
<!ELEMENT env-entry-name(#PCDATA)>
<!--
Env-entry-type 元素包含環境入口值的fully-qualified java類型,這是web應用程序期望有的。
Env-enry-type合法的類型如下:
Java.lang.Boolean
Java.lang.Byte
Java.lang.Character
Java.lang.String
Java.lang.Short
Java.lang.Integer
Java.lang.Long
Java.lang.Float
Java.lang.Double
Used in : env-entry
-->
<!ELEMENT env-entry-type(#PCDATA)>
<!--
Env-entry-value元素包含了web應用環境入口的值,值必須是一個字符串。
例如:
<env-entry-value>100.00</env-entry-value>
Used in : env-entry
<!ELEMENT env-entry-value(#PCDATA)>
<!--
Error-code元素包含HTTP的一個錯誤代碼,如:404
Used in : error-page
-->
<!ELEMENT error-code(#PCDATA)>
<!--
error-page 元素包含一個錯誤代碼映射或錯誤類型資源的一個路徑
Used in : web-app
-->
<!ELEMENT error-page((error-code | exception-type),location)>
<!--
exception-type 包含一個java exception 類型的類名稱
Used in : error-page
-->
<!ELEMENT exception-type(#PCDATA)>
<!--
extension元素包含一個擴展名。如“txt”
Used in : mine-mapping
-->
<!ELEMENT extension (#PCDATA)>
<!--
filter被filter-mapping中的一個servlet或一個URL通過filter-name映射。filter在運行時能夠通過FilterConfig接口訪問初始化的參數。
Used in : web-app
-->
<!ELEMENT filter (icon?,filter-name,display-name?,description?,filter-class,init-param*)>
<!--
filter-class元素指明filter類.
Used in :filter
-->
<!ELEMENT filtere-class(#PCDATA)>
<!--
引擎用filter-mapping去匹配請求的URI以及匹配的順序,引擎在把匹配的URI匹配一個servlet。
Used in : web-app
-->
<!ELEMENT filter-mapping (Filter-name,(url-pattern | servlet-name))>
<!--
filtere-name元素表明了一個filter的邏輯名稱用于匹配用的。邏輯名稱必須唯一
Used in : filter,filere-mapping
-->
<!ELEMENT filter-name (#PCDATA)>
<!--
form-error-page元素定義了當登陸失敗是調用的頁面。這個路徑以“/”開始
Used in: form-login-config
-->
<!ELEMENT form-error-page (#PCDATA)>
<!--
form-login-config元素指定了登陸的錯誤頁面,如果form不需要驗證,這個元素將被忽略。
Used in : login-config
-->
<!ELEMENT form-login-cofig (form-login-page,form-error-page)>
<!--
form-login-page 元素定義了登陸的頁面。路徑以“/”開頭
used in :form-login-config
-->
<!ELEMENT form-login-page (#PCDATA)>
<!--
home元素包含了enterprise bean的home接口的名稱
Used in :ejb-ref
例如:
<home>com.aardvark.payroll.PayrollHome</home>
<!ELEMENT home (#PCDATA)>
<!--
http-method 包含了HTTP 方法(GET | POST |...)
Used in:web-resource-collection
-->
<!ELEMENT http-method (#PCDATA)>
<!--
icon 元素包含small-icon 和large-icon元素,指明一個gif或jpeg的圖標名稱
Used in : filter,servlet,web-app
-->
<!ELEMENT icon (small-icon?,large-icon?)>
<!--
init-param元素包含了name/value的servlet的初始化參數
Used in : filter,servlet
-->
<!ELEMETN init-param (param-name,param-value,description?)>
<!--
jsp-file 元素 包含了一個以“/”開頭JSP文件的全名。
Used in : servlet
-->
<!ELEMENT jsp-file (#PCDATA)>
<!--
large-icon 元素包含一個32*32的圖標文件名稱。圖片可以是jpeg或gif。
used in :icon
例如:
<large-icon>employee-service-icon32*32.jsp</large-icon>
-->
<!ELEMENT large-icon (#PCDATA)>
<!--
listener 元素對應著listener bean
Used in : web-app
-->
<!ELEMENT listener (listener-class)>
<!--
listener-class 元素,元素值是監聽類的類名。
Used in : listener
-->
<!ELEMENT listener-class (#PCDATA)>
<!--
load-on-startup 元素指明了這個servlet在web啟動時是否必須裝入(調用servlet的init()方法)。這個內容是可選的,但有值時必須是個整數,如果是負數,引擎可以選擇在任何時候裝載該servlet,如果是整數或0,引擎就必須在web應用啟動時裝入該servlet。數字越小越被優先裝入。如果值一樣,引擎可以自由選擇裝入的順序。
Used in : servlet
-->
<!ELEMENT load-on-startup (#PCDATA)>
<!--
local元素包含了enterprise bean的local接口
Used in : ejb-local-ref
-->
<!ELEMENT local (#PCDATA)>
<!--
local-home元素包含了enterprise bean的本地home接口
Used in : ejb-local-ref
-->
<!ELEMENT local-home (#PCDATA)>
<!--
location 元素包含與web應用根目錄關聯的資源,值必須以‘/’開頭
Used in : error-page
-->
<!ELEMENT location (#PCDATA)>
<!--
login-config 元素用于配置驗證的方法的。
Used in :web-app
-->
<!ELEMENT login-conifg (auth-method?,realm-name?,form-login-config?)>
<!--
mime-mapping 元素定義了擴展名和mime類型的映射關系。
Used in :web-app
-->
<!ELEMENT mime-mapping (extension,mime-type)>
<!--
mime-type 元素包含了mime類型,如“text/plain”
Used in : mime-mapping
-->
<!ELEMENT mime-type (#PCDATA)>
<!--
param-name 元素包含參數的名稱,參數名必須唯一。
Used in : context-param,init-param
-->
<!ELEMENT param-name (#PCDATA)>
<!--
param-value元素包含了參數的值
Used in : context-param,init-param
-->
<!ELEMENT param-value (#PCDATA)>
<!--
realm-name 元素用于HTTP Basic 驗證中
Used in : login-config
-->
<!ELEMENT realm-name (#PCDATA)>
<!--
remote 元素包含了enterprise bean 的remote接口
Used in : ejb-ref
例如:
<remote>com.wombat.empl.EmployeeService</remote>
-->
<!ELEMENT remote (#PCDATA)>
<!--
res-auth 元素表明是web應用代碼控制資源,還是引擎控制資源。該元素的值只能是以下的一種
<res-auth>Application</res-auth>
<res-auth>Container</res-auth>
Used in : resource-ref
-->
<!ELEMENT res-auth (#PCDATA)>
<!--
res-ref-name 元素指明了資源管理器(連接工廠)的名稱,這個名稱是和java:comp/env cocntext關聯的JNDI名稱。該名稱必須是唯一的。
Used in:resource-ref
-->
<!ELEMENT res-ref-name (#PCDATA)>
<!--
res-sharing-scope 元素表明了從資源管理器連接工廠獲得的連接是否可以被共享。值必須是下面的一種:
<res-sharing-scope>Shareable</res-sharing-scope>
<res-sharing-scope>Unshareable</res-sharing-scope>
默認的值是Shareable
Used in : resource-ref
<!ELEMENT ref-sharing-scope (#PCDATA)>
<!--
res-type 元素描述了資源的數據類型。
Used in : resource-ref
-->
<!ELEMENT res-type (#PCDATA)>
<!--
resource-env-ref 元素描述了與web應用管理對象相關的資源。包含一個可選的描述,一個資源環境名稱,一個環境資源類型。
Used in :web-app
例如:
<resource-env-ref>
<resource-env-ref-name>jms/StockQueue</resource-env-ref-name>
<resource-env-type>javax.jms/Queue</resource-env-ref-type>
</resource-env-ref>
-->
<!ELEMENT resource-env-ref (description?,resource-env-ref-name,resource-env-ref-type)>
<!--
resource-env-ref-name元素一定一個環境資源名稱,這個名字是與java:comp/env context關聯的JNDI名稱,必須以唯一的。
Used in : resource-env-ref
-->
<!ELEMENT resource-env-ref-name (#PCDATA)>
<!--
resource-env-ref-type元素定義了環境資源的類型,是一個java類或接口的全名。
Used in: resource-env-ref
-->
<!ELEMENT resource-env-ref-type (#PCDATA)>
<!--
resource-ref 元素包含web應用涉及的外部資源的描述。它有一個可選的描述,一個資源管理連接工廠的名稱,一個資源管理連接工廠的類型id,一個驗證類型(Application 或 Container),和一個可選的連接共享的選項(Shareale 或 Unshareable)
Used in : web-app
例如:
<resource-ref>
<res-ref-name>jdbc/EmployeeApppDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
-->
<!ELEMENT resource-ref (description?,res-ref-name,res-type,res-auth,res-sharing-scope?)>
<!--
role-link 元素是與安全角色相關的。Role-link元素必須包含一個在security-role元素中定義的安全角色的名稱。
Used in: security-role-ref
-->
<!ELEMENT role-link (#PCDATA)>
<!--
role-name 元素包含一個安全角色的名稱,名稱必須遵守NMTOKEN規則。
Used in : auth-constraint,run-as,security-role,security-role-ref
-->
<!ELEMENT role-name (#PCDATA)>
<!--
run-as 元素包含一個可選的描述,和一個安全角色的名稱。
Used in : servlet
-->
<!ELEMENT run-as (description?,role-name)>
<!--
security-constraint元素用于安全約束與一個或多個web資源相關聯。
Used in :web-app
-->
<!ELEMENT security-constraint (display-name?,web-resource-collection+,auth-constraint?,user-data-constraint?)>
<!--
security-role元素包含安全角色的定義,它由一個可選的安全角色的描述,一個安全角色名稱組成。
Used in : web-app
例如:
<security-role>
<description>
this role includes all employees who are authorized to access the employee service application.
</description>
<role-name>employee</role-name>
</security-role>
-->
<!ELEMENT security-role (description?,role-name)>
<!--
security-role-ref 元素包含一個可選的描述,一個調用代碼中的安全角色名稱,一個可選的安全角色連接。如果安全角色沒有被指定,開發者必須選擇一個適當的安全角色。這個role-name元素的值必須是EJBConteext.isCallerInRole(String roleName)或HttpServletRequest.isUserInRole(String role)中的參數。
Used in :servlet
-->
<!ELEMENT security-role-ref (description?,role-name,role-link?)>
<!--
servlet 元素包含一個servlet的數據描述。如果load-on-startup元素中指定了一個jsp文件,該JSP將被裝入。
Used in : web-app
<!ELEMENT servlet (icon?,servlet-name,display-name?,description?,(servlet-class|jsp-file),init-param*,load-on-startup?,run-as?,security-role-ref*)>
<!--
servlet-class元素包含一個全名的servlet類名稱。
Used in : servlet
-->
<!ELEMENT servlet-class (#PCDATA)>
<!--
servlet-mapping元素定義了一個servlet和url的關聯
Used in : web-app
-->
<!ELEMENT servlet-mapping (servlet-name,url-pattern)>
<!--
servlet-name元素包含servlet的名稱,名稱是唯一的。
Used in : filter-mapping,servlet,servlet-mapping
-->
<!ELEMENT servlet-name (#PCDATA)>
<!--
session-config 元素定義了session參數
Used in : web-app
-->
<!ELEMENT session-config (session-timeout?)>
<!--
session-timeout 元素定義了一個默認的會話超時的時間,使用于web應用中的所有會話。時間必須是用分鐘的數值表示。
如果timeout是0或負數,引擎將確保會話永遠不會超時。
Used in : session-config
-->
<!ELEMENT session-timeout (#PCDATA)>
<!--
small-icon 元素包含一個16*16圖標文件的名稱。
Used in : icon
例如:
<small-icon>employee-service-icon16*16.jpg</small-icon>
-->
<!ELEMENT small-icon (#pCDATA)>
taglib 元素用于描述JSP tag 庫。
Used in : web-app
-->
<!ELEMENT taglib (taglib-uri,taglib-location)>
<!--
taglib-location 元素包含一個資源定位,為tag庫找到tag描述文件
Used in:taglib
-->
<!ELEMENT taglib-location (#PCDATA)>
<!--
taglib-uri元素描述了一個URI
Used in: taglib
-->
<!ELEMENT taglib-uri (#PCDATA)>
<!--
transport-guarantee元素指定了客戶端和服務端的通信關系,有NONE,INTEGRAL,CONFIDENTIAL。NONE表示著應用不需要任何傳輸保障。INTEGRAL表示著在數據在客戶端到服務端的過程中不能有任何改變。CONFIDENTIAL表示在傳輸過程中防止其他傳輸內容的干擾。在使用SSl時常用的就INTEGRAL或CONFIDENTIL。
Used in : user-data-constraint
<!ELEMENT transport-guarantee (#PCDATA)>
<!--
url-pattern 元素包含映射的url。必須符合11.2章中servlet API描述的規則。
Used in:filter-mapping,servlet-mapping,web-resource-collection
-->
<!ELEMENT url-pattern (#PCDATA)>
<!--
user-data-constraint元素用于表明數據在客戶端到服務器端是怎么保護的。
Used in :security-constraint
-->
<!ELEMENT user-data-constraint (description?,transport-guarantee)>
<!--
web-resource-collection元素用于web應用中安全限制的資源被那些方法使用,如果沒有指定,就可以被web用的所有方法調用。
Used in:security-constraint
-->
<!ELEMENT web-resource-collection (web-resource-name,description?,url-pattern*,http-method*)>
<!--
web-resource-name 包含一個web資源集合的名稱
Used in:web-resource-collection
-->
<!ELEMENT web-resource-name (#PCDATA)>
<!--
welcome-file元素包含了web應用中默認的訪問文件,如index.html
Used in:welcome-file-list
-->
<!ELEMENT welcome-file (#PCDATA)>
<!--
welcome-file-list包含welcome-file的列表
Used in:web-app
-->
<!ELEMENT welcome-file-list (welcome-file+)>
<!--
ID機制可以增加額外的部署信息,不允許加一個非標準的元素到標準的部署描述中
-->
<!ATTLIST auth-constraint id ID #IMPLIED>
<!ATTLIST auth-method id ID #IMPLIED>
<!ATTLIST context-param id ID #IMPLIED>
<!ATTLIST description id ID #IMPLIED>
<!ATTLIST display-name id ID #IMPLIED>
<!ATTLIST ejb-link id ID #IMPLIED>
<!ATTLIST ejb-local-ref id ID #IMPLIED>
<!ATTLIST ejb-ref id ID #IMPLIED>
<!ATTLIST ejb-ref-name id ID #IMPLIED>
<!ATTLIST ejb-ref-type id ID #IMPLIED>
<!ATTLIST env-entry id ID #IMPLIED>
<!ATTLIST env-entry-name id ID #IMPLIED>
<!ATTLIST env-entry-type id ID #IMPLIED>
<!ATTLIST env-enry-value id ID #IMPLIED>
<!ATTLIST error-code id ID #IMPLIED>
<!ATTLIST error-page id ID #IMPLIED>
<!ATTLIST exception-type id ID #IMPLIED>
<!ATTLIST extension id ID #IMPLIED>
<!ATTLIST filter id ID #IMPLIED>
<!ATTLIST filter-class id ID #IMPLIED>
<!ATTLIST filtere-mapping id ID #IMPLIED>
<!ATTLIST filter-name id ID #IMPLIED>
<!ATTLIST form-error-page id ID #IMPLIED>
<!ATTLIST form-login-config id ID #IMPLIED>
<!ATTLIST form-login-page id ID #IMPLIED>
<!ATTLIST home id ID #IMPLIED>
<!ATTLIST http-method id ID #IMPLIED>
<!ATTLIST icon id ID #IMPLIED>
<!ATTLIST init-param id ID #IMPLIED>
<!ATTLIST jsp-file id ID #IMPLIED>
<!ATTLIST large-icon id ID #IMPLIED>
<!ATTLIST listener id ID #IMPLIED>
<!ATTLIST listener-class id ID #IMPLIED>
<!ATTLIST load-on-startup id ID #IMPLIED>
<!ATTLIST local id ID #IMPLIED>
<!ATTLIST local-home id ID #IMPLIED>
<!ATTLIST location id ID #IMPLIED>
<!ATTLIST login-config id ID #IMPLIED>
<!ATTLIST mime-mapping id ID #IMPLIED>
<!ATTLIST mime-type id ID #IMPLIED>
<!ATTLIST param-name id ID #IMPLIED>
<!ATTLIST param-value id ID #IMPLIED>
<!ATTLIST realm-name id ID #IMPLIED>
<!ATTLIST remote id ID #IMPLIED>
<!ATTLIST res-auth id ID #IMPLIED>
<!ATTLIST res-ref-name id ID #IMPLIED>
<!ATTLIST res-sharing-scope id ID #IMPLIED>
<!ATTLIST res-type id ID #IMPLIED>
<!ATTLIST resource-env-ref id ID #IMPLIED>
<!ATTLIST resource-env-ref-name id ID #IMPLIED>
<!ATTLIST resource-env-ref-type id ID #IMPLIED>
<!ATTLIST resource-ref id ID #IMPLIED>
<!ATTLIST role-link id ID #IMPLIED>
<!ATTLIST role-name id ID #IMPLIED>
<!ATTLIST run-as id ID #IMPLIED>
<!ATTLIST security-constraint id ID #IMPLIED>
<!ATTLIST security-role id ID #IMPLIED>
<!ATTLIST security-role-ref id ID #IMPLIED>
<!ATTLIST sevlet id ID #IMPLIED>
<!ATTLIST servlet-class id ID #IMPLIED>
<!ATTLIST servlet-mapping id ID #IMPLIED>
<!ATTLIST servlet-name id ID #IMPLIED>
<!ATTLIST session-config id ID #IMPLIED>
<!ATTLIST session-timeout id ID #IMPLIED>
<!ATTLIST small-icon id ID #IMPLIED>
<!ATTLIST taglib id ID #IMPLIED>
<!ATTLIST taglib-location id ID #IMPLIED>
<!ATTLIST taglib-uri id ID #IMPLIED>
<!ATTLIST transport-guarantee id ID #IMPLIED>
<!ATTLIST rul-pattern id ID #IMPLIED>
<!ATTLIST user-data-constraint id ID #IMPLIED>
<!ATTLIST web-app id ID #IMPLIED>
<!ATTLIST web-resource-collection id ID #IMPLIED>
<!ATTLIST web-resource-name id ID #IMPLIED>
<!ATTLIST welcome-file id ID #IMPLIED>
<!ATTLIST welcome-file-list id ID #IMPLIED>
13.4 例子
13.4.1 基本的例子
<!DOCTYPE web-app PUBLIC "-//Sun Mmicrosystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">
<web-app>
<display-name>A Simple Application</display-name>
<context-param>
<param-name>Webmaster</param-name>
<param-value>webmaster@mycorp.com</param-value>
</context-param>
<servlet>
<servlet-name>catalog</servlet-name>
<serrvlet-class>com.mycorp.Catalogservlet</servlet-class>
<init-param>
<param-name>catalog</param-name>
<param-value>Spring</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>catalog</servlet-name>
<url-pattern>/catalog/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<mime-mapping>
<extension>pdf</extension>
<mime-type>application/pdf</mime-type>
</mime-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
<error-page>
</web-app>
13.4.2 一個安全的例子
<!DOCTYPE web-app PUBLIC "-//Sun Mmicrosystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">
<web-app>
<display-name>A Secure Application</display-name>
<security-role>
<role-name>manager</role-name>
</security-role>
<servlet>
<servlet-name>catalog</servlet-name>
<servlet-class>com.mycorp.CatalogServlet</servlet-class>
<init-param>
<param-name>catalog</param-name>
<param-value>Spring</param-value>
</init-param>
<security-role-ref>
<role-name>MGR</role-name>
<!-- 在代碼中用的角色名稱-->
<role-link>manager</role-link>
</security-role-ref>
</servlet>
<servlet-mapping>
<servlet-name>catalog</servlet-name>
<url-pattern>/catalog/*</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>SalesInfo</web-resource-name>
<url-pattern>/salesinfo/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>manager</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
</web-app>
posted on 2008-05-29 11:40
???MengChuChen 閱讀(336)
評論(0) 編輯 收藏 所屬分類:
server