Servlet学习2 -- Request对象

一.Servlet中处理请求的方式

​ 之前介绍过Servlet的体系结构,广义上来说,Servlet是一个接口,有实现类GenericsServlet,而GenericsServlet是一个抽象类,有直接的子类HttpServlet。

​ 而HttpServlet要比GenericsServlet要强大,因为它是由GenericsServlet抽象类扩展而来的,并且现在大部分的应用程序都是与HTTP结合起来使用,而且HTTPServlet封装了许多,使得我们的开发变得更加简洁。

​ 之前当我们要实现Servlet接口时,是需要重写5个方法的:init,destroy,service,getServletConfig,getServletInfo,这样太麻烦,我们可以直接继承HttpServlet类,因为HTTPServlet默认已经实现了Servlet接口中的所有方法了,写代码时只需要重写需要的方法即可。

​ 具体操作方式为:

  • 继承HttpServlet
  • 重写doGet()和doPost()方法,并且在doGet()或者doPost()中写入一句this.doPost(req,resp)this.doGet(req,resp),因为这样子无论是Get请求还是POST请求,处理的方式都相同。

二.Request对象

  1. request对象的原理

    • request对象是由服务器创建的,我们只需要直接使用就好了。
    • request对象就是将浏览器的请求封装成的对象,能够获取请求文本中的所有内容,包括请求头,请求体和请求行
  2. request对象的继承体系

    ServletRequest -- 接口
    | 继承
    HttpServletRequest -- 接口
    | 实现
    org.apache.catalina.connector.RequestFacade 类(tomcat)

  3. request对象的功能

    • 获取请求行数据

      1. 获取请求方式

        String getMethod()

      2. 获取虚拟目录

        String getContextPath()

      3. 获取Servlet路径

        String getServletPath()

      4. 获取get方式请求参数

        String getQueryString()

      5. 获取请求URI

        String getRequestURI()

        String getRequestURL()

      6. 获取协议和版本

        String getProtocol()

      7. 获取客户机的IP地址

        String getRemoteAddr()

      @WebServlet("/RequestServlet")
      public class RequestServlet extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              // 1. 获取请求方式
              String method = request.getMethod();
              System.out.println("请求方式为:" + method);
      
              // 2. 获取虚拟目录
              String contextPath = request.getContextPath();
              System.out.println("虚拟目录是:" + contextPath);
      
              // 3. 获取Servlet路径
              String servletPath = request.getServletPath();
              System.out.println("Servlet路径为:" + servletPath);
      
              // 4. 获取get请求参数
              String queryString = request.getQueryString();
              System.out.println("Get请求参数:" + queryString);
      
              // 5. 获取请求URI
              String requestURI = request.getRequestURI();
              StringBuffer requestURL = request.getRequestURL();
              System.out.println("请求URI为:" + requestURI);
              System.out.println("请求URL为:" + requestURL);
      
              // 6. 获取协议和版本
              String protocol = request.getProtocol();
              System.out.println("协议和版本为:" + protocol);
      
              // 7. 获取客户机的IP地址
              String remoteAddr = request.getRemoteAddr();
              System.out.println("客户机IP地址为:" + remoteAddr);
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              doPost(request, response);
          }
      }
      
      浏览器请求为:http://localhost/BlogTest/RequestServlet?name=zhangsan&age=18
      控制台输出为:
          请求方式为:GET
          虚拟目录是:/BlogTest
          Servlet路径为:/RequestServlet
          Get请求参数:name=zhangsan&age=18
          请求URI为:/BlogTest/RequestServlet
          请求URL为:http://localhost/BlogTest/RequestServlet
          协议和版本为:HTTP/1.1
          客户机IP地址为:0:0:0:0:0:0:0:1
      
      
    • 获取请求头数据

      • String getHeader(String name):通过请求头名字获取请求头的值
      • Enumeration<String> getHeaderNames():获取所有请求头的名字
      @WebServlet("/RequestServlet2")
      public class RequestServlet2 extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              // 1. 获取请求头  -- 获取User-Agent的值,获知浏览器版本信息
              String header = request.getHeader("User-Agent");
              System.out.println("请求头User-Agent:" + header);
      
              // 2. 获取所有的请求头
              Enumeration<String> headerNames = request.getHeaderNames();
              System.out.println("所有请求头列表:");
              while (headerNames.hasMoreElements()) {
                  String name = headerNames.nextElement();
                  // 获取请求头数据
                  String head = request.getHeader(name);
                  System.out.println(name + ":" + head);
              }
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              doPost(request, response);
          }
      }
      
      请求头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
      所有请求头列表:
          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
      
    • 获取请求体数据

      请求体只有POST请求才有,封装了post请求的请求参数。

      获取请求体数据的操作步骤为:

      1. 获取流对象

        BufferedReader getReader():获取字符输入流,只能操作字符数据

        ServletInputStream getInputStream():获取字节输入流,可以操作所有数据类型

      2. 从流对象中获取数据

      @WebServlet("/RequestServlet3")
      public class RequestServlet3 extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      
              // 字节流
      //        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对象其他功能

    • 通用的获取请求参数

      由上面的可以看出,get方式获取请求参数使用的是getQueryString(),post方式是通过获取请求体来得到请求参数,这样子太麻烦,还要区分,所以有以下几个方法,不论是get还是post都可以使用来获取请求参数,属于通用的。

      1. String getParameter(String name):根据参数名获取参数值
      2. String[] getParameterValues(String name):根据参数名获取参数值的数组(对于一些同一个名字有多个值的情况,比如复选框checkbox)
      3. Enumeration<String> getParameterNames():获取所有请求参数的名称
      4. Map<String,String[]> getParameterMap():获取所有参数的名称和值的Map集合
      @WebServlet("/RequestServlet4")
      public class RequestServlet4 extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              // 1. 获取请求参数username的值
              String username = request.getParameter("username");
              System.out.println("username :" + username);
              System.out.println("--------------------");
      
              // 2. 获取请求参数sport的所有值
              String[] sports = request.getParameterValues("sport");
              for (String sport : sports) {
                  System.out.println("sport : " + sport);
              }
              System.out.println("--------------------");
      
              // 3. 获取所有请求参数的名字
              Enumeration<String> names = request.getParameterNames();
              while (names.hasMoreElements()) {
                  String name = names.nextElement();
                  System.out.println("name: " + name);
              }
              System.out.println("--------------------");
      
              // 4. 获取所有请求参数的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);
          }
      }
      
      请求为:
      	http://localhost/BlogTest/RequestServlet4?username=zhangsan&&sport=basketball&&sport=football
      控制台输出为:
      	username :zhangsan
          --------------------
          sport : basketball
          sport : football
          --------------------
          name: username
          name: sport
          --------------------
          username ---> zhangsan
          sport ---> basketball
          sport ---> football
      
    • 请求转发

      请求转发是在服务器内的资源跳转方式(还有一种是重定向),具有以下特点:

      1. 浏览器的地址栏路径是不会发生变化的。
      2. 只能转发到当前服务器的内部资源。
      3. 转发是一次请求

      操作步骤为:

      1. 通过request获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
      2. 使用forward方法进行转发:forward(ServletRequest request, ServletResponse response)
    • 共享数据

      在进行请求转发时,请求转发是一次请求,会将request和response传递给要转发到的请求中,在这中间,两个请求间可能需要共享一些数据,这些数据只存在一次请求的范围。

      主要有以下方法:

      1. void setAttribute(String name, Object obj):存储数据,以键值对的方式存储
      2. Object getAttribute(String name):通过键获取值
      3. void removeAttribute(String name):移除指定的键值对

      第一个Servlet:

      @WebServlet("/RequestServlet5")
      public class RequestServlet5 extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              System.out.println("这是RequestServlet5...");
      
              // 设置共享数据
              request.setAttribute("usernmae", "zhangsan");
      
              // 请求转发
              request.getRequestDispatcher("/RequestServlet6").forward(request, response);
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              doPost(request, response);
          }
      }
      

      第二个Servlet:

      @WebServlet("/RequestServlet6")
      public class RequestServlet6 extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              System.out.println("这是RequestServlet6...");
      
              // 获取共享数据
              String username = (String)request.getAttribute("usernmae");
              if (username != null) {
                  System.out.println("共享数据是: username ---> " + username);
              }
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              doPost(request, response);
          }
      }
      
      请求为:http://localhost/BlogTest/RequestServlet5
      控制台输出为:
      	这是RequestServlet5...
      	这是RequestServlet6...
      	共享数据是: username ---> zhangsan
      
    • 获取ServletContext(以后再详解)

      ServletContext getServletContext()

  5. 中文乱码问题

    1. 对于get方式,在service中使用的编码和解码方式默认为:ISO-8859-1,这个编码不支持中文,所以会出现乱码,需要手动修改编码方式为UTF-8,才能解决中文乱码问题。

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

      注意:tomcat 8 中get方式的中文乱码问题已经解决了,可以不用自己去手动修改。

    2. 对于post方式,中文请求会乱码

      解决方式:在获取请求参数前,设置request的编码:request.setCharacterEncoding("utf-8");

posted @ 2020-04-23 20:27  小毛驴Lucas  阅读(196)  评论(0编辑  收藏  举报