久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Servlet/JSP深入詳解:基于Tomcat的Web開發(fā)--第二章01

 krrish 2010-07-09

— 了解如何通過實現(xiàn)Servlet接口來編寫Servlet

— 掌握ServletRequest和ServletResponse接口

— 掌握ServletConfig接口

— 掌握GenericServlet和HttpServlet抽象類

— 掌握HttpServletRequest和HttpServletResponse接口

— 掌握Servlet開發(fā)中一些方法和技巧的使用

— 熟悉Servlet異常

— 掌握Servlet上下文

— 掌握RequestDispatcher對象的使用

— 區(qū)分sendRedirect()和forward()方法的使用

文本框:  
圖2-1  Servlet API中主要的接口與類的UML類圖
從這一章開始,,我  們將詳細介紹Java服務(wù)器端編程的重要技術(shù)——Servlet。

2.1   Servlet API

這一節(jié)我們主要介紹一下開發(fā)Servlet需要用到的主要接口和類,,這些接口和類的UML類圖如圖2-1所示,。

2.1.1  Servlet接口

在Java語言中,我們已經(jīng)了解了Java Applet(Java小應(yīng)用程序),。它運行在客戶端的瀏覽器中,。Java Applet與Java Servlet有以下一些共同點。

— 它們都不是獨立的應(yīng)用程序,,都沒有main()方法,。

— 它們都不是由用戶或程序員直接調(diào)用,而是生存在容器中,,由容器管理,。Applet運行在瀏覽器中,Servlet運行在Servlet容器中,。

— 它們都有生命周期,,都包含了init()和destroy()方法。

當然,,Applet與Servlet也有不同點,。

—  Applet具有圖形界面,運行在客戶端的瀏覽器中,。

—  Servlet沒有圖形界面,,運行在服務(wù)器端的Servlet容器中。

要編寫一個Applet,,需要從java.applet.Applet類派生一個子類,;和Applet類似,要編寫一個Servlet,,需要實現(xiàn)javax.servlet.Servlet接口,,該接口定義了如下5個方法。

Ø  public void init(ServletConfig config) throws ServletException

Ø  public void service(ServletRequest req, ServletResponse res) throws ServletException, java.io.IOException

Ø  public void destroy()

Ø  public ServletConfig getServletConfig()

Ø  public java.lang.String getServletInfo()

下面介紹一下這5個方法的作用,。

—  init():在Servlet實例化之后,,Servlet容器會調(diào)用init()方法,來初始化該對象,,主要是為了讓Servlet對象在處理客戶請求前可以完成一些初始化的工作,,例如,建立數(shù)據(jù)庫的連接,獲取配置信息等,。對于每一個Servlet實例,,init()方法只能被調(diào)用一次。init()方法有一個類型為ServletConfig的參數(shù),,Servlet容器通過這個參數(shù)向Servlet傳遞配置信息,。Servlet使用ServletConfig對象從Web應(yīng)用程序的配置信息中獲取以名-值對形式提供的初始化參數(shù)。另外,,在Servlet中,,還可以通過ServletConfig對象獲取描述Servlet運行環(huán)境的ServletContext對象,使用該對象,,Servlet可以和它的Servlet容器進行通信,。

—  service():容器調(diào)用service()方法來處理客戶端的請求。要注意的是,,在service()方法被容器調(diào)用之前,,必須確保init()方法正確完成。容器會構(gòu)造一個表示客戶端請求信息的請求對象(類型為ServletRequest)和一個用于對客戶端進行響應(yīng)的響應(yīng)對象(類型為ServletResponse)作為參數(shù)傳遞給service()方法,。在service()方法中,,Servlet對象通過ServletRequest對象得到客戶端的相關(guān)信息和請求信息,在對請求進行處理后,,調(diào)用ServletResponse對象的方法設(shè)置響應(yīng)信息,。

—  destroy():當容器檢測到一個Servlet對象應(yīng)該從服務(wù)中被移除的時候,,容器會調(diào)用該對象的destroy()方法,,以便讓Servlet對象可以釋放它所使用的資源,保存數(shù)據(jù)到持久存儲設(shè)備中,,例如,,將內(nèi)存中的數(shù)據(jù)保存到數(shù)據(jù)庫中,關(guān)閉數(shù)據(jù)庫的連接等,。當需要釋放內(nèi)存或者容器關(guān)閉時,,容器就會調(diào)用Servlet對象的destroy()方法。在Servlet容器調(diào)用destroy()方法前,,如果還有其他的線程正在service()方法中執(zhí)行,,容器會等待這些線程執(zhí)行完畢或等待服務(wù)器設(shè)定的超時值到達。一旦Servlet對象的destroy()方法被調(diào)用,,容器不會再把其他的請求發(fā)送給該對象。如果需要該Servlet再次為客戶端服務(wù),,容器將會重新產(chǎn)生一個Servlet對象來處理客戶端的請求,。在destroy()方法調(diào)用之后,容器會釋放這個Servlet對象,在隨后的時間內(nèi),,該對象會被Java的垃圾收集器所回收。

—  getServletConfig():該方法返回容器調(diào)用init()方法時傳遞給Servlet對象的ServletConfig對象,,ServletConfig對象包含了Servlet的初始化參數(shù),。

—  getServletInfo():返回一個String類型的字符串,其中包括了關(guān)于Servlet的信息,,例如,,作者、版本和版權(quán),。該方法返回的應(yīng)該是純文本字符串,,而不是任何類型的標記(HTML,、XML等),。

Servlet API包含在J2EE中,如果要查看Servlet API的文檔,,你需要下載J2EE(從J2EE 1.5開始改名為Java EE 5)SDK,Java EE 5 SDK的下載地址如下:http://java./javaee/downloads/?intcmp=1282,。

2.1.2  ServletRequest和ServletResponse

Servlet由Servlet容器來管理,,當客戶請求到來時,,容器創(chuàng)建一個ServletRequest對象,封裝請求數(shù)據(jù),同時創(chuàng)建一個ServletResponse對象,封裝響應(yīng)數(shù)據(jù),。這兩個對象將被容器作為service()方法的參數(shù)傳遞給Servlet,,Servlet利用ServletRequest對象獲取客戶端發(fā)來的請求數(shù)據(jù),,利用ServletResponse對象發(fā)送響應(yīng)數(shù)據(jù)。

ServletRequest和ServletResponse接口都在javax.servlet包中定義,,我們首先看一下ServletRequest接口中的常用方法,。

Ø  public java.lang.Object getAttribute(java.lang.String name)

返回以name為名字的屬性的值。如果該屬性不存在,,這個方法將返回null。

Ø  public java.util.Enumeration getAttributeNames()

返回請求中所有可用的屬性的名字,。如果在請求中沒有屬性,,這個方法將返回一個空的枚舉集合。

Ø  public void removeAttribute(java.lang.String name)

移除請求中名字為name的屬性,。

Ø  public void setAttribute(java.lang.String name, java.lang.Object o)

在請求中保存名字為name的屬性,。如果第二個參數(shù)o為null,那么相當于調(diào)用removeAttribute(name),。

Ø  public java.lang.String getCharacterEncoding()

返回請求正文使用的字符編碼的名字,。如果請求沒有指定字符編碼,這個方法將返回null。

Ø  public int getContentLength()

以字節(jié)為單位,,返回請求正文的長度,。如果長度不可知,這個方法將返回-1,。

Ø  public java.lang.String getContentType()

返回請求正文的MIME類型,。如果類型不可知,這個方法將返回null,。

Ø  public ServletInputStream getInputStream()

返回一個輸入流,,使用該輸入流以二進制方式讀取請求正文的內(nèi)容。javax.servlet.ServletInputStream是一個抽象類,,繼承自java.io.InputStream,。

Ø  public java.lang.String getLocalAddr()

返回接收到請求的網(wǎng)絡(luò)接口的IP地址,這個方法是在Servlet 2.4規(guī)范中新增的方法,。

Ø  public java.lang.String getLocalName()

返回接收到請求的IP接口的主機名,,這個方法是在Servlet 2.4規(guī)范中新增的方法。

Ø  public int getLocalPort()

返回接收到請求的網(wǎng)絡(luò)接口的IP端口號,,這個方法是在Servlet 2.4規(guī)范中新增的方法,。

Ø  public java.lang.String getParameter(java.lang.String name)

返回請求中name參數(shù)的值。如果name參數(shù)有多個值,,那么這個方法將返回值列表中的第一個值,。如果在請求中沒有找到這個參數(shù),這個方法將返回null,。

Ø  public java.util.Enumeration getParameterNames()

返回請求中包含的所有的參數(shù)的名字,。如果請求中沒有參數(shù),這個方法將返回一個空的枚舉集合,。

Ø  public java.lang.String[] getParameterValues(java.lang.String name)

返回請求中name參數(shù)所有的值,。如果這個參數(shù)在請求中并不存在,這個方法將返回null,。

Ø  public java.lang.String getProtocol()

返回請求使用的協(xié)議的名字和版本,,例如:HTTP/1.1。

Ø  public java.io.BufferedReader getReader() throws java.io.IOException

返回BufferedReader對象,,以字符數(shù)據(jù)方式讀取請求正文,。

Ø  public java.lang.String getRemoteAddr()

返回發(fā)送請求的客戶端或者最后一個代理服務(wù)器的IP地址。

Ø  public java.lang.String getRemoteHost()

返回發(fā)送請求的客戶端或者最后一個代理服務(wù)器的完整限定名,。

Ø  public int getRemotePort()

返回發(fā)送請求的客戶端或者最后一個代理服務(wù)器的IP源端口,,這個方法是在Servlet 2.4規(guī)范中新增的方法。

Ø  public RequestDispatcher getRequestDispatcher(java.lang.String path)

返回RequestDispatcher對象,,作為path所定位的資源的封裝,。

Ø  public java.lang.String getServerName()

返回請求發(fā)送到的服務(wù)器的主機名,。

Ø  public int getServerPort()

返回請求發(fā)送到的服務(wù)器的端口號。

Ø  public void setCharacterEncoding (java.lang.String env) throws java.io.Unsupported EncodingException

覆蓋在請求正文中所使用的字符編碼的名字,。

下面我們看一下ServletResponse接口中的常用方法:

Ø  public void flushBuffer() throws java.io.IOException

強制把任何在緩存中的內(nèi)容發(fā)送到客戶端,。

Ø  public int getBufferSize()

返回實際用于響應(yīng)的緩存的大小。如果沒有使用緩存,,這個方法將返回0,。

Ø  public java.lang.String getCharacterEncoding()

返回在響應(yīng)中發(fā)送的正文所使用的字符編碼(MIME字符集)。

Ø  public java.lang.String getContentType()

返回在響應(yīng)中發(fā)送的正文所使用的MIME類型,。

Ø  public ServletOutputStream getOutputStream() throws java.io.IOException

返回ServletOutputStream對象,,用于在響應(yīng)中寫入二進制數(shù)據(jù)。javax.servlet. ServletOutputStream是一個抽象類,,繼承自java.io.OutputStream,。

Ø  public java.io.PrintWriter getWriter() throws java.io.IOException

返回PrintWriter對象,用于發(fā)送字符文本到客戶端,。PrintWriter對象使用getCharacterEncoding()方法返回的字符編碼,。如果沒有指定響應(yīng)的字符編碼方式,默認將使用ISO-8859-1,。

Ø  public boolean isCommitted()

返回一個布爾值,,指示是否已經(jīng)提交了響應(yīng)。

Ø  public void reset()

清除在緩存中的任何數(shù)據(jù),,包括狀態(tài)代碼和消息報頭,。如果響應(yīng)已經(jīng)被提交,這個方法將拋出IllegalStateException異常,。

Ø  public void resetBuffer()

清除在緩存中的響應(yīng)內(nèi)容,,保留狀態(tài)代碼和消息報頭。如果響應(yīng)已經(jīng)被提交,,這個方法將拋出IllegalStateException異常。

Ø  public void setBufferSize(int size)

設(shè)置響應(yīng)正文的緩存大小,。Servlet容器將使用一個緩存,,其大小至少是請求的尺寸大小。這個方法必須在響應(yīng)正文被寫入之前調(diào)用,,如果內(nèi)容已經(jīng)被寫入或者響應(yīng)對象已經(jīng)被提交,,這個方法將拋出IllegalStateException異常。

Ø  public void setCharacterEncoding(java.lang.String charset)

設(shè)置發(fā)送到客戶端的響應(yīng)的字符編碼,,例如,UTF-8,。

Ø  public void setContentLength(int len)

對于HTTP Servlet,,在響應(yīng)中,,設(shè)置內(nèi)容正文的長度,,這個方法設(shè)置HTTP Content-Length實體報頭。

Ø  public void setContentType(java.lang.String type)

設(shè)置要發(fā)送到客戶端的響應(yīng)的內(nèi)容類型,,此時響應(yīng)應(yīng)該還沒有提交,。給出的內(nèi)容類型可以包括字符編碼說明,例如:text/html;charset=UTF-8,。如果這個方法在getWriter()方法被調(diào)用之前調(diào)用,那么響應(yīng)的字符編碼將僅從給出的內(nèi)容類型中設(shè)置,。這個方法如果在getWriter()方法被調(diào)用之后或者在響應(yīng)被提交之后調(diào)用,,將不會設(shè)置響應(yīng)的字符編碼。在使用HTTP協(xié)議的情況中,,這個方法設(shè)置Content-Type實體報頭,。

細心的讀者可能注意到了,在上面所列舉的方法中,,有的可能會拋出IllegalStateException異常,,然而在函數(shù)聲明時,卻沒有聲明拋出此異常,,這是為什么呢,?java.lang.IllegalStateException是java.lang.RuntimeException的子類。我們知道對于RuntimeException及其派生的異常是由Java運行系統(tǒng)自動拋出并自動處理,,不需要我們?nèi)ゲ东@,,所以也就不需要在函數(shù)聲明時聲明拋出異常了。

上面所列的方法,,讀者不需要將它們都記下來,,只要大致看一下,有一個初步的印象就可以了,。關(guān)鍵是要理解請求和響應(yīng)對象能夠提供哪些方法,,讀者可以從客戶端與服務(wù)器端的交互過程來思考,想想哪些信息是需要獲取到的,。在Servlet中,,用請求對象表示的是什么信息,用響應(yīng)對象來做什么,,哪些信息應(yīng)該是從請求對象中得到,,哪些信息應(yīng)該是用響應(yīng)對象來設(shè)置,。只要理解了交互的過程及請求對象和響應(yīng)對象所起的作用,當我們需要用到某個方法時,,就可以在API文檔中進行查找,,用的次數(shù)多了,這些方法自然也就記住了,。

2.1.3  ServletConfig

在javax.servlet包中,,定義了ServletConfig接口。Servlet容器使用ServletConfig對象在Servlet初始化期間向它傳遞配置信息,,一個Servlet只有一個ServletConfig對象,。在這個接口中,定義了下面四個方法:

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

返回名字為name的初始化參數(shù)的值,,初始化參數(shù)在web.xml配置文件中進行配置,。如果參數(shù)不存在,這個方法將返回null,。

Ø  public java.util.Enumeration getInitParameterNames()

返回Servlet所有初始化參數(shù)的名字的枚舉集合,。如果Servlet沒有初始化參數(shù),這個方法將返回一個空的枚舉集合,。

Ø  public ServletContext getServletContext()

返回Servlet上下文對象的引用,,關(guān)于ServletContext的使用,請參見第2.5節(jié),。

Ø  public java.lang.String getServletName()

返回Servlet實例的名字,。這個名字是在Web應(yīng)用程序的部署描述符中指定的。如果是一個沒有注冊的Servlet實例,,這個方法返回的將是Servlet的類名,。

2.1.4  一個簡單的Servlet

這一節(jié)我們編寫一個最簡單的Servlet,其功能就是向客戶端輸出一個字符串“Hello World”,。實例的開發(fā)主要有下列步驟,。

Step1:編寫HelloWorldServlet類

編寫一個Servlet,實際上就是編寫一個實現(xiàn)了javax.servlet.Servlet接口的類,。我們首先在%CATALINA_HOME%\webapps目錄下新建一個子目錄ch02,,然后用記事本或者UltraEdit等文本編輯工具編寫HelloWorldServlet.java源文件,將編寫好的HelloWorldServlet. java源文件放到%CATALINA_HOME%\webapps\ch02\src目錄下(讀者也可以自行選擇存放源代碼的目錄),。完整的源代碼如例2-1所示,。

例2-1  HelloWorldServlet.java

package org.sunxin.ch02.servlet;

import java.io.IOException;

import java.io.PrintWriter;

import javax.servlet.Servlet;

import javax.servlet.ServletConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

public class HelloWorldServlet implements Servlet

{

    private ServletConfig config;

    public void destroy(){}

    public ServletConfig getServletConfig()

    {

        return config;

    }

   

    /**

     * 該方法很少使用,因此返回null即可

     */

    public String getServletInfo()

    {      

        return null;

    }

    /**

     * ServletConfig對象由容器構(gòu)造,。容器在調(diào)用init()方法時,,將其作為參數(shù)傳給Servlet

     */

    public void init(ServletConfig config) throws ServletException

    {

        this.config = config;

    }

    public void service(ServletRequest req, ServletResponse res)

            throws ServletException, IOException

    {

        //得到PrintWriter對象。Servlet使用輸出流來產(chǎn)生響應(yīng)

        PrintWriter out=res.getWriter();

        //向客戶端發(fā)送字符數(shù)據(jù)

        out.println("Hello World");

        //關(guān)閉輸出流

        out.close();

    }

}

在Servlet中,,主要的方法是service(),,當客戶端請求到來時,,Servlet容器將調(diào)用Servlet實例的service()方法對請求進行處理,。我們在service()方法中,,首先通過ServletResponse類中的getWriter()方法調(diào)用得到一個PrintWriter類型的輸出流對象out,然后調(diào)用out對象的println()方法向客戶端發(fā)送字符串“Hello World”,,最后關(guān)閉out對象,。

Servlet容器調(diào)用Servlet實例對請求的處理過程如圖2-2所示。

圖2-2  Servlet容器調(diào)用Servlet實例對請求進行處理的全過程

Step2:編譯HelloWorldServlet.java

打開命令提示符,,轉(zhuǎn)到HelloWorldServlet.java所在的目錄%CATALINA_HOME%\ webapps\ch02\src下,,然后執(zhí)行:

javac -d . HelloWorldServlet.java

大多數(shù)情況下,你會看到如圖2-3所示的畫面,。

圖2-3  編譯HelloWorldServlet.java的出錯信息

產(chǎn)生這些錯誤的原因是Java編譯器沒有找到j(luò)avax.servlet包中的類,。要解決這個問題,我們需要讓Java編譯器知道Servlet API庫所在的位置,。Tomcat在其發(fā)行版中已經(jīng)包含了Servlet API庫,,是以JAR文件的形式提供的,這個JAR文件的完整路徑名是:

%CATALINA_HOME%\lib\servlet-api.jar

我們只需要在系統(tǒng)的CLASSPATH環(huán)境變量下添加這個JAR文件的路徑名就可以了,。

設(shè)置CLASSPATH環(huán)境變量的方法和第1章設(shè)置JAVA_HOME環(huán)境變量的方法是一樣的,,在筆者的機器上CLASSPATH環(huán)境變量的配置如下:

CLASSPATH=.;D:\OpenSource\apache-tomcat-6.0.16\lib\servlet-api.jar

關(guān)閉剛才打開的命令提示符窗口,重新打開一個新的命令提示符窗口,,進入HelloWorldServlet.java所在的目錄,,再次執(zhí)行:

javac -d . HelloWorldServlet.java

生成org\sunxin\ch02\servlet目錄結(jié)構(gòu),以及在servlet子目錄中的HelloWorldServlet.class文件,。

如果你已經(jīng)安裝了J2EE SDK,,那么在安裝目錄的lib子目錄下有一個javaee.jar文件(J2EE 1.4以及之前的版本是j2ee.jar文件),其中包含了Servlet API庫,。你可以在CLASSPATH環(huán)境變量下添加javaee.jar所在的路徑名,,就不需要再配置Tomcat中的servlet-api.jar了。配置了javaee.jar后,,你還可以開發(fā)其他的J2EE應(yīng)用,。

Step3:部署HelloWorldServlet

Servlet是Web應(yīng)用程序中的一個組件。一個Web應(yīng)用程序是由一組Servlet,、HTML頁面,、類,以及其他的資源組成的運行在Web服務(wù)器上的完整的應(yīng)用程序,,以一種結(jié)構(gòu)化的有層次的目錄形式存在,。組成Web應(yīng)用程序的這些資源文件要部署在相應(yīng)的目錄層次中,根目錄代表了整個Web應(yīng)用程序的根,。我們通常是將Web應(yīng)用程序的目錄放到%CATALINA_HOME%\webapps目錄下,,在webapps目錄下的每一個子目錄都是一個獨立的Web應(yīng)用程序,,子目錄的名字就是Web應(yīng)用程序的名字,也稱為Web應(yīng)用程序的上下文根,。用戶通過Web應(yīng)用程序的上下文根來訪問Web應(yīng)用程序中的資源,,如圖2-4所示。

如果你要新建一個Web應(yīng)用程序,,可以在webapps目錄下先建一個目錄,,在這個例子中,我們所建的目錄是ch02,,作為第一個Web應(yīng)用程序的上下文根,。Java開發(fā)的Web應(yīng)用程序需要遵照一定的目錄層次結(jié)構(gòu),在Servlet規(guī)范中定義了Web應(yīng)用程序的目錄層次結(jié)構(gòu),,如圖2-5所示,。

        

圖2-4  多個Web應(yīng)用程序和上下文根             圖2-5  Web應(yīng)用程序的目錄層次結(jié)構(gòu)

Web應(yīng)用程序的目錄層次結(jié)構(gòu)如表2-1所示。

表2-1  Web應(yīng)用程序的目錄層次結(jié)構(gòu)

   

   

\ch02

Web應(yīng)用程序的根目錄,,屬于此Web應(yīng)用程序的所有文件都存放在這個目錄下

\ch02\WEB-INF

存放Web應(yīng)用程序的部署描述符文件web.xml

\ch02\WEB-INF\classes

存放Servlet和其他有用的類文件

\ch02\WEB-INF\lib

存放Web應(yīng)用程序需要用到的JAR文件,,這些JAR文件中可以包含ServletBean和其他有用的類文件

\ch02\WEB-INF\web.xml

web.xml文件包含Web應(yīng)用程序的配置和部署信息

從表2-1中可以看到,,WEB-INF目錄下的classes和lib目錄都可以存放Java的類文件,,在Servlet容器運行時,Web應(yīng)用程序的類加載器將首先加載classes目錄下的,,其次才是lib目錄下的類,。如果這兩個目錄下存在同名的類,起作用的將是classes目錄下的類,。

在表2-1中,,我們還可以看到一個特殊的目錄WEB-INF,注意在書寫時不要寫錯,,所有字母都要大寫,。說這個目錄特殊,是因為這個目錄并不屬于Web應(yīng)用程序可以訪問的上下文路徑的一部分,,對客戶端來說,,這個目錄是不可見的。如果你將index.html文件放到WEB-INF目錄下,,對于客戶端是無法通過下面的方式訪問到這個文件的:

http://localhost:8080/ch02/WEB-INF/index.html

不過,,WEB-INF目錄下的內(nèi)容對于Servlet代碼是可見的,在Servlet代碼中可以通過調(diào)用ServletContext對象中的getResource()或者getResourceAsStream()方法來訪問WEB-INF目錄下的資源,,也可以使用RequestDispatcher調(diào)用(參見第2.6節(jié))將WEB-INF目錄下的內(nèi)容呈現(xiàn)給客戶端,。

如果我們想要在Servlet代碼中訪問保存在文件中的配置信息,而又不希望這些配置信息被客戶端訪問到,就可以把這個文件放到WEB-INF目錄下,。

在%CATALINA_HOME%\webapps\ch02目錄下新建一個目錄WEB-INF,,進入WEB-INF目錄,新建一個classes目錄,,整個目錄結(jié)構(gòu)是:

%CATALINA_HOME%\webapps\ch02\WEB-INF\classes

將編譯生成的HelloWorldServlet.class文件連同所在的包一起放到WEB-INF\classes目錄下,。

接下來,我們需要部署這個Servlet,,Web應(yīng)用程序的配置和部署是通過web.xml文件來完成的,。web.xml文件被稱為Web應(yīng)用程序的部署描述符,它可以包含如下的配置和部署信息:

—  ServletContext的初始化參數(shù)

—  Session的配置

—  Servlet/JSP的定義和映射

—  應(yīng)用程序生命周期監(jiān)聽器類

—  過濾器定義和過濾器映射

—  MIME類型映射

—  歡迎文件列表

—  錯誤頁面

—  語言環(huán)境和編碼映射

—  聲明式安全配置

—  JSP配置

我們所編寫的web.xml文件必須是格式良好的XML,。用記事本或者UltraEdit等文本編輯工具編寫web.xml文件,內(nèi)容如例2-2所示,。

例2-2  web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.5"

    xmlns="http://java./xml/ns/javaee"

    xmlns:xsi="http://www./2001/XMLSchema-instance"

    xsi:schemaLocation="http://java./xml/ns/javaee

    http://java./xml/ns/javaee/web-app_2_5.xsd">

 

    <servlet>

        <servlet-name>HelloWorldServlet</servlet-name>

        <servlet-class>

             org.sunxin.ch02.servlet.HelloWorldServlet</servlet-class>

    </servlet>

    <servlet-mapping>

        <servlet-name>HelloWorldServlet</servlet-name>

        <url-pattern>/helloworld</url-pattern>

    </servlet-mapping>

</web-app>

第一行是XML聲明,,接下來在根元素<web-app>上聲明了使用的XML Schema的版本。這段代碼是固定的,,你無須記憶它,,只要知道復(fù)制/粘貼就可以了。

注意代碼中以粗體顯示的部分,,這部分代碼使用了<servlet>和<servlet-mapping>元素,,以及它們的子元素來部署HelloWorldServlet。在web.xml文件中,,可以包含多個<servlet>和<servlet-mapping>元素,,用于部署多個Servlet。

<servlet>元素用于聲明Servlet,,<servlet-name>子元素用于指定Servlet的名字,,在同一個Web應(yīng)用程序中,每一個Servlet的名字必須是唯一的,,該元素的內(nèi)容不能為空,。<servlet-class>子元素用于指定Servlet類的完整限定名(如果有包名,要同時給出包名),。

<servlet-mapping>元素用于在Servlet和URL樣式之間定義一個映射,。它的子元素<servlet-name>指定的Servlet名字必須和<servlet>元素中的子元素<servlet-name>給出的名字相同。<url-pattern>子元素用于指定對應(yīng)于Servlet的URL路徑,,該路徑是相對于Web應(yīng)用程序上下文根的路徑,。

經(jīng)過這樣的配置之后,我們可以在瀏覽器的地址欄中輸入http://localhost:8080/ ch02/helloworld來訪問HelloWorldServlet,。當Servlet容器接收到/ch02/helloworld的請求后,,就會將發(fā)送給ch02 Web應(yīng)用程序的Context(參見第1.6節(jié)),ch02 Web應(yīng)用程序的Context首先移除該Web應(yīng)用程序上下文路徑的前綴/ch02,然后將剩余部分與web.xml文件中配置的<url-pattern>元素的內(nèi)容相比較,,找到對應(yīng)的Servlet名字為HelloWorldServlet,,再根據(jù)這個名字找到HelloWorldServlet類,進而實例化這個類,,對請求進行處理,。

將編寫好的web.xml文件保存到%CATALINA_HOME%\webapps\ch02\WEB-INF目錄下。讀者也可以將%CATALINA_HOME%\webapps\ROOT\WEB-INF目錄下的web.xml復(fù)制一份,,存放到%CATALINA_HOME%\webapps\ch02\WEB-INF目錄下,,這個文件的內(nèi)容如下:

<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app xmlns="http://java./xml/ns/javaee"

   xmlns:xsi="http://www./2001/XMLSchema-instance"

   xsi:schemaLocation="http://java./xml/ns/javaee

   http://java./xml/ns/javaee/web-app_2_5.xsd"

   version="2.5">

  <display-name>Welcome to Tomcat</display-name>

  <description>

     Welcome to Tomcat

  </description>

</web-app>

然后編輯這個文件,添加HelloWorldServlet的配置,,如下所示:

<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app xmlns="http://java./xml/ns/javaee"

   xmlns:xsi="http://www./2001/XMLSchema-instance"

   xsi:schemaLocation="http://java./xml/ns/javaee

http://java./xml/ns/javaee/web-app_2_5.xsd"

   version="2.5">

  <display-name>Welcome to Tomcat</display-name>

  <description>

     Welcome to Tomcat

  </description>

 

  <servlet>

    <servlet-name>HelloWorldServlet</servlet-name>

    <servlet-class>org.sunxin.ch02.servlet.HelloWorldServlet

    </servlet-class>

  </servlet>

  <servlet-mapping>

    <servlet-name>HelloWorldServlet</servlet-name>

    <url-pattern>/helloworld</url-pattern>

  </servlet-mapping>

</web-app>

這個文件中其他元素的作用請參看附錄D,。

%CATALINA_HOME%\webapps\ROOT目錄是Tomcat默認的Web應(yīng)用程序的起始路徑,當我們輸入http://localhost:8080/時,,訪問的就是該目錄下的Web應(yīng)用程序資源,。如果你將本例的Servlet部署在該目錄下,訪問時只需輸入http://localhost:8080/helloworld即可,。

Step4:訪問HelloWorldServlet

當部署好Servlet之后,,對客戶端來說,訪問Servlet和訪問靜態(tài)頁面沒有什么區(qū)別,。為了讓讀者對Servlet的訪問有一個較好的感性認識,,在這里我們通過兩種方式來訪問SimpleHello。

第一種方式,,我們通過telnet工具來訪問本例中的Servlet,,具體操作步驟,讀者可以參看附錄B,。

首先確保Tomcat服務(wù)器正常啟動了,。打開命令提示符,輸入

telnet localhost 8080

回車后,,輸入

GET /ch02/helloworld HTTP/1.1

Host: localhost

注意書寫與空格,。然后連續(xù)兩個回車,你將看到如圖2-6所示的畫面,。

第二種方式,,通過瀏覽器訪問Servlet,打開IE,,在地址欄中輸入:

http://localhost:8080/ch02/helloworld

注意在helloworld后面不要加斜杠(/),,然后回車,你將看到如圖2-7所示的畫面,。

      

圖2-6  使用telnet工具與Servlet交互的信息      圖2-7  使用IE訪問HelloWorldServlet

在訪問Servlet和JSP的時候,,Servlet的名字和JSP的文件名都是區(qū)分大小寫的,,對于本例來說,如果你輸入的是HelloWorld,,那么Tomcat服務(wù)器會給出404的錯誤代碼,,提示“The requested resource (/ch02/HelloWorld) is not available”。

Web應(yīng)用程序的開發(fā)分為設(shè)計開發(fā)與配置部署兩個階段,。通過部署,,實現(xiàn)了組件與組件之間的松耦合,降低了Web應(yīng)用程序維護的難度,。在本例中,,為Servlet指定了一個名字和URL映射,,其他的組件或頁面可以使用URL來調(diào)用這個Servlet,,一旦Servlet發(fā)生了改動,,例如,,整個類被替換、重新命名等,,只需修改web.xml文件中<servlet-class>元素的內(nèi)容,,在設(shè)計開發(fā)階段確定的程序結(jié)構(gòu)與代碼不需要做任何的改動,,降低了程序維護的難度,。當然,事物都有兩面性,,在享受好處的同時,,也需要我們花費額外的時間和精力去了解和掌握部署過程。

2.1.5  GenericServlet

在第2.3節(jié)中,,我們是通過實現(xiàn)Servlet接口來編寫的Servlet類,,這需要實現(xiàn)Servlet接口中定義的5個方法。為了簡化Servlet的編寫,,在javax.servlet包中提供了一個抽象的類GenericServlet,,它給出了除service()方法外的其他4個方法的簡單實現(xiàn)。GenericServlet類定義了一個通用的,、不依賴于具體協(xié)議的Servlet,,它實現(xiàn)了Servlet接口和ServletConfig接口。

Ø  public abstract class GenericServlet extends java.lang.Object implements Servlet, ServletConfig, java.io.Serializable

如果我們要編寫一個通用的Servlet,,只需要從GenericServlet類繼承,,并實現(xiàn)其中的抽象方法service()。

在GenericServlet類中,,定義了兩個重載的init()方法:

Ø  public void init(ServletConfig config) throws ServletException
Ø  public void init() throws ServletException

第一個init()方法是Servlet接口中init()方法的實現(xiàn),。在這個方法中,首先將ServletConfig對象保存在一個transient實例變量中,,然后調(diào)用第二個不帶參數(shù)的init()方法,。

通常我們在編寫繼承自GenericServlet的Servlet類時,只需要重寫第二個不帶參數(shù)的init()方法就可以了。如果覆蓋了第一個init()方法,,那么應(yīng)該在子類的該方法中,,包含一句super.init(config)代碼的調(diào)用。

在GenericServlet類中還定義了下列的方法,。

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

返回名字為name的初始化參數(shù)的值,,初始化參數(shù)在web.xml配置文件中進行配置。如果參數(shù)不存在,,這個方法將返回null,。

注意,這個方法只是為了方便而給出的,,它實際上是通過調(diào)用ServletConfig對象的getInitParameter()方法來得到初始化參數(shù)的,。

Ø  public java.util.Enumeration getInitParameterNames()

返回Servlet所有初始化參數(shù)的名字的枚舉集合。如果Servlet沒有初始化參數(shù),,這個方法將返回一個空的枚舉集合,。

注意,這個方法只是為了方便而給出的,,它實際上是通過調(diào)用ServletConfig對象的getInitParameterNames()方法來得到所有的初始化參數(shù)的名字,。

Ø  public ServletContext getServletContext()

返回Servlet上下文對象的引用,關(guān)于ServletContext的使用,,請參見第2.5節(jié),。

注意,這個方法只是為了方便而給出的,,它實際上是通過調(diào)用ServletConfig對象的getServletContext()方法來得到的Servlet上下文對象的引用,。

2.1.6  HttpServlet

在絕大多數(shù)的網(wǎng)絡(luò)應(yīng)用中,都是客戶端(瀏覽器)通過HTTP協(xié)議去訪問服務(wù)器端的資源,,而我們所編寫的Servlet也主要是應(yīng)用于HTTP協(xié)議的請求和響應(yīng),。為了快速開發(fā)應(yīng)用于HTTP協(xié)議的Servlet類,Sun公司在javax.servlet.http包中給我們提供了一個抽象的類HttpServlet,,它繼承自GenericServlet類,,用于創(chuàng)建適合Web站點的HTTP Servlet。

public abstract class HttpServlet extends GenericServlet implements java.io.Serializable

在HttpServlet類中提供了兩個重載的service()方法:

Ø  public void service(ServletRequest req, ServletResponse res) throws ServletException, java.io.IOException
Ø  protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, java.io.IOException

第一個service()方法是GenericServlet類中service()方法的實現(xiàn),。在這個方法中,,首先將req和res對象轉(zhuǎn)換為HttpServletRequest(繼承自ServletRequest接口)和HttpServletResponse(繼承自ServletResponse接口)類型,然后調(diào)用第二個service方法,,對客戶請求進行處理,。

針對HTTP1.1中定義的7種請求方法GET、POST,、HEAD,、PUT,、DELETE、TRACE和OPTIONS,,HttpServlet分別提供了7個處理方法:

Ø  protected void doGet (HttpServletRequest req, HttpServletResponse resp) throws ServletException, java.io.IOException
Ø  protected void doPost (HttpServletRequest req, HttpServletResponse resp) throws ServletException, java.io.IOException
Ø  protected void doHead (HttpServletRequest req, HttpServletResponse resp) throws ServletException, java.io.IOException
Ø  protected void doPut (HttpServletRequest req, HttpServletResponse resp) throws ServletException, java.io.IOException
Ø  protected void doDelete (HttpServletRequest req, HttpServletResponse resp) throws ServletException, java.io.IOException
Ø  protected void doTrace (HttpServletRequest req, HttpServletResponse resp) throws ServletException, java.io.IOException
Ø  protected void doOptions (HttpServletRequest req, HttpServletResponse resp) throws ServletException, java.io.IOException

這7個方法的參數(shù)類型及異常拋出類型與HttpServlet類中的第二個重載的service()方法是一致的,。當容器接收到一個針對HttpServlet對象的請求時,調(diào)用該對象中的方法順序如下:

① 調(diào)用公共的(public)service()方法,。

② 在公共的service()方法中,,首先將參數(shù)類型轉(zhuǎn)換為HttpServletRequest和HttpServletResponse,然后調(diào)用保護的(protected)service()方法,,將轉(zhuǎn)換后的HttpServletRequest對象和HttpServletResponse對象作為參數(shù)傳遞進去,。

③ 在保護的service()方法中,首先調(diào)用HttpServletRequest對象的getMethod()方法,,獲取HTTP請求方法的名字,,然后根據(jù)請求方法的類型,調(diào)用相應(yīng)的doXxx ()方法,。

因此,,我們在編寫HttpServlet的派生類時,通常不需要去覆蓋service()方法,,而只需重寫相應(yīng)的doXXX()方法,。

HttpServlet類對TRACE和OPTIONS方法做了適當?shù)膶崿F(xiàn),因此我們不需要去覆蓋doTrace()和doOptions()方法,。而對于其他的5個請求方法,,HttpServlet類提供的實現(xiàn)都是返回HTTP錯誤,對于HTTP 1.0的客戶端請求,,這些方法返回狀態(tài)代碼為400的HTTP錯誤,表示客戶端發(fā)送的請求在語法上是錯誤的,。而對于HTTP 1.1的客戶端請求,,這些方法返回狀態(tài)代碼為405的HTTP錯誤,表示對于指定資源的請求方法不被允許,。這些方法都是使用javax.servlet.ServletRequest接口中的getProtocol()方法來確定協(xié)議的,。

HttpServlet雖然是抽象類,但在這個類中沒有抽象的方法,,其中所有的方法都是已經(jīng)實現(xiàn)的,。只是在這個類中對客戶請求進行處理的方法,沒有真正的實現(xiàn),,當然也不可能真正實現(xiàn),,因為對客戶請求如何進行處理,需要根據(jù)實際的應(yīng)用來決定,。我們在編寫HTTP Servlet的時候,,根據(jù)應(yīng)用的需要,,重寫其中的對客戶請求進行處理的方法即可。

2.1.7  HttpServletRequest和HttpServletResponse

在javax.servlet.http包中,,定義了HttpServletRequest和HttpServletResponse這兩個接口,。這兩個接口分別繼承自javax.servlet.ServletRequest和javax.servlet.ServletResponse接口。在HttpServletRequest接口中新增的常用方法如下:

Ø  public java.lang.String getContextPath()

返回請求URI中表示請求上下文的部分,,上下文路徑是請求URI的開始部分,。上下文路徑總是以斜杠(/)開頭,但結(jié)束沒有斜杠(/),。在默認(根)上下文中,,這個方法返回空字符串""。例如,,請求URI為“/sample/test”,,調(diào)用該方法返回路徑為“/sample”。

Ø  public Cookie[] getCookies()

返回客戶端在此次請求中發(fā)送的所有Cookie對象,。

Ø  public java.lang.String getHeader(java.lang.String name)

返回名字為name的請求報頭的值,。如果請求中沒有包含指定名字的報頭,這個方法返回null,。

Ø  public java.util.Enumeration getHeaderNames()

返回此次請求中包含的所有報頭名字的枚舉集合,。

Ø  public java.util.Enumeration getHeaders(java.lang.String name)

返回名字為name的請求報頭所有的值的枚舉集合。

Ø  public java.lang.String getMethod()

返回此次請求所使用的HTTP方法的名字,,例如,,GET、POST或PUT,。

Ø  public java.lang.String getPathInfo()

返回與客戶端發(fā)送的請求URL相聯(lián)系的額外的路徑信息,。額外的路徑信息是跟在Servlet的路徑之后、查詢字符串之前的路徑,,并以斜杠(/)字符開始,。例如,假定在web.xml文件中MyServlet類映射的URL是:/myservlet/*,,用戶請求的URL是:http://localhost:8080/ ch02/myservlet/test,,當我們在HttpServletRequest對象上調(diào)用getPathInfo()時,該方法將返回/test,。如果沒有額外的路徑信息,,getPathInfo()方法將返回null。

Ø  public java.lang.String getPathTranslated()

將額外的路徑信息轉(zhuǎn)換為真實的路徑,。例如,,在上面的例子中假定ch02 Web應(yīng)用程序位于D:\OpenSource\apache-tomcat-6.0.16\webapps\ch02目錄,當用戶請求http://localhost: 8080/ch02/myservlet/test時,,在請求對象上調(diào)用getPathTranslated()方法將返回D:\OpenSource\apache-tomcat-6.0.16\webapps\ch02\test,。

Ø  public java.lang.String getQueryString()

返回請求URL中在路徑后的查詢字符串,。如果在URL中沒有查詢字符串,該方法返回null,。例如,,有如下的請求URL:

http://localhost:8080/ch02/logon.jsp?action=logon

調(diào)用getQueryString()方法將返回action=logon。

Ø  public java.lang.String getRequestURI()

返回請求URL中從主機名到查詢字符串之間的部分,。例如:

請求行                                                    返回值

POST /some/path.html HTTP/1.1                /some/path.html

GET http://r/a.html HTTP/1.0            /a.html

HEAD /xyz?a=b HTTP/1.1                         /xyz

Ø  public java.lang.StringBuffer getRequestURL()

重新構(gòu)造客戶端用于發(fā)起請求的URL,。返回的URL包括了協(xié)議、服務(wù)器的名字,、端口號和服務(wù)器的路徑,,但是不包括查詢字符串參數(shù)。

要注意的是,,如果請求使用RequestDispatcher.forward(ServletRequest, ServletResponse)方法被轉(zhuǎn)發(fā)到另一個Servlet中,,那么你在這個Servlet中調(diào)用getRequestURL(),得到的將是獲取RequestDispatcher對象時使用的URL,,而不是原始的請求URL,。

Ø  public java.lang.String getServletPath()

返回請求URI中調(diào)用Servlet的部分。這部分的路徑以斜杠(/)開始,,包括了Servlet的名字或者路徑,,但是不包括額外的路徑信息和查詢字符串。例如,,假定在web.xml文件中MyServlet類映射的URL是:/myservlet/*,,用戶請求的URL是:http://localhost:8080/ ch02/myservlet/test,當我們在HttpServletRequest對象上調(diào)用getServletPath ()時,,該方法將返回/myservlet,。如果用于處理請求的Servlet與URL樣式“/*”相匹配,那么這個方法將返回空字符串(""),。

Ø  public HttpSession getSession()

返回和此次請求相關(guān)聯(lián)的Session,,如果沒有給客戶端分配Session,則創(chuàng)建一個新的Session,。

Ø  public HttpSession getSession(boolean create)

返回和此次請求相關(guān)聯(lián)的Session,如果沒有給客戶端分配Session,,而create參數(shù)為true,,則創(chuàng)建一個新的Session。如果create參數(shù)為false,,而此次請求沒有一個有效的HttpSession,,則返回null。

在HttpServletResponse接口中,,新增的常用方法如下:

Ø  public void addCookie(Cookie cookie)

增加一個Cookie到響應(yīng)中,。這個方法可以被多次調(diào)用,,用于設(shè)置多個Cookie。

Ø  public void addHeader(java.lang.String name, java.lang.String value)

用給出的name和value,,增加一個響應(yīng)報頭到響應(yīng)中,。

Ø  public boolean containsHeader(java.lang.String name)

判斷以name為名字的響應(yīng)報頭是否已經(jīng)設(shè)置。

Ø  public java.lang.String encodeRedirectURL(java.lang.String url)

使用Session ID對用于重定向的url進行編碼,,以便用于sendRedirect()方法中,。如果該url不需要編碼,則返回未改變的url,。(關(guān)于這個方法的使用,,請參見第5章)

Ø  public java.lang.String encodeURL(java.lang.String url)

使用Session ID對指定的url進行編碼。如果該url不需要編碼,,則返回未改變的url,。(關(guān)于這個方法的使用,請參見第5章)

Ø  public void sendError(int sc) throws java.io.IOException

使用參數(shù)sc表示的狀態(tài)代碼發(fā)送一個錯誤響應(yīng)到客戶端,,同時清除緩存,。如果響應(yīng)已經(jīng)被提交,這個方法將拋出IllegalStateException異常,。

Ø  public void sendError(int sc, java.lang.String msg) throws java.io.IOException

使用指定的狀態(tài)代碼發(fā)送一個錯誤響應(yīng)到客戶端,。服務(wù)器默認會創(chuàng)建一個包含了指定消息的服務(wù)器端錯誤頁面作為響應(yīng),設(shè)置內(nèi)容類型為“text/html”,。如果Web應(yīng)用程序已經(jīng)聲明了對應(yīng)于指定狀態(tài)代碼的錯誤頁面,,則服務(wù)器會將這個頁面發(fā)送給客戶端,而不理會參數(shù)msg指定的錯誤消息,。如果響應(yīng)已經(jīng)被提交,,這個方法將拋出IllegalStateException異常。

Ø  public void sendRedirect(java.lang.String location) throws java.io.IOException

發(fā)送一個臨時的重定向響應(yīng)到客戶端,,讓客戶端訪問新的URL,。如果指定的位置是相對URL,Servlet容器在發(fā)送響應(yīng)到客戶端之前,,必須將相對URL轉(zhuǎn)換為絕對URL,。如果響應(yīng)已經(jīng)被提交,這個方法將拋出IllegalStateException異常,。

Ø  public void setHeader(java.lang.String name, java.lang.String value)

用給出的name和value,,設(shè)置一個響應(yīng)報頭。如果這個報頭已經(jīng)被設(shè)置,,新的值將覆蓋先前的值,。

Ø  public void setStatus(int sc)

為響應(yīng)設(shè)置狀態(tài)代碼。

此外,,在HttpServletResponse接口中,,還定義了一組整型的靜態(tài)常量,,用于表示HTTP錯誤代碼,這些錯誤代碼對應(yīng)于HTTP/1.1中的錯誤代碼,。關(guān)于這些錯誤代碼常量,,請參看HttpServletResponse接口的API文檔。

要想更好地理解HttpServletRequest和HttpServletResponse的使用,,應(yīng)該結(jié)合HTTP協(xié)議來看,,彼此對照。HTTP協(xié)議的介紹參見附錄B,。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多