1. 程式人生 > >Servlet編程專題4之Servlet核心

Servlet編程專題4之Servlet核心

genericservlet類 httpservlet類 httpservletrequest類 請求的生命周期 請求提交時中文亂碼問題 請求轉發和重定向問題

1、javax.servlet.GenericServlet類:

- 該類定義一般的,與協議無關的servlet。在Web應用中用於寫入servlet,HttpServlet繼承自它。

- 該類實現了Servlet接口和ServletConfig接口,GenericServlet類可以被servlet類繼承,但一般具體的子類是HttpServlet。

技術分享


- 需要註意的是,如果繼承自GeniricServlet抽象類的自定義Servlet類,則需要實現GeniricServlet抽象類的service()方法;如果需要重寫Servlet接口中的初始化init方法,則需要重寫GeniricServlet類的init()方法。(不能夠重寫init(ServletConfig config)方法,因為重寫後會導致ServletConfig類對象無法被註冊,當調用Servlet類對象對應的ServletConfig類對象的方法時會出現空指針異常。)

技術分享


2、javax.servlet.http.HttpServlet類:提供一個抽象類用於創建適合網站HTTP Servlet的實例,HttpServlet的子類至少得重寫以下一個方法:

技術分享


- HttpServlet類繼承自GenericServlet抽象類,重寫了其service(ServletRequest req, ServletResponse res)方法:(將ServletRequest類對象向下轉型為HttpServletRequest類對象,並將ServletResponse類對象向下轉型為HttpServletResponse類對象。)。以下為類中的service方法的源碼:

技術分享


- HttpServlet類中的doGet()或者doPost()方法:由服務器調用(通過service()方法),允許servlet處理一個GET請求或者POST請求:

技術分享

技術分享


3、javax.servlet.http.HttpServletRequest接口:SUN制定的Servlet規範,是一個接口,表示請求,其父接口是javax.servlet.ServletRequest。“Http請求協議”的完整內容都被封裝到request對象中。

- Apache軟件基金會開發的“Tomcat容器”對java.serlvlet.http.HttpServletRequest接口進行了實現,其實現類完整類名是org.apache.catallina.connector.RequestFacade,但是程序員不需要關心具體的請求對象的實現類,不需要關心是哪個容器,只需要向HttpServletRequest接口調用方法即可。(面向接口編程,面向抽象編碼)


a、關於請求的生命周期問題:HttpServletRequest實例對象是什麽時候創建和銷毀的呢?

- 當客戶端瀏覽器將請求(字符序列)發送到服務器後,服務器會根據HTTP請求協議的格式對請求進行解析。同時,服務器會創建HttpServletRequest的實現類RequestFacade的對象,即請求對象。然後再調用相應的set方法,將解析出來的數據封裝到請求對象中。此時HttpServletRequest實例就創建並初始化完畢。也就是說,請求對象是由服務器創建。

- 當服務器向客戶端發送響應結束後,HttpServletRequest實例對象被服務器銷毀。

- 一次請求對應一個請求對象,另外一次請求對應另外一個請求對象,與之前的請求對象沒有任何關系。HttpServletRequest實例的生命周期很短暫。


b、關於請求參數問題:HttpServletRequest對於請求中所攜帶的參數是以Map的形式接收的,並且該Map的key為String,value為String數組。

- 為什麽是String數組而不是String呢?因為Http請求協議允許一個請求參數具有多個值的情況出現。如表單中復選框值就可以是多個。


c、javax.servlet.http.HttpServletRequest接口中的方法:

- getMethod()方法獲取用戶請求的方式:

技術分享


- 獲取請求參數的方式:(javax.servlet.ServletRequest接口中的方法,HttpServletRequest接口繼承自ServletRequest接口)

- getParameter(String name)方法根據提供的字符串序列參數獲取用戶請求中的對應參數值。

- getParameterMap()方法返回用戶請求中的請求參數和請求參數值組成的鍵值對序列。(返回的是Map<String, String[]>對象)

- getParameterNames()方法返回用戶請求中的請求參數序列。

- getParameterValues(String name)方法返回指定請求參數對應的參數值序列(用於復選框)。

技術分享


- 域屬性:在request中也存在域屬性,用於存放有名稱的數據。該數據只在當前的Request請求中才能夠訪問。

- 常用方法:(域屬性的生命周期與request對象的生命周期相同。)(javax.servlet.ServletRequest接口中的方法,HttpServletRequest接口繼承自ServletRequest接口)

技術分享

技術分享

技術分享


- 從請求中獲取服務端相關信息:(javax.servlet.http.HttpServletRequest接口中的方法,getRemoteAddr()方法除外。)

- 獲取客戶端訪問服務器時請求的url路徑(即瀏覽器地址欄中的路徑)

技術分享

- 獲取客戶端訪問服務器時請求的uri路徑(即請求行中第一個空格後,第二個空格前的內容,即瀏覽器地址欄上端口號後的內容【包含斜杠/】)

技術分享

- 獲取當前Web應用的根路徑:(即:/ +項目名)

技術分享

- 獲取客戶端IP:

技術分享

- getServletPath()方法返回的是<url-pattern>路徑的精確部分(如果沒有非精確部分(通配符部分),則是<url-pattern>中的全部內容);getPathInfo()方法會的是非精確部分,即地址欄上與<url-pattern>匹配之外的額外的部分(如果不存在,則為null)。

技術分享

技術分享


- 請求提交時中文亂碼問題:(需要註意的是,Tomcat9.0解決了get請求提交時的中文亂碼問題。)

- POST請求提交時中文亂碼問題解決:(javax.servlet.ServletRequest接口中的方法)

- 設置請求體中的字符編碼方式:

技術分享


- GET請求時中文亂碼問題:在Tomcat安裝根目錄的conf目錄下的server.xml文件的<Connector>標簽中添加URIEncoding="UTF-8"屬性(我的路徑為:D:\apache-tomcat-7.0.72\conf。)

技術分享

- 需要註意的是,如果在Eclipse中使用的Tomcat服務器,則需要修改當前工作空間上的server.xml文件。

技術分享


- 既可以解決POST請求又可以解決GET請求提交時中文亂碼問題:在自定義的servlet類中,將請求參數值字符串使用getBytes(String charsetName)方法(傳入參數“ISO8859-1”字符串)方式進行解碼,以byte[]類型的引用接收,再使用String類的構造器String(byte[] bytes, String charsetName)將byte[]類型的數據編碼成字符串類型。(需要註意的是,Tomcat服務器從瀏覽器中接收的字符串參數值統一編碼為“ISO8859-1”)

- java.lang.String類的getBytes(String charsetName)方法:

技術分享

- java.lang.String類的構造器String(byte[] bytes, String charsetName):

技術分享

- 以下為示例代碼:

技術分享


4、javax.servlet.ServletRequest接口:請求的轉發

- 獲取ServletRequest接口的實現類對象:(javax.servlet.ServletRequest接口中的方法,HttpServletRequest接口繼承自ServletRequest接口)傳遞的參數為給定的當前web的路徑,返回RequestDispatcher接口的實現類對象。需要註意的是,請求的轉發,request對象沒有被銷毀,域屬性還可以繼續使用。

技術分享


- javax.servlet.RequestDispatcher接口中的方法:

- 請求轉發的forward(ServletRequest request, ServletResponse response)方法:轉發一個請求從一個servlet到服務器中的另外一個資源(包括servlet,JSP文件或者HTML文件)

技術分享


- 註:javax.servlet.http.HttpServletResponse接口中sendRedirect(String location)方法為請求的重定向方法。


5、javax.servlet.http.HttpServletResponse接口:Web服務器收到一個Http請求後,會針對每個請求創建一個HttpServletRequest對象和HttpServletResponse對象。若需要獲取客戶端提交請求的相關信息,則需要從HttpServletRequest對象中獲取;若需要向客戶端發送數據,則需要通過HttpSerlvetResponse對象來完成。


- javax.servlet.ServletResponse接口中的方法:(javax.servlet.http.HttpServletResponse接口的父接口)

- getWriter()方法返回一個標準輸出流對象,用於向客戶端中輸出字符數據:

技術分享

java.io.PrintWriter類中的print(String s)方法和write(String s)方法都可以向標準輸出流中寫入數據:(客戶端瀏覽器可以直接看到這些數據)

技術分享

技術分享


- response的中文亂碼解決方案:(例如在HttpServletResponse接口類對象使用getWriter()方法返回標準輸出流對象,向標準輸入流中寫入中文)

- 設置響應的MIME類型:(可以設置為文本中的HTML,即“text/html;charset=UTF-8”)(javax.servlet.ServletResponse接口中的方法)

技術分享

- 設置響應的字符編碼(MIME字符集),即“text/html;charset=UTF-8”中的“charset=”後的字符串的設置:(javax.servlet.ServletResponse接口中的方法)

技術分享


- 請求的重定向:使用指定url路徑為客戶端發送一個臨時的重定向響應(以此清空緩存)(javax.servlet.http.HttpServletResponse接口中的方法)

技術分享


6、附加說明:

a、關於請求轉發和重定向問題:

- 請求轉發和重定向均是指的是請求的跳轉方式。但請求轉發是指服務器內跳轉,重定向是指服務器外部跳轉。(可以使用重定向由一個項目跳轉到另外一個項目。)

- 轉發是一次請求,重定向是兩次請求。請求轉發只會發出一次請求,收到一次響應,所轉發到的資源可以直接獲取到請求中所攜帶的數據,瀏覽器中的地址欄顯示的為用戶所提交的請求路徑,不會發生改變【只能跳轉到當前應用的資源中】。重定向無法獲取到用戶請求提交的數據,也無法獲取HttpServletRequest接口的實現類對象中設置的域屬性的值。【同時重定向發送的請求方式為get請求,會導致瀏覽器中地址欄發生變化】(重定向可以防止表單重復提交)

技術分享

- 關於重定向中數據傳遞問題解決:可以在使用HttpServletResponse接口中的方法sendRedirect(String locaction)重定向傳遞參數時傳遞相關的數據。(以“?username=xxx&password=ooo”的方式)


b、請求轉發和重定向的選擇問題:

- 若需要跳轉到其他應用,則使用重定向。

- 若是處理表單數據的Servlet,需要跳轉到其他Servlet,則需要選擇重定向。以此防止表單重復提交。

- 若對某一請求進行處理的Servlet的執行需要消耗大量的服務器資源(CPU、內存),此時這個Servlet執行完畢後,需要重定向。

- 其他情況下,一般使用請求轉發。


c、訪問路徑問題:

- URL和URI的認識:

- 統一資源定位符,用於定位資源的一種方式。通常的URL資源訪問路徑由兩部分構成:資源路徑和資源名稱。資源名稱指的是要訪問資源的直接名稱。如show.html,或與要訪問資源存在映射關系的間接名稱,如show.do。而資源路徑,則是通過該路徑則可以定位到指定的資源。即資源路徑是指在URL資源訪問路徑中除了資源名稱以外的其他部分。

- 根據以上規則,URI,統一資源標識符,也可以分為資源路徑和資源名稱兩部分。

- 一般情況下,在URL或者URI以外,最後一個斜杠後的部分為資源名稱,而其他部分則為資源路徑。

技術分享

技術分享

- 絕對路徑和相對路徑的區別:

- 根據“資源路徑是否可以獨立完成資源準確定位”的判別標準,可以將訪問路徑分為絕對路徑和相對路徑。

- 對於計算機中Web應用的絕對路徑,則是指帶訪問協議的路徑,即URL。例如下面的路徑就是一個帶有http訪問協議的絕對路徑:http://127.0.0.1:8080/primary/index.jsp。

- 相對路徑,是指僅根據訪問路徑無法準確定位資源的路徑。相對路徑必須要結合其參照路徑才能夠組成準確定位資源的絕對路徑。

- 需要註意的是,相對路徑的寫法有兩種:一種是以斜杠開頭的相對路徑,一種是以路徑名稱開頭的相對路徑。根據相對路徑是否以斜杠開頭,且路徑所在文件所處位置的不同,其默認的參照路徑是不同的。

- 絕對路徑和相對路徑的關系為:絕對路徑 = 參照路徑 + 相對路徑。


- 相對路徑的區分:

i、以斜杠開頭的相對路徑,根據路徑所在文件所處位置的不同,可以分為前臺路徑和後臺路徑兩類。

- 所謂前臺路徑是指,由瀏覽器解析執行的代碼中所包含的路徑。前臺路徑的的參照路徑是Web服務器的根路徑,即http://127.0.01:8080。(將前臺路徑轉換成絕對路徑的工作,是由瀏覽器自動完成的)

- 所謂後臺路徑是指,由服務器解析執行的代碼以及文件中所包含的路徑。例如,java代碼中的路徑、jsp文件動態部分(java代碼塊)中的路徑、xml等配置文件中的路徑(配置文件是要被java代碼解析後加載到內存的,其中的路徑會出現在java代碼中)。後臺路徑的參照路徑是Web應用的根路徑。如http:127.0.0.1:8080/primary。(將後臺路徑轉換成絕對路徑的工作,是由服務器自動完成的。)

- 後臺路徑中的特例:當代碼中使用response的sendRedirect()方法進行重定向的時候,若其參照路徑是以斜杠開頭,則其參照路徑不是web路徑的根路徑,而是web服務器的根路徑。例如,執行reponse.sendRedirect("show.jsp")將會報404錯誤。因為其參照路徑是Tomcat的根,而非當前項目的根。所以若是使用重定向,就需要在路徑上添加其項目名稱:(為什麽是特例?因為sendRedirect()方法可以重定向到其他應用,若不指定要跳轉的應用,將無法確定跳轉方向。)

response.sendRedirect(request.getContextPath + "/show.jsp");


ii、以路徑名稱開頭的相對路徑:

- 以路徑名稱開頭的相對路徑,無論是出現在前臺頁面,還是出現在後臺java代碼或者配置文件中,其參照路徑都是“當前訪問路徑的資源路徑”。即使是response的sendRedirect()方法的參照路徑,若是不以斜杠開頭,其也屬於“以路徑名稱開頭的相對路徑”類,參照路徑為當前訪問路徑的資源路徑。




本文出自 “12392717” 博客,請務必保留此出處http://12402717.blog.51cto.com/12392717/1973984

Servlet編程專題4之Servlet核心