1. 程式人生 > 實用技巧 >2.servlet常見的介面和方法

2.servlet常見的介面和方法

1、常見介面:

2、ServletRequset介面

Servlet容器對於接受到的每一個Http請求,都會建立一個ServletRequest物件,並把這個物件傳遞給Servlet的Sevice( )方法。其中,ServletRequest物件內封裝了關於這個請求的許多詳細資訊。

常用的方法:

public interface ServletRequest {
 
    Map<String, String[]> getParameterMap();//返回請求主體引數的key-value
 
    String getContentType();//返回主體的MIME型別
String getParameter(String var1);//返回請求引數的值 }

3、ServletResponse介面

javax.servlet.ServletResponse介面表示一個Servlet響應,在呼叫Servlet的Service( )方法前,Servlet容器會先建立一個ServletResponse物件,並把它作為第二個引數傳給Service( )方法。ServletResponse隱藏了向瀏覽器傳送響應的複雜過程。

方法:

public interface ServletResponse {
    String getCharacterEncoding();

    String getContentType();

    ServletOutputStream getOutputStream() 
throws IOException; PrintWriter getWriter() throws IOException; void setCharacterEncoding(String var1); void setContentLength(int var1); void setContentLengthLong(long var1); void setContentType(String var1); void setBufferSize(int var1); int getBufferSize();
void flushBuffer() throws IOException; void resetBuffer(); boolean isCommitted(); void reset(); void setLocale(Locale var1); Locale getLocale(); }

其中的getWriter()方法,它返回了一個可以向客戶端傳送文字的的Java.io.PrintWriter物件。預設情況下,PrintWriter物件使用ISO-8859-1編碼(該編碼在輸入中文時會發生亂碼)

在向客戶端傳送響應時,大多數都是使用該物件向客戶端傳送HTML。

還有一個方法也可以用來向瀏覽器傳送資料,它就是getOutputStream,從名字就可以看出這是一個二進位制流物件,因此這個方法是用來發送二進位制資料的。

在傳送任何HTML之前,應該先呼叫setContentType()方法,設定響應的內容型別,並將“text/html”作為一個引數傳入,這是在告訴瀏覽器響應的內容型別為HTML,需要以HTML的方法解釋響應內容而不是普通的文字,或者也可以加上“charset=UTF-8”改變響應的編碼方式以防止發生中文亂碼現象。

4、ServletConfig介面

當Servlet容器初始化Servlet時,Servlet容器會給Servlet的init( )方式傳入一個ServletConfig物件。

public interface ServletConfig {
    String getServletName();//獲取該servlet在web.xml中配置的name值

    ServletContext getServletContext();//獲取應用上下文物件

    String getInitParameter(String var1);//獲取該servlet的初始化引數

    Enumeration<String> getInitParameterNames();//獲取該servlet的name集合
}

5、ServletContext物件

ServletContext物件表示Servlet應用程式。每個Web應用程式都有且只有一個ServletContext象。在將一個應用程式同時部署到多個容器的分散式環境中,每臺Java虛擬機器上的Web應用都會有一個ServletContext物件。

servletConfig.getServletContext();獲得ServletContext物件

ServletContext物件物件的作用?

有了ServletContext物件,就可以共享從應用程式中的所有資料處訪問到的資訊,並且可以動態註冊Web物件。前者將物件儲存在ServletContext中的一個內部Map中。儲存在ServletContext中的物件被稱作屬性。

屬性常見方法:

Object getAttribute(String var1);//根據name獲取屬性值
 
Enumeration<String> getAttributeNames();//獲取屬性的name集合
 
void setAttribute(String var1, Object var2);//設定name屬性的值
 
void removeAttribute(String var1);//根據name值移除對應屬性

6、GenericServlet抽象類

編寫Servlet一直是通過實現Servlet介面來編寫的,但是,使用這種方法,則必須要實現Servlet介面中定義的所有的方法,即使有一些方法中沒有任何東西也要去實現,並且還需要自己手動的維護ServletConfig這個物件的引用。因此,這樣去實現Servlet是比較麻煩的。

GenericServlet抽象類的出現很好的解決了這個問題。本著儘可能使程式碼簡潔的原則,GenericServlet實現了Servlet和ServletConfig介面,下面是GenericServlet抽象類的具體程式碼:

public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
    private static final long serialVersionUID = 1L;
    private transient ServletConfig config;

    public GenericServlet() {
    }

    public void destroy() {
    }

    public String getInitParameter(String name) {
        return this.getServletConfig().getInitParameter(name);
    }

    public Enumeration<String> getInitParameterNames() {
        return this.getServletConfig().getInitParameterNames();
    }

    public ServletConfig getServletConfig() {
        return this.config;
    }

    public ServletContext getServletContext() {
        return this.getServletConfig().getServletContext();
    }

    public String getServletInfo() {
        return "";
    }

    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }

    public void init() throws ServletException {
    }

    public void log(String msg) {
        this.getServletContext().log(this.getServletName() + ": " + msg);
    }

    public void log(String message, Throwable t) {
        this.getServletContext().log(this.getServletName() + ": " + message, t);
    }

    public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

    public String getServletName() {
        return this.config.getServletName();
    }
}

GenericServlet抽象類相比於直接實現Servlet介面的優點:

1.為Servlet介面中的所有方法提供了預設的實現,則程式設計師需要什麼就直接改什麼,不再需要把所有的方法都自己實現了。

2.提供方法,包圍ServletConfig物件中的方法。

3.將init( )方法中的ServletConfig引數賦給了一個內部的ServletConfig引用從而來儲存ServletConfig物件,不需要程式設計師自己去維護ServletConfig了。

多出的方法init()的作用:

public void init() throws ServletException {
}

為什麼已經有了一個init(ServletConfig config)方法,還要再提供一個init()空參的方法呢?

抽象類是無法直接產生例項的,需要另一個類去繼承這個抽象類,那麼就會發生方法覆蓋的問題,如果在類中覆蓋了GenericServlet抽象類的init()方法,那麼程式設計師就必須手動的去維護ServletConfig物件了,還得呼叫super.init(servletConfig)方法去呼叫父類GenericServlet的初始化方法來儲存ServletConfig物件,這樣會給程式設計師帶來很大的麻煩。GenericServlet提供的第二個不帶引數的init( )方法,就是為了解決上述問題的。

這個不帶引數的init()方法,是在ServletConfig物件被賦給ServletConfig引用後,由第一個帶引數的init(ServletConfig servletconfig)方法呼叫的,那麼這意味著,當程式設計師如果需要覆蓋這個GenericServlet的初始化方法,則只需要覆蓋那個不帶引數的init( )方法就好了,此時,servletConfig物件仍然有GenericServlet儲存著。

GenericServlet中,從servlet介面帶來的init(ServletConfig config)對它進行重寫時,如果忘了呼叫super.init(config)時,就會出現空指標異常,為了解決這樣的情況,GenericServlet中於是有了一個無參的init()方法

如何沒有空參init()方法的話,繼承MygenericServlet 的類 要想在初始化的時候做些事,就必須
呼叫super.init(servletConfig) ————麻煩;
或者 複寫掉父類的方法————導致父類的初始化操作無效;

7、HttpServlet抽象類(常用)

HttpServlet是由GenericServlet抽象類擴充套件而來的,HttpServlet抽象類的宣告如下所示:

public abstract class HttpServlet extends GenericServlet 

使用HttpServlet抽象類時,還需要藉助分別代表Servlet請求和Servlet響應的HttpServletRequest和HttpServletResponse物件

public interface HttpServletRequest extends ServletRequest
public interface HttpServletResponse extends ServletResponse

HttpServlet抽象類覆蓋了GenericServlet抽象類中的Service( )方法,並且在該方法中呼叫了自己獨有的Service(HttpServletRequest request,HttpServletResponse方法。

    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {//覆蓋的SenericServlet類的service方法
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        } catch (ClassCastException var6) {
            throw new ServletException(lStrings.getString("http.non_http"));
        }

        this.service(request, response);//自己重寫的service方法
    }

HttpServlet中的service方法把接收到的ServletRequsest型別的物件轉換成了HttpServletRequest型別的物件,把ServletResponse型別的物件轉換成了HttpServletResponse型別的物件

自己重寫的service方法程式碼:

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader("If-Modified-Since");
                } catch (IllegalArgumentException var9) {
                    ifModifiedSince = -1L;
                }

                if (ifModifiedSince < lastModified / 1000L * 1000L) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }

    }
View Code

我們會發現在service方法中還是沒有任何的服務邏輯,但是卻在解析HttpServletRequest中的方法引數,並呼叫以下方法之一:doGet,doPost,doHead,doPut,doTrace,doOptions和doDelete。這7種方法中,每一種方法都表示一個Http方法。doGet和doPost是最常用的。所以,如果我們需要實現具體的服務邏輯,不再需要覆蓋service方法了,只需要覆蓋doGet或者doPost就好了。

總之,HttpServlet有兩個特性是GenericServlet所不具備的:

1.不用覆蓋service方法,而是覆蓋doGet或者doPost方法。在少數情況,還會覆蓋其他的5個方法。

2.使用的是HttpServletRequest和HttpServletResponse物件。

8、HttpServletRequest介面

HttpServletRequest表示Http環境中的Servlet請求。它擴充套件於javax.servlet.ServletRequest介面,並添加了幾個方法。方法頭:

public interface HttpServletRequest extends ServletRequest

常用方法:

    String getHeader(String var1);//返回指定http標題的值

    Cookie[] getCookies();//返回一個cookie物件的陣列

    String getContextPath();//返回請求上下文的請求URL部分

    String getQueryString();//返回請求URL中的查詢字串

    HttpSession getSession();////返回與這個請求相關的會話物件

    String getMethod();//返回生成這個請求HTTP的方法名稱

9、HttpServletRequest內封裝的請求

9.1、通過request獲得請求行

假設查詢字串為:username=zhangsan&password=123

獲得客戶端的請求方式:String getMethod()

獲得請求的資源:

String getRequestURI()

StringBuffer getRequestURL()

String getContextPath() ---web應用的名稱

String getQueryString() ---- get提交url地址後的引數字串

9.2、通過request獲得請求頭

long getDateHeader(String name)

String getHeader(String name)

Enumeration getHeaderNames()

Enumeration getHeaders(String name)

int getIntHeader(String name)

referer頭的作用:執行該此訪問的的來源,做防盜鏈

9.3、通過request獲得請求體

請求體中的內容是通過post提交的請求引數,格式是:

username=zhangsan&password=123&hobby=football&hobby=basketball

key ---------------------- value

username [zhangsan]

password [123]

hobby [football,basketball]

以上面引數為例,通過一下方法獲得請求引數:

String getParameter(String name)

String[] getParameterValues(String name)

Enumeration getParameterNames()

Map<String,String[]> getParameterMap()

注意:get請求方式的請求引數 上述的方法一樣可以獲得。

9.4、Request亂碼問題的解決方法

在前面我們講過,在service中使用的編碼解碼方式預設為:ISO-8859-1編碼,但此編碼並不支援中文,因此會出現亂碼問題,所以我們需要手動修改編碼方式為UTF-8編碼,才能解決中文亂碼問題,下面是發生亂碼的具體細節:

解決post提交方式的亂碼:request.setCharacterEncoding("UTF-8");

解決get提交的方式的亂碼:

parameter = newString(parameter.getbytes("iso8859-1"),"utf-8");

10、HttpServletResponse介面

在Service API中,定義了一個HttpServletResponse介面,它繼承自ServletResponse介面,專門用來封裝HTTP響應訊息。 由於HTTP請求訊息分為狀態行,響應訊息頭,響應訊息體三部分,因此,在HttpServletResponse介面中定義了向客戶端傳送響應狀態碼,響應訊息頭,響應訊息體的方法。

10.1、通過Response設定響應

void addCookie(Cookie var1);//給這個響應新增一個cookie

void addHeader(String var1, String var2);//給這個請求新增一個響應頭

void sendRedirect(String var1) throws IOException;//傳送一條響應碼,講瀏覽器跳轉到指定的位置

void setStatus(int var1);//設定響應行的狀態碼

addHeader(String name, String value)

addIntHeader(String name, int value)

addDateHeader(String name, long date)

setHeader(String name, String value)

setDateHeader(String name, long date)

setIntHeader(String name, int value)

其中,add表示新增,而set表示設定

PrintWriter getWriter()

獲得字元流,通過字元流的write(String s)方法可以將字串設定到response 緩衝區中,隨後Tomcat會將response緩衝區中的內容組裝成Http響應返回給瀏覽器端。

ServletOutputStreamgetOutputStream()

獲得位元組流,通過該位元組流的write(byte[] bytes)可以向response緩衝區中寫入位元組,再由Tomcat伺服器將位元組內容組成Http響應返回給瀏覽器。

注意:雖然response物件的getOutSream()和getWriter()方法都可以傳送響應訊息體,但是他們之間相互排斥,不可以同時使用,否則會發生異常。

10.2、Response的亂碼問題

原因:response緩衝區的預設編碼是iso8859-1,此碼錶中沒有中文。所以需要更改response的編碼方式:

httpServletResponse.setCharacterEncoding("UTF-8");

通過更改response的編碼方式為UTF-8,仍然無法解決亂碼問題,因為傳送端服務端雖然改變了編碼方式為UTF-8,但是接收端瀏覽器端仍然使用GB2312編碼方式解碼,還是無法還原正常的中文,因此還需要告知瀏覽器端使用UTF-8編碼去解碼。

httpServletResponse.setHeader("Content-Type","text/html;charset=UTF-8");

上面通過呼叫兩個方式分別改變服務端對於Response的編碼方式以及瀏覽器的解碼方式為同樣的UTF-8編碼來解決編碼方式不一樣發生亂碼的問題。

response.setContentType("text/html;charset=UTF-8")這個方法包含了上面的兩個方法的呼叫,因此在實際的開發中,只需要呼叫一個response.setContentType("text/html;charset=UTF-8")方法即可。

10.3、Response的工作流程

11、Servlet的工作流程

12、編寫第一個Servlet

寫一個簡單的使用者名稱,密碼的登入介面的html檔案:

  <form action="/servlet/form" method="post">
    <span>使用者名稱</span><input type="text" name="username"><br>
    <span>密碼</span><input type="password" name="password"><br>
    <input type="submit" name="submit">
  </form>

寫一個Servlet用來接收處理表單傳送過來的請求,這個Servlet的名稱就叫做HiHttpServlet:

public class HiHttpServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //設定請求的編碼格式為UTF-8編碼,否則發生中文亂碼現象
        request.setCharacterEncoding("UTF-8");
        System.out.println(request.getMethod());//獲取請求的方式
        System.out.println(request.getRequestURL());//獲取請求的連結
        System.out.println(request.getRequestURI());//獲取請求的URI
        System.out.println(request.getContextPath());//獲取web應用名稱
        System.out.println(request.getParameterMap());//獲取請求的引數map集合(get和post都可以)
        System.out.println(request.getQueryString());//獲取get提交url地址後的引數字串(get方式的能獲取到)
        System.out.println("username:"+request.getParameter("username"));
        System.out.println("password:"+request.getParameter("password"));

        //設定響應的編碼格式為UTF-8編碼,否則發生中文亂碼現象
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println("你好,HiHttpServlet");
    }
}

web.xml:

    <servlet>
        <servlet-name>hiHttpServlet</servlet-name>
        <servlet-class>com.servlet.javaweb.HiHttpServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>hiHttpServlet</servlet-name>
        <url-pattern>/form</url-pattern>
    </servlet-mapping>

結果:

功能點小結:

1. Servlet 的 HelloWorld
1). 建立一個 Servlet 介面的實現類. 
public class HelloServlet implements Servlet

2). 在 web.xml 檔案中配置和對映這個 Servlet

    <!-- 配置和對映 Servlet -->
    <servlet>
        <!-- Servlet 註冊的名字 -->
        <servlet-name>helloServlet</servlet-name>
        <!-- Servlet 的全類名 -->
        <servlet-class>com.atguigu.javaweb.HelloServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <!-- 需要和某一個 servlet 節點的 serlvet-name 子節點的文字節點一致 -->
        <servlet-name>helloServlet</servlet-name>
        <!-- 對映具體的訪問路徑: / 代表當前 WEB 應用的根目錄. -->
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

2. Servlet 容器: 執行 Servlet、JSP、Filter 等的軟體環境. 
1). 可以來建立 Servlet, 並呼叫 Servlet 的相關生命週期方法. 
2). JSP, Filter, Listener, Tag ...

3. Servlet 生命週期的方法: 以下方法都是由 Serlvet 容器負責呼叫. 
1). 構造器: 只被呼叫一次. 只有第一次請求 Servlet 時, 建立 Servlet 的例項. 呼叫構造器. 
這說明 Serlvet 的單例項的!
2). init 方法: 只被呼叫一次. 在建立好例項後立即被呼叫. 用於初始化當前 Servlet. 
3). service: 被多次呼叫. 每次請求都會呼叫 service 方法. 實際用於響應請求的. 
4). destroy: 只被呼叫一次. 在當前 Servlet 所在的 WEB 應用被解除安裝前呼叫. 用於釋放當前 Servlet 所佔用的資源. 

4. load-on-startup 引數:
1).  配置在 servlet 節點中:

    <servlet>
        <!-- Servlet 註冊的名字 -->
        <servlet-name>secondServlet</servlet-name>
        <!-- Servlet 的全類名 -->
        <servlet-class>com.atguigu.javaweb.SecondServlet</servlet-class>
        <!-- 可以指定 Servlet 被建立的時機 -->
        <load-on-startup>2</load-on-startup>
    </servlet>
    
2). load-on-startup: 可以指定 Serlvet 被建立的時機. 若為負數, 則在第一次請求時被建立.若為 0 或正數, 則在當前 WEB 應用被
Serlvet 容器載入時建立例項, 且陣列越小越早被建立. 

5. 關於 serlvet-mapping:

1). 同一個Servlet可以被對映到多個URL上,即多個 <servlet-mapping> 元素的<servlet-name>子元素的設定值可以是同一個
Servlet的註冊名。 

2). 在Servlet對映到的URL中也可以使用 * 萬用字元,但是隻能有兩種固定的格式:
一種格式是“*.副檔名”,另一種格式是以正斜槓(/)開頭並以“/*”結尾。

<servlet-mapping>
    <servlet-name>secondServlet</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

OR

<servlet-mapping>
    <servlet-name>secondServlet</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>

注意: 以下的既帶 / 又帶副檔名的不合法. 

<servlet-mapping>
    <servlet-name>secondServlet</servlet-name>
    <url-pattern>/*.action</url-pattern>
</servlet-mapping>

6. ServletConfig: 封裝了 Serlvet 的配置資訊, 並且可以獲取 ServletContext 物件

1). 配置 Serlvet 的初始化引數

    <servlet>
        <servlet-name>helloServlet</servlet-name>
        <servlet-class>com.atguigu.javaweb.HelloServlet</servlet-class>
        
        <!-- 配置 Serlvet 的初始化引數。 且節點必須在 load-on-startup 節點的前面 -->
        <init-param>
            <!-- 引數名 -->
            <param-name>user</param-name>
            <!-- 引數值 -->
            <param-value>root</param-value>
        </init-param>
        
        <init-param>
            <param-name>password</param-name>
            <param-value>1230</param-value>
        </init-param>
        
        <load-on-startup>-1</load-on-startup>
        
    </servlet>

2). 獲取初始化引數: 

    > getInitParameter(String name): 獲取指定引數名的初始化引數
    > getInitParameterNames(): 獲取引數名組成的 Enumeration 物件. 
    
    String user = servletConfig.getInitParameter("user");
    System.out.println("user: " + user);
    
    Enumeration<String> names = servletConfig.getInitParameterNames();
    while(names.hasMoreElements()){
        String name = names.nextElement();
        String value = servletConfig.getInitParameter(name);
        System.out.println("^^" + name + ": " + value);
    }

3). 獲取 Serlvet 的配置名稱(瞭解)

7. ServletContext

1). 可以由  SerlvetConfig 獲取:

ServletContext servletContext = servletConfig.getServletContext();


2). 該物件代表當前 WEB 應用: 可以認為 SerlvetContext 是當前 WEB 應用的一個大管家. 可以從中獲取到當前 WEB 應用的各個方面的資訊.

①. 獲取當前 WEB 應用的初始化引數

設定初始化引數: 可以為所有的 Servlet 所獲取, 而 Servlet 的初始化引數只用那個 Serlvet 可以獲取. 

<!-- 配置當前 WEB 應用的初始化引數 -->
<context-param>
    <param-name>driver</param-name>
    <param-value>com.mysql.jdbc.Driver</param-value>
</context-param>

方法:

getInitParameter
getInitParameterNames    

程式碼:

ServletContext servletContext = servletConfig.getServletContext();
        
String driver = servletContext.getInitParameter("driver");
System.out.println("driver:" + driver);

Enumeration<String> names2 = servletContext.getInitParameterNames();
while(names2.hasMoreElements()){
    String name = names2.nextElement();
    System.out.println("-->" + name); 
}

②. 獲取當前 WEB 應用的某一個檔案在伺服器上的絕對路徑, 而不是部署前的路徑

getRealPath(String path);

程式碼:

String realPath = servletContext.getRealPath("/note.txt");
System.out.println(realPath);

③. 獲取當前 WEB 應用的名稱: 

getContextPath()

程式碼:

String contextPath = servletContext.getContextPath();
System.out.println(contextPath); 

④. 獲取當前 WEB 應用的某一個檔案對應的輸入流. 

getResourceAsStream(String path): path 的 / 為當前 WEB 應用的根目錄. 

程式碼:

InputStream is2 = servletContext.getResourceAsStream("/WEB-INF/classes/jdbc.properties");
    
⑤. 和 attribute 相關的幾個方法:     

8. GET 請求和 POST 請求:

1). 使用GET方式傳遞引數:

①. 在瀏覽器位址列中輸入某個URL地址或單擊網頁上的一個超連結時,瀏覽器發出的HTTP請求訊息的請求方式為GET。 
②. 如果網頁中的<form>表單元素的 method 屬性被設定為了“GET”,瀏覽器提交這個FORM表單時生成的HTTP請求訊息的請求方式也為GET。 
③. 使用GET請求方式給WEB伺服器傳遞引數的格式:  

http://www.atguigu.com/counter.jsp?name=lc&password=123

④. 使用GET方式傳送的資料量一般限制在 1KB 以下。 

2). 使用 POST 方式傳遞引數:

①. POST 請求方式主要用於向 WEB 伺服器端程式提交 FORM 表單中的資料: form 表單的 method 置為 POST
②. POST 方式將各個表單欄位元素及其資料作為 HTTP 訊息的實體內容傳送給 WEB 伺服器,傳送的資料量要比使用GET方式傳送的資料量大得多。  

POST /counter.jsp HTTP/1.1
referer: http://localhost:8080/Register.html
content-type: application/x-www-form-urlencoded
host: localhost:8080
content-length: 43

name=zhangsan&password=123              --請求體中傳遞引數. 

9. 如何在 Serlvet 中獲取請求資訊:

1). Servlet 的 service() 方法用於應答請求: 因為每次請求都會呼叫 service() 方法

public void service(ServletRequest request, ServletResponse response)
            throws ServletException, IOException
            
ServletRequest: 封裝了請求資訊. 可以從中獲取到任何的請求資訊.
ServletResponse: 封裝了響應資訊, 如果想給使用者什麼響應, 具體可以使用該介面的方法實現. 

這兩個介面的實現類都是伺服器給予實現的, 並在伺服器呼叫 service 方法時傳入. 

2). ServletRequest: 封裝了請求資訊. 可以從中獲取到任何的請求資訊.

①. 獲取請求引數: 

    > String getParameter(String name): 根據請求引數的名字, 返回引數值. 
    若請求引數有多個值(例如 checkbox), 該方法只能獲取到第一個提交的值. 

    > String[] getParameterValues(String name): 根據請求引數的名字, 返回請求引數對應的字串陣列. 
    
    > Enumeration getParameterNames(): 返回引數名對應的 Enumeration 物件, 
    類似於 ServletConfig(或 ServletContext) 的 getInitParameterNames() 方法. 

    > Map getParameterMap(): 返回請求引數的鍵值對: key: 引數名,  value: 引數值, String 陣列型別. 

②. 獲取請求的 URI:

    HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        
    String requestURI = httpServletRequest.getRequestURI();
    System.out.println(requestURI); //  /day_29/loginServlet

③. 獲取請求方式: 

    String method = httpServletRequest.getMethod();
    System.out.println(method); //GET
    
④. 若是一個 GET 請求, 獲取請求引數對應的那個字串, 即 ? 後的那個字串. 

    String queryString = httpServletRequest.getQueryString();
    System.out.println(queryString); //user=atguigu&password=123456&interesting=game&interesting=party&interesting=shopping

⑤. 獲取請求的 Serlvet 的對映路徑 
  
   String servletPath = httpServletRequest.getServletPath();
   System.out.println(servletPath);  //  /loginServlet
   
⑥. 和 attribute 相關的幾個方法:        

3). HttpServletRequest: 是 SerlvetRequest 的子介面. 針對於 HTTP 請求所定義. 裡邊包含了大量獲取 HTTP 請求相關的方法. 
 
4). ServletResponse: 封裝了響應資訊, 如果想給使用者什麼響應, 具體可以使用該介面的方法實現. 

①. *getWriter(): 返回 PrintWriter 物件. 呼叫該物件的 print() 方法, 將把 print() 中的引數直接列印
到客戶的瀏覽器上. 

②. 設定響應的內容型別: response.setContentType("application/msword");

③. void sendRedirect(String location): 請求的重定向. (此方法為 HttpServletResponse 中定義.)

參考部落格:https://blog.csdn.net/qq_19782019/article/details/80292110