1. 程式人生 > >JavaWeb Servlet知識點歸納

JavaWeb Servlet知識點歸納

Servlet概述

生命週期方法:

void init(ServletConfig):出生之後(1次);

void service(ServletRequest request, ServletResponse response):每次處理請求時都會被呼叫;

void destroy():臨死之前(1次);

特性:

1)單例,一個類只有一個物件;當然可能存在多個Servlet類;

 2)執行緒不單例的,所以它的效率是高的!

Servlet類由我們來寫,但物件由伺服器來建立,並且由伺服器來呼叫相應的方法。

1 什麼是Servlet

ServletJavaWeb三大元件之一,它屬於動態資源。

Servlet的作用是處理請求,伺服器會把接收到的請求交給Servlet來處理,在Servlet中通常需要:

l 接收請求資料;

l 處理請求;

l 完成響應。

  例如客戶端發出登入請求,或者輸出註冊請求,這些請求都應該由Servlet來完成處理!Servlet需要我們自己來編寫,每個Servlet必須實現javax.servlet.Servlet介面。

2 實現Servlet的方式(由我們自己來寫!)

實現Servlet有三種方式:

實現javax.servlet.Servlet介面;

繼承javax.servlet.GenericServlet類;

繼承javax.servlet.http.HttpServlet類;

  通常我們會去繼承HttpServlet類來完成我們的Servlet,但學習Servlet還要從javax.servlet.Servlet介面開始學習。

Servlet.java

public interface Servlet {

    public void init(ServletConfig config) throws ServletException;

    public ServletConfig getServletConfig();

    public void service(ServletRequest req, ServletResponse res)

            throws

 ServletException, IOException;

    public String getServletInfo();

    public void destroy();

}

3 建立helloservlet應用

我們開始第一個Servlet應用吧!首先在webapps目錄下建立helloservlet目錄,它就是我們的應用目錄了,然後在helloservlet目錄中建立準備JavaWeb應用所需內容:

建立/helloservlet/WEB-INF目錄;

建立/helloservlet/WEB-INF/classes目錄;

建立/helloservlet/WEB-INF/lib目錄;

建立/helloservlet/WEB-INF/web.xml檔案;

接下來我們開始準備完成Servlet,完成Servlet需要分為兩步:

編寫Servlet類;

web.xml檔案中配置Servlet

HelloServlet.java

public class HelloServlet implements Servlet {

public void init(ServletConfig config) throws ServletException {}

public ServletConfig getServletConfig() {return null;}

public void destroy() {}

public String getServletInfo() {return null;}

public void service(ServletRequest req, ServletResponse res)

throws ServletException, IOException {

System.out.println("hello servlet!");

}

}

  我們暫時忽略Servlet中其他四個方法,只關心service()方法,因為它是用來處理請求的方法。我們在該方法內給出一條輸出語句!

web.xml(下面內容需要背下來)

<servlet>

<servlet-name>hello</servlet-name>

<servlet-class>cn.itcast.servlet.HelloServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>hello</servlet-name>

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

</servlet-mapping>  

web.xml中配置Servlet的目的其實只有一個,就是把訪問路徑與一個Servlet繫結到一起,上面配置是把訪問路徑:“/helloworld”與“cn.itcast.servlet.HelloServlet”繫結到一起。

l <servlet>:指定HelloServlet這個Servlet的名稱為hello

l <servlet-mapping>:指定/helloworld訪問路徑所以訪問的Servlet名為hello

<servlet><servlet-mapping>通過<servlet-name>這個元素關聯在一起了!

接下來,我們編譯HelloServlet,注意,編譯HelloServlet時需要匯入servlet-api.jar,因為Servlet.class等類都在servlet-api.jar中。

javac -classpath F:/tomcat6/lib/servlet-api.jar -d . HelloServlet.java

然後把HelloServlet.class放到/helloworld/WEB-INF/classes/目錄下,然後啟動Tomcat,在瀏覽器中訪問:http://localhost:8080/helloservlet/helloworld即可在控制檯上看到輸出!

l /helloservlet/WEB-INF/classes/cn/itcast/servlet/HelloServlet.class

Servlet介面

1 Servlet的生命週期

所謂xxx的生命週期,就是說xxx的出生、服務,以及死亡。Servlet生命週期也是如此!與Servlet的生命週期相關的方法有:

l void init(ServletConfig)

l void service(ServletRequest,ServletResponse)

l void destroy()

1.1  Servlet的出生

伺服器會在Servlet第一次被訪問時建立Servlet,或者是在伺服器啟動時建立Servlet。如果伺服器啟動時就建立Servlet,那麼還需要在web.xml檔案中配置。也就是說預設情況下,Servlet是在第一次被訪問時由伺服器建立的。

而且一個Servlet型別,伺服器只建立一個例項物件,例如在我們首次訪問http://localhost:8080/helloservlet/helloworld時,伺服器通過“/helloworld”找到了繫結的Servlet名稱為cn.it.servlet.HelloServlet,然後伺服器檢視這個型別的Servlet是否已經建立過,如果沒有建立過,那麼伺服器才會通過反射來建立HelloServlet的例項。當我們再次訪問http://localhost:8080/helloservlet/helloworld時,伺服器就不會再次建立HelloServlet例項了,而是直接使用上次建立的例項。

Servlet被建立後,伺服器會馬上呼叫Servletvoid init(ServletConfig)方法。請記住, Servlet出生後馬上就會呼叫init()方法,而且一個Servlet的一生。這個方法只會被呼叫一次。這好比小孩子出生後馬上就要去剪臍帶一樣,而且剪臍帶一生只有一次。

我們可以把一些對Servlet的初始化工作放到init方法中!

1.2  Servlet服務

  當伺服器每次接收到請求時,都會去呼叫Servletservice()方法來處理請求。伺服器接收到一次請求,就會呼叫service() 方法一次,所以service()方法是會被呼叫多次的。正因為如此,所以我們才需要把處理請求的程式碼寫到service()方法中!

1.3Servlet的離去

Servlet是不會輕易離去的,通常都是在伺服器關閉時Servlet才會離去!在伺服器被關閉時,伺服器會去銷燬Servlet,在銷燬Servlet之前伺服器會先去呼叫Servletdestroy()方法,我們可以把Servlet的臨終遺言放到destroy()方法中,例如對某些資源的釋放等程式碼放到destroy()方法中。

1.4 測試生命週期方法

修改HelloServlet如下,然後再去訪問http://localhost:8080/helloservlet/helloworld

public class HelloServlet implements Servlet {

public void init(ServletConfig config) throws ServletException {

System.out.println("Servlet被建立了!");

}

public ServletConfig getServletConfig() {return null;}

public void destroy() {

System.out.println("Servlet要離去了!");

}

public String getServletInfo() {return null;}

public void service(ServletRequest req, ServletResponse res)

throws ServletException, IOException {

System.out.println("hello servlet!");

}

}

在首次訪問HelloServlet時,init方法會被執行,而且也會執行service方法。再次訪問時,只會執行service方法,不再執行init方法。在關閉Tomcat時會呼叫destroy方法。

2Servlet介面相關型別

Servlet介面中還存在三個我們不熟悉的型別:

l ServletRequestservice() 方法的引數,它表示請求物件,它封裝了所有與請求相關的資料,它是由伺服器建立的;

l ServletResponseservice()方法的引數,它表示響應物件,在service()方法中完成對客戶端的響應需要使用這個物件;

l ServletConfiginit()方法的引數,它表示Servlet配置物件,它對應Servlet的配置資訊,那對應web.xml檔案中的<servlet>元素。

2.1ServletRequestServletResponse

ServletRequestServletResponseServlet#service() 方法的兩個引數,一個是請求物件,一個是響應物件,可以從ServletRequest物件中獲取請求資料,可以使用ServletResponse物件完成響應。你以後會發現,這兩個物件就像是一對恩愛的夫妻,永遠不分離,總是成對出現。

ServletRequestServletResponse的例項由伺服器建立,然後傳遞給service()方法。如果在service() 方法中希望使用HTTP相關的功能,那麼可以把ServletRequestServletResponse強轉成HttpServletRequestHttpServletResponse。這也說明我們經常需要在service()方法中對ServletRequestServletResponse進行強轉,這是很心煩的事情。不過後面會有一個類來幫我們解決這一問題的。

HttpServletRequest方法:

l String getParameter(String paramName):獲取指定請求引數的值;

l String getMethod():獲取請求方法,例如GETPOST

l String getHeader(String name):獲取指定請求頭的值;

l void setCharacterEncoding(String encoding):設定請求體的編碼!因為GET請求沒有請求體,所以這個方法只只對POST請求有效。當呼叫request.setCharacterEncoding(“utf-8”)之後,再通過getParameter()方法獲取引數值時,那麼引數值都已經通過了轉碼,即轉換成了UTF-8編碼。所以,這個方法必須在呼叫getParameter()方法之前呼叫!

HttpServletResponse方法:

l PrintWriter getWriter():獲取字元響應流,使用該流可以向客戶端輸出響應資訊。例如response.getWriter().print(“<h1>Hello JavaWeb!</h1>”)

l ServletOutputStream getOutputStream():獲取位元組響應流,當需要向客戶端響應位元組資料時,需要使用這個流,例如要向客戶端響應圖片;

l void setCharacterEncoding(String encoding):用來設定字元響應流的編碼,例如在呼叫setCharacterEncoding(“utf-8”);之後,再response.getWriter()獲取字元響應流物件,這時的響應流的編碼為utf-8,使用response.getWriter()輸出的中文都會轉換成utf-8編碼後傳送給客戶端;

l void setHeader(String name, String value):向客戶端新增響應頭資訊,例如setHeader(“Refresh”, “3;url=http://www.itcast.cn”),表示3秒後自動重新整理到http://www.itcast.cn

l void setContentType(String contentType):該方法是setHeader(“content-type”, “xxx”)的簡便方法,即用來新增名為content-type響應頭的方法。content-type響應頭用來設定響應資料的MIME型別,例如要向客戶端響應jpg的圖片,那麼可以setContentType(“image/jepg”),如果響應資料為文字型別,那麼還要臺同時設定編碼,例如setContentType(“text/html;chartset=utf-8”)表示響應資料型別為文字型別中的html型別,並且該方法會呼叫setCharacterEncoding(“utf-8”)方法;

l void sendError(int code, String errorMsg):向客戶端傳送狀態碼,以及錯誤訊息。例如給客戶端傳送404response(404, “您要查詢的資源不存在!”)

2.1ServletConfig

ServletConfig物件對應web.xml檔案中的<servlet>元素。例如你想獲取當前Servletweb.xml檔案中的配置名,那麼可以使用servletConfig.getServletName()方法獲取!

ServletConfig物件是由伺服器建立的,然後傳遞給Servletinit()方法,你可以在init()方法中使用它!

l String getServletName():獲取Servletweb.xml檔案中的配置名稱,即<servlet-name>指定的名稱;

l ServletContext getServletContext():用來獲取ServletContext物件,ServletContext會在後面講解;

l String getInitParameter(String name):用來獲取在web.xml中配置的初始化引數,通過引數名來獲取引數值;

l Enumeration getInitParameterNames():用來獲取在web.xml中配置的所有初始化引數名稱;

<servlet>元素中還可以配置初始化引數:

  <servlet>

    <servlet-name>One</servlet-name>

    <servlet-class>cn.itcast.servlet.OneServlet</servlet-class>

    <init-param>

       <param-name>paramName1</param-name>

         <param-value>paramValue1</param-value>

    </init-param>

    <init-param>

         <param-name>paramName2</param-name>

         <param-value>paramValue2</param-value>

    </init-param>

  </servlet>

OneServlet中,可以使用ServletConfig物件的getInitParameter()方法來獲取初始化引數,例如:

String value1 = servletConfig.getInitParameter(“paramName1”);//獲取到paramValue1

GenericServlet

1GenericServlet概述

GenericServletServlet介面的實現類,我們可以通過繼承GenericServlet來編寫自己的Servlet。下面是GenericServlet類的原始碼:

GenericServlet.java

public abstract class GenericServlet implements Servlet, ServletConfig,

        java.io.Serializable {

    private static final long serialVersionUID = 1L;

    private transient ServletConfig config;

    public GenericServlet() {}

    @Override

    public void destroy() {}

    @Override

    public String getInitParameter(String name) {

        return getServletConfig().getInitParameter(name);

    }

    @Override

    public Enumeration<String> getInitParameterNames() {

        return getServletConfig().getInitParameterNames();

    }

    @Override

    public ServletConfig getServletConfig() {

        return config;

    }

    @Override

    public ServletContext getServletContext() {

        return getServletConfig().getServletContext();

    }

    @Override

    public String getServletInfo() {

        return "";

    }

    @Override

    public void init(ServletConfig config) throws ServletException {

        this.config = config;

        this.init();

    }

    public void init() throws ServletException {}

    public void log(String msg) {

        getServletContext().log(getServletName() + ": " + msg);

    }

    public void log(String message, Throwable t) {

        getServletContext().log(getServletName() + ": " + message, t);

    }

    @Override

    public abstract void service(ServletRequest req, ServletResponse res)

            throws ServletException, IOException;

    @Override

    public String getServletName() {

        return config.getServletName();

    }

}

2GenericServletinit()方法

GenericServlet中,定義了一個ServletConfig config例項變數,並在init(ServletConfig)方法中把引數ServletConfig賦給了例項變數。然後在該類的很多方法中使用了例項變數config

如果子類覆蓋了GenericServletinit(StringConfig)方法,那麼this.config=config這一條語句就會被覆蓋了,也就是說GenericServlet的例項變數config的值為null,那麼所有依賴config的方法都不能使用了。如果真的希望完成一些初始化操作,那麼去覆蓋GenericServlet提供的init()方法,它是沒有引數的init()方法,它會在init(ServletConfig)方法中被呼叫。

3 實現了ServletConfig介面

GenericServlet還實現了ServletConfig介面,所以可以直接呼叫getInitParameter()getServletContext()ServletConfig的方法。

HttpServlet

1HttpServlet概述

HttpServlet類是GenericServlet的子類,它提供了對HTTP請求的特殊支援,所以通常我們都會通過繼承HttpServlet來完成自定義的Servlet

2HttpServlet覆蓋了service()方法

HttpServlet類中提供了service(HttpServletRequest,HttpServletResponse)方法,這個方法是HttpServlet自己的方法,不是從Servlet繼承來的。在HttpServletservice(ServletRequest,ServletResponse)方法中會把ServletRequestServletResponse強轉成HttpServletRequestHttpServletResponse,然後呼叫service(HttpServletRequest,HttpServletResponse)方法,這說明子類可以去覆蓋service(HttpServletRequest,HttpServletResponse)方法即可,這就不用自己去強轉請求和響應物件了。

其實子類也不用去覆蓋service(HttpServletRequest,HttpServletResponse)方法,因為HttpServlet還要做另一步簡化操作,下面會介紹。

HttpServlet.java

public abstract class HttpServlet extends GenericServlet {

    protected void service(HttpServletRequest req, HttpServletResponse resp)

        throws ServletException, IOException {

        ……

}

    @Override

    public void service(ServletRequest req, ServletResponse res)

        throws ServletException, IOException {

        HttpServletRequest  request;

        HttpServletResponse response;

        try {

            request = (HttpServletRequest) req;

            response = (HttpServletResponse) res;

        } catch (ClassCastException e) {

            throw new ServletException("non-HTTP request or response");

        }

        service(request, response);

}

……

}

3doGet()doPost()

HttpServletservice(HttpServletRequest,HttpServletResponse)方法會去判斷當前請求是GET還是POST,如果是GET請求,那麼會去呼叫本類的doGet()方法,如果是POST請求會去呼叫doPost()方法,這說明我們在子類中去覆蓋doGet()doPost()方法即可。

public class AServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletRespo