JavaWeb之servlet的request对象

概述

前面介绍过response对象了,下面介绍一下它的双胞胎兄弟request。request对象通常指实现HttpServletRequest接口的对象。
引用百度百科的概念:

request对象是从客户端向服务器发出请求,包括用户提交的信息以及客户端的一些信息。客户端可通过HTML表单或在网页地址后面提供参数的方法提交数据,然后通过request对象的相关方法来获取这些数据。request的各种方法主要用来处理客户端浏览器提交的请求中的各项参数和选项。

直白的说,HttpServletRequest对象代表客户端的请求,当客户端通过http协议访问服务器时,HTTP请求头中的所有信息(请求行,请求头,请求数据)都封装在这个对象中。

开发者可以通过servlet 容器创建 HttpServletRequest 对象,并将该对象作为参数传递给 servlet 的 service 方法(doGet、doPost,等等)。我们具体看它的方法.

用Request获取客户端的信息

  • getRequestURL() 获得客户端发出请求的完整URL(网址)。
  • getReuqestURI() 返回请求行中的资源名部分。
  • getQueryString() 返回请求行中的参数部分。
  • getRemoteAddr() 返回发送请求的客户端的IP地址(来访者的ip)。
  • getRemoteHost() 返回发送请求的客户端的主机名(要在dns上注册,如不是返回ip)。
  • getRemotePort() 返回客户端所使用的网络端口号(每次访问时端口基本会变化)。
  • getLocalAddr() 返回web服务器的IP地址。
  • getLocalName() 返回web服务器的主机名。
  • getMethod() 得到请求URL地址所使用的方法(post、get)。
    System.out.print("返回客户端发出请求时的完整URL(网址):");
    System.out.println(request.getRequestURL());

    System.out.print("返回请求行中的资源名部分:");
    System.out.println(request.getRequestURI());

    System.out.print("返回请求行中的参数部分:");
    System.out.println(request.getQueryString());

    System.out.print("返回发送请求的客户端的IP地址(来访者的ip):");
    System.out.println(request.getRemoteAddr());

    System.out.print("返回发送请求的客户端的主机名(要在dns上注册,如不是返回ip):");
    System.out.println(request.getRemoteHost());

    System.out.print("返回客户端所使用的网络端口号:");
    System.out.println(request.getRemotePort());

    System.out.print("返回web服务器的IP地址:");
    System.out.println(request.getLocalAddr());

    System.out.print("返回web服务器的主机名:");
    System.out.println(request.getLocalName());

    System.out.print("得到请求URL地址所使用的方法(post、get):");
    System.out.println(request.getMethod());

结果:
这里写图片描述


获取请求头信息

获取请求头的常用三个方法,这三个方法传的参数都是指定的请求头名:

  1. getHeader()
  2. getHeaders()
  3. getHeaderNames()
    在代码示例之前,我要普及一下Http请求头,请求头指:用于描述客户端请求哪台主机,以及客户端的一些环境信息等。常用的请求头:

    • accept:用于告诉服务器,客户端支持的数据类型
    • accept-charset:用于告诉服务器,客户端采用的编码
    • accept-encoding:支持客户端的压缩格式
    • accept-language:客户端的语言环境
    • host:客户端通过这个头告诉服务器,想访问的主机名
    • if-modified-since:客户机通过这个头告诉服务器,资源的缓存时间
    • referer:客户端通过这个头告诉服务器,它是从哪个资源来访问服务器的(防盗链)
    • user-agent:客户机通过这个头告诉服务器,客户机的软件环境
    • cookie:客户机通过这个头可以向服务器带数据
    • connection:保持连接还是关闭连接 close/keep-live

我们可以打开网址,按F12进行调试,可以看到请求头的信息,如:

接下来我们以servlet程序用request获取请求头的信息:

        //用getHeader获取指定的头信息
        String headValue = request.getHeader("Accept-Encoding");
        System.out.println(headValue);

        System.out.println("---------------");

        //用getHeaders获取指定的头信息,同一个头可能可以有多个值,这个时候就可以使用该方法。
        Enumeration<String> e = request.getHeaders("Accept-Encoding");
        while(e.hasMoreElements()){
            String value = e.nextElement();
            System.out.println(value);
        }

        System.out.println("--------------");
        //获取所有的头的名字和值 请求头相当于一个具有键值对的map
        e = request.getHeaderNames();
        while(e.hasMoreElements()){
            String name = e.nextElement();
            String value = request.getHeader(name);
            System.out.println(name + ": " + value);
        }

结果:
获取请求头的三个方法


获取请求的数据

在request中最常用的还是获取请求的数据,我们可以用客户端打开网页(在html、jsp中)通过form表单的post或者get方式向服务器发送数据,这些数据都将会封装在request中。与获取请求头的方法类似,我们可以通过下面几个方法获取客户端请求的数据:

  1. getParameter(String name) 常用
  2. getParameterValues(String name) 常用
  3. getParameterNames(String name) 不常用
  4. getParameterMap() 编写框架时常用

重点讨论一下request的乱码问题

与response一样,request也有很多的乱码问题。还是一样,头疼的还是get方式的数据提交。post方式只需要在相关业务代码前面加上requset.setCharacterEncoding("utf-8");//设置服务器以UTF-8的编码接收数据即可。

那我们用get方式,进行form表单提交,来解决乱码问题。
简单写一个html的form表单。

    <form action="${pageContext.request.contextPath}/servlet/RequestDemo" method="post">
    用户1:<input type="text" name="uname" ><br>
    用户2:<input type="text" name="uname" ><br>       
    密码:<input type="submit" value="提交">
    </form>

在控制层的业务代码:

//get方式请求  这样设置编码无效  需要自己手动设置
//      req.setCharacterEncoding("utf-8");//设置服务器以UTF-8的编码接收数据
        //为什么?
        //web服务器(tomcat)对GET方式的数据提交采用的解码字符集是"ISO-8859-1" 
        //所以明显服务器的解码方式是不对的,因为编码采用的是UTF-8,而解码却用的ISO-8859-1。

        //使用getParameterValues获取多个uname的值
        System.out.println("--------------------------getParameterValues");
        String []unames = req.getParameterValues("uname");
        int i = 1;
        for(String uname : unames){

            //get方式提交数据 要通过String类的getBytes方法进行编码转换
            //首先用iso8859反向编码到原始数据后 再用utf8重新编码 从而得到中文
            String uname1 = new String(uname.getBytes("iso-8859-1"),"utf-8");
            System.out.println("用户"+(i++)+":"+uname1);
        }
        System.out.println("--------------------------getParameterMap");

        //使用getParameterMap 并未进行乱码转换
        Map<String, String[]> map = req.getParameterMap();
        if(map!=null){
            Set<Entry<String, String[]>> set = map.entrySet();
            Iterator<Entry<String, String[]>> iterator = set.iterator();
            while(iterator.hasNext()){
                Entry<String, String[]> entry = iterator.next();
                System.out.println("参数名:"+ entry.getKey());
                String[] values = entry.getValue();
                if(values != null && values.length > 0){
                    for(String v : values){
                        System.out.print(v+",");
                    }
                }
                System.out.println();
            }
        }

        System.out.println("--------------------------getParameterNames");
        //使用getParameterNames 并未进行乱码转换
        Enumeration names = req.getParameterNames();  
        if(names != null){  
            while(names.hasMoreElements()){  
                String name = (String) names.nextElement();  
                System.out.println("参数名:"+name);  
                System.out.println("参数值:"+req.getParameter(name));  
            }  
        }  
  1. 因为web服务器(tomcat)对GET方式的数据提交采用的解码字符集是”ISO-8859-1” 。中文用ISO8859解码必然乱码。
  2. 所以我们先要用iso8859反向编码到原始数据后 再用utf8重新编码 从而得到中文。

我在form表单填入如下数据:
这里写图片描述

结果:
这里写图片描述

可以看出没有进行编码的代码,输出的结果是乱码的。

同时也要说明一下超链接地址以?传输数据的方式也是get方式,所以也要进行手工编码。如:

    <a href="${pageContext.request.contextPath}/servlet/RequestDemo2?name=徐达">测试是否乱码</a>

request实现请求转发

在response对象中,我们知道了重定向(response.sendRedirect(String url)),重定向(302状态码)使用时会改变网址,它指向要获取资源的网址(告诉客户端找谁,找什么资源),接下来介绍请求转发,与重定向相似,它也是去获取资源,但是不改变当前的网址。

请求转发的要点:

  • 请求转发指一个web资源受到客户端请求后,通知服务器去调用另一个web资源进行处理。
  • 请求转发的应用场景:MVC设计模式
  • request对象提供了一个getRequestDispatch方法,该方法返回一个RequestDispatcher对象,调用这个对象的forward方法可以实现请求转发。
  • request对象同时也是一个域对象,开发人员通过request对象在实现转发时,把数据通过request对象带给其他web资源处理。(这是个容器。)
    1. setAttribute方法
    2. getAttribute方法
    3. removeAttribute方法
    4. getAttributeNames方法
      做一个简单的测试:
package eden.study.request;

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 eden
 *
 */
public class MyRequestDispatcher extends HttpServlet {

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

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //在request容器中存入一个属性值 
        String text = "Hello world";
        request.setAttribute("text",text);

        //转发给RequestDispatch1进行读取
        request.getRequestDispatcher("/servlet/MyRequestDispatcher1").forward(request, response);

        //一个web资源收到客户端请求后,通知服务器去调用另外一个web资源进行处理,称之为请求转发/307。
        //  一个web资源收到客户端请求后,通知浏览器去访问另外一个web资源进行处理,称之为请求重定向/302。
    }

}

请求转发到的MyRequestDispatcher1代码:

package eden.study.request;

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;

public class MyRequestDispatcher1 extends HttpServlet {

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

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setCharacterEncoding("utf-8");
        request.setCharacterEncoding("utf-8");
        //获取属性值
        String text = (String) request.getAttribute("text");

        PrintWriter out = response.getWriter();
        out.write( text );
    }

}

结果:
这里写图片描述

上面也是转发另一个Servlet,当然转发到jsp也是可以的,而且更加好。

String data = "我叫Eden,我今年18岁。";
request.setAttribute("data", data);

//客户端访问这个Servlet后,MyRequestDispatcher2通知服务器将请求转发(forward)到test.jsp页面进行处理
                request.getRequestDispatcher("/test.jsp").forward(request, response);

test.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<!--告诉浏览器以utf-8编码打开页面-->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
<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>

结果:
这里写图片描述

中文数据这里转发到jsp页面,没有乱码问题,但是转发到servlet输出在浏览器就是乱码。我有点搞不懂,网上查了资料,setAttribute时最好传一个list,这个list专门存数据,这样会好一点。

还有一点在request域存数据比sevletContent域中存数据要好。

论使用request域存数据是可靠性:

在ServletContext域中也可以存入了data属性值,那个也是可以读取的,但是这种方式是不可靠的,因为ServletContext是全局的,整个web应用都是有效的,所以可能发生数据错乱的情况,比如现在一个人去请求servlet1,就在要进行转发到servlet2的时候,这时候又来一个人去请求servlet1,这时候他也去设置data属性值,因为ServletContext是全局的,所以第一个人在servlet2中读取的可能是第一个人在servlet1中存入的属性值,那样数据就乱了,所以我们只能使用request域了,而且转发都是在一个request域中的,当多个用户来访问servlet1的时候,是有多个request域的,所以互相是不会干扰的,这样数据也是不会乱的,所以说在使用转发技术的时候使用request域存数据是可靠的,而不是用ServletContext域。

RequestDispatcher的include方法

  • RequestDispatcher.inclue方法用于将RequestDispatcher对象封装的资源内容作为当前响应内容的一部分包含进来,从而实现可编程的服务器端包含功能。

  • 被包含的Servlet程序不能改变响应消息的状态码和响应头,如果有,则忽略。

  • 被包含页面不要出现全局架构标签(就是说 直接写body标签里面的内容就好啦)。

如:

请求转发的细节

  • forward方法用于将请求转发到RequestDispatcher对象封装的资源。

  • 如果在调用forward方法之前,在Servlet程序中写入的部分内容已经被真正地传送到了客户端,forward方法将抛出illegalStateException异常。

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

错误代码:

//在使用转发的时候不能将response流关闭,否则将会illegalStateException报错的
//关闭流
response.getOutputStream().close();
//进行转发
RequestDispatcher rd = request.getRequestDispatcher("/test.jsp");//不是使用ServletContext的
rd.forward(request, response);

还有一个错误:

request.getRequestDispatcher("/test.jsp").forward(request, response);
//转发完之后再去转发
request.getRequestDispatcher("/index.jsp").forward(request, response);

//return;

这个报错的原因和上面的是一样的,因为当一个转发之后,response就是向浏览器输出数据,当输出完数据之后,response就会自动的关闭流。所以,我们要在转发之后要添加一句return,这样就不会报错了。

还有一点:
在使用转发技术的时候,会冲掉response中已写入的数据

//在调用转发之前向response中写入的数据,会被冲掉
String data = "123";
response.getWriter().write(data);
request.getRequestDispatcher("/test.jsp").forward(request, response);

这样的话只能看到test.jsp界面,而data数据(123)就被冲掉了。

web工程的各类地址写法

规则:
写任何地址都是使用斜杠开头:如果是写给服务器用的这个”/”就代表当前web应用,如果是写给浏览器用的:这个”/”是指当前网站

  • 浏览器用的:客户机需要这个地址去请求服务器
  • 服务器用的:服务器本身用的
//1:写给服务器用的
                      request.getRequestDispatcher("/form1.html").forward(request, response);

//2:写给浏览器的
response.sendRedirect("/ServletDemo/form1.html");

//3:写给服务器用的
this.getServletContext().getRealPath("/WEB-INF/form1.html");

//4:写给服务器用的
        this.getServletContext().getResourceAsStream("/form1.html");

//5:写给浏览器用的
/**
 * <a href="/ServletDemo/form1.html">点点</a>
 */

//6:写给浏览器用的
/**
 * <form action="/ServletDemo/form1.html">
 *  </form>
**/
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值