Servlet详解——第二篇(HttpServletRequest对象、HttpServletResponse对象、转发、重定向)

前言

上一篇我们在Servlet的调用过程中讲到服务器在接收到来自浏览器的请求信息后,会调用Servlet的service()方法处理请求,而在调用service()方法之前会创建HttpServletRequest对象(用于封装HTTP请求信息)和HttpServletResponse对象(用于封装服务器的响应信息)

这一篇我们着重介绍HttpServletRequest对象和HttpServletResponse对象的方法以及一些应用

HttpServletRequest对象

公共接口类HttpServletRequest继承自ServletRequest。客户端浏览器发出的请求被封装成为一个HttpServletRequest对象。对象包含了客户端请求信息包括请求的地址,请求的参数,提交的数据,上传的文件客户端的ip甚至客户端操作系统都包含在其内。

获取客户端请求头
方法 说明
getHeader() 获取单个请求头域对应的value值
getHeaders() 获取多个同名请求头对应的一组value值,返回的是枚举类型数据
getHeaderNames() 获取所有的请求头域对应的value值
  • 测试代码

    
    public class Demo2 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req, resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    		 /**
             * 因为浏览器的编码是UTF-8,而Tomcat的编码则是ISO 8859-1
             * 浏览器的中文提交给Tomcat后,Tomcat以SO 8859-1去解析,就导致我们拿到的中文数据是乱码,
             * 通过我们设置响应头的编码格式后,乱码就解决了
             */
            resp.setContentType("text/html;charset=UTF-8");
            PrintWriter printWriter = resp.getWriter();
    
            printWriter.write("------单个请求头的值------"+ "
    "
    ); String header = req.getHeader("Accept-Encoding"); printWriter.write("Accept-Encoding : "+ header + "
    "
    ); printWriter.write("-----多个同名请求头对应的值-------"+ "
    "
    ); Enumeration e = req.getHeaders("Accept-Encoding"); //遍历 while (e.hasMoreElements()){ String element = (String) e.nextElement(); printWriter.write(element + "
    "
    ); } printWriter.write("------所有请求头的值------"+ "
    "
    ); Enumeration er = req.getHeaderNames(); //遍历 while(er.hasMoreElements()){ String element1 =(String) er.nextElement(); String value = req.getHeader(element1); printWriter.write(element1 + " = " + value + "
    "
    ); } } }
  • 输出结果
    Servlet详解——第二篇(HttpServletRequest对象、HttpServletResponse对象、转发、重定向)_第1张图片

获取客户端信息
方法 说明
getRequestURL() 返回客户端发送请求时的完整URL
getRequestURI() 返回客户端发送请求时的资源
getQueryString() 返回请求行中的参数部分
getPathInfo() 返回请求URL路径中的额外路径信息,额外路径信息是请求URL中的位于Servlet的路径之后和查询参数之前的内容,它以“/”开头。
getRemoteAddr() 返回发出请求的客户机的IP地址
getRemoteHost() 返回发出请求的客户机的完整主机名
getRemotePort() 返回客户机所使用的网络端口号
getLocalAddr() 返回WEB服务器的IP地址
getLocalName() 返回WEB服务器的主机名
  • 测试代码

    public class Demo2 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req, resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            resp.setContentType("text/html;charset=UTF-8");
            PrintWriter printWriter = resp.getWriter();
    
            StringBuffer url = req.getRequestURL();
            printWriter.write("请求的URL地址:"+ url + "
    "
    ); String uri = req.getRequestURI(); printWriter.write("请求的资源:"+ uri + "
    "
    ); String queryString = req.getQueryString(); printWriter.write("请求的URL地址中附带的参数:"+queryString + "
    "
    ); String pathInfo = req.getPathInfo(); printWriter.write("pathInfo:"+pathInfo + "
    "
    ); String remoteAddr = req.getRemoteAddr(); printWriter.write("客户机的IP地址:"+remoteAddr + "
    "
    ); String remoteHost = req.getRemoteHost(); printWriter.write("客户机的完整主机名:"+remoteHost + "
    "
    ); Integer remotePort= req.getRemotePort(); printWriter.write("客户机使用的网络端口号:"+remotePort + "
    "
    ); String localAddr = req.getLocalAddr(); printWriter.write("WEB服务器的IP地址:"+localAddr + "
    "
    ); String localName = req.getLocalName(); printWriter.write("WEB服务器的主机名:"+localName + "
    "
    ); } }
  • 输出结果

Servlet详解——第二篇(HttpServletRequest对象、HttpServletResponse对象、转发、重定向)_第2张图片

获取客户端请求信息(提交的数据)
方法 说明
getParameter() 获取前台表单单个元素name对应的value值
getParameterValues () 获取前台表单多个标签同名name对应的所有value值
getParameterNames() 获取前台表单所有标签元素name的对应的所有value值
  • 编写index.jsp页面,方便我们测试

    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <body>
    <form action="/Demo2" method="post">
        <table>
            <input type="hidden" name="hidden" value="my name is juzi">
            <tr>
                <td>用户名</td>
                <td><input type="text" name="username"></td>
            </tr>
            <tr>
                <td>密码</td>
                <td><input type="password" name="password"></td>
            </tr>
            <tr>
                <td>性别</td>
                <td>
                    <input type="radio" name="gender" value="男"><input type="radio" name="gender" value="⼥"></td>
            </tr>
            <tr>
                <td>爱好</td>
                <td>
                    <input type="checkbox" name="hobbies" value="游泳">游泳
                    <input type="checkbox" name="hobbies" value="跑步">跑步
                    <input type="checkbox" name="hobbies" value="健身">健身
                </td>
            </tr>
            <tr>
                <td>城市</td>
                <td>
                    <select name="address">
                        <option value="广州">广州</option>
                        <option value="深圳">深圳</option>
                        <option value="北京">北京</option>
                    </select>
                </td>
            </tr>
            <tr>
                <td>说明:</td>
                <td>
                    <textarea cols="30" rows="2" name="textarea"></textarea>
                </td>
            </tr>
            <tr>
                <td><input type="submit" value="提交"></td>
                <td><input type="reset" value="重置"></td>
            </tr>
        </table>
    </form>
    </body>
    </html>
    
  • 配置web.xml文件

    
    
    <web-app version="3.0" 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_3_0.xsd">
    
        <display-name>Archetype Created Web Applicationdisplay-name>
    
         <servlet>
            <servlet-name>Demo2servlet-name>
            <servlet-class>com.cn.request.Demo2servlet-class>
        servlet>
        <servlet-mapping>
            <servlet-name>Demo2servlet-name>
            <url-pattern>/Demo2url-pattern>
        servlet-mapping>
    <web-app>
    
  • 测试代码

    
    public class Demo2 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req, resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            //设置request字符编码的格式
            req.setCharacterEncoding("UTF-8");
    
            System.out.println("1.获取前台表单单个元素name对应的value值");
            String submitvalue = req.getParameter("username");
            System.out.println(submitvalue);
    
            System.out.println("2.获取前台表单多个标签同名name对应的所有value值");
            String[] paramvalues = req.getParameterValues("hobbies");
            for(String i:paramvalues){
                System.out.println(i);
            }
    
            System.out.println("3.获取前台表单所有标签元素name的对应的所有value值");
            Enumeration paramNames = req.getParameterNames();
            while(paramNames.hasMoreElements()){
                String paramName = (String)paramNames.nextElement();
                String[] paramValue = req.getParameterValues(paramName);
                for(String j : paramValue){
                    System.out.println(j);
                }
            }
        }
    }
    
  • 输出结果

Servlet详解——第二篇(HttpServletRequest对象、HttpServletResponse对象、转发、重定向)_第3张图片

中文乱码问题

  • 上部分测试代码中,我们加入了这样一行代码

     //设置request字符编码的格式
     req.setCharacterEncoding("UTF-8");
    
  • 如果把这行代码去掉,重新测试

    Servlet详解——第二篇(HttpServletRequest对象、HttpServletResponse对象、转发、重定向)_第4张图片

  • 我们发现所有提交过来的中文都乱码了,这是为什么呢?

    ​ 我们知道Tomcat服务器的编码是ISO 8859-1,而浏览器的编码是UTF-8,浏览器的中文数据提交给Tomcat,Tomcat以ISO 8859-1进行编码传给Servlet,这样就导致我们拿到的数据就是乱码,通过我们设置request的编码为UTF-8后,数据就正常了

    接下来我们测试get方式提交数据

    <form action="/Demo2" method="get">
    省略部分代码
    
  • 测试代码输出结果

    Servlet详解——第二篇(HttpServletRequest对象、HttpServletResponse对象、转发、重定向)_第5张图片

中文数据显示正常,没有乱码,那意思就是无论Post请求还是Get请求,只要设置了request的编码后,数据就没有问题

结论似乎下的有点太早,我们看下Tomcat配置的是8以上的版本

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hQ6jCIp0-1660716532393)(Servlet详解.assets/微信图片_20220817120025.png)]

我们改成稍低的版本试一下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nrfPbvIZ-1660716532393)(Servlet详解.assets/微信图片_20220817120030.png)]

  • 测试结果

    Servlet详解——第二篇(HttpServletRequest对象、HttpServletResponse对象、转发、重定向)_第6张图片

这什么情况,又乱码了

在Tomcat8中,其对应的官方文档是这样说明的:

Servlet详解——第二篇(HttpServletRequest对象、HttpServletResponse对象、转发、重定向)_第7张图片

翻译如下: 这指定了在解码URL之后内容时所使用的编码。如果没有设置 -Dorg.apache.catalina.STRICT_SERVLET_COMPLIANCE=true,则默认使用UTF-8,否则将使用"iso8859-1"。

但是在Tomcat8之前的版本中官方文档这样说明的:

Servlet详解——第二篇(HttpServletRequest对象、HttpServletResponse对象、转发、重定向)_第8张图片

翻译如下: 这指定了在解码URL之后内容时所使用的编码。如果没有指定,将使用"iso8859-1"。

现在我们可以下结论了,Tomcat8以及之后的版本已经帮我们解决了中文乱码的问题,而Tomcat7以及之前的版本没有帮我们

我们应该怎么做呢?

可以在[tomcat]/conf/server.xml中添加一下配置就可以解决中文乱码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NsbusbUJ-1660716532394)(Servlet详解.assets/微信图片_20220817120300.png)]

请求转发和域对象

请求转发

是指定服务器中的某一个资源(Servlet或者jsp)在处理请求的过程中,将请求转发给另一个资源,让其他资源来处理请求

域对象

能够在指定的范围内,利用自身的map实现数据共享,这个map我们可以称之为request域

应用
  • 测试代码

    省略部分代码
    //1.模拟个人信息
    String name = "juzi";
    String age = "18";
    //2.将数据存入到request域中
    req.setAttribute("name",name);
    req.setAttribute("age",age);
    //3.获取到requestDispatcher对象,跳转到index.jsp
    RequestDispatcher dispatcher = req.getRequestDispatcher("/index.jsp");
    //4.调用requestDispatcher对象的forward()实现转发,传入request和response
    dispatcher.forward(req,resp);
    
  • 编辑index.jsp页面

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
    
    

    姓名:<%= request.getAttribute("name") %>

    年龄:<%= request.getAttribute("age") %>

  • 输出结果

​	[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-24p1B1RF-1660716532394)(Servlet详解.assets/微信图片_20220817120300-166071024097614.png)]

我们发现转发的地址栏是没有发生变化的,也就是说转发相对于浏览器是透明的,请求转发只是一次Http请求,一次转发中request和response都是同一个

这也就验证了我们上面测试的request作为域对象可以进行Servlet之间的通讯

HttpServletResponse

HttpServletResponse继承了ServletResponse接口,并提供了与Http协议有关的方法,这些方法的主要功能是设置HTTP状态码和管理Cookie。

方法
方法 说明
setStatus() 设置响应的状态码
setHeader() 使用指定名称和值设置响应头的名称和内容
setContentType() 设置响应数据类型
getOutputStream() 返回字节输出流对象
getWriter() 返回字符输出流对象
使用字节输出流输出对象
//第一种
resp.getOutputStream().print();
//第二种
resp.getOutputStream().write();
第一种
  • 测试代码

    
    public class Demo2 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req, resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            //使用resp.getOutputStream()向浏览器输出数据
            ServletOutputStream outputStream = resp.getOutputStream();
            //.print
            outputStream.print("juzi")
        }
    }
    
  • 输出结果

    Servlet详解——第二篇(HttpServletRequest对象、HttpServletResponse对象、转发、重定向)_第9张图片

  • 如果修改为中文数据

    outputStream.print("桔子");
    
  • 输出结果

    Servlet详解——第二篇(HttpServletRequest对象、HttpServletResponse对象、转发、重定向)_第10张图片

报错原因

outputStream是输出二进制数据的,print()方法要把一个字符串改成二进制数据,Tomcat是以ISO 8859-1进行编码,而字符串对ISO 8859-1根本就不支持,所以就出现了异常

第二种
  • 测试代码

    省略部分代码。。。
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //使用resp.getOutputStream()向浏览器输出数据
            ServletOutputStream outputStream = resp.getOutputStream();
            //.print
             outputStream.write("juzi".getBytes());
        }
    
  • 输出结果

    Servlet详解——第二篇(HttpServletRequest对象、HttpServletResponse对象、转发、重定向)_第11张图片

  • 如果修改为中文数据

     outputStream.write("桔子".getBytes());
    
  • 输出结果

    Servlet详解——第二篇(HttpServletRequest对象、HttpServletResponse对象、转发、重定向)_第12张图片

原因:

字符串在封装成byte[]数组的时候默认查的是gb2312编码,而字符串又支持gb2312编码,所以数据正常显示了出来

综上所述,解决乱码有两种方式:
  • 第一种:设置响应数据类型(最方便)

    resp.setContentType("text/html;charset=UTF-8");
    
  • 第二种:设置消息头

    resp.setHeader("Content-Type","text/html;charset=UTF-8");
    

重定向

是指用户浏览某个网址时,将其导向到另一个网址的技术,也就是说通知浏览器去跳转

  • 测试代码

    public class Demo3 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req, resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {   
            resp.setContentType("text/html;charset=UTF-8");
    
            //重定向到index.jsp页面
            resp.sendRedirect("/index.jsp");
        }
    }
    
  • 输出结果

    Servlet详解——第二篇(HttpServletRequest对象、HttpServletResponse对象、转发、重定向)_第13张图片

我们发现转发的地址栏已经发生了变化

重定向是浏览器进行的页面跳转发出了两次Http请求,request对象是无效的,因为是两个不同的request域

这篇文章主要介绍了Servlet的继承类HttpServlet的request,response的常见方法、应用以及解决乱码相关的知识,希望对您有所帮助,别忘了点赞噢。

下一篇我们继续开始学习Servlet的第三部分,Cookie和Session相关的内容,来一起把头发熬秃。。。

你可能感兴趣的:(WEB,servlet,tomcat,java)