寫過Web程序的你,真的瞭解Servlets嗎?

前言

      在寫這篇博客之前,我也寫過一些Web程序,豐富的畫面激發了我的學習興趣,也終於可以告別控制檯的黑白框了。但是雖然加了一些前端,讓程序以網頁的形式顯示,但其中的很多操作都不太理解,只是有人告訴你,要實現什麼功能需要添加什麼代碼。而我也是孰能生巧的記住了這些套路,僅此而已。現在打算通過這一專欄把Web相關知識梳理一遍,而掌握Servlet API是成爲一名強大的Java web開發者的基本條件,你必須熟悉ServletAPI中定義的核心接口和類。

1.Servlet API概覽

      Servlet API有以下4個java包:

  • javax.servlet,其中包含定義Servlet和Servlet容器之間契約的類和接口。
  • javax.servlet.http,其中包含定義HTTPServlet和Servlet容器之間契約的類和接口。
  • javax.servlet.annotation,其中包含標註Servlet、Filter、Listener的標註。它還爲被標註元件定義元數據。
  • javax.servlet.descriptor,其中包含提供程序登錄Web應用程序的配置信息的類型。

圖1.1中展示了javax.servlet中的主要類型。
在這裏插入圖片描述
Servlet接口定義了Servlet與Servlet容器之間的契約。這個契約歸結起來就是,Servlet容器將Servlet類載入內存,並在Servlet實例上調用具體的方法。在一個應用程序中,每種Servlet類型只能有一個實例。
      用戶請求致使Servlet容器調用Servlet的service方法,並傳入一個ServletRequest實例和一個ServletResponse實例。ServletRequest封裝了當前的HTTP請求,ServletResponse表示當前用戶的HTTP響應。對於每一個應用程序,Servlet容器還會創建一個ServletContext實例。這個對象中封裝了上下文(應用程序)的環境詳情。每個上下文只有一個ServletContext。每個Servlet實例也都有一個封裝Servlet配置的ServletConfig。下面來看Servlet接口。

2.Servlet

      Servlet接口中定義了以下5個方法:

void init(ServletConfig config)throws ServletException
void service(ServletRequest request,ServletResponse response)throws ServletException,java.io.IOException
void destroy()
java.lang.String getServletInfo()
ServletConfig getServletConfig()

      init、service和destroy是生命週期方法。Servlet容器根據以下規則調用者3個方法。

  • init,當該Servlet第一次被請求時,Servlet容器會調用這個方法。這個方法在後繼請求中不會再被調用。我們可以利用這個方法執行相應初始化工作。
  • service,每當請求Servlet時,Servlet容器就會調用這個方法。編寫代碼時,是假設Servlet要在這裏被請求。第一次請求Servlet時,Servlet容器調用init方法和service方法。後續的請求將只調用service方法。
  • destroy,當要銷燬Servlet時,Servlet容器就會調用這個方法。當要卸載應用程序,或者當要關閉Servlet容器時,就會發生這種情況。一般會在這個方法中編寫清除代碼。
  • getServletInfo,這個方法會返回Servlet的描述。你可以返回有用或爲null的任意字符串。
  • getServletConfig,這個方法會返回由Servlet容器傳給init方法的ServletConfig。但是,爲了讓getServletConfig返回一個非null值,必須將傳給init方法的ServletConfig賦給一個類級變量。注意線程安全性。Servlet實例會被一個應用程序中的所有用戶共享,因此不建議使用類級變量,除非它們是隻讀的。

3.ServletRequest

      對於每一個HTTP請求,Servlet容器都會創建一個ServletRequest實例,並將它傳給Servlet的Service方法。ServletRequest封裝了關於這個請求的信息。
      ServletRequest接口中有一些方法:

public int getContentLength();//返回請求主體的字節數。如果不知道字節長度,這個方法就會返回-1
public java.lang.String getContentType();//返回請求主體的MIME類型,如果不知道類型,則返回null
public java.lang.String getParameter(java.lang.String name);//返回指定請求參數的值
public java.lang.String getProtocol();//返回這個HTTP請求的協議名稱和版本

      getParameter是在ServletRequest中最常用的方法。該方法通常用於返回HTML表單域的值。
      getParameter也可以用於獲取查詢字符串的值。例如,利用下面的URI調用Servlet:
http://domain/context/servletName?id=123
      利用下面這個語句,可以通過Servlet內部獲取id值:
String id=request.getParameter(“id”);//注意,如果該參數不存在,getParameter將返回null。
      除了getParameter外,還可以使用getParameterNames、getParameterMap和getParameterValues獲取表單域名、值以及查詢字符串。

4.ServletResponse

      javax.servlet.ServletResponse接口表示一個Servlet響應。在調用Servlet的Service方法前,Servlet容器首先創建一個ServletResponse,並將它作爲第二個參數傳給Service方法。在ServletResponse中定義的方法之一是getWriter方法,它返回了一個可以向客戶端發送文本的java.io.PrintWriter。默認情況下,PrintWriter對象使用ISO-8859-1編碼。
      在發送任何HTML標籤前,應該先調用setContentType方法,設置響應的內容類型,並將“text/html”作爲一個參數傳入。這是在告訴瀏覽器,內容類型爲HTML。在沒有內容類型的情況下,大多數瀏覽器會默認將響應渲染成HTML。但是,如果沒有設置響應內容類型,有些瀏覽器就會將HTML標籤顯示爲普通文本。

5.ServletConfig

      將Servlet容器初始化Servlet時,Servlet容器會給Servlet的init方法傳入一個ServletConfig。ServletConfig.Servlet封裝可以通過@WebServlet或者部署描述符傳給Servlet的配置信息。這樣傳入的每一條信息就叫一個初始參數。一次初始參數有key和value兩個元件。
      爲了從Servlet內部存取到初始參數的值,要在Servlet容器傳給Servlet的init方法的ServletConfig中調用getInitParameter方法。getInitParameter的方法簽名如下:

java.lang.String getInitParameter(java.lang.String name)

      此外,getInitParameterNames方法則是返回所有初始參數名稱的一個Enumeration

java.util.Enumberation<java.lang.String> getInitParameterNames()

6.ServletContext

      ServletContext表示Servlet應用程序。每個Web應用程序只有一個上下文。在將一個應用程序同時部署到多個容器的分佈式環境中,每臺Java虛擬機上上的Web應用都會有一個ServletContext對象。通過在ServletConfig中調用getServletContext方法,可以獲得ServletContext。
      有了ServletContext,就可以共享從應用程序中的所有資料處訪問到的信息,並且可以註冊Web對象。前者將對象保存在ServletContext中的一個內部Map中。保存在ServletContext中的對象被稱作屬性:
      ServletContext中的下列方法讀者處理屬性:

java.lang.Object getAttribute(java.lang.String name)
java.util.Enumeration<java.lang.String> getAttributeNames()
void setAttribute(java.lang.String name,java.lang.Object object()
void removeAttribute(java.lang.String name);

7.Http Servlets

      大多數應用程序都要與HTTP結合起來使用。這意味着可以利用HTTP提供的特性。javax.servlet.http包是Servlet API中的第二個包,其中包含了用於編寫Servlet應用程序的類和接口。javax.servlet.http中的許多類型都繼承了javax.servlet中的類型。圖2展示了javax.servlet.http中的主要類型。
在這裏插入圖片描述
(1)HttpServlet
      HttpServlet類繼承了javax.servlet.GenericServlet類。使用HttpServlet時,還要藉助分別代表Servlet請求和Servlet響應的HttpServletRequest和HttpServletResponse對象。HttpServletRequest接口擴展javax.servlet.ServletRequest,HttpServletResponse擴展javax.servlet.ServletResponse。
      HttpServlet覆蓋GenericServlet中是service方法,並通過下列簽名再添加一個service方法:

protected void service(HttpServletRequest request,HttpServletResponse response)throws ServletException,java.io.IOException

      新service方法和javax.servlet.Servlet中的service方法之間的區別在於,前者接收HttpServletRequest和HttpServletResponse,而不是ServletRequest和ServletResponse。嚮往常一樣,Servlet容器調用javax.servlet.Servlet中原始的Service方法。HttpServlet中的編寫方法如下:

public void service(ServletRequest req,ServletResponse res)throws ServletException,IOException
{
  HttpServletRequest request;
  HttpServletResponse response;
  try{
    reqeust=(HttpServletRequest)req;
    response=(HttpServletResponse)res;
  }catch(ClassCastException e)
  {
    throw new ServletException("non-HTTP" request or response");
  }
  service(request,response);
}

      原始service方法將Servlet容器的request和response對象分別轉換成HttpServletRequest和HttpServletResponse,並調用新的service方法。這種轉換總是會成功的,因爲在調用Servlet的service方法時,Servlet容器總誰傳入一個HttpServletRequest和一個HttpServletResponse,預備使用HTTP。即便正在實現javax.servlet.servlet,或者擴展javax.servlet.GenericServlet,也可以將傳給service方法的servlet request和servlet response分別轉換成HttpServletRequest和HeepServletResponse。然後HttpServlet中的service方法會檢驗用來發送請求的HTTP方法(通過調用request.getMethod),並調用以下方法之一:doGet、doPost、doHead、doPut、doTrace、doOptions和doDelete。這7種方法中,每一種方法都表示一個HTTP方法。doGet和doPost是最常用的。因此,不再需要覆蓋Service方法了,只要覆蓋doGet或者doPost,或者覆蓋doGet和doPost即可。
(2)HttpServletRequest
      HttpServletRequest表示HTTP環境中的Servlet請求。它擴展javax.servlet.ServletRequest接口,並添加了幾個方法。新增的部分方法如下:

java.lang.String getContextPath();//返回表示請求上下文的請求URI部分。
Cookie[] getCookies();//返回一個Cookie對象數組
java.lang.String getHeader(java.lang.String name);//返回指定HTTP標題的值
java.lang.String getMethod();//返回生成這個請求的HTTP方法名稱
java.lang.String getQueryString();//返回請求URL的查詢字符串
HttpSession getSession();//返回與這個請求相關的會話對象。如果沒有,將創建一個新的會話對象。
HttpSession getSession(boolean create);//返回與這個請求相關的會話對象。如果沒有,並且create參數爲true,將創建一個新的會話對象

(3)HttpservletResponse
      HttpServletResponse表示HTTP環境中的Servlet響應。下面是它裏面定義的部分方法

void addCookie(Cookie cookie);//給這個響應對象添加一個Cookie
void addHeader(java.lang.String name,java.lang.String value);//給這個響應對象添加一個header
void sendRedirect(java.lang.String location);//發送一條響應碼,將瀏覽器跳轉到指定的位置。

8.處理HTML表單

      一個Web應用程序幾乎總會包含一個或者多個HTML表單,供用戶輸入值。你可以輕鬆地將一個HTML表單從一個Servlet發送到瀏覽器。當用戶提交表單時,在表單元素中輸入的值就會被當做請求參數發送到服務器。
      HTML輸入域(文本域、隱藏域或者密碼域)或者文本區的值,會被當做字符串發送到服務器。空的輸入域或者文本域會發送空的字符串。因此,有輸入域名稱的,ServletRequest.getParameter絕對不會返回nul。
      HTML的select元素也想header發送了一個字符串。如果select元素中沒有任何選項被選中,那麼就會發出所顯示的這個選項值。
      包含多個值的select元素(允許選擇多個選項並且用select multiple表示的select元素)發出一個字符串數組。並且必須通過SelectRequest.getParameterValues處理。
      複選框比較奇特。覈查過的複選框會發送字符串“on”到服務器。未經覈查的複選框則不向服務器發送任何內容,ServletRequest.getParameter(fieldName)返回null。
      單選框將被選中按鈕的值發送到服務器。如果沒有選擇任何按鈕,將沒有任何內容被髮送到服務器,並且ServletRequest.getParameter(fieldName)返回null。
      如果一個表單中包含多個輸入同名的元素,那麼所有值都會被提交,並且必須利用ServletRequest.getParameterValues來獲取它們。ServletRequest.getParameter將只返回最後一個值。

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