1. 程式人生 > >JavaWeb學習總結(五)——HttpServletRequest物件

JavaWeb學習總結(五)——HttpServletRequest物件

一、HttpServletRequest介紹

  HttpServletRequest物件代表客戶端的請求,當客戶端通過HTTP協議訪問伺服器時,HTTP請求頭中的所有資訊都封裝在這個物件中,通過這個物件提供的方法,可以獲得客戶端請求的所有資訊。

二、Request常用方法

    2.1、獲得客戶機資訊

  getRequestURL方法返回客戶端發出請求時的完整URL。  getRequestURI方法返回請求行中的資源名部分。  getQueryString 方法返回請求行中的引數部分。   getPathInfo方法返回請求URL中的額外路徑資訊。額外路徑資訊是請求URL中的位於Servlet的路徑之後和查詢引數之前的內容,它以“/”開頭。   getRemoteAddr方法返回發出請求的客戶機的IP地址。

  getRemoteHost方法返回發出請求的客戶機的完整主機名。   getRemotePort方法返回客戶機所使用的網路埠號。   getLocalAddr方法返回WEB伺服器的IP地址。   getLocalName方法返回WEB伺服器的主機名。

範例:通過request物件獲取客戶端請求資訊

package gacl.request.study;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * @author gacl
 * 通過request物件獲取客戶端請求資訊
 */
public class RequestDemo01 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        /**
         * 1.獲得客戶機資訊
         */
        String requestUrl = request.getRequestURL().toString();//得到請求的URL地址
        String requestUri = request.getRequestURI();//得到請求的資源
        String queryString = request.getQueryString();//得到請求的URL地址中附帶的引數
        String remoteAddr = request.getRemoteAddr();//得到來訪者的IP地址
        String remoteHost = request.getRemoteHost();
        int remotePort = request.getRemotePort();
        String remoteUser = request.getRemoteUser();
        String method = request.getMethod();//得到請求URL地址時使用的方法
        String pathInfo = request.getPathInfo();
        String localAddr = request.getLocalAddr();//獲取WEB伺服器的IP地址
        String localName = request.getLocalName();//獲取WEB伺服器的主機名
        response.setCharacterEncoding("UTF-8");//設定將字元以"UTF-8"編碼輸出到客戶端瀏覽器
        //通過設定響應頭控制瀏覽器以UTF-8的編碼顯示資料,如果不加這句話,那麼瀏覽器顯示的將是亂碼
        response.setHeader("content-type", "text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.write("獲取到的客戶機資訊如下:");
        out.write("<hr/>");
        out.write("請求的URL地址:"+requestUrl);
        out.write("<br/>");
        out.write("請求的資源:"+requestUri);
        out.write("<br/>");
        out.write("請求的URL地址中附帶的引數:"+queryString);
        out.write("<br/>");
        out.write("來訪者的IP地址:"+remoteAddr);
        out.write("<br/>");
        out.write("來訪者的主機名:"+remoteHost);
        out.write("<br/>");
        out.write("使用的埠號:"+remotePort);
        out.write("<br/>");
        out.write("remoteUser:"+remoteUser);
        out.write("<br/>");
        out.write("請求使用的方法:"+method);
        out.write("<br/>");
        out.write("pathInfo:"+pathInfo);
        out.write("<br/>");
        out.write("localAddr:"+localAddr);
        out.write("<br/>");
        out.write("localName:"+localName);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

執行結果:

2.2、獲得客戶機請求頭

       getHeader(string name)方法:String    getHeaders(String name)方法:Enumeration    getHeaderNames()方法

範例:通過request物件獲取客戶端請求頭資訊

package gacl.request.study;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * @author gacl
 * 獲取客戶端請求頭資訊
 * 客戶端請求頭:
 * 
 */
public class RequestDemo02 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");//設定將字元以"UTF-8"編碼輸出到客戶端瀏覽器
        //通過設定響應頭控制瀏覽器以UTF-8的編碼顯示資料
        response.setHeader("content-type", "text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        Enumeration<String> reqHeadInfos = request.getHeaderNames();//獲取所有的請求頭
        out.write("獲取到的客戶端所有的請求頭資訊如下:");
        out.write("<hr/>");
        while (reqHeadInfos.hasMoreElements()) {
            String headName = (String) reqHeadInfos.nextElement();
            String headValue = request.getHeader(headName);//根據請求頭的名字獲取對應的請求頭的值
            out.write(headName+":"+headValue);
            out.write("<br/>");
        }
        out.write("<br/>");
        out.write("獲取到的客戶端Accept-Encoding請求頭的值:");
        out.write("<hr/>");
        String value = request.getHeader("Accept-Encoding");//獲取Accept-Encoding請求頭對應的值
        out.write(value);
        
        Enumeration<String> e = request.getHeaders("Accept-Encoding");
        while (e.hasMoreElements()) {
            String string = (String) e.nextElement();
            System.out.println(string);
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

執行結果如下:

2.3、獲得客戶機請求引數(客戶端提交的資料)

  • getParameter(String)方法(常用)
  • getParameterValues(String name)方法(常用)
  • getParameterNames()方法(不常用)
  • getParameterMap()方法(編寫框架時常用)

比如現在有如下的form表單

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
    <title>Html的Form表單元素</title>
</head>
<fieldset style="width:500px;">
    <legend>Html的Form表單元素</legend>
    <!--form表單的action屬性規定當提交表單時,向何處傳送表單資料,method屬性指明表單的提交方式,分為get和post,預設為get-->
    <form action="${pageContext.request.contextPath}/servlet/RequestDemo03" method="post">
    <!--輸入文字框,SIZE表示顯示長度,maxlength表示最多輸入長度-->
    編&nbsp;&nbsp;號(文字框):
    <input type="text" name="userid" value="NO." size="2" maxlength="2"><br>
    <!--輸入文字框,通過value指定其顯示的預設值-->
    使用者名稱(文字框):<input type="text" name="username" value="請輸入使用者名稱"><br>
    <!--密碼框,其中所有輸入的內容都以密文的形式顯示-->
    密&nbsp;&nbsp;碼(密碼框):
    <!--&nbsp;表示的是一個空格-->
    <input type="password" name="userpass" value="請輸入密碼"><br>
    <!--單選按鈕,通過checked指定預設選中,名稱必須一樣,其中value為真正需要的內容-->
    性&nbsp;&nbsp;別(單選框):
    <input type="radio" name="sex" value="男" checked>男 
    <input type="radio" name="sex" value="女">女<br>
    <!--下拉列表框,通過<option>元素指定下拉的選項-->
    部&nbsp;&nbsp;門(下拉框):
    <select name="dept">
        <option value="技術部">技術部</option>
        <option value="銷售部" SELECTED>銷售部</option>
        <option value="財務部">財務部</option>
    </select><br>
    <!--複選框,可以同時選擇多個選項,名稱必須一樣,其中value為真正需要的內容-->
    興&nbsp;&nbsp;趣(複選框): 
    <input type="checkbox" name="inst" value="唱歌">唱歌 
    <input type="checkbox" name="inst" value="游泳">游泳 
    <input type="checkbox" name="inst" value="跳舞">跳舞 
    <input type="checkbox" name="inst" value="程式設計" checked>程式設計 
    <input type="checkbox" name="inst" value="上網">上網
    <br>
    <!--大文字輸入框,寬度為34列,高度為5行-->
    說&nbsp;&nbsp;明(文字域):
    <textarea name="note" cols="34" rows="5">
     </textarea>
    <br>
    <!--隱藏域,在頁面上無法看到,專門用來傳遞引數或者儲存引數-->
    <input type="hidden" name="hiddenField" value="hiddenvalue"/>
    <!--提交表單按鈕,當點選提交後,所有填寫的表單內容都會被傳輸到伺服器端-->
    <input type="submit" value="提交(提交按鈕)">
    <!--重置表單按鈕,當點選重置後,所有表單恢復原始顯示內容-->
    <input type="reset" value="重置(重置按鈕)">
</form>
<!--表單結束-->
</fieldset>
</body>
<!--完結標記-->
</html>
<!--完結標記-->

在Form表單中填寫資料,然後提交到RequestDemo03這個Servlet進行處理,填寫的表單資料如下:

在伺服器端使用getParameter方法getParameterValues方法接收表單引數,程式碼如下

package gacl.request.study;
import java.io.IOException;
import java.text.MessageFormat;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * @author gacl
 * 獲取客戶端通過Form表單提交上來的引數
 */
public class RequestDemo03 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //客戶端是以UTF-8編碼提交表單資料的,所以需要設定伺服器端以UTF-8的編碼進行接收,否則對於中文資料就會產生亂碼
        request.setCharacterEncoding("UTF-8");
        /**
         * 編&nbsp;&nbsp;號(文字框):
           <input type="text" name="userid" value="NO." size="2" maxlength="2">
         */
        String userid = request.getParameter("userid");//獲取填寫的編號,userid是文字框的名字,<input type="text" name="userid">
        /**
         * 使用者名稱(文字框):<input type="text" name="username" value="請輸入使用者名稱">
         */
        String username = request.getParameter("username");//獲取填寫的使用者名稱
        /**
         * 密&nbsp;&nbsp;碼(密碼框):<input type="password" name="userpass" value="請輸入密碼">
         */
        String userpass = request.getParameter("userpass");//獲取填寫的密碼
        String sex = request.getParameter("sex");//獲取選中的性別
        String dept = request.getParameter("dept");//獲取選中的部門
        //獲取選中的興趣,因為可以選中多個值,所以獲取到的值是一個字串陣列,因此需要使用getParameterValues方法來獲取
        String[] insts = request.getParameterValues("inst");
        String note = request.getParameter("note");//獲取填寫的說明資訊
        String hiddenField = request.getParameter("hiddenField");//獲取隱藏域的內容
        
        String instStr="";
        /**
         * 獲取陣列資料的技巧,可以避免insts陣列為null時引發的空指標異常錯誤!
         */
        for (int i = 0; insts!=null && i < insts.length; i++) {
            if (i == insts.length-1) {
                instStr+=insts[i];
            }else {
                instStr+=insts[i]+",";
            }
        }
        
        String htmlStr = "<table>" +
                            "<tr><td>填寫的編號:</td><td>{0}</td></tr>" +
                            "<tr><td>填寫的使用者名稱:</td><td>{1}</td></tr>" +
                            "<tr><td>填寫的密碼:</td><td>{2}</td></tr>" +
                            "<tr><td>選中的性別:</td><td>{3}</td></tr>" +
                            "<tr><td>選中的部門:</td><td>{4}</td></tr>" +
                            "<tr><td>選中的興趣:</td><td>{5}</td></tr>" +
                            "<tr><td>填寫的說明:</td><td>{6}</td></tr>" +
                            "<tr><td>隱藏域的內容:</td><td>{7}</td></tr>" +
                        "</table>";
        htmlStr = MessageFormat.format(htmlStr, userid,username,userpass,sex,dept,instStr,note,hiddenField);
        
        response.setCharacterEncoding("UTF-8");//設定伺服器端以UTF-8編碼輸出資料到客戶端
        response.setContentType("text/html;charset=UTF-8");//設定客戶端瀏覽器以UTF-8編碼解析資料
        response.getWriter().write(htmlStr);//輸出htmlStr裡面的內容到客戶端瀏覽器顯示
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

執行結果如下:

在伺服器端使用getParameterNames方法接收表單引數,程式碼如下:

 Enumeration<String> paramNames = request.getParameterNames();//獲取所有的引數名
         while (paramNames.hasMoreElements()) {
             String name = paramNames.nextElement();//得到引數名
             String value = request.getParameter(name);//通過引數名獲取對應的值
             System.out.println(MessageFormat.format("{0}={1}", name,value));
         }

執行結果如下:

在伺服器端使用getParameterMap方法接收表單引數,程式碼如下:

//request物件封裝的引數是以Map的形式儲存的
        Map<String, String[]> paramMap = request.getParameterMap();
        for(Map.Entry<String, String[]> entry :paramMap.entrySet()){
            String paramName = entry.getKey();
            String paramValue = "";
            String[] paramValueArr = entry.getValue();
            for (int i = 0; paramValueArr!=null && i < paramValueArr.length; i++) {
                if (i == paramValueArr.length-1) {
                    paramValue+=paramValueArr[i];
                }else {
                    paramValue+=paramValueArr[i]+",";
                }
            }
            System.out.println(MessageFormat.format("{0}={1}", paramName,paramValue));
        }

執行結果如下:

三、request接收表單提交中文引數亂碼問題

3.1、以POST方式提交表單中文引數的亂碼問題

例如有如下的form表單頁面:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>request接收中文引數亂碼問題</title>
  </head>
  
  <body>
      <form action="<%=request.getContextPath()%>/servlet/RequestDemo04" method="post">
          使用者名稱:<input type="text" name="userName"/>
          <input type="submit" value="post方式提交表單"> 
      </form>
  </body>
</html>

此時在伺服器端接收中文引數時就會出現中文亂碼,如下所示:

3.2、post方式提交中文資料亂碼產生的原因和解決辦法

  可以看到,之所以會產生亂碼,就是因為伺服器和客戶端溝通的編碼不一致造成的,因此解決的辦法是:在客戶端和伺服器之間設定一個統一的編碼,之後就按照此編碼進行資料的傳輸和接收。

  由於客戶端是以UTF-8字元編碼將表單資料傳輸到伺服器端的,因此伺服器也需要設定以UTF-8字元編碼進行接收,要想完成此操作,伺服器可以直接使用從ServletRequest介面繼承而來的"setCharacterEncoding(charset)"方法進行統一的編碼設定。修改後的程式碼如下:

public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        /**
         * 客戶端是以UTF-8編碼傳輸資料到伺服器端的,所以需要設定伺服器端以UTF-8的編碼進行接收,否則對於中文資料就會產生亂碼
         */
        request.setCharacterEncoding("UTF-8");
        String userName = request.getParameter("userName");
        System.out.println("userName:"+userName);
}

  使用request.setCharacterEncoding("UTF-8");設定伺服器以UTF-8的編碼接收資料後,此時就不會產生中文亂碼問題了,如下所示:

3.3、以GET方式提交表單中文引數的亂碼問題

例如有如下的form表單頁面:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>request接收中文引數亂碼問題</title>
  </head>
  
  <body>
        <form action="${pageContext.request.contextPath}/servlet/RequestDemo04" method="get">
          姓名:<input type="text" name="name"/>
          <input type="submit" value="get方式提交表單"> 
      </form>
  </body>
</html>

此時在伺服器端接收中文引數時就會出現中文亂碼,如下所示:

  那麼這個中文亂碼問題又該如何解決呢,是否可以通過request.setCharacterEncoding("UTF-8");設定伺服器以UTF-8的編碼進行接收這種方式來解決中文亂碼問題呢,注意,對於以get方式傳輸的中文資料,通過request.setCharacterEncoding("UTF-8");這種方式是解決不了中文亂碼問題,如下所示:

3.4、get方式提交中文資料亂碼產生的原因和解決辦法

 對於以get方式傳輸的資料,request即使設定了以指定的編碼接收資料也是無效的(至於為什麼無效我也沒有弄明白),預設的還是使用ISO8859-1這個字元編碼來接收資料,客戶端以UTF-8的編碼傳輸資料到伺服器端,而伺服器端的request物件使用的是ISO8859-1這個字元編碼來接收資料,伺服器和客戶端溝通的編碼不一致因此才會產生中文亂碼的。解決辦法:在接收到資料後,先獲取request物件以ISO8859-1字元編碼接收到的原始資料的位元組陣列,然後通過位元組陣列以指定的編碼構建字串,解決亂碼問題程式碼如下:

public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        /**
         *
         * 對於以get方式傳輸的資料,request即使設定了以指定的編碼接收資料也是無效的,預設的還是使用ISO8859-1這個字元編碼來接收資料
         */
        String name = request.getParameter("name");//接收資料
        name =new String(name.getBytes("ISO8859-1"), "UTF-8") ;//獲取request物件以ISO8859-1字元編碼接收到的原始資料的位元組陣列,然後通過位元組陣列以指定的編碼構建字串,解決亂碼問題
        System.out.println("name:"+name);    
}

執行結果如下:

3.5、以超連結形式傳遞中文引數的亂碼問題

  客戶端想傳輸資料到伺服器,可以通過表單提交的形式,也可以通過超連結後面加引數的形式,例如:

<a href="${pageContext.request.contextPath}/servlet/RequestDemo05?userName=gacl&name=徐達沛">點選</a>

  點選超連結,資料是以get的方式傳輸到伺服器的,所以接收中文資料時也會產生中文亂碼問題,而解決中文亂碼問題的方式與上述的以get方式提交表單中文資料亂碼處理問題的方式一致,如下所示:

 String name = request.getParameter("name");
 name =new String(name.getBytes("ISO8859-1"), "UTF-8");

  另外,需要提的一點就是URL地址後面如果跟了中文資料,那麼中文引數最好使用URL編碼進行處理,如下所示:

 <a href="${pageContext.request.contextPath}/servlet/RequestDemo05?userName=gacl&name=<%=URLEncoder.encode("徐達沛", "UTF-8")%>">點選</a>

3.6、提交中文資料亂碼問題總結

 1、如果提交方式為post,想不亂碼,只需要在伺服器端設定request物件的編碼即可,客戶端以哪種編碼提交的,伺服器端的request物件就以對應的編碼接收,比如客戶端是以UTF-8編碼提交的,那麼伺服器端request物件就以UTF-8編碼接收(request.setCharacterEncoding("UTF-8"))

  2、如果提交方式為get,設定request物件的編碼是無效的,request物件還是以預設的ISO8859-1編碼接收資料,因此要想不亂碼,只能在接收到資料後再手工轉換,步驟如下:

      1).獲取獲取客戶端提交上來的資料,得到的是亂碼字串,data="???è?????"

   String data = request.getParameter("paramName"); 

  2).查詢ISO8859-1碼錶,得到客戶機提交的原始資料的位元組陣列

   byte[] source = data.getBytes("ISO8859-1"); 

  3).通過位元組陣列以指定的編碼構建字串,解決亂碼

   data = new String(source, "UTF-8"); 

      通過位元組陣列以指定的編碼構建字串,這裡指定的編碼是根據客戶端那邊提交資料時使用的字元編碼來定的,如果是GB2312,那麼就設定成data = new String(source, "GB2312"),如果是UTF-8,那麼就設定成data = new String(source, "UTF-8")

四、Request物件實現請求轉發

4.1、請求轉發的基本概念

 請求轉發:指一個web資源收到客戶端請求後,通知伺服器去呼叫另外一個web資源進行處理。  請求轉發的應用場景:MVC設計模式

 在Servlet中實現請求轉發的兩種方式:

         1、通過ServletContext的getRequestDispatcher(String path)方法,該方法返回一個RequestDispatcher物件,呼叫這個物件的forward方法可以實現請求轉發。    

例如:將請求轉發的test.jsp頁面

 RequestDispatcher reqDispatcher =this.getServletContext().getRequestDispatcher("/test.jsp");
 reqDispatcher.forward(request, response);

     2、通過request物件提供的getRequestDispatche(String path)方法,該方法返回一個RequestDispatcher物件,呼叫這個物件的forward方法可以實現請求轉發。

例如:將請求轉發的test.jsp頁面

request.getRequestDispatcher("/test.jsp").forward(request, response);

  request物件同時也是一個域物件(Map容器),開發人員通過request物件在實現轉發時,把資料通過request物件帶給其它web資源處理。

例如:請求RequestDemo06 Servlet,RequestDemo06將請求轉發到test.jsp頁面

package gacl.request.study;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class RequestDemo06 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String data="大家好,我是孤傲蒼狼,我正在總結JavaWeb";
        /**
         * 將資料存放到request物件中,此時把request物件當作一個Map容器來使用
         */
        request.setAttribute("data", data);
        //客戶端訪問RequestDemo06這個Servlet後,RequestDemo06通知伺服器將請求轉發(forward)到test.jsp頁面進行處理
        request.getRequestDispatcher("/test.jsp").forward(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

  test.jsp頁面程式碼如下:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Request物件實現請求轉發</title>
  </head>
  
  <body>
      使用普通方式取出儲存在request物件中的資料:
      <h3 style="color:red;"><%=(String)request.getAttribute("data")%></h3>
     使用EL表示式取出儲存在request物件中的資料:
     <h3 style="color:red;">${data}</h3>
  </body>
</html>

執行結果如下:

request物件作為一個域物件(Map容器)使用時,主要是通過以下的四個方法來操作

  • setAttribute(String name,Object o)方法,將資料作為request物件的一個屬性存放到request物件中,例如:request.setAttribute("data", data);
  • getAttribute(String name)方法,獲取request物件的name屬性的屬性值,例如:request.getAttribute("data")
  • removeAttribute(String name)方法,移除request物件的name屬性,例如:request.removeAttribute("data")
  • getAttributeNames方法,獲取request物件的所有屬性名,返回的是一個,例如:Enumeration<String> attrNames = request.getAttributeNames();

4.2、請求重定向和請求轉發的區別

一個web資源收到客戶端請求後,通知伺服器去呼叫另外一個web資源進行處理,稱之為請求轉發/307。 一個web資源收到客戶端請求後,通知瀏覽器去訪問另外一個web資源進行處理,稱之為請求重定向/302。