Servlet學(xué)習(xí)2 -- Request對(duì)象

一.Servlet中處理請(qǐng)求的方式

之前介紹過(guò)Servlet的體系結(jié)構(gòu),廣義上來(lái)說(shuō),Servlet是一個(gè)接口,有實(shí)現(xiàn)類GenericsServlet,而GenericsServlet是一個(gè)抽象類,有直接的子類HttpServlet。

而HttpServlet要比GenericsServlet要強(qiáng)大,因?yàn)樗怯蒅enericsServlet抽象類擴(kuò)展而來(lái)的,并且現(xiàn)在大部分的應(yīng)用程序都是與HTTP結(jié)合起來(lái)使用,而且HTTPServlet封裝了許多,使得我們的開(kāi)發(fā)變得更加簡(jiǎn)潔。

之前當(dāng)我們要實(shí)現(xiàn)Servlet接口時(shí),是需要重寫5個(gè)方法的:init,destroy,service,getServletConfig,getServletInfo,這樣太麻煩,我們可以直接繼承HttpServlet類,因?yàn)镠TTPServlet默認(rèn)已經(jīng)實(shí)現(xiàn)了Servlet接口中的所有方法了,寫代碼時(shí)只需要重寫需要的方法即可。

具體操作方式為:
  • 繼承HttpServlet
  • 重寫doGet()和doPost()方法,并且在doGet()或者doPost()中寫入一句this.doPost(req,resp)this.doGet(req,resp),因?yàn)檫@樣子無(wú)論是Get請(qǐng)求還是POST請(qǐng)求,處理的方式都相同。

二.Request對(duì)象

  1. request對(duì)象的原理

    • request對(duì)象是由服務(wù)器創(chuàng)建的,我們只需要直接使用就好了。
    • request對(duì)象就是將瀏覽器的請(qǐng)求封裝成的對(duì)象,能夠獲取請(qǐng)求文本中的所有內(nèi)容,包括請(qǐng)求頭,請(qǐng)求體和請(qǐng)求行
  2. request對(duì)象的繼承體系

    ServletRequest -- 接口
    | 繼承
    HttpServletRequest -- 接口
    | 實(shí)現(xiàn)
    org.apache.catalina.connector.RequestFacade 類(tomcat)

  3. request對(duì)象的功能

    • 獲取請(qǐng)求行數(shù)據(jù)

      1. 獲取請(qǐng)求方式

        String getMethod()

      2. 獲取虛擬目錄

        String getContextPath()

      3. 獲取Servlet路徑

        String getServletPath()

      4. 獲取get方式請(qǐng)求參數(shù)

        String getQueryString()

      5. 獲取請(qǐng)求URI

        String getRequestURI()

        String getRequestURL()

      6. 獲取協(xié)議和版本

        String getProtocol()

      7. 獲取客戶機(jī)的IP地址

        String getRemoteAddr()

      @WebServlet("/RequestServlet")
      public class RequestServlet extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              // 1. 獲取請(qǐng)求方式
              String method = request.getMethod();
              System.out.println("請(qǐng)求方式為:" + method);
      
              // 2. 獲取虛擬目錄
              String contextPath = request.getContextPath();
              System.out.println("虛擬目錄是:" + contextPath);
      
              // 3. 獲取Servlet路徑
              String servletPath = request.getServletPath();
              System.out.println("Servlet路徑為:" + servletPath);
      
              // 4. 獲取get請(qǐng)求參數(shù)
              String queryString = request.getQueryString();
              System.out.println("Get請(qǐng)求參數(shù):" + queryString);
      
              // 5. 獲取請(qǐng)求URI
              String requestURI = request.getRequestURI();
              StringBuffer requestURL = request.getRequestURL();
              System.out.println("請(qǐng)求URI為:" + requestURI);
              System.out.println("請(qǐng)求URL為:" + requestURL);
      
              // 6. 獲取協(xié)議和版本
              String protocol = request.getProtocol();
              System.out.println("協(xié)議和版本為:" + protocol);
      
              // 7. 獲取客戶機(jī)的IP地址
              String remoteAddr = request.getRemoteAddr();
              System.out.println("客戶機(jī)IP地址為:" + remoteAddr);
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              doPost(request, response);
          }
      }
      
      瀏覽器請(qǐng)求為:http://localhost/BlogTest/RequestServlet?name=zhangsan&age=18
      控制臺(tái)輸出為:
          請(qǐng)求方式為:GET
          虛擬目錄是:/BlogTest
          Servlet路徑為:/RequestServlet
          Get請(qǐng)求參數(shù):name=zhangsan&age=18
          請(qǐng)求URI為:/BlogTest/RequestServlet
          請(qǐng)求URL為:http://localhost/BlogTest/RequestServlet
          協(xié)議和版本為:HTTP/1.1
          客戶機(jī)IP地址為:0:0:0:0:0:0:0:1
      
      
    • 獲取請(qǐng)求頭數(shù)據(jù)

      • String getHeader(String name):通過(guò)請(qǐng)求頭名字獲取請(qǐng)求頭的值
      • Enumeration<String> getHeaderNames():獲取所有請(qǐng)求頭的名字
      @WebServlet("/RequestServlet2")
      public class RequestServlet2 extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              // 1. 獲取請(qǐng)求頭  -- 獲取User-Agent的值,獲知瀏覽器版本信息
              String header = request.getHeader("User-Agent");
              System.out.println("請(qǐng)求頭User-Agent:" + header);
      
              // 2. 獲取所有的請(qǐng)求頭
              Enumeration<String> headerNames = request.getHeaderNames();
              System.out.println("所有請(qǐng)求頭列表:");
              while (headerNames.hasMoreElements()) {
                  String name = headerNames.nextElement();
                  // 獲取請(qǐng)求頭數(shù)據(jù)
                  String head = request.getHeader(name);
                  System.out.println(name + ":" + head);
              }
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              doPost(request, response);
          }
      }
      
      請(qǐng)求頭User-Agent:Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36
      所有請(qǐng)求頭列表:
          host:localhost
          connection:keep-alive
          cache-control:max-age=0
          upgrade-insecure-requests:1
          user-agent:Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36
          accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
          accept-encoding:gzip, deflate, br
          accept-language:zh-CN,zh;q=0.9,en;q=0.8
          cookie:JSESSIONID=2BFDB4BDC8DF9089DEE0BAA90B9EF721; Idea-6b401060=b4304026-b59a-47c6-8b46-5e6042267d2c
      
    • 獲取請(qǐng)求體數(shù)據(jù)

      請(qǐng)求體只有POST請(qǐng)求才有,封裝了post請(qǐng)求的請(qǐng)求參數(shù)。

      獲取請(qǐng)求體數(shù)據(jù)的操作步驟為:

      1. 獲取流對(duì)象

        BufferedReader getReader():獲取字符輸入流,只能操作字符數(shù)據(jù)

        ServletInputStream getInputStream():獲取字節(jié)輸入流,可以操作所有數(shù)據(jù)類型

      2. 從流對(duì)象中獲取數(shù)據(jù)

      @WebServlet("/RequestServlet3")
      public class RequestServlet3 extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      
              // 字節(jié)流
      //        ServletInputStream inputStream = request.getInputStream();
      //
      //        byte[] bytes = new byte[1024];
      //        int len = 0;
      //        while ((len = inputStream.read(bytes)) != -1) {
      //            System.out.println(new String(bytes,0, len));
      //        } // 輸出:username=zhangsan&password=12345678
      
              // 字符流
              BufferedReader reader = request.getReader();
              String line = null;
      
              while ((line = reader.readLine()) != null) {
                  System.out.println(line);
              }
             // 輸出:username=zhangsan&password=12345678
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              doPost(request, response);
          }
      }
      
  4. request對(duì)象其他功能

    • 通用的獲取請(qǐng)求參數(shù)

      由上面的可以看出,get方式獲取請(qǐng)求參數(shù)使用的是getQueryString(),post方式是通過(guò)獲取請(qǐng)求體來(lái)得到請(qǐng)求參數(shù),這樣子太麻煩,還要區(qū)分,所以有以下幾個(gè)方法,不論是get還是post都可以使用來(lái)獲取請(qǐng)求參數(shù),屬于通用的。

      1. String getParameter(String name):根據(jù)參數(shù)名獲取參數(shù)值
      2. String[] getParameterValues(String name):根據(jù)參數(shù)名獲取參數(shù)值的數(shù)組(對(duì)于一些同一個(gè)名字有多個(gè)值的情況,比如復(fù)選框checkbox)
      3. Enumeration<String> getParameterNames():獲取所有請(qǐng)求參數(shù)的名稱
      4. Map<String,String[]> getParameterMap():獲取所有參數(shù)的名稱和值的Map集合
      @WebServlet("/RequestServlet4")
      public class RequestServlet4 extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              // 1. 獲取請(qǐng)求參數(shù)username的值
              String username = request.getParameter("username");
              System.out.println("username :" + username);
              System.out.println("--------------------");
      
              // 2. 獲取請(qǐng)求參數(shù)sport的所有值
              String[] sports = request.getParameterValues("sport");
              for (String sport : sports) {
                  System.out.println("sport : " + sport);
              }
              System.out.println("--------------------");
      
              // 3. 獲取所有請(qǐng)求參數(shù)的名字
              Enumeration<String> names = request.getParameterNames();
              while (names.hasMoreElements()) {
                  String name = names.nextElement();
                  System.out.println("name: " + name);
              }
              System.out.println("--------------------");
      
              // 4. 獲取所有請(qǐng)求參數(shù)的Map集合
              Map<String, String[]> parameterMap = request.getParameterMap();
              Set<String> keyset = parameterMap.keySet();
              for (String name: keyset) {
                  String[] values = parameterMap.get(name);
                  for (String v : values) {
                      System.out.println(name + " ---> " + v);
                  }
              }
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              doPost(request, response);
          }
      }
      
      請(qǐng)求為:
         http://localhost/BlogTest/RequestServlet4?username=zhangsan&&sport=basketball&&sport=football
      控制臺(tái)輸出為:
         username :zhangsan
          --------------------
          sport : basketball
          sport : football
          --------------------
          name: username
          name: sport
          --------------------
          username ---> zhangsan
          sport ---> basketball
          sport ---> football
      
    • 請(qǐng)求轉(zhuǎn)發(fā)

      請(qǐng)求轉(zhuǎn)發(fā)是在服務(wù)器內(nèi)的資源跳轉(zhuǎn)方式(還有一種是重定向),具有以下特點(diǎn):

      1. 瀏覽器的地址欄路徑是不會(huì)發(fā)生變化的。
      2. 只能轉(zhuǎn)發(fā)到當(dāng)前服務(wù)器的內(nèi)部資源。
      3. 轉(zhuǎn)發(fā)是一次請(qǐng)求

      操作步驟為:

      1. 通過(guò)request獲取請(qǐng)求轉(zhuǎn)發(fā)器對(duì)象:RequestDispatcher getRequestDispatcher(String path)
      2. 使用forward方法進(jìn)行轉(zhuǎn)發(fā):forward(ServletRequest request, ServletResponse response)
    • 共享數(shù)據(jù)

      在進(jìn)行請(qǐng)求轉(zhuǎn)發(fā)時(shí),請(qǐng)求轉(zhuǎn)發(fā)是一次請(qǐng)求,會(huì)將request和response傳遞給要轉(zhuǎn)發(fā)到的請(qǐng)求中,在這中間,兩個(gè)請(qǐng)求間可能需要共享一些數(shù)據(jù),這些數(shù)據(jù)只存在一次請(qǐng)求的范圍。

      主要有以下方法:

      1. void setAttribute(String name, Object obj):存儲(chǔ)數(shù)據(jù),以鍵值對(duì)的方式存儲(chǔ)
      2. Object getAttribute(String name):通過(guò)鍵獲取值
      3. void removeAttribute(String name):移除指定的鍵值對(duì)

      第一個(gè)Servlet:

      @WebServlet("/RequestServlet5")
      public class RequestServlet5 extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              System.out.println("這是RequestServlet5...");
      
              // 設(shè)置共享數(shù)據(jù)
              request.setAttribute("usernmae", "zhangsan");
      
              // 請(qǐng)求轉(zhuǎn)發(fā)
              request.getRequestDispatcher("/RequestServlet6").forward(request, response);
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              doPost(request, response);
          }
      }
      

      第二個(gè)Servlet:

      @WebServlet("/RequestServlet6")
      public class RequestServlet6 extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              System.out.println("這是RequestServlet6...");
      
              // 獲取共享數(shù)據(jù)
              String username = (String)request.getAttribute("usernmae");
              if (username != null) {
                  System.out.println("共享數(shù)據(jù)是: username ---> " + username);
              }
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              doPost(request, response);
          }
      }
      
      請(qǐng)求為:http://localhost/BlogTest/RequestServlet5
      控制臺(tái)輸出為:
         這是RequestServlet5...
         這是RequestServlet6...
         共享數(shù)據(jù)是: username ---> zhangsan
      
  • 獲取ServletContext(以后再詳解)

    ServletContext getServletContext()

  1. 中文亂碼問(wèn)題

    1. 對(duì)于get方式,在service中使用的編碼和解碼方式默認(rèn)為:ISO-8859-1,這個(gè)編碼不支持中文,所以會(huì)出現(xiàn)亂碼,需要手動(dòng)修改編碼方式為UTF-8,才能解決中文亂碼問(wèn)題。

      使用方式為:parameter = new String(parameter.getBytes("iso8859-1"), "utf-8");

      注意:tomcat 8 中g(shù)et方式的中文亂碼問(wèn)題已經(jīng)解決了,可以不用自己去手動(dòng)修改。

  1. 對(duì)于post方式,中文請(qǐng)求會(huì)亂碼

    解決方式:在獲取請(qǐng)求參數(shù)前,設(shè)置request的編碼:request.setCharacterEncoding("utf-8");

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容