http请求request详解

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

获得客户机信息

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

获得客户机请求头

  getHeader(string name)方法:String 
  getHeaders(String name)方法:Enumeration 
  getHeaderNames()方法

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

      getParameter(String)方法
      getParameterValues(String name)方法
      getParameterNames()方法
     getParameterMap()方法

request是一个域对象
request对象也是一个存储数据的区域对象,所以也具有如下方法:

     setAttribute(String name, Object o)

     getAttribute(String name)

     removeAttribute(String name)

request完成请求转发
      RequestDispatcher getRequestDispatcher(String path)  // 获得请求转发

     requestDispathcer.forward(ServletRequest request, ServletResponse response) // 通过转发器对象转发

Http 请求传输时将 url 以 ISO-8859-1 编码,服务器收到字节流后默认会以 ISO-8859-1 编码来解码成字符流(造成中文乱码)

// POST请求,处理中文乱码

request.setCharacterEncoding("UTF-8");
 //get请求,需要把 request.getParameter(“参数名”) 获取到的字符串先用 ISO-8859-1 编码成字节流,然后再将其用 utf-8 解码成字符流
String str = new String(request.getParameter("参数名").getBytes("iso-8859-1"), "utf-8");  

 

一、获取请求消息行的方法
这部分内容很简单直接上代码:

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    req.setCharacterEncoding("UTF-8");   //告诉服务器使用什么编码,要与浏览器传过来的编码一致
    System.out.println("请求方法是:"+req.getMethod());     //获取请求方式    
    System.out.println("请求的URL是:"+req.getRequestURL());   //获取请求完整url    
    System.out.println("请求的URI是:"+req.getRequestURI());       //获取请求资源名部分
    System.out.println("请求的当前目录(项目目录)是:"+req.getContextPath());     //获取当前目录(项目目录)<重要>
    String queryString = req.getQueryString();        //获取url中参数部分
    System.out.println("请求的参数是:"+URLDecoder.decode(queryString,"UTF-8"));      
    //这边对参数进行了解码,因为在url中直接输入中文不解码的话,拿到的会是带有百分号的那种字符串,无法正常展示
    //这里还要注意一点,如果请求url没有带参数,这句话会报空指针,所以保险起见,用解码的时候,最好加上非空判断。
    }


输出的结果如下图:


二、获取请求消息头的方法
代码演示两种方法:

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    Enumeration<String> names = req.getHeaderNames();     //获得所有请求消息头的name,返回一个枚举类型
    while (names.hasMoreElements()){
        String key = names.nextElement();
        System.out.println(key+":"+req.getHeader(key));     //根据请求头参数的key值获取对应的value值
    }
}


还有一个request.getHeaders(key)的方法,获取的是具有相同key的请求头的value值,返回的一个枚举类型。

三、获取表单数据的方法
首先,我们先创建一个表单,如下:

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Register</title>
</head>
<body>
<form action="/java_web_day01/request/demo4" method="post">
    用户名:<input type="text" name="userName"></br>
    密  码:<input type="password" name="pwd"></br>
    性  别:<input type="radio" name="sex" value="男" checked="checked">男
    <input type="radio" name="sex" value="女">女</br>
    爱  好:
    <input type="checkbox" name="hobby" value="篮球">篮球
    <input type="checkbox" name="hobby" value="唱歌">唱歌
    <input type="checkbox" name="hobby" value="跳舞">跳舞
    </br>
    所在城市:
    <select name="city">
        <option>------请选择------</option>
        <option value="BJ">北京</option>
        <option value="SH">上海</option>
        <option value="GZ">广州</option>
    </select>
    </br>
    <input type="submit" value="注册">
</form>
</body>
</html>

1. 几个简单的方法介绍下用法:
request.getParameter(name):获取表单中,名字为name的值。
request.getParameterValues(name):获取复选框的值,返回一个数组类型;也可以获取只有一个值的表单。
request.getParameterNames():获取所有的表单的name,返回一个枚举类型。

2. 关于getParameterMap()的用法以及数据的封装
首先根据html表单中的数据封装一个User类,类中的属性要包含表单中所有name的数据,并且User类的属性名最好与name保持一致。注意这两点就可以了,这里就不放User类的创建代码了。
创建完成后,就可以写获取表单参数的代码,并封装成User对象,代码如下:
 

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	req.setCharacterEncoding("UTF-8");
	Map<String, String[]> map = req.getParameterMap();
	//获取表单数据的map,返回的是一个Map<String, String[]>
	User user = new User();
	//创建User对象
	for (String key : map.keySet()) {
		String[] value = map.get(key);
		try {
			PropertyDescriptor p = new PropertyDescriptor(key, User.class);
			//PropertyDescriptor这里运用到了反射的原理,key值是从表单中的name得到的
			//我们创建的User对象的属性与name值是对应的,传入User的字节码对象,这时候,我们就可以通过反射拿到User中对应属性的get和set方法了。
			Method method = p.getWriteMethod();
			//getWriteMethod拿到的就是set方法(如果key是userName,那我们拿到的就是setUserName())
			if(!key.equalsIgnoreCase("hobby")) {
			//这里对hobby做一个区分,因为hobby是可以多选的,同样也可能只选了一个,所以直接区分是不是hobby,而不是区分value长度。
				method.invoke(user, value[0]);
				//不是hobby的那么,value里面只会有一个值,取出第一个值,就是我们要赋值给对应属性的值。
				//反射的方法调用,传入user对象,以及set方法所需的参数,此时,我们就把拿到的表单数据的值保存在了User对象中
			}else {
				method.invoke(user, (Object)value);
				//这里value是一个数组,根据反射传入参数的方式,这里必须强转成Object类型才可以传入数组
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	System.out.println(user);
}

上面这种方法需要我们自己对数据进行区分判断,有一点点麻烦,Apache提供了一个工具叫BeanUtils,用起来就非常简单了。下面是这种方法的实现:
首先,我们需要安装这个工具,因为我使用的是maven工程,所以直接找到这个工具的坐标加到pom.xml文件中,具体版本如下:

<dependency>
      <groupId>commons-beanutils</groupId>
      <artifactId>commons-beanutils</artifactId>
      <version>1.9.3</version>
      <!--maven仓库里还有更新的版本,我选了个使用人数相对更多的-->
    </dependency>

代码如下:

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	req.setCharacterEncoding("UTF-8");
	try {
		User user = new User();
		BeanUtils.populate(user, req.getParameterMap());
		//这里一行就可以搞定,非常简单
		System.out.println(user);
	} catch (Exception e) {
		e.printStackTrace();
	}
}

小结:这里显然更推荐使用Apache提供的工具了,完全不用考虑表单数据是一个值还是多个值,工具都会帮我处理好,我们只需要创建好我们自己的对象就可以了。不过还是把另一种方式记录下来,有助于我们理解反射的使用。

3. 使用getInputStream()获取表单数据
getInputStream()得到的是一个ServletStream对象,我们用读取流对象的方式来读取,用的表单还是上面那个,代码如下:
 

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
	ServletInputStream inputStream = req.getInputStream();
	int len;
	byte[] arr = new byte[1024];
	while ((len=inputStream.read(arr))!=-1){
		String s = new String(arr, 0, len);
		s = URLDecoder.decode(s,"UTF-8");
		//这里需要对拿到的数据进行解码操作,要不然读取到的数据会是乱码的
		System.out.println(s);
	}
	inputStream.close();
}

 

这种方式拿到的数据如下图:

四、请求的转发和包含

请求转发:一个servlet完成不了,把任务委派给其他servlet,共同完成一个请求。

 

请求转发和请求包含:

RequestDispatcher  rd=request.getRequestDispatcher("/servlet");

请求转发:rd.forward(request,reponse);

请求包含:rd.include(request,reponse);

 有时一个请求需要多个Servlet协作才能完成,所以需要在一个Servlet跳到另一个Servlet!
    > 一个请求跨多个Servlet,需要使用转发和包含。
    > 请求转发:由下一个Servlet完成响应体!当前Servlet可以设置响应头!(留头不留体)
    > 请求包含:由两个Servlet共同未完成响应体!(都留)
    > 无论是请求转发还是请求包含,都在一个请求范围内!使用同一个request和response!

request.getRequestDispatcher("/bservlet").forward(request, response);留头不留体

request.getRequestDispatcher("/bservlet").include(request, response);都留

最后我们来看下转发,之前我们了解了使用ServletContext实现转发,这里我们使用Request,达到的效果和之前是一样的。
代码如下:

@Override
//实现转发的代码
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	System.out.println("即将为您转发......");
	req.getRequestDispatcher("/request/demo6").forward(req,resp);
	System.out.println("业务处理完成啦!");
}

 

@Override
//实际业务处理的代码
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	System.out.println("业务正在处理中......");
}

输出结果:

 

 

面试题一    ServletContext域与Request域的生命周期比较?
ServletContext:

创建:服务器启动

销毁:服务器关闭

域的作用范围:整个web应用

request:

创建:访问时创建request

销毁:响应结束request销毁

域的作用范围:一次请求中

面试题二     转发与重定向的区别?
1)重定向两次请求,转发一次请求

2)重定向地址栏的地址变化,转发地址不变

3)重新定向可以访问外部网站 转发只能访问内部资源

4)转发的性能要优于重定向
 

 

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值