JavaWeb Request和Response

1. RequestResponse

1.1. Web應用運行機制

到目前爲止,咱們已經掌握了Web應用程序的運行機制,如今學習的就是Web應用程序運行機制中很重要的內容 —— RequestResponsejavascript

首先,咱們先來看一看RequestResponseWeb應用程序運行時,是怎麼樣的。html

 

經過上圖的Web應用程序運行機制,咱們能夠知道關於RequestResponse的信息:java

  • Web應用程序接收一次請求,就建立一個Request對象和Response對象。
  • 經過Request對象能夠在服務器端獲取客戶端發送的請求數據內容。
  • 經過Response對象能夠生成服務器端向客戶端響應的數據內容。
  • Request對象和Response對象並非Web應用程序所建立的,而是由Tomcat服務器建立(JavaEE並無RequestResponse的實現類)。
  • JavaEE提供了javax.servlet.http包中提供了HttpServletRequestHttpServletResponse接口,這兩個接口是繼承於javax.servlet包中的ServletRequestServletResponse接口。
  • javax.servlet包中的ServletRequestServletResponse接口是與協議無關的,而javax.servlet.http包中的HttpServletRequestHttpServletResponse接口是與Http協議有關的。

1.2. 百度百科

  • Request

Request這個對象不用事先聲明,就能夠在JSP網頁中使用,在編譯爲Servlet以後,它會轉換爲javax.servlet.http.HttpServletRequest形態的對象,HttpServletRequest對象是有關於客戶端所發出的請求的對象,只要是有關於客戶端請求的信息,均可以藉由它來取得,例如請求標頭、請求方法、請求參數、客戶端IP,客戶端瀏覽器等等信息。web

  • Response

Response對象用於動態響應客戶端請示,控制發送給用戶的信息,並將動態生成響應。Response對象只提供了一個數據集合cookie,它用於在客戶端寫入cookie值。若指定的cookie不存在,則建立它。若存在,則將自動進行更新。結果返回給客戶端瀏覽器。數據庫

2. 掌握Response

2.1. Response概述

ResponseWeb應用程序用來封裝向客戶端響應信息的,是Servlet接口的service()方法的一個參數,類型爲javax.servlet.http.HttpServletResponse。客戶端每次發送請求時,服務器都會建立一個Response對象,並傳遞給Servlet接口的service()方法,來完成向客戶端的響應工做。api

下列是javax.servlet.http.HttpServletResponse經常使用的API列表:瀏覽器

Method Summary緩存

 void服務器

addDateHeader(String name, long date) 
          Adds a response header with the given name and date-value.cookie

 void

addHeader(String name, String value) 
          Adds a response header with the given name and value.

 void

sendRedirect(String location) 
          Sends a temporary redirect response to the client using the specified redirect location URL.

 void

setDateHeader(String name, long date) 
          Sets a response header with the given name and date-value.

 void

setHeader(String name, String value) 
          Sets a response header with the given name and value.

 void

setStatus(int sc) 
          Sets the status code for this response.

下列是javax.servlet.ServletResponse經常使用的API列表:

Method Summary

 ServletOutputStream

getOutputStream() 
          Returns a ServletOutputStream suitable for writing binary data in the response.

 PrintWriter

getWriter() 
          Returns a PrintWriter object that can send character text to the client.

 void

setCharacterEncoding(String charset) 
          Sets the character encoding (MIME charset) of the response being sent to the client, for example, to UTF-8.

 void

setContentType(String type) 
          Sets the content type of the response being sent to the client, if the response has not been committed yet.

針對HttpServletResponseServletResponse經常使用的API,咱們進行逐一討論。

2.2. Response重定向

在學習Http響應協議時,咱們曾作太重定向案例,但那時咱們並不清楚其原理,下面咱們就討論一下利用HttpServletResponse來完成重定向的功能。

  • 建立一個Servlet來完成重定向功能。
public class ResponseServlet1 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setStatus(302);
        response.setHeader("Location", "/response/index.html");
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
  • Web工程的web.xml文件中註冊Servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet>
    <servlet-name>ResponseServlet1</servlet-name>
    <servlet-class>app.java.response.ResponseServlet1</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>ResponseServlet1</servlet-name>
    <url-pattern>/response1</url-pattern>
  </servlet-mapping>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>
  • 建立一個HTML頁面。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>index.html</title>
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <h1>Request與Response內容</h1>
  </body>
</html>
  • Web工程發佈到Tomcat服務器,並啓動Tomcat服務器。
  • 打開瀏覽器,在地址欄中輸入http://localhost:8080/response/response1。

經過上述案例,咱們能夠發如今重定向中,實際上客戶端向服務器端發送了兩次請求,具體步驟以下:

  • 在瀏覽器地址輸入URL,訪問服務器端的Servlet,這是第一次發送的請求。
  • 服務器端接收到客戶端的請求後,由Servlet作出處理,重定向到index.html頁面,並響應給客戶端瀏覽器。
  • 客戶端瀏覽器接收到服務器端的響應後,再次發送第二次請求。
  • 服務器端接收到客戶端的第二次請求後,並響應index.html給客戶端瀏覽器顯示。

其實Response對象提供了sendRedirect(String location)方法,一樣能夠完成重定向的工做。

public class ResponseServlet1 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.sendRedirect("/09_request&response/response/index.html");
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
} 

2.3. 登陸錯誤案例

利用Response對象提供了sendRedirect(String location)方法能夠完成重定向的功能,實現登陸功能中若是錯誤的案例。具體實現步驟以下:

  • 建立一個用於登陸的HTML頁面。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>login.html</title>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <h1>登陸案例:登陸錯誤重定向回當前頁面</h1>
    <form id="form1" action="/response/response2" method="post">
        用戶名:<input type="text" name="username"><br>
        密碼:<input type="password" name="password"><br>
        <input type="submit" value="登陸">
    </form>
  </body>
</html>
  • 建立一個Servlet用於處理登陸是否成功邏輯。
public class ResponseServlet2 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 獲取客戶端瀏覽器提交的用戶名與密碼內容
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //模擬查詢數據庫:admin/admin
        if(username.equals("admin")&&password.equals("admin")){
            // 登陸成功
            response.setContentType("text/html;charset=utf-8");
            PrintWriter out = response.getWriter();
            out.println("<h1>登陸成功</h1>");
        }else{
            // 登陸錯誤
    response.sendRedirect("/response/response/login.html");
        }
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
} 
  • Web工程的web.xml文件中註冊Servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet>
    <servlet-name>ResponseServlet2</servlet-name>
    <servlet-class>app.java.response.ResponseServlet2</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>ResponseServlet2</servlet-name>
    <url-pattern>/response2</url-pattern>
  </servlet-mapping>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>
  • Web工程發佈到Tomcat服務器,並啓動Tomcat服務器。
  • 打開瀏覽器,在地址欄中輸入http://localhost:8080/response/response/login.html

2.4. 自動刷新案例

在學習Http響應協議時,咱們曾作過自動刷新案例,但那時咱們並不清楚其原理,下面咱們就討論一下利用HttpServletResponse來完成自動刷新的功能。

  • 建立一個Servlet用於設置5秒鐘後自動刷新頁面的功能(自動跳轉到登陸頁面)。
public class ResponseServlet3 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setHeader("refresh", "5;url=/response/response/login.html");
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println("當前頁面會在5秒鐘後自動跳轉到登陸頁面.");
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
} 
  • Web工程的web.xml文件中註冊Servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet>
    <servlet-name>ResponseServlet3</servlet-name>
    <servlet-class>app.java.response.ResponseServlet3</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>ResponseServlet3</servlet-name>
    <url-pattern>/response3</url-pattern>
  </servlet-mapping>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>
  • Web工程發佈到Tomcat服務器,並啓動Tomcat服務器。
  • 打開瀏覽器,在地址欄中輸入http://localhost:8080/response/response3

在學習HTML技術的時候,咱們知道在head標籤中有meta標籤,該標籤一樣能夠完成自動刷新頁面的功能。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>refresh.html</title>
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <meta http-equiv="refresh" content="5;url=/response/response/login.html">
  </head>
  <body>
    <h1>當前頁面會在5秒鐘後自動跳轉到登陸頁面.</h1>
  </body>
</html>

使用Response對象的setHeader()方法與HTML頁面的<meta>標籤,一樣能夠完成頁面自動刷新功能,可是二者是有區別的:

  • 使用Response對象的setHeader()方法:refresh信息是顯示在響應頭信息中。
  • 使用HTML頁面的<meta>標籤:refresh信息是顯示在響應體信息中。

在上述基礎上,完成動態效果的倒計時功能,須要使用javascript技術來完成。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>refresh.html</title>
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <meta http-equiv="refresh" content="5;url=/response/response/login.html">
  </head>
  <script type="text/javascript">
      var times = 5;
      function init(){
        document.getElementById("times").innerHTML = times;
        times--;
        setTimeout("init()",1000);
    }
  </script>
  <body onload="init();">
    <h1>當前頁面會在<span id="times"></span>秒鐘後自動跳轉到登陸頁面</h1>
  </body>
</html>

2.5. 禁止瀏覽器緩存案例

在學習Http響應協議時,咱們知道響應協議中有三個頭信息能夠禁止瀏覽器本地緩存,分別是Cache-Control、Pragma和Expires。下面咱們就經過一個案例來討論一下。

  • 建立一個Servlet用來向客戶端瀏覽器響應一些數據內容。
public class ResponseServlet4 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        out.println("當前時間是:"+new Date().toString());
        System.out.println("已經成功地訪問了當前Servlet...");
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
} 
  • Web工程的web.xml文件中註冊Servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet>
    <servlet-name>ResponseServlet4</servlet-name>
    <servlet-class>app.java.response.ResponseServlet4</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>ResponseServlet4</servlet-name>
    <url-pattern>/response4</url-pattern>
  </servlet-mapping>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>
  • 打開瀏覽器,選擇「工具」->Internet選項」->「瀏覽歷史記錄」中的「設置」->「查看文件」,清空全部緩存內容。
  • 在瀏覽器在地址欄中輸入http://localhost:8080/response/response4進行訪問。
  • 這時再查看瀏覽器緩存內容的文件夾,會發現產生了此次訪問的緩存內容。
  • 這時再查看控制檯信息,會發現打印了相關內容,說明客戶端成功訪問了服務器端的Servlet
  • 這時再次訪問http://localhost:8080/response/response4地址,會發現內容再也不變化,也不會產生請求和響應內容。

因爲IE瀏覽器的本地緩存問題,第二次再次訪問相同Servlet攔截路徑時,不會再訪問服務器端的Servlet,而是訪問本地緩存內容。要想每次客戶端訪問都訪問到服務器端的Servlet的話,咱們須要禁止瀏覽器緩存機制。

  • 咱們能夠經過響應頭信息中的三個相關內容來設置禁止瀏覽器緩存。
public class ResponseServlet4 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        //設置響應頭信息,禁止瀏覽器緩存.
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", -1);
        PrintWriter out = response.getWriter();
        out.println("<h1>已經成功地訪問了當前Servlet...</h1>");
     }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
} 
  • 從新發布Web工程到Tomcar服務器,並重啓Tomcat服務器。
  • 打開瀏覽器,清空本地緩存內容,在地址欄中輸入相同URL地址。
  • 可是,如今查看瀏覽器本地緩存文件夾,會發現沒有任何緩存內容。
  • 這時再次訪問http://localhost:8080/response/response4地址。
  • 並且控制檯也會打印相關信息,說明第二次也成功地訪問服務器端的Servlet

2.6. 生成響應體內容

到目前爲止,操做的都是Response對象的響應頭信息。而Http協議的響應協議中,除了響應頭信息以外,還有響應體,如何利用Response對象向客戶端發送響應體呢?能夠利用Response對象的getWriter()方法或getOutputStream()方法獲取響應輸出流,經過響應輸出流向客戶端進行響應。具體操做步驟以下:

  • 建立一個Servlet用於向客戶端響應內容。
public class ResponseServlet5 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        out.println("<HTML>");
        out.println("  <BODY>");
        out.println("    <H1>Servlet生成的HTML頁面.</H1>");
        out.println("  </BODY>");
        out.println("</HTML>");
    }
 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
  • Web工程的web.xml文件中註冊Servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet>
    <servlet-name>ResponseServlet5</servlet-name>
    <servlet-class>app.java.response.ResponseServlet5</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>ResponseServlet5</servlet-name>
    <url-pattern>/response5</url-pattern>
  </servlet-mapping>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>
  • 打開瀏覽器,在地址欄中輸入http://localhost:8080/response/response5。
  • 發如今響應內容的頁面中,中文顯示爲亂碼。利用Response對象響應前,須要設置響應編碼的字符集。
response.setCharacterEncoding("utf-8");

須要注意的是,調用Response對象的setCharacterEncoding()方法設置編碼字符集時,必需要在調用Response對象的getWriter()方法或getOutputStream()方法以前。

  • 從新打開IE瀏覽器,在地址欄中輸入http://localhost:8080/response/response5。
  • 可是,打開火狐瀏覽器,在地址欄中輸入http://localhost:8080/response/response5。

雖然在響應以前設置了響應編碼字符集,可是使用火狐瀏覽器顯示時,依舊是亂碼。

  • 查看火狐瀏覽器的字符集編碼,會發現並非utf-8編碼。

這說明利用Response對象的setCharacterEncoding()方法雖然能夠設置響應體內容的編碼字符集,但並不能經過瀏覽器,瀏覽器顯示默認使用的編碼集仍是瀏覽器默認設置的。能夠調用Response對象的setContentType()方法設置響應體的文件類型和編碼字符集。

response.setContentType("text/html;charset=utf-8");
  • 從新打開火狐瀏覽器,在地址欄中輸入http://localhost:8080/response/response5亂碼問題解決

須要注意的是,其實在調用Response對象的setContentType()方法時,設置的編碼字符集是覆蓋了Response對象的setCharacterEncoding()方法設置的編碼字符集的。因此,實際上只調用setContentType()方法便可。

利用Response對象的getWriter()方法或getOutputStream()方法向客戶端進行響應的時候,須要注意的問題是:

  • 若是須要手動響應內容的時候,使用getWriter()方法,不然使用getOutputStream()方法。
  • getWriter()方法和getOutputStream()方法之間是互斥的,也就是說只能使用其中一個方法。
  • 使用getWriter()方法或getOutputStream()方法只能向客戶端響應體,而不能修改響應行和響應頭信息。
  • getWriter()方法或getOutputStream()方法進行響應時,Tomcat服務器會自動關閉響應輸出流,沒必要手動關閉響應輸出流。

2.7. 生成驗證碼圖片

利用Response對象向客戶端進行響應的功能,來完成頁面中驗證碼生成的案例,具體實現步驟以下:

  • 建立一個HTML頁面用於顯示生成的驗證碼。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>identi.html</title>
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <img src="/response/response6">
  </body>
</html>
  • 建立一個Servlet用於生成頁面實現的驗證碼。
public class ResponseServlet6 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /*
         * 當前Servlet的做用:生成HTML頁面顯示的驗證碼(圖片).
         *  * Java生成圖片內容,使用圖形界面技術的awt、swing包.
         */
        /*
         *  1 在內存中建立圖片
         *   * 建立圖片,須要定義圖片的寬度和高度.
         *   * 利用BufferedImage類來建立圖片.
         *   * new BufferedImage(寬度, 高度, 圖片類型)
         */
        int width = 120;
        int height = 30;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        /*
         *  2 繪製圖片背景顏色
         *   * 經過建立的圖片對象的getGraphics()方法,獲取畫筆.
         *   * 經過畫筆對象的setColor()方法設置圖片的背景顏色.
         *   * 經過畫筆對象的fillRect()方法設置背景顏色填充的面積.
         */
        Graphics2D graphics2d = (Graphics2D)image.getGraphics();
        graphics2d.setColor(Color.GRAY);
        graphics2d.fillRect(0, 0, width, height);
        /*
         *  3 繪製邊框
         *   * 經過畫筆對象的drawRect()方法繪製邊框的面積.
         */
        graphics2d.setColor(Color.BLACK);
        graphics2d.drawRect(1, 1, width - 1, height - 1);
        /*
         *  4 向圖片中生成顯示的驗證碼內容
         *   * 經過畫筆對象的setFont()方法設置驗證碼內容的字體、大小等.
         *   * word表示生成驗證碼的備選文本內容.
         */
        graphics2d.setColor(Color.RED);
        graphics2d.setFont(new Font("新宋體", Font.BOLD, 24));
        String word = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
        // 這段代碼用於將生成的驗證碼內容寫入到圖片中.
        Random random = new Random();
        int x = 5;
        for (int i = 0; i < 4; i++) {
            // 加入字體旋轉 角度爲"-30-30"之間.
            int jiaodu = random.nextInt(60) - 30;
            // 轉換角度爲弧度.
            double theta = jiaodu * Math.PI / 180;
            // 生成下標
            int randomIndex = random.nextInt(word.length());
            // 獲取用於驗證碼顯示的字符.
            char c = word.charAt(randomIndex);
            // 將字符寫入圖片.
            graphics2d.rotate(theta, x, 20);
            graphics2d.drawString(c + "", x, 20);
            graphics2d.rotate(-theta, x, 20);
            // 設置下一個字符出現的水平座標.
            x += 30;
        }
        // 5 繪製干擾線
        graphics2d.setColor(Color.LIGHT_GRAY);
        for (int i = 0; i < 10; i++) {
            int x1 = random.nextInt(width);
            int x2 = random.nextInt(width);
            int y1 = random.nextInt(height);
            int y2 = random.nextInt(height);
            graphics2d.drawLine(x1, y1, x2, y2);
        }
        // 6 釋放內存中的資源
        graphics2d.dispose();
        // 7 將生成的圖片,響應到客戶端瀏覽器
        ImageIO.write(image, "jpg", response.getOutputStream());
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
  • Web工程的web.xml文件中註冊Servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet>
    <servlet-name>ResponseServlet6</servlet-name>
    <servlet-class>app.java.response.ResponseServlet6</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>ResponseServlet6</servlet-name>
    <url-pattern>/response6</url-pattern>
  </servlet-mapping>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>
  • 打開瀏覽器,在地址欄中輸入http://localhost:8080/response/response6

若是驗證碼的內容設置爲中文的話,只須要將上述代碼中的word變量的值設置爲經常使用漢字便可。

到目前爲止,生成的驗證碼須要每次刷新頁面才能從新生成驗證碼,如何實現鼠標點擊驗證碼圖片改變驗證碼內容呢?具體實現步驟以下:

  • 須要在顯示驗證碼圖片的HTML頁面中,使用JavaScript代碼來實現。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>identi.html</title>
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  <script type="text/javascript">
      function change(){
        document.getElementById("myimg").src = "/response/response6";
    }
  </script>
  <body>
    <img src="/response/response6" id="myimg" onclick="change();" style="cursor: pointer;">
  </body>
</html>

這樣實現以後,實際測試發現驗證碼內容並無改變。緣由是IE瀏覽器緩存問題,有兩種方式來解決:

  • 利用以前掌握的經過設置響應頭信息中的內容,禁止瀏覽器保存緩存內容。
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", -1);
  • 經過設置img圖片每次請求的URL地址不一樣解決這個問題。
document.getElementById("myimg").src = "/response/response6?"+new Date().getTime();

3. 掌握Request

3.1. Request概述

RequestWeb應用程序用來封裝向客戶端請求信息的,是Servlet接口的service()方法的一個參數,類型爲javax.servlet.http.HttpServletRequest。客戶端每次發送請求時,服務器都會建立一個Request對象,並傳遞給Servlet接口的service()方法,來完成向客戶端的請求工做。

下列是javax.servlet.http. HttpServletRequest經常使用的API列表:

Method Summary

 String

getContextPath() 
          Returns the portion of the request URI that indicates the context of the request.

 long

getDateHeader(String name) 
          Returns the value of the specified request header as a long value that represents a Date object.

 String

getHeader(String name) 
          Returns the value of the specified request header as a String.

 Enumeration

getHeaderNames() 
          Returns an enumeration of all the header names this request contains.

 Enumeration

getHeaders(String name) 
          Returns all the values of the specified request header as an Enumeration of String objects.

 int

getIntHeader(String name) 
          Returns the value of the specified request header as an int.

 String

getMethod() 
          Returns the name of the HTTP method with which this request was made, for example, GET, POST, or PUT.

 String

getPathInfo() 
          Returns any extra path information associated with the URL the client sent when it made this request.

 String

getQueryString() 
          Returns the query string that is contained in the request URL after the path.

 String

getRequestURI() 
          Returns the part of this request's URL from the protocol name up to the query string in the first line of the HTTP request.

 StringBuffer

getRequestURL() 
          Reconstructs the URL the client used to make the request.

 String

getServletPath() 
          Returns the part of this request's URL that calls the servlet.

下列是javax.servlet.ServletRequest經常使用的API列表:

Method Summary

 String

getCharacterEncoding() 
          Returns the name of the character encoding used in the body of this request.

 String

getContentType() 
          Returns the MIME type of the body of the request, or null if the type is not known.

 String

getParameter(String name) 
          Returns the value of a request parameter as a String, or null if the parameter does not exist.

 String

getProtocol() 
          Returns the name and version of the protocol the request uses in the form protocol/majorVersion.minorVersion, for example, HTTP/1.1.

 String

getRealPath(String path) 
          Deprecated. As of Version 2.1 of the Java Servlet API, use ServletContext.getRealPath(java.lang.String) instead.

 String

getRemoteAddr() 
          Returns the Internet Protocol (IP) address of the client or last proxy that sent the request.

 String

getRemoteHost() 
          Returns the fully qualified name of the client or the last proxy that sent the request.

 int

getRemotePort() 
          Returns the Internet Protocol (IP) source port of the client or last proxy that sent the request.

 RequestDispatcher

getRequestDispatcher(String path) 
          Returns a RequestDispatcher object that acts as a wrapper for the resource located at the given path.

 String

getServerName() 
          Returns the host name of the server to which the request was sent.

 int

getServerPort() 
          Returns the port number to which the request was sent.

 

3.2. 獲取請求行信息

在學習Http請求協議時,知道Http請求協議包含請求行、請求頭及請求體三個部分。首先咱們來討論請求協議中的請求行,請求行包含請求方式、請求連接及GET方式的參數和Http請求協議版本。

GET方式的請求行內容:

GET /http/01_get.html?username=zhangsan HTTP/1.1

POST方式的請求行內容

POST /http/02_post.html HTTP/1.1

獲取Http請求協議中請求行的內容,能夠經過如下方法:

  • getMethod()方法:獲取Http請求協議的請求方式,例如GETPOST等。
  • getRequestRUI()方法:獲取Http請求協議的資源路徑。
  • getProtocol()方法:獲取Http請求協議的協議版本。
  • getQueryString()方法:獲取Http請求協議GET方式的請求參數。

下面咱們經過代碼實現,來驗證一下上述方法的功能:

  • 建立一個Servlet用於打印上述方法。
public class RequestServlet1 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 獲取請求方式,GET或POST
        System.out.println("請求方式:"+request.getMethod());
        // 獲取請求協議
        System.out.println("請求協議:"+request.getProtocol());
        // 獲取請求路徑URI和URL
        System.out.println("請求路徑URI:"+request.getRequestURI());
        System.out.println("請求路徑URL:"+request.getRequestURL());
        // 獲取請求參數
        System.out.println("請求參數:"+request.getQueryString());
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
  • Web工程的web.xml文件中註冊Servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet>
    <servlet-name>RequestServlet1</servlet-name>
    <servlet-class>app.java.request.RequestServlet1</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>RequestServlet1</servlet-name>
    <url-pattern>/request1</url-pattern>
  </servlet-mapping>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>
  • Web工程發佈到Tomcat服務器,並啓動Tomcat服務器。
  • 打開瀏覽器,在地址欄中輸入http://localhost:8080/response/request1。
  • 在地址後增長參數http://localhost:8080/response/request1?username=zhangsan

除上述方法能夠獲取請求協議的請求行中信息外,咱們還能夠經過getRemoteAddr()方法獲取客戶端IP地址和getContextPath()方法獲取Web工程虛擬目錄名稱。

// 獲取客戶端IP地址
System.out.println("客戶端IP地址:"+request.getRemoteAddr());
// 獲取Web工程虛擬目錄名稱
System.out.println("Web工程虛擬目錄名稱:"+request.getContextPath());

3.3. 獲取請求頭信息

下面咱們來討論Http請求協議中的請求頭信息,下面是一個Http請求協議的請求頭信息內容:

Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, */*
Referer: http://localhost:8080/07_http/01_get.html
Accept-Language: zh-CN
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; qdesk 2.5.1277.202; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.3)
Accept-Encoding: gzip, deflate
If-Modified-Since: Thu, 11 Sep 2014 02:44:35 GMT
If-None-Match: W/"679-1410403475587"
Host: localhost:8080
Connection: Keep-Alive

咱們以前曾利用請求頭信息中的Referer完成了防盜鏈案例,下面咱們來回顧一下。

  • 首先咱們建立一個網站的主頁面。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>index.html</title>
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <a href="refererServlet">特價商品</a>
  </body>
</html>
  • 而後咱們完成服務器端Servlet防止盜鏈的邏輯內容。
public class RefererServlet extends HttpServlet {
    // 處理GET方式的請求
    public void doGet(HttpServletRequest request, HttpServletResponse response)  throws ServletException, IOException {
        // 判斷請求中referer是否存在,有效  --- 防止盜鏈
        String referer = request.getHeader("referer");
        if(referer!=null && referer.equals("http://localhost:8080/http/index.html")){
            // 有效
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().println("筆記本1000元");
        }else{
            // 無效
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().println("盜鏈真無恥!");
        }
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
  • 將工程發佈到Tomcat服務器,啓動Tomcat服務器。
  • 打開瀏覽器,輸入http://localhost:8080/http/index.html地址。
  • 在網站主頁面中,點擊「特價商品」連接,會返回正確內容。
  • 若是在瀏覽器地址欄中直接輸入http://localhost:8080/http/refererServlet連接。
  • 因爲直接輸入連接地址的請求協議中,沒有referer信息,因此會顯示報錯信息。

在請求頭信息中,除了Referer能夠實現防盜鏈,還能夠利用User-Agent獲取客戶端瀏覽器相關信息。

  • 建立一個Servlet用於打印User-Agent請求頭信息。
public class RequestServlet2 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("瀏覽器是:"+request.getHeader("user-agent"));
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
  • Web工程的web.xml文件中註冊Servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet>
    <servlet-name>RequestServlet2</servlet-name>
    <servlet-class>app.java.request.RequestServlet2</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>RequestServlet2</servlet-name>
    <url-pattern>/request2</url-pattern>
  </servlet-mapping>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>
  • Web工程發佈到Tomcat服務器,並啓動Tomcat服務器。
  • 打開瀏覽器,在地址欄中輸入http://localhost:8080/response/request2。

咱們還能夠利用getHeaderNames()方法打印全部請求頭信息。

Enumeration<String> names = request.getHeaderNames();
while (names.hasMoreElements()) {
    String name = (String) names.nextElement();
    System.out.println(name+":"+request.getHeader(name));
}

3.4. 獲取請求參數

因爲Http請求協議中的請求方式經常使用的有兩種GETPOSTGET方式的請求參數在請求行中的資源路徑後面,POST方式的請求參數在請求體中。

在服務器端Servlet獲取請求參數共有如下四種方法:

  • getParameter()方法:獲取指定參數名的參數值(單個值)。
  • getParameterValues()方法:獲取指定參數名的參數值(多個值)。
  • getParameterNames()方法:獲取全部參數的參數名。
  • getParameterMap()方法:獲取參數以name=value形式存儲在Map集合中,將Map集合返回。

首先,咱們來討論POST方式的請求參數,在服務器端如何獲取:

  • 建立一個HTML頁面編寫form表單用於提交客戶端數據。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>POST方式請求.html</title>
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <h1>最複雜form表單</h1>
    <form method="post" action="/response/request3">
        用戶名 <input type="text" name="username" /><br/>
        密碼 <input type="password" name="password" /><br/>
        性別 <input type="radio" name="gender" value="男" /><input type="radio" name="gender" value="女" /><br/>
        愛好 <input type="checkbox" name="hobby" value="體育" />體育
        <input type="checkbox" name="hobby" value="音樂" />音樂
        <input type="checkbox" name="hobby" value="讀書" />讀書<br/>
        城市 <select name="city">
            <option value="北京">北京</option>
            <option value="上海">上海</option>
            <option value="廣州">廣州</option>
        </select> <br/>
        我的簡介 <textarea rows="5" cols="60" name="introduce"></textarea><br/>
        <input type="submit" value="提交" />
    </form>
  </body>
</html>
  • 建立一個Servlet用於接收客戶端瀏覽器請求參數。
public class RequestServlet3 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String gender = request.getParameter("gender");
        String hobby = request.getParameter("hobby");
        String city = request.getParameter("city");
        String introduce = request.getParameter("introduce");
        
        System.out.println("姓名:" + username);
        System.out.println("密碼:" + password);
        System.out.println("性別:" + gender);
        System.out.println("愛好:" + hobby);
        System.out.println("城市:" + city);
        System.out.println("我的介紹:" + introduce);
    }
}
  • Web工程的web.xml文件中註冊Servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet>
    <servlet-name>RequestServlet3</servlet-name>
    <servlet-class>app.java.request.RequestServlet3</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>RequestServlet3</servlet-name>
    <url-pattern>/request3</url-pattern>
  </servlet-mapping>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>
  • Web工程發佈到Tomcat服務器,並啓動Tomcat服務器。
  • 打開瀏覽器,在地址欄中輸入http://localhost:8080/response/request/ POST.html。
  • HTML頁面中,輸入相關信息後,點擊「提交」按鈕。
  • 在控制檯打印信息時,發現都是亂碼。POST方式解決亂碼,須要使用setCharacterEncoding()方法。
request.setCharacterEncoding("utf-8");
  • 在查看控制檯打印信息,這時的信息已經顯示正常中文了。

獲取頁面請求的數據信息中,「愛好」內容爲多選框,但實際上只打印其中一項。須要調用getParameterValues()方法來解決。

String[] hobby = request.getParameterValues("hobby");
System.out.println("愛好:" + Arrays.toString(hobby));

下面,咱們來討論一下GET方式的請求參數,在服務器端如何獲取:

  • HTML頁面中表單的Method改成「GET」。
  • 編寫Servlet用於接收客戶端瀏覽器請求參數。
public class RequestServlet3 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String gender = request.getParameter("gender");
        String hobby = request.getParameter("hobby");
        String city = request.getParameter("city");
        String introduce = request.getParameter("introduce");
        
        System.out.println("姓名:" + username);
        System.out.println("密碼:" + password);
        System.out.println("性別:" + gender);
        System.out.println("愛好:" + hobby);
        System.out.println("城市:" + city);
        System.out.println("我的介紹:" + introduce);
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
    }
}
  • 打開瀏覽器,在地址欄中輸入http://localhost:8080/response/request/ POST.html。
  • 在控制檯打印信息時,發現都是亂碼。

POST方式解決亂碼,有兩種方式:

  • 修改Tomcat服務器安裝目錄的conf目錄中的server.xml文件。
<Connector port="8080" protocol="HTTP/1.1"
         connectionTimeout="20000"
         redirectPort="8443"
RUIEncoding="utf-8" />
  • 經過代碼進行逆向解碼(以用戶名爲例)。
username = URLEncoder.encode(username, "ISO-8859-1");
username = URLDecoder.decode(username, "utf-8");

或者也能夠利用下面這種方式來解決逆向解碼。

gender = new String(gender.getBytes("ISO-8859-1"), "utf-8");

固然,獲取到客戶端瀏覽器發送的請求參數內容後,還能夠完成非空的驗證功能。

if (username != null && username.length() > 0) {
    System.out.println("username 有效.");
}

3.5. 請求轉發數據

以前咱們完成了重定向的功能,如今要完成請求轉發的功能。這兩個功能常常會放在一塊兒比較:

  • 重定向:
    • 發生兩次請求,兩次響應。
    • 重定向在客戶端瀏覽器能夠查看到。
    • 重定向沒法攜帶數據。
    • 重定向中的第二次請求資源路徑來源於客戶端。
  • 請求轉發:
    • 發生一次請求,一次響應。
    • 請求轉發在客戶端瀏覽器沒法查看。
    • 請求轉發能夠攜帶數據。
    • 請求轉發的第二次請求資源路徑來源於服務器端內部。

下面咱們來實現請求轉發的功能,再比較請求轉發與重定向的區別。

  • 建立一個Servlet用於接收客戶端請求。
public class RequestServlet4 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("這是Servlet4...");
        // 獲取請求轉發對象
        RequestDispatcher dispatcher = request.getRequestDispatcher("/request5");
        // 利用forward()方法進行請求轉發.
        dispatcher.forward(request, response);
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
  • 再建立一個Servlet用於接收請求轉發的請求。
public class RequestServlet5 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("這是Servlet5...");
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
  • Web工程的web.xml文件中註冊Servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet>
    <servlet-name>RequestServlet4</servlet-name>
    <servlet-class>app.java.request.RequestServlet4</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>RequestServlet5</servlet-name>
    <servlet-class>app.java.request.RequestServlet5</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>RequestServlet4</servlet-name>
<url-pattern>/request4</url-pattern>
  </servlet-mapping>    
  <servlet-mapping>
    <servlet-name>RequestServlet5</servlet-name>
<url-pattern>/request5</url-pattern>
  </servlet-mapping>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>
  • 打開瀏覽器,在地址欄輸入http://localhost:8080/response/request4
  • 經過Request對象的setAttribute()方法和getAttribute()方法來攜帶數據。

RequestServlet4

// 向Request對象中,存儲數據內容.
request.setAttribute("name", "longestory");

RequestServlet5

String name = (String)request.getAttribute("name");
System.out.println("獲取的name爲:"+name);
  • 打開瀏覽器,在地址欄輸入http://localhost:8080/response/request4
  • 而從客戶端瀏覽器經過HttpWatch工具查看請求時,只發生了一次請求。
相關文章
相關標籤/搜索