天天看點

request與response

請求響應流程圖

response

response概述

response是Servlet.service方法的一個參數,類型為javax.servlet.http.HttpServletResponse。在用戶端發出每個請求時,伺服器都會建立一個response對象,并傳入給Servlet.service()方法。response對象是用來對用戶端進行響應的,這說明在service()方法中使用response對象可以完成對用戶端的響應工作。

response對象的功能分為以下四種:

設定響應頭資訊;

發送狀态碼;

設定響應正文;

重定向;

2 response響應正文

response是響應對象,向用戶端輸出響應正文(響應體)可以使用response的響應流,repsonse一共提供了兩個響應流對象:

PrintWriter out = response.getWriter():擷取字元流;

ServletOutputStream out = response.getOutputStream():擷取位元組流;

當然,如果響應正文内容為字元,那麼使用response.getWriter(),如果響應内容是位元組,例如下載下傳時,那麼可以使用response.getOutputStream()。

注意,在一個請求中,不能同時使用這兩個流!也就是說,要麼你使用repsonse.getWriter(),要麼使用response.getOutputStream(),但不能同時使用這兩個流。不然會抛出IllegalStateException異常。

2.1 字元響應流

字元編碼

在使用response.getWriter()時需要注意預設字元編碼為ISO-8859-1,如果希望設定字元流的字元編碼為utf-8,可以使用response.setCharaceterEncoding(“utf-8”)來設定。這樣可以保證輸出給用戶端的字元都是使用UTF-8編碼的!

但用戶端浏覽器并不知道響應資料是什麼編碼的!如果希望通知用戶端使用UTF-8來解讀響應資料,那麼還是使用response.setContentType("text/html;charset=utf-8")方法比較好,因為這個方法不隻會調用response.setCharaceterEncoding(“utf-8”),還會設定content-type響應頭,用戶端浏覽器會使用content-type頭來解讀響應資料。

緩沖區

response.getWriter()是PrintWriter類型,是以它有緩沖區,緩沖區的預設大小為8KB。也就是說,在響應資料沒有輸出8KB之前,資料都是存放在緩沖區中,而不會立刻發送到用戶端。當Servlet執行結束後,伺服器才會去重新整理流,使緩沖區中的資料發送到用戶端。

如果希望響應資料馬上發送給用戶端:

向流中寫入大于8KB的資料;

調用response.flushBuffer()方法來手動重新整理緩沖區;

3 設定響應頭資訊

  可以使用response對象的setHeader()方法來設定響應頭!使用該方法設定的響應頭最終會發送給用戶端浏覽器!

response.setHeader(“content-type”, “text/html;charset=utf-8”):設定content-type響應頭,該頭的作用是告訴浏覽器響應内容為html類型,編碼為utf-8。而且同時會設定response的字元流編碼為utf-8,即response.setCharaceterEncoding(“utf-8”);

response.setHeader("Refresh","5; URL=http://www.itcast.cn"):5秒後自動跳轉到智首頁。

4 設定狀态碼及其他方法

response.setContentType("text/html;charset=utf-8"):等同與調用response.setHeader(“content-type”, “text/html;charset=utf-8”);

response.setCharacterEncoding(“utf-8”):設定字元響應流的字元編碼為utf-8;

response.setStatus(200):設定狀态碼;

response.sendError(404, “您要查找的資源不存在”):當發送錯誤狀态碼時,Tomcat會跳轉到固定的錯誤頁面去,但可以顯示錯誤資訊。

5 重定向

5.1 什麼是重定向

當你通路http://www.sun.com時,你會發現浏覽器位址欄中的URL會變成http://www.oracle.com/us/sun/index.htm,這就是重定向了。

重定向是伺服器通知浏覽器去通路另一個位址,即再發出另一個請求。

5.2 完成重定向

響應碼為200表示響應成功,而響應碼為302表示重定向。是以完成重定向的第一步就是設定響應碼為302。

因為重定向是通知浏覽器再第二個請求,是以浏覽器需要知道第二個請求的URL,是以完成重定向的第二步是設定Location頭,指定第二個請求的URL位址。

public class AServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        response.setStatus(302);

        response.setHeader("Location", "http://www.baidu.com");

    }

}

  上面代碼的作用是:當通路AServlet後,會通知浏覽器重定向到智首頁。用戶端浏覽器解析到響應碼為302後,就知道伺服器讓它重定向,是以它會馬上擷取響應頭Location,然發出第二個請求。

5.3 便捷的重定向方式

public class AServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        response.sendRedirect("http://www.baidu.com");

    }

}

response.sendRedirect()方法會設定響應頭為302,以設定Location響應頭。

如果要重定向的URL是在同一個伺服器内,那麼可以使用相對路徑,例如:

public class AServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        response.sendRedirect("/hello/BServlet");

    }

}

重定向的URL位址為:http://localhost:8080/hello/BServlet。

5.4 重定向小結

重定向是兩次請求;

重定向的URL可以是其他應用,不局限于目前應用;

重定向的響應頭為302,并且必須要有Location響應頭;

重定向就不要再使用response.getWriter()或response.getOutputStream()輸出資料,不然可能會出現異常;

request

1 request概述

request是Servlet.service()方法的一個參數,類型為javax.servlet.http.HttpServletRequest。在用戶端發出每個請求時,伺服器都會建立一個request對象,并把請求資料封裝到request中,然後在調用Servlet.service()方法時傳遞給service()方法,這說明在service()方法中可以通過request對象來擷取請求資料。

request的功能可以分為以下幾種:

封裝了請求頭資料;

封裝了請求正文資料,如果是GET請求,那麼就沒有正文;

request是一個域對象,可以把它當成Map來添加擷取資料;

request提供了請求轉發和請求包含功能。

2 request域方法

request是域對象!在JavaWeb中一共四個域對象,其中ServletContext就是域對象,它在整個應用中隻建立一個ServletContext對象。request其中一個,request可以在一個請求中共享資料。

一個請求會建立一個request對象,如果在一個請求中經曆了多個Servlet,那麼多個Servlet就可以使用request來共享資料。現在我們還不知道如何在一個請求中經曆之個Servlet,後面在學習請求轉發和請求包含後就知道了。

下面是request的域方法:

void setAttribute(String name, Object value):用來存儲一個對象,也可以稱之為存儲一個域屬性,例如:servletContext.setAttribute(“xxx”, “XXX”),在request中儲存了一個域屬性,域屬性名稱為xxx,域屬性的值為XXX。請注意,如果多次調用該方法,并且使用相同的name,那麼會覆寫上一次的值,這一特性與Map相同;

Object getAttribute(String name):用來擷取request中的資料,目前在擷取之前需要先去存儲才行,例如:String value = (String)request.getAttribute(“xxx”);,擷取名為xxx的域屬性;

void removeAttribute(String name):用來移除request中的域屬性,如果參數name指定的域屬性不存在,那麼本方法什麼都不做;

Enumeration getAttributeNames():擷取所有域屬性的名稱;

3 request擷取請求頭資料

request與請求頭相關的方法有:

String getHeader(String name):擷取指定名稱的請求頭;

Enumeration getHeaderNames():擷取所有請求頭名稱;

int getIntHeader(String name):擷取值為int類型的請求頭。

4 request擷取請求相關的其它方法

request中還提供了與請求相關的其他方法,有些方法是為了我們更加便捷的方法請求頭資料而設計,有些是與請求URL相關的方法。

int getContentLength():擷取請求體的位元組數,GET請求沒有請求體,沒有請求體傳回-1;

String getContentType():擷取請求類型,如果請求是GET,那麼這個方法傳回null;如果是POST請求,那麼預設為application/x-www-form-urlencoded,表示請求體内容使用了URL編碼;

String getMethod():傳回請求方法,例如:GET

Locale getLocale():傳回目前用戶端浏覽器的Locale。java.util.Locale表示國家和言語,這個東西在國際化中很有用;

String getCharacterEncoding():擷取請求編碼,如果沒有setCharacterEncoding(),那麼傳回null,表示使用ISO-8859-1編碼;

void setCharacterEncoding(String code):設定請求編碼,隻對請求體有效!注意,對于GET而言,沒有請求體!!!是以此方法隻能對POST請求中的參數有效!

String getContextPath():傳回上下文路徑,例如:/hello

String getQueryString():傳回請求URL中的參數,例如:name=zhangSan

String getRequestURI():傳回請求URI路徑,例如:/hello/oneServlet

StringBuffer getRequestURL():傳回請求URL路徑,例如:http://localhost/hello/oneServlet,即傳回除了參數以外的路徑資訊;

String getServletPath():傳回Servlet路徑,例如:/oneServlet

String getRemoteAddr():傳回目前用戶端的IP位址;

String getRemoteHost():傳回目前用戶端的主機名,但這個方法的實作還是擷取IP位址;

String getScheme():傳回請求協定,例如:http;

String getServerName():傳回主機名,例如:localhost

int getServerPort():傳回伺服器端口号,例如:8080

    System.out.println("request.getContentLength(): " + request.getContentLength());

    System.out.println("request.getContentType(): " + request.getContentType());

    System.out.println("request.getContextPath(): " + request.getContextPath());

    System.out.println("request.getMethod(): " + request.getMethod());

    System.out.println("request.getLocale(): " + request.getLocale());

    System.out.println("request.getQueryString(): " + request.getQueryString());

    System.out.println("request.getRequestURI(): " + request.getRequestURI());

    System.out.println("request.getRequestURL(): " + request.getRequestURL());

    System.out.println("request.getServletPath(): " + request.getServletPath());

    System.out.println("request.getRemoteAddr(): " + request.getRemoteAddr());

    System.out.println("request.getRemoteHost(): " + request.getRemoteHost());

    System.out.println("request.getRemotePort(): " + request.getRemotePort());

    System.out.println("request.getScheme(): " + request.getScheme());

    System.out.println("request.getServerName(): " + request.getServerName());

    System.out.println("request.getServerPort(): " + request.getServerPort());

4.1 案例:request.getRemoteAddr():封IP

  可以使用request.getRemoteAddr()方法擷取用戶端的IP位址,然後判斷IP是否為禁用IP。

        String ip = request.getRemoteAddr();

        System.out.println(ip);

        if(ip.equals("127.0.0.1")) {

            response. getWriter().print("您的IP已被禁止!");

        } else {

            response.getWriter().print("Hello!");

        }

5 request擷取請求參數

最為常見的用戶端傳遞參數方式有兩種:

浏覽器位址欄直接輸入:一定是GET請求;

超連結:一定是GET請求;

表單:可以是GET,也可以是POST,這取決與<form>的method屬性值;

GET請求和POST請求的差別:

GET請求:

請求參數會在浏覽器的位址欄中顯示,是以不安全;

請求參數長度限制長度在1K之内;

GET請求沒有請求體,無法通過request.setCharacterEncoding()來設定參數的編碼;

POST請求:

請求參數不會顯示浏覽器的位址欄,相對安全;

請求參數長度沒有限制;

    <a href="/hello/ParamServlet?p1=v1&p2=v2">超連結</a>

    <hr/>

    <form action="/hello/ParamServlet" method="post">

        參數1:<input type="text" name="p1"/><br/>

        參數2:<input type="text" name="p2"/><br/>

        <input type="submit" value="送出"/>

    </form>

下面是使用request擷取請求參數的API:

String getParameter(String name):通過指定名稱擷取參數值;

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        String v1 = request.getParameter("p1");

        String v2 = request.getParameter("p2");

        System.out.println("p1=" + v1);

        System.out.println("p2=" + v2);

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        String v1 = request.getParameter("p1");

        String v2 = request.getParameter("p2");

        System.out.println("p1=" + v1);

        System.out.println("p2=" + v2);        

    }

String[] getParameterValues(String name):當多個參數名稱相同時,可以使用方法來擷取;

<a href="/hello/ParamServlet?name=zhangSan&name=liSi">超連結</a>

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        String[] names = request.getParameterValues("name");

        System.out.println(Arrays.toString(names));

    }

Enumeration getParameterNames():擷取所有參數的名字;

    <form action="/hello/ParamServlet" method="post">

        參數1:<input type="text" name="p1"/><br/>

        參數2:<input type="text" name="p2"/><br/>

        <input type="submit" value="送出"/>

    </form>

    public void doPost(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        Enumeration names = request.getParameterNames();

        while(names.hasMoreElements()) {

            System.out.println(names.nextElement());

        }

    }

Map getParameterMap():擷取所有參數封裝到Map中,其中key為參數名,value為參數值,因為一個參數名稱可能有多個值,是以參數值是String[],而不是String。

<a href="/day05_1/ParamServlet?p1=v1&p1=vv1&p2=v2&p2=vv2">超連結</a>

        Map<String,String[]> paramMap = request.getParameterMap();

        for(String name : paramMap.keySet()) {

            String[] values = paramMap.get(name);

            System.out.println(name + ": " + Arrays.toString(values));

        }

p2: [v2, vv2]

p1: [v1, vv1]

6 請求轉發和請求包含

無論是請求轉發還是請求包含,都表示由多個Servlet共同來處理一個請求。例如Servlet1來處理請求,然後Servlet1又轉發給Servlet2來繼續處理這個請求。

6.1 請求轉發

在AServlet中,把請求轉發到BServlet:

public class AServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        System.out.println("AServlet");

        RequestDispatcher rd = request.getRequestDispatcher("/BServlet");

        rd.forward(request, response);

    }

}

public class BServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        System.out.println("BServlet");

    }

}

Aservlet

BServlet

6.2 請求包含

在AServlet中,把請求包含到BServlet:

public class AServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        System.out.println("AServlet");

        RequestDispatcher rd = request.getRequestDispatcher("/BServlet");

        rd.include(request, response);

    }

}

public class BServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        System.out.println("BServlet");

    }

}

Aservlet

BServlet

6.3 請求轉發與請求包含比較

如果在AServlet中請求轉發到BServlet,那麼在AServlet中就不允許再輸出響應體,即不能再使用response.getWriter()和response.getOutputStream()向用戶端輸出,這一工作應該由BServlet來完成;如果是使用請求包含,那麼沒有這個限制;

請求轉發雖然不能輸出響應體,但還是可以設定響應頭的,例如:response.setContentType(”text/html;charset=utf-8”);

請求包含大多是應用在JSP頁面中,完成多頁面的合并;

請求請求大多是應用在Servlet中,轉發目标大多是JSP頁面;

6.4 請求轉發與重定向比較

請求轉發是一個請求,而重定向是兩個請求;

請求轉發後浏覽器位址欄不會有變化,而重定向會有變化,因為重定向是兩個請求;

請求轉發的目标隻能是本應用中的資源,重定向的目标可以是其他應用;

請求轉發對AServlet和BServlet的請求方法是相同的,即要麼都是GET,要麼都是POST,因為請求轉發是一個請求;

重定向的第二個請求一定是GET;

路徑

1 與路徑相關的操作

超連結

表單

轉發

包含

重定向

<url-pattern>

ServletContext擷取資源

Class擷取資源

ClassLoader擷取資源

2 用戶端路徑

超連結、表單、重定向都是用戶端路徑,用戶端路徑可以分為三種方式:

絕對路徑;

以“/”開頭的相對路徑;

不以“/”開頭的相對路徑;

例如:http://localhost:8080/hello1/pages/a.html中的超連結和表單如下:

絕對路徑:<a href="http://localhost:8080/hello2/index.html">連結1</a>

用戶端路徑:<a href="/hello3/pages/index.html">連結2</a>

相對路徑:<a href="index.html">連結3</a>

<hr/>

絕對路徑:

<form action="http://localhost:8080/hello2/index.html">

  <input type="submit" value="表單1"/>

</form>

用戶端路徑:

<form action="/hello2/index.html">

  <input type="submit" value="表單2"/>

</form>

相對路徑:

<form action="index.html">

  <input type="submit" value="表單3"/>

</form>

連結1和表單1:沒什麼可說的,它使用絕對路徑;

連結2和表單2:以“/”開頭,相對主機,與目前a.html的主機相同,即最終通路的頁面為http://localhost:8080/hello2/index.html;

連結3和表單3:不以“/”開頭,相對目前頁面的路徑,即a.html所有路徑,即最終通路的路徑為:http://localhost:8080/hello1/pages/index.html;

重定向1:

public class AServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        response.sendRedirect("/hello/index.html");

    }

}

  假設通路AServlet的路徑為:http://localhost:8080/hello/servlet/AServlet

  因為路徑以“/”開頭,是以相對目前主機,即http://localhost:8080/hello/index.html。

重定向2:

public class AServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        response.sendRedirect("index.html");

    }

}

假設通路AServlet的路徑為:http://localhost:8080/hello/servlet/AServlet

因為路徑不以“/”開頭,是以相對目前路徑,即http://localhost:8080/hello/servlet/index.html

2.1 建議使用“/”

強烈建議使用“/”開頭的路徑,這說明在頁面中的超連結和表單都要以“/”開頭,後面是目前應用的名稱,再是通路路徑:

<form action="/hello/servlet/AServlet">

</form>

<a href="/hello/b.html">連結</a>

其中/hello是目前應用名稱,這也說明如果将來修改了應用名稱,那麼頁面中的所有路徑也要修改,這一點确實是個問題。這一問題的處理方案會在學習了JSP之後講解!

在Servlet中的重定向也建議使用“/”開頭。同理,也要給出應用的名稱!例如:

response.sendRedirect("/hello/BServlet");

其中/hello是目前應用名,如果将來修改了應用名稱,那麼也要修改所有重定向的路徑,這一問題的處理方案是使用request.getContextPath()來擷取應用名稱。

response.sendRedirect(request.getContextPath() + "/BServlet");

3 伺服器端路徑

伺服器端路徑必須是相對路徑,不能是絕對路徑。但相對路徑有兩種形式:

以“/”開頭;

不以“/”開頭;

其中請求轉發、請求包含都是伺服器端路徑,伺服器端路徑與用戶端路徑的差別是:

用戶端路徑以“/”開頭:相對目前主機;

伺服器端路徑以“/”開頭:相對目前應用;

轉發1:

public class AServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        request.getRequestDispatcher("/BServlet").forward(request, response);

    }

}

假設通路AServlet的路徑為:http://localhost:8080/hello/servlet/AServlet

因為路徑以“/”開頭,是以相對目前應用,即http://localhost:8080/hello/BServlet。

轉發2:

public class AServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        request.getRequestDispatcher("BServlet").forward(request, response);

    }

}

假設通路AServlet的路徑為:http://localhost:8080/hello/servlet/AServlet

因為路徑不以“/”開頭,是以相對目前應用,即http://localhost:8080/hello/servlet/BServlet。

4 <url-pattern>路徑

  <url-pattern>必須使用“/”開頭,并且相對的是目前應用。

5 ServletContext擷取資源

必須是相對路徑,可以“/”開頭,也可以不使用“/”開頭,但無論是否使用“/”開頭都是相對目前應用路徑。

例如在AServlet中擷取資源,AServlet的路徑路徑為:http://localhost:8080/hello/servlet/AServlet:

public class AServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        String path1 = this.getServletContext().getRealPath("a.txt");

        String path2 = this.getServletContext().getRealPath("/a.txt");

        System.out.println(path1);

        System.out.println(path2);

    }

}

path1和path2是相同的結果:http://localhost:8080/hello/a.txt

6 Class擷取資源

Class擷取資源也必須是相對路徑,可以“/”開頭,也可以不使用“/”開頭。

package cn.itcast;

import java.io.InputStream;

public class Demo {

    public void fun1() {

        InputStream in = Demo.class.getResourceAsStream("/a.txt");

    }

    public void fun2() {

        InputStream in = Demo.class.getResourceAsStream("a.txt");

    }

}

其中fun1()方法擷取資源時以“/”開頭,那麼相對的是目前類路徑,即/hello/WEB-INF/classes/a.txt檔案;

其中fun2()方法擷取資源時沒有以“/”開頭,那麼相對目前Demo.class所在路徑,因為Demo類在cn.itcast包下,是以資源路徑為:/hello/WEB-INF/classes/cn/itcast/a.txt。

7 ClassLoader擷取資源

ClassLoader擷取資源也必須是相對路徑,可以“/”開頭,也可以不使用“/”開頭。但無論是否以“/”開頭,資源都是相對目前類路徑。

public class Demo {

    public void fun1() {

        InputStream in = Demo.class.getClassLoader().getResourceAsStream("/a.txt");

    }

    public void fun2() {

        InputStream in = Demo.class.getClassLoader().getResourceAsStream("a.txt");

    }

}

  fun1()和fun2()方法的資源都是相對類路徑,即classes目錄,即/hello/WEB-INF/classes/a.txt

編碼

1 請求編碼

1.1 直接在位址欄中給出中文

請求資料是由用戶端浏覽器發送伺服器的,請求資料的編碼是由浏覽器決定的。例如在浏覽器位址欄中給出:http://localhost:8080/hello/AServlet?name=智,那麼其中“智”是什麼編碼的呢?不同浏覽器使用不同的編碼,是以這是不确定的!

IE:使用GB2312;

FireFox:使用GB2312;

Chrome:使用UTF-8;

  通常沒有哪個應用要求使用者在浏覽器位址欄中輸入請求資料的,是以大家隻需了解一下即可。

1.2 在頁面中送出請求

通常向伺服器發送請求資料都需要先請求一個頁面,然後使用者在頁面中輸入資料。頁面中有超連結和表單,通過超連結和表單就可以向伺服器發送資料了。

因為頁面是伺服器發送到用戶端浏覽器的,是以這個頁面本身的編碼由伺服器決定。而使用者在頁面中輸入的資料也是由頁面本身的編碼決定的。

index.html

<!DOCTYPE html>

<html>

  <head>

    <title>index.html</title>

    <meta http-equiv="content-type" content="text/html; charset=UTF-8">

  </head>

  <body>

<form action="/hello/servlet/AServlet">

  名稱:<input type="text" name="name"/>

  <input type="submit" value="送出"/>

</form>

<a href="/hello/servlet/AServlet?name=智">連結</a>

  </body>

</html>

當使用者在index.html頁面中輸入資料時,都是UTF-8清單的。因為這個頁面本身就是UTF-8編碼的!

頁面的編譯就是頁面中輸入資料的編碼。

1.3 GET請求解讀編碼

當用戶端通過GET請求發送資料給伺服器時,使用request.getParameter()擷取的資料是被伺服器誤認為ISO-8859-1編碼的,也就是說用戶端發送過來的資料無論是UTF-8還是GBK,伺服器都認為是ISO-8859-1,這就說明我們需要在使用request.getParameter()擷取資料後,再轉發成正确的編碼。

例如用戶端以UTF-8發送的資料,使用如下轉碼方式:

String name = request.getParameter(“name”);

name = new String(name.getBytes(“iso-8859-1”), “utf-8”);

1.4 POST請求解讀編碼

  當用戶端通過POST請求發送資料給伺服器時,可以在使用request.getParameter()擷取請求參數之前先通過request.setCharacterEncoding()來指定編碼,然後再使用reuqest.getParameter()方法來擷取請求參數,那麼就是用指定的編碼來讀取了。

也就是說,如果是POST請求,伺服器可以指定編碼!但如果沒有指定編碼,那麼預設還是使用ISO-8859-1來解讀。

request.setCharacterEncoding(“utf-8”);

String name = request.getParameter(“name”);

2 響應編碼

響應:伺服器發送給用戶端資料!響應是由response對象來完成,如果響應的資料不是字元資料,那麼就無需去考慮編碼問題。當然,如果響應的資料是字元資料,那麼就一定要考慮編碼的問題了。

response.getWriter().print(“智”);

上面代碼因為沒有設定repsonse.getWriter()字元流的編碼,是以伺服器使用預設的編碼(ISO-8859-1)來處理,因為ISO-8859-1不支援中文,是以一定會出現編碼的。

是以在使用response.getWriter()發送資料之前,一定要設定response.getWriter()的編碼,這需要使用response.setCharacterEncoding()方法:

response.setCharacterEncoding(“utf-8”);

response.getWriter().print(“智”);

上面代碼因為在使用response.getWriter()輸出之前已經設定了編碼,是以輸出的資料為utf-8編碼。但是,因為沒有告訴浏覽器使用什麼編碼來讀取響應資料,是以很可能浏覽器會出現錯誤的解讀,那麼還是會出現亂碼的。當然,通常浏覽器都支援來設定目前頁面的編碼,如果使用者在看到編碼時,去設定浏覽器的編碼,如果設定的正确那麼亂碼就會消失。但是我們不能讓使用者總去自己設定編碼,而且應該直接通知浏覽器,伺服器發送過來的資料是什麼編碼,這樣浏覽器就直接使用伺服器告訴他的編碼來解讀!這需要使用content-type響應頭。

response.setContentType(“text/html;charset=utf-8”);

response.getWriter().print(“智”);

  上面代碼使用setContentType()方法設定了響應頭content-type編碼為utf-8,這不隻是在響應中添加了響應頭,還等于調用了一次response.setCharacterEncoding(“utf-8”),也就是說,通過我們隻需要調用一次response.setContentType(“text/html;charset=utf-8”)即可,而無需再去調用response.setCharacterEncoding(“utf-8”)了。

在靜态頁面中,使用<meta>來設定content-type響應頭,例如:

<meta http-equiv="content-type" content="text/html; charset=UTF-8">

3 URL編碼

通過頁面傳輸資料給伺服器時,如果包含了一些特殊字元是無法發送的。這時就需要先把要發送的資料轉換成URL編碼格式,再發送給伺服器。

其實需要我們自己動手給資料轉換成URL編碼的隻有GET超連結,因為表單發送資料會預設使用URL編碼,也就是說,不用我們自己來編碼。

例如:“智”這兩個字通過URL編碼後得到的是:“%E4%BC%A0%E6%99%BA”。URL編碼是先需要把“智”轉換成位元組,例如我們現在使用UTF-8把“智”轉換成字元,得到的結果是:“[-28, -68, -96, -26, -103, -70]”,然後再把所有負數加上256,得到[228, 188, 160, 230, 153, 186],再把每個int值轉換成16進制,得到[E4, BC, A0, E6, 99, BA],最後再每個16進制的整數前面加上“%”。

通過URL編碼,把“智”轉換成了“%E6%99%BA”,然後發送給伺服器!伺服器會自動識别出資料是使用URL編碼過的,然後會自動把資料轉換回來。

當然,在頁面中我們不需要自己去通過上面的過程把“智”轉換成“%E6%99%BA”,而是使用Javascript來完成即可。當後面我們學習了JSP後,就不用再使用Javascript了。

  <script type="text/javascript">

      function _go() {

          location = "/day05_2/AServlet?name=" + encodeURIComponent("智+客");

      }

  </script>

<a href="javascript:_go();">連結</a>

因為URL預設隻支援ISO-8859-1,這說明在URL中出現中文和一些特殊字元可能無法發送到伺服器。是以我們需要對包含中文或特殊字元的URL進行URL編碼。

伺服器會自動識别資料是否使用了URL編碼,如果使用了伺服器會自動把資料解碼,無需我們自己動手解碼。

請求響應對象

request和response

  * 當伺服器接收到請求後,伺服器會建立request和response對象,把請求資料封裝到request對象中;

  * 然後調用Servlet的service()方法時把這兩個對象傳遞給service()方法;

  * 在service()方法中可以通過request對象擷取請求資料,可以使用response對象向用戶端完成響應;

  * 每次請求伺服器都會建立新的request和response對象,即每個請求有自己獨自的request和response對象。

==============================

==============================

==============================

response對象

1. response簡介

  response是響應對象,用來在Servlet的service()方法中向用戶端響應資料。

  response的功能如下:

  * 設定響應頭

  * 發送狀态碼

  * 設定響應正文

  * 重定向

2. response響應正文

  * ServletOutputStream getOutputStream():用來向用戶端響應位元組資料;

  * PrintWriter getWriter():用來向用戶端響應字元資料;

  response.getWriter().print("你好");//向用戶端響應字元資料

  byte[] bytes = ...;

  response.getOutputStream().write(bytes);//向用戶端響應位元組資料

3. response字元編碼

  * Tomcat響應資料預設使用ISO-8859-1

  * 通常浏覽器預設使用GBK編碼

  * response.setCharacterEncoding("utf-8");//設定response.getWriter()的字元編碼

  1)

  response.getWriter().print("大家好");

  因為Tomcat預設使用的是ISO-8859-1編碼,不支援中文。是以一定編碼!

  2)

  response.setCharacterEncoding("utf-8");

  response.getWriter().print("大家好");

  因為已經設定了字元流編碼為utf-8,是以響應給用戶端的資料為utf-8編碼!

  但因為浏覽器預設使用的是gbk來解析響應資料,是以亂碼!如果浏覽器使用utf-8編碼,那麼就不會亂碼了。

  3)

  response.setCharacterEncoding("gbk");

  response.getWriter().print("大家好");

  因為設定了字元流編碼為gbk,是以響應給用戶端的資料為gbk編碼!

  因為浏覽器預設使用gbk來解析資料,是以不會出現亂碼!如果浏覽器使用utf-8編碼,那麼就會出現亂碼!

  4)

  response.setContentType("text/html;charset=utf-8");

  response.getWriter().print("大家好");

  setContentType()方法有兩個作用:

  * 設定字元流編碼。等同與調用了response.setCharacterEncoding("utf-8");

  * 設定Content-type響應頭,即通知浏覽器響應資料的編碼為utf-8。

  因為設定字元流的編碼為utf-8,是以響應給用戶端資料為utf-8編碼

  因為設定了Content-type頭為utf-8,是以浏覽器會使用utf-8來解析響應資料

  沒有亂碼!

  5)

  response.setContentType("text/html;charset=gbk");

  response.getWriter().print("大家好");

  * 設定了字元流為gbk,是以響應給用戶端的資料為gbk

  * 設定了Content-type頭為gbk,是以通知浏覽器響應資料為gbk編碼

  沒有亂碼!

  6)

  response.setHeader("Content-type", "text/html;charset=utf-8")

  等同于

  repsonse.setContentType("text/html;charset=utf-8")

  7)

  response.getOutputStream().write("大家好".getBytes("gbk"));

  響應的資料是gbk編碼

  用戶端浏覽器預設使用gbk編碼

  是以沒有亂碼

======================

4. response字元流緩沖區

  response字元流緩沖區大小為8KB,當向字元流中寫入資料後,資料可能隻在緩沖區中,而沒有發送到浏覽器。

  可以調用response.flushBuffer()或response.getWriter().flush()方法重新整理緩沖區,把資料發送到浏覽器。

======================

5. 設定響應頭

  response.setHeader("Content-type", "text/html;charset=utf-8");

  等同與

  response.setContentType("text/html;charset=utf-8");

  response.setHeader("Refresh", "5; URL=http://www.itcast.cn");

======================

6. 指定狀态碼

response.setStatus(200):設定狀态碼為200

response.sendError(404, “您要查找的資源不存在”):設定狀态碼為404

repsonse.sendError(500, “伺服器出氏了”):設定狀态碼為500

在調用sendError()方法時,不隻是設定了狀态碼,而且還會給浏覽器一個顯示錯誤的頁面。

======================

7. 重定向

response.sendStatus(302);

repsonse.setHeader("Location", "http://www.baidu.com");

快捷的方法重定向:

response.sendRedirect("http://www.baidu.com");

* 重定向是兩次請求

* 重定向不局限與目前應用,也可以是其他應用,例如重定向到百度

* 重定向響應碼為302,而且必須有Location響應頭

* 重定向與response響應流同時使用。

======================

======================

======================

request

1. request功能介紹

 * 擷取請求頭

 * 擷取請求參數

 * Servlet三大域對象之一

 * 請求包含和請求轉發

2. request域方法

 * void setAttribute(String name, Object value):添加或替換request域屬性

 * Object getAttribute(String name):擷取request域指定名稱的域屬性

 * void removeAttribute(String name):移除request域指定名稱的域屬性

 * Enumeration getAttributeNames():擷取所有request域的屬性名稱

3. request擷取請求頭

 * String getHeader(String name):擷取指定名稱的請求頭

 * int getIntHeader(String name):擷取指定名稱的請求頭,把值轉換成int類型。

 * Enumeration getHeaderNames():擷取所有請求頭名稱

4. request請求資料相關其他方法

 重點:

 * String getMethod():擷取請求方式

 * String getContextPath():擷取上下文路徑,即“/” + 應用名稱,例如:/day05_1

 * void setCharacterEncoding(String):設定請求體的編碼

 * String getRemoteAddr():擷取用戶端IP位址

 非重點:

 * int getContentLength():擷取請求體位元組數

 * Locale getLocale():擷取請求Locale,例如zh_CN表示中文,中國

 * String getCharacterEncoding():擷取請求體編碼,在沒有調用setCharacterEncoding()之前該方法傳回null

 * String getQueryString():擷取參數清單,例如:username=zhangSan&password=123

 * String getRequestURI():傳回請求URI路徑,從應用名稱開始,到參數之前這一段,例如:/day05_1/AServlet

 * StringBuffer getRequestURL():整個請求URL,不包含參數部分

 * String getServletPath():傳回Servlet路徑,從應用名稱後開始,到參數之前這一段,不包含應用名稱。

 * String getServerName():傳回主機名,例如:localhost

 * int getServerPort():傳回伺服器端口号,例如:8080

5. 請求參數

 擷取請求參數,即擷取超連結上的參數和表單中的參數

 * String getParameter(String name):擷取指定名稱的參數,如果存在同名參數,那麼該方法隻擷取第一個參數值

 * String[] getParameterValues(String name):擷取指定名稱的參數,因為同名參數的存在,是以傳回值為String[]

 * Enumeration getParameterNames():擷取所有參數名稱

 * Map getParameterMap():擷取所有參數,封裝到Map中,key為參數名稱,value為參數值。

6. 請求包含和請求轉發

 * 請求包含和請求轉發都是在一個請求中,通路兩個Servlet。

 * 請求包含和請求轉發都是有一個Servlet去調用執行另一個Servlet

 * 請求包含和請求轉發都可以共享request中的資料,因為都是一個請求。

 * 從AServlet請求轉發到BServlet

   > 在AServlet中可以設定響應頭

   > 在AServlet中不能使用響應流輸出

 如果在AServlet中執行了響應操作,那麼有兩種可能:

 * 如果在AServlet中響應的資料導緻response送出,那麼在轉發時抛出異常;

 * 如果在AServlet中響應的資料沒有導緻response送出,那麼response中的資料會被清空。

 * 從AServlet請求包含BServlet

   > 在AServlet可以設定響應頭

   > 在AServlet可以使用響應流輸出

 * 請求轉發和請求包含都要使用RequestDispatcher對象:RequestDispatcher rd = request.getRequestDispatcher("/BServlet");

 * 請求轉發執行RequestDispatcher的forward()方法:rd.forward(request,response);

 * 請求包含執行RequestDispatcher的include()方法:rd.include(request,response);

 * 請求轉發和請求包含的路徑都是伺服器端路徑,相對目前應用

7. 請求轉發與重定向

 * 請求轉發是一個請求,而重定向是兩個請求

 * 請求轉發,是使用RequestDispatcher來完成,重定向使用response對象來完成

 * 請求轉發的路徑都是伺服器端路徑,而重定向是用戶端路徑,需要給出應用名稱

 * 請求轉發在浏覽器位址欄中的位址是第一個Servlet的路徑,而重定向在位址欄中的位址是第二個請求的Servlet的路徑

 * 請求轉發中的兩個Servlet是可以共享request資料的,而重定向因為是兩個請求,是以不能共享request資料

 * 請求轉發隻能轉發到本應用的其他Servlet,而重定向可以重定向到其他應用中。

8. request.getParameter()和request.getAttribute()

 * getParameter()是擷取用戶端參數,它是從用戶端傳遞給伺服器的資料。

 * getAttribute()是擷取伺服器端自己設定的資料,而不是用戶端的資料。

 * request沒有setParameter()方法,不能自己設定參數,參數都由用戶端傳遞

 * request有setAttribute()方法,在getAttribute()之前,需要先setAttribute()才能擷取到。

 * getAttribute()和setAttribute()是用來在請求轉發和請求包含中的多個Servlet中共享資料。

======================

======================

======================

路徑

1. 用戶端路徑和伺服器端路徑

 * 用戶端路徑需要給出應用名稱,例如:/day05_1/AServlet

 * 伺服器端路徑無需給出應用名稱,例如:/AServlet

2. 用戶端路徑

 1). 頁面中都是用戶端路徑:

 * 超連結的href

 * 表單的action

 * <img>的src

 2). 重定向也是用戶端路徑:response.sendRedirect("/day05_1/BServlet");

3. 伺服器端路徑

 * <url-pattern>

 * 請求轉發和請求包含

 * ServletContext擷取資源等

======================

======================

======================

亂碼

1. 請求編碼

 * 用戶端發送的資料編碼:由浏覽器來決定:

  1). 如果是在位址欄中直接給出url,那麼一般都是預設為GBK,但這個可能不太大。

  2). 如果是通過頁面上的表單或超連結送出請求,那麼由目前頁面的編碼來決定發送的參數的編碼。

 * 無論浏覽器發送過來的是什麼編碼的資料,Tomcat都預設使用ISO-8859-1來解碼

  1). POST:可以使用request.setCharacterEncoding()方法來設定請求體資料的編碼,因為POST請求參數在請求體中,是以是可以設定編碼的。在使用request.getParameter()方法擷取參數之前,先使用request.setCharacterEncoding()方法來設定編碼即可。

  2). GET:沒有方法可以設定它,因為參數在url中。是以使用request.getParameter()擷取到的資料一定是錯誤的使用了iso-8859-1解碼的。可以再使用iso-8859-1把字元串轉回到byte[],再重新使用正确的編碼來解碼即可。

  String s = request.getParameter("s");//使用iso-8859-1錯誤的解碼了

  byte[] bytes = s.getBytes("iso-8859-1");//退回錯誤的解碼,讓字元串通過iso-8859-1傳回到位元組資料,即還原位元組資料

  s = new String(bytes, "utf-8");//重新使用正确的utf-8來解碼。

内容:

* response

* request

* 編碼

* 路徑

------------------

伺服器處理請求的流程:

  伺服器每次收到請求時,都會為這個請求開辟一個新的線程。

  伺服器會把用戶端的請求資料封裝到request對象中,request就是請求資料的載體!(袋子)

  伺服器還會建立response對象,這個對象與用戶端連接配接在一起,它可以用來向用戶端發送響應。(手機)

------------------

response:其類型為HttpServletResponse

  ServletResponse-->與協定無關的類型

  HttpServletResponse-->與http協定相關的類型

  回憶一下http協定!http協定中響應的内容包含哪些東西呢?

  * 狀态碼:200表示成功、302表示重定向、404表示用戶端錯(通路的資源不存在)、500表示伺服器端錯

    > sendError(int sc) --> 發送錯誤狀态碼,例如404、500

    > sendError(int sc, String msg) --> 也是發送錯誤狀态碼,還可以帶一個錯誤資訊!

    > setStatus(int sc) --> 發送成功的狀态碼,可以用來發送302

    案例:

    > 發送404

  * 響應頭:Content-Type、Refresh、Location等等

    頭就是一個鍵值對!可能會存在一個頭(一個名稱,一個值),也可能會存在一個頭(一個名稱,多個值!)

    > *****setHeader(String name, String value):适用于單值的響應頭,例如:response.setHeader("aaa", "AAA");

    > addHeader(String name, String value):适用于多值的響應頭

        response.addHeader("aaa", "A");

        response.addHeader("aaa", "AA");

        response.addHeader("aaa", "AAA");

    > setIntHeader(String name, int value):适用于單值的int類型的響應頭

    `    response.setIntHeader("Content-Length", 888);

    > addIntHeader(String name, int value):适用于多值的int類型的響應頭

    > setDateHeader(String name, long value):适用于單值的毫秒類型的響應頭

        response.setDateHeader("expires", 1000 * 60 * 60 * 24);

    > addDateHeader(String name, long value):适用于多值的毫秒類型的響應頭

    案例:

    > 發送302,設定Location頭,完成重定向!

    > 定時重新整理:設定Refresh頭,你可以把它了解成,定時重定向!

    > 禁用浏覽器緩存:Cache-Control、pragma、expires

    > <meta>标簽可以代替響應頭:<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

  * 響應體:通常是html、也可以是圖檔!

    > response的兩個流:

      <> ServletOutputStream,用來向用戶端發送位元組資料。ServletOutputStream out = resopnse.getOutputStream();

      <> PrintWriter,用來向用戶端發送字元資料!需要設定編碼。PrintWriter writer = response.getWriter();

      <> 兩個流不能同時使用!

    案例:

    > 使用PrintWriter發送字元資料

    > 使用ServletOutputStream發送位元組資料(圖檔)

  * 重定向:設定302,設定Location!其中變化的隻有Location,是以java提供了一個快捷方法,完成重定向!

   > sendRedirect(String location)方法

------------------

request --> 封裝了用戶端所有的請求資料!

請求行

請求頭

空行

請求體(GET沒體)

  回憶一下http協定!請求協定中的資料都可以通過request對象來擷取!

  * 擷取常用資訊

    > 擷取用戶端IP,案例:封IP。request.getRemoteAddr()

    > 請求方式,request.getMethod(),可能是POST也可能是GET

  * 擷取HTTP請求頭

    > *****String getHeader(String name),适用于單值頭

    > int getIntHeader(String name),适用于單值int類型的請求頭

    > long getDateHeader(String name),适用于單值毫秒類型的請求頭

    > Enumeration<String> getHeaders(String name),适用于多值請求頭

   案例:

    > 通過User-Agent識别使用者浏覽器類型

    > 防盜鍊:如果請求不是通過本站的超連結發出的,發送錯誤狀态碼404。Referer這個請求頭,表示請求的來源!

  * 擷取請求URL

    http://localhost:8080/day10_2/AServlet?username=xxx&password=yyy

    > String getScheme():擷取協定,http

    > String getServerName():擷取伺服器名,localhost

    > String getServerPort():擷取伺服器端口,8080

    > *****String getContextPath():擷取項目名,/day10_2

    > String getServletPath():擷取Servlet路徑,/AServlet

    > String getQueryString():擷取參數部分,即問号後面的部分。username=xxx&password=yyy

    > String getRequestURI():擷取請求URI,等于項目名+Servlet路徑。/day10_2/AServlet

    > String getRequestURL():擷取請求URL,等于不包含參數的整個請求路徑。http://localhost:8080/day10_2/AServlet

  * 擷取請求參數:請求參數是由用戶端發送給伺服器的!有可能是在請求體中(POST),也可能是在URL之後(GET)

    請求參數:有一個參數一個值的,還有一個參數多個值!

    > *****String getParameter(String name):擷取指定名稱的請求參數值,适用于單值請求參數

    > String[] getParameterValues(String name):擷取指定名稱的請求參數值,适用于多值請求參數

    > Enumeration<String> getParameterNames():擷取所有請求參數名稱

    > *****Map<String,String[]> getParameterMap():擷取所有請求參數,其中key為參數名,value為參數值。

    案例:超連結參數

    案例:表單資料

  * 請求轉發和請求包含

    RequestDispatcher rd = request.getRequestDispatcher("/MyServlet");  使用request擷取RequestDispatcher對象,方法的參數是被轉發或包含的Servlet的Servlet路徑

    請求轉發:*****rd.forward(request,response);

    請求包含:rd.include(request,response);

    有時一個請求需要多個Servlet協作才能完成,是以需要在一個Servlet跳到另一個Servlet!

    > 一個請求跨多個Servlet,需要使用轉發和包含。

    > 請求轉發:由下一個Servlet完成響應體!目前Servlet可以設定響應頭!(留頭不留體)

    > 請求包含:由兩個Servlet共同未完成響應體!(都留)

    > 無論是請求轉發還是請求包含,都在一個請求範圍内!使用同一個request和response!

  * request域

    Servlet中三大域對象:request、session、application,都有如下三個方法:

    > void setAttribute(String name, Object value)

    > Object getAttribute(String name)

    > void removeAttribute(String name);

    > 同一請求範圍内使用request.setAttribute()、request.getAttribute()來傳值!前一個Servlet調用setAttribute()儲存值,後一個Servlet調用getAttribute()擷取值。

  * 請求轉發和重定向的差別

    > 請求轉發是一個請求一次響應,而重定向是兩次請求兩次響應

    > 請求轉發位址欄不變化,而重定向會顯示後一個請求的位址

    > 請求轉發隻能轉發到本項目其他Servlet,而重定向不隻能重定向到本項目的其他Servlet,還能定向到其他項目

    > 請求轉發是伺服器端行為,隻需給出轉發的Servlet路徑,而重定向需要給出requestURI,即包含項目名!

    > 請求轉發和重定向效率是轉發高!因為是一個請求!

      <> 需要位址欄發生變化,那麼必須使用重定向!

      <> 需要在下一個Servlet中擷取request域中的資料,必須要使用轉發!

  

------------------

編碼

  常見字元編碼:iso-8859-1(不支援中文)、gb2312、gbk、gb18030(系統預設編碼,中國的國标碼)、utf-8(萬國碼,支援全世界的編碼,是以我們使用這個)

1. 響應編碼

  * 當使用response.getWriter()來向用戶端發送字元資料時,如果在之前沒有設定編碼,那麼預設使用iso,因為iso不支援中文,一定亂碼

  * 在使用response.getWriter()之前可以使用response.setCharaceterEncoding()來設定字元流的編碼為gbk或utf-8,當然我們通常會選擇utf-8。這樣使用response.getWriter()發送的字元就是使用utf-8編碼的。但還是會出現亂碼!因為浏覽器并不知道伺服器發送過來的是什麼編碼的資料!這時浏覽器會使用gbk來解碼,是以亂碼!

  * 在使用response.getWriter()之前可以使用response.setHeader("Content-type","text/html;charset=utf-8")來設定響應頭,通知浏覽器伺服器這邊使用的是utf-8編碼,而且在調用setHeader()後,還會自動執行setCharacterEncding()方法。這樣浏覽器會使用utf-8解碼,是以就不會亂碼了!

  * setHeader("Content-Type", "text/html;charset=utf-8")的快捷方法是:setContentType("text/html;charset=utf-8)。

2. 請求編碼

  * 用戶端發送給伺服器的請求參數是什麼編碼:

    用戶端首先要打開一個頁面,然後在頁面中送出表單或點選超連結!在請求這個頁面時,伺服器響應的編碼是什麼,那麼用戶端發送請求時的編碼就是什麼。

  * 伺服器端預設使用什麼編碼來解碼參數:

    伺服器端預設使用ISO-8859-1來解碼!是以這一定會出現亂碼的!因為iso不支援中文!

  * 請求編碼處理分為兩種:GET和POST:GET請求參數不在請求體中,而POST請求參數在請求體中,是以它們的處理方式是不同的!

  * GET請求編碼處理:

    > String username = new String(request.getParameter("iso-8859-1"), "utf-8");

    > 在server.xml中配置URIEncoding=utf-8

  * POST請求編碼處理:

    > String username = new String(request.getParameter("iso-8859-1"), "utf-8");

    > 在擷取參數之前調用request.setCharacterEncoding("utf-8");

3. URL編碼

  表單的類型:Content-Type: application/x-www-form-urlencoded,就是把中文轉換成%後面跟随兩位的16進制。

  為什麼要用它:在用戶端和伺服器之間傳遞中文時需要把它轉換成網絡适合的方式。

  * 它不是字元編碼!

  * 它是用來在用戶端與伺服器之間傳遞參數用的一種方式!

  * URL編碼需要先指定一種字元編碼,把字元串解碼後,得到byte[],然後把小于0的位元組+256,再轉換成16進制。前面再添加一個%。

  * POST請求預設就使用URL編碼!tomcat會自動使用URL解碼!

  * URL編碼:String username = URLEncoder.encode(username, "utf-8");

  * URL解碼:String username = URLDecoder.decode(username, "utf-8");

  最後我們需要把連結中的中文參數,使用url來編碼!今天不行,因為html中不能給出java代碼,但後面學了jsp就可以了。

------------------

路徑

  * web.xml中<url-pattern>路徑,(叫它Servlet路徑!)

    > 要麼以“*”開關,要麼為“/”開頭

  * 轉發和包含路徑

    > *****以“/”開頭:相對目前項目路徑,例如:http://localhost:8080/項目名/ request.getRequestdispacher("/BServlet").for...();

    > 不以“/”開頭:相對目前Servlet路徑。 request.getRequestdispacher("/BServlet").for...();,假如目前Servlet是:http://localhost:8080/項目名/servlet/AServlet, 就是http://localhost:8080/項目名/servlet/BServlet

  * 重定向路徑(用戶端路徑)

    > 以“/”開頭:相對目前主機,例如:http://localhost:8080/, 是以需要自己手動添加項目名,例如;response.sendRedirect("/day10_1/Bservlet");

  * 頁面中超連結和表單路徑

    > 與重定向相同,都是用戶端路徑!需要添加項目名

    > <form action="/day10_1/AServlet">

    > <a href="/day10_/AServlet">

    > <a href="AServlet">,如果不以“/”開頭,那麼相對目前頁面所在路徑。如果是http://localhost:8080/day10_1/html/form.html。 即:http://localhost:8080/day10_1/html/ASevlet

    > *****建立使用以“/”開頭的路徑,即絕對路徑!

  * ServletContext擷取資源路徑

    > 相對目前項目目錄,即當然index.jsp所在目錄

  * ClassLoader擷取資源路徑

    > 相對classes目錄

  * Class擷取資源路徑

    > 以“/”開頭相對classes目錄

    > 不以“/”開頭相對目前.class檔案所在目錄。

GET請求編碼:

URL編碼:

請求編碼:

請求參數和request域:

請求轉發和請求包含是一個請求:

響應編碼:

重定向: