zoukankan      html  css  js  c++  java
  • 2020.11.1收获

    Servlet第四篇【request对象常用方法、应用】

    什么是HttpServletRequest

    HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,开发人员通过这个对象的方法,可以获得客户这些信息。

    简单来说,要得到浏览器信息,就找HttpServletRequest对象

    HttpServletRequest常用方法

    获得客户机【浏览器】信息

    • getRequestURL方法返回客户端发出请求时的完整URL。

    • getRequestURI方法返回请求行中的资源名部分。

    • getQueryString 方法返回请求行中的参数部分。

    • getPathInfo方法返回请求URL中的额外路径信息。额外路径信息是请求URL中的位于Servlet的路径之后和查询参数之前的内容,它以“/”开头。

    • getRemoteAddr方法返回发出请求的客户机的IP地址

    • getRemoteHost方法返回发出请求的客户机的完整主机名

    • getRemotePort方法返回客户机所使用的网络端口号

    • getLocalAddr方法返回WEB服务器的IP地址。

    • getLocalName方法返回WEB服务器的主机名

    获得客户机请求头

    • getHeader方法

    • getHeaders方法

    • getHeaderNames方法

    获得客户机请求参数(客户端提交的数据)

    • getParameter方法

    • getParameterValues(String name)方法

    • getParameterNames方法

    • getParameterMap方法


    HttpServletRequest应用

    防盗链

    什么是防盗链呢?比如:我现在有海贼王最新的资源,想要看海贼王的要在我的网页上看。现在别的网站的人看到我有海贼王的资源,想要把我的资源粘贴在他自己的网站上。这样我独家的资源就被一个CTRL+C和CTRL+V抢走了?而反盗链就是不能被他们CRTL+C和CRTL+V

    • 下面我模拟一下场景。现在我首页先有一个超链接,指向着海贼王最新资源

    图片

    • 当我点进去,就能看到海贼王最新资源了

    图片

    • 其他的人可以通过复制粘贴我的地址,放到它们的网页上

    图片

    •  

      这样我就划不来啦【我的广告你来没看呢!】。想要看我的资源,就必须经过我的首页点进去看

       

    •  

      想要实现这样的效果,就要获取Referer这个消息头判断Referer是不是从我的首页来的。如果不是从我的首页来的,跳转回我的首页

       

    1.        //获取到网页是从哪里来的

    2.        String referer = request.getHeader("Referer");

    3.  

    4.        //如果不是从我的首页来或者从地址栏直接访问的,

    5.        if ( referer == null || !referer.contains("localhost:8080/zhongfucheng/index.jsp") ) {

    6.  

    7.            //回到首页去

    8.            response.sendRedirect("/zhongfucheng/index.jsp");

    9.            return;

    10.        }

    11.  

    12.        //能执行下面的语句,说明是从我的首页点击进来的,那没问题,照常显示

    13.        response.setContentType("text/html;charset=UTF-8");

    14.        response.getWriter().write("路飞做了XXXXxxxxxxxxxxxxxxxx");

    • 首先按正常预想的,别人从首页点击我的资源,访问我海贼王最新的资源

    图片\

    • 能够成功访问到资源

    图片

    • 如果我在浏览器直接输入地址【此时Referer是为null的】,我们来看看

    图片

    • 跳回到首页上,不能访问到海贼王资源

    图片

    • 再试试,如果别人粘贴了我的资源url,在它的网页上挂了一个网址呢。

    图片

    • 在别人网页上点击的时候

    图片

    • 又跳回到了我的首页了。 图片


    表单提交数据【通过post方式提交数据】

    1. <form action="/zhongfucheng/Servlet111" method="post">

    2.    <table>

    3.        <tr>

    4.            <td>用户名</td>

    5.            <td><input type="text" name="username"></td>

    6.        </tr>

    7.        <tr>

    8.            <td>密码</td>

    9.            <td><input type="password" name="password"></td>

    10.        </tr>

    11.        <tr>

    12.            <td>性别</td>

    13.            <td>

    14.                <input type="radio" name="gender" value="男">男

    15.                <input type="radio" name="gender" value="女">女

    16.            </td>

    17.        </tr>

    18.        <tr>

    19.            <td>爱好</td>

    20.            <td>

    21.                <input type="checkbox" name="hobbies" value="游泳">游泳

    22.                <input type="checkbox" name="hobbies" value="跑步">跑步

    23.                <input type="checkbox" name="hobbies" value="飞翔">飞翔

    24.            </td>

    25.        </tr>

    26.        <input type="hidden" name="aaa" value="my name is zhongfucheng">

    27.        <tr>

    28.            <td>你的来自于哪里</td>

    29.            <td>

    30.                <select name="address">

    31.                    <option value="广州">广州</option>

    32.                    <option value="深圳">深圳</option>

    33.                    <option value="北京">北京</option>

    34.                </select>

    35.            </td>

    36.        </tr>

    37.        <tr>

    38.            <td>详细说明:</td>

    39.            <td>

    40.                <textarea cols="30" rows="2" name="textarea"></textarea>

    41.            </td>

    42.        </tr>

    43.        <tr>

    44.            <td><input type="submit" value="提交"></td>

    45.            <td><input type="reset" value="重置"></td>

    46.        </tr>

    47.    </table>

    • 在Servlet111中获取到提交的数据,代码如下

    1.        //设置request字符编码的格式

    2.        request.setCharacterEncoding("UTF-8");

    3.  

    4.        //通过html的name属性,获取到值

    5.        String username = request.getParameter("username");

    6.        String password = request.getParameter("password");

    7.        String gender = request.getParameter("gender");

    8.  

    9.        //复选框和下拉框有多个值,获取到多个值

    10.        String[] hobbies = request.getParameterValues("hobbies");

    11.        String[] address = request.getParameterValues("address");

    12.  

    13.        //获取到文本域的值

    14.        String description = request.getParameter("textarea");

    15.  

    16.        //得到隐藏域的值

    17.        String hiddenValue = request.getParameter("aaa");

    18.  

    19.        ....各种System.out.println().......

    • 向表单输入数据

    图片

    • Servlet111得到表单带过来的数据,最后的一个数据是隐藏域带过来的。

    图片


    超链接方式提交数据

    常见的get方式提交数据有使用超链接,sendRedirect()

    格式如下:

    1.    sendRedirect("servlet的地址?参数名="+参数值 &"参数名="+参数值);

    • 我们来使用一下,通过超链接将数据带给浏览器

    1.     <a href="/zhongfucheng/Servlet111?username=xxx">使用超链接将数据带给浏览器</a>

    • 在Servlet111接收数据

    1.        //接收以username为参数名带过来的值

    2.        String username = request.getParameter("username");

    3.        System.out.println(username);

    • 注意看浏览器左下角

    图片

    • 服务器成功接收到浏览器发送过来的数据

    图片

    • 并且,传输数据明文的出现在浏览器的地址栏上

    图片

    • sendRedirect()和超链接类似,在这里就不赘述了


    解决中文乱码问题

    细心的朋友会发现,我在获取表单数据的时候,有这句代码 request.setCharacterEncoding("UTF-8");,如果没有这句代码,会发生什么事呢?我们看看。

    • 再重新填写数据

    图片

    • 在服务器查看提交过来的数据,所有的中文数据都乱码了

    图片

    •  

      来这里我们来分析一下乱码的原因,在前面的博客中我已经介绍了,Tomcat服务器默认编码是ISO 8859-1,而浏览器使用的是UTF-8编码。浏览器的中文数据提交给服务器,Tomcat以ISO 8859-1编码对中文编码,当我在Servlet读取数据的时候,拿到的当然是乱码。而我设置request的编码为UTF-8,乱码就解决了。

       

    •  

      接下来使用get方式传递中文数据,把表单的方式改成get即可

       

    •  

      当我们访问的时候,又出现乱码了!

       

    图片

    图片

    • 于是我按照上面的方式,把request对象设置编码为UTF-8试试

    1.        request.setCharacterEncoding("UTF-8");

    2.        String name = request.getParameter("name");

    •  

      结果还是乱码。这是为什么呢?我明明已经把编码设置成UTF-8了,按照post方式,乱码问题已经解决了!。我们来看看get和post方式的区别在哪?为什么post方式设置了request编码就可以解决乱码问题,而get方式不能呢。

       

    •  

      首先我们来看一下post方法是怎么进行参数传递的。当我们点击提交按钮的时候,数据封装进了Form Data中http请求中把实体主体带过去了【传输的数据称之为实体主体】,既然request对象封装了http请求,所以request对象可以解析到发送过来的数据,于是只要把编码设置成UTF-8就可以解决乱码问题了

       

    图片

    • 而get方式不同,它的数据是从消息行带过去的,没有封装到request对象里面,所以使用request设置编码是无效的。

    图片

    • 要解决get方式乱码问题也不难,我们既然知道Tomcat默认的编码是ISO 8859-1,那么get方式由消息体带过去给浏览器的时候肯定是用ISO 8859-1编码了

    1.        //此时得到的数据已经是被ISO 8859-1编码后的字符串了,这个是乱码

    2.        String name = request.getParameter("username");

    3.  

    4.        //乱码通过反向查ISO 8859-1得到原始的数据

    5.        byte[] bytes = name.getBytes("ISO8859-1");

    6.  

    7.        //通过原始的数据,设置正确的码表,构建字符串

    8.        String value = new String(bytes, "UTF-8");

    上面的代码有些难理解,我画张图说明一下:

    图片

    • 经过我们手工转换,再来访问一下

    图片

    •  

      好的,成功解决掉乱码问题了。

       

    •  

      除了手工转换,get方式还可以改Tomcat服务器的配置来解决乱码,但是不推荐使用,这样不灵活。

       

    •  

      我们都知道Tomcat默认的编码是ISO 8859-1,如果在Tomcat服务器的配置下改成是UTF-8的编码,那么就解决服务器在解析数据的时候造成乱码问题了

       

    •  

      在8080端口的Connector上加入 URIEncoding="utf-8",设置Tomcat的访问该端口时的编码为utf-8,从而解决乱码,这种改法是固定使用UTF-8编码的

       

    1.    <Connector port="8080" protocol="HTTP/1.1"

    2.               connectionTimeout="20000"

    3.               redirectPort="8443" URIEncoding="utf-8"/>

    • 设置了编码后,没有做任何手工转换,成功拿到数据

    图片

    • 当然也有另一种改服务器编码的方式。设置Tomcat的访问该端口时的编码为页面的编码,这种改法是随着页面的编码而变

    1.    <Connector port="8080" protocol="HTTP/1.1"

    2.               connectionTimeout="20000"

    3.               redirectPort="8443" useBodyEncodingForURI="true" />

    • 设置编码为UTF-8

    1.        request.setCharacterEncoding("UTF-8");

    2.        String name = request.getParameter("name");

    • 再次访问

    图片

    •  

      手写超链接如果附带中文参数问题,要URL重写,在JSP博客中会讲到

       

    •  

      总结:

       

    •  

      post方式直接改request对象的编码

       

    •  

      get方式需要手工转换编码

       

    •  

      get方式也可以修改Tomcat服务器的编码,不推荐,因为会太依赖服务器了!

       

    •  

      提交数据能用post就用post

       


    实现转发

    之前讲过使用response的sendRedirect()可以实现重定向,做到的功能是页面跳转,使用request的getRequestDispatcher.forward(request,response)实现转发,做到的功能也是页面跳转,他们有什么区别呢?现在我先来说下转发

    • 代码如下所示

    1.        //获取到requestDispatcher对象,跳转到index.jsp

    2.        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/index.jsp");

    3.  

    4.        //调用requestDispatcher对象的forward()实现转发,传入request和response方法

    5.        requestDispatcher.forward(request, response);

    • 访问Servlet111

    图片

    •  

      上面已经说了,可以通过sendRedirect()重定向可以在资源尾部添加参数提交数据给服务器。那么转发能不能提交数据给服务器呢?

       

    •  

      答案明显是可以的,并且使用这种方法非常频繁

       

    •  

      在讲ServletContext的时候,曾经说过Servlet之间可以通过ServletContext实现通讯,ServletContext也能称之为域对象。而request也可以称之为域对象,只不过ServletContext的域是整个web应用,而request的域仅仅代表一次http请求

       

    •  

      下面我们来使用request实现Servlet之间的通讯,Servlet111代码

       

    1.        //以username为关键字存zhongfucheng值

    2.        request.setAttribute("username", "zhongfucheng");

    3.  

    4.        //获取到requestDispatcher对象

    5.        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/Servlet222");

    6.  

    7.        //调用requestDispatcher对象的forward()实现转发,传入request和response方法

    8.        requestDispatcher.forward(request, response);

    • Servlet222代码

    1.        //获取到存进request对象的值

    2.        String userName = (String) request.getAttribute("username");

    3.  

    4.        //在浏览器输出该值

    5.        response.getWriter().write("i am :"+userName);

    • 访问Servlet111看下效果

    图片

    •  

      如上图所示,Servlet222成功拿到了request对象在Servlet111存进的数据

       

    •  

      现在问题又来了,我们可以使用ServletContext和request实现Servlet之间的通讯,那么我们用哪一种呢?一般的原则:可以使用request就尽可能使用request。因为ServletContext代表着整个web应用,使用ServletContext会消耗大量的资源,而request对象会随着请求的结束而结束,资源会被回收使用request域进行Servlet之间的通讯在开发中是非常频繁的

       

    转发的时序图

    图片

    请求转发的细节

    •  

      如果在调用forward方法之前,在Servlet程序中写入的部分内容已经被真正地传送到了客户端,forward方法将抛出IllegalStateException异常。 也就是说:不要在转发之前写数据给浏览器

       

    •  

      我们来试试是不是真的会出现异常。

       

    1.        OutputStream outputStream = response.getOutputStream();

    2.        outputStream.write("--------------------------------------------".getBytes());

    3.  

    4.        //关闭流,确保让数据到浏览器中

    5.        outputStream.close();

    6.  

    7.        //跳转

    8.        request.getRequestDispatcher("/Foot").forward(request, response);

    • 访问的时候,看到浏览器可以输出数据,Tomcat后台抛出了异常

    图片

    • 如果在调用forward方法之前向Servlet引擎的缓冲区中写入了内容,只要写入到缓冲区中的内容还没有被真正输出到客户端,forward方法就可以被正常执行,原来写入到输出缓冲区中的内容将被清空,但是,已写入到HttpServletResponse对象中的响应头字段信息保持有效

    转发和重定向的区别

    实际发生位置不同,地址栏不同

    • 转发是发生在服务器的

    • 转发是由服务器进行跳转的,细心的朋友会发现,在转发的时候,浏览器的地址栏是没有发生变化的,在我访问Servlet111的时候,即使跳转到了Servlet222的页面,浏览器的地址还是Servlet111的。也就是说浏览器是不知道该跳转的动作,转发是对浏览器透明的。通过上面的转发时序图我们也可以发现,实现转发只是一次的http请求一次转发中request和response对象都是同一个。这也解释了,为什么可以使用request作为域对象进行Servlet之间的通讯。

    • 重定向是发生在浏览器的

    • 重定向是由浏览器进行跳转的,进行重定向跳转的时候,浏览器的地址会发生变化的。曾经介绍过:实现重定向的原理是由response的状态码和Location头组合而实现的。这是由浏览器进行的页面跳转实现重定向会发出两个http请求request域对象是无效的,因为它不是同一个request对象

    用法不同

    很多人都搞不清楚转发和重定向的时候,资源地址究竟怎么写。有的时候要把应用名写上,有的时候不用把应用名写上。很容易把人搞晕。记住一个原则:给服务器用的直接从资源名开始写,给浏览器用的要把应用名写上

    • request.getRequestDispatcher("/资源名 URI").forward(request,response)

    • 转发时"/"代表的是本应用程序的根目录【zhongfucheng】

    • response.send("/web应用/资源名 URI");

    • 重定向时"/"代表的是webapps目录

    能够去往的URL的范围不一样

    • 转发是服务器跳转只能去往当前web应用的资源

    • 重定向是浏览器跳转,可以去往任何的资源

    传递数据的类型不同

    • 转发的request对象可以传递各种类型的数据,包括对象

    • 重定向只能传递字符串

    跳转的时间不同

    • 转发时:执行到跳转语句时就会立刻跳转

    • 重定向:整个页面执行完之后才执行跳转


    转发和重定向使用哪一个?

    根据上面说明了转发和重定向的区别也可以很容易概括出来。转发是带着转发前的请求的参数的。重定向是新的请求

    典型的应用场景:

    1. 转发: 访问 Servlet 处理业务逻辑,然后 forward 到 jsp 显示处理结果,浏览器里 URL 不变

    2. 重定向: 提交表单,处理成功后 redirect 到另一个 jsp,防止表单重复提交,浏览器里 URL 变了


    RequestDispatcher再说明

    RequestDispatcher对象调用forward()可以实现转发上面已经说过了。RequestDispatcher还有另外一个方法include(),该方法可以实现包含,有什么用呢?

    我们在写网页的时候,一般网页的头部和尾部是不需要改变的。如果我们多个地方使用Servlet输出网头和网尾的话,需要把代码重新写一遍。而使用RequestDispatcher的include()方法就可以实现包含网头和网尾的效果了

    • 我们来操作吧!现在我有网头和网尾的Servlet

    图片

    • 使用Servlet111将网头和网尾包含

    1.        request.getRequestDispatcher("/Head").include(request, response);

    2.  

    3.        response.getWriter().write("--------------------------------------------");

    4.  

    5.  

    6.        request.getRequestDispatcher("/Foot").include(request, response);

    • 访问一下Servlet111,成功把网头和网尾包含了

    图片

     

    转载至:Servlet第四篇【request对象常用方法、应用】(修订版)

  • 相关阅读:
    Linux标准C头文件和内核头文件的理解
    linux GCC编译C程序的问题
    C#类型反射、晚期绑定、特性编程的使用背景与分析
    linux下C#开发mongoDB
    C中“指针和数组”引发的探索一
    C#学习记录
    linux下Apache+PHP+mysql+phpMyAdmin源码包安装配置
    基于mongoDB和C#分布式海量文件存储实验
    C中指针和数组引发的探索二
    算法研究学习一(用C和C#实现)
  • 原文地址:https://www.cnblogs.com/ltw222/p/13920484.html
Copyright © 2011-2022 走看看