2014-07-09 Java Web的学习(4)-----Response和Request

1.Response和Request实际对象是什么?

   虽然我们都是面向Servlet API的接口规范编程,但是还是应该了解一下web服务器是如何实现它的(以tomcat为例).

    Servlet规范是这样定义相关的接口:

1.ServletResponse:Defines an object to assist a servlet in sending a response to the client. The   servlet container creates a ServletResponse object and passes it as an argument to the servlet'  s service method. 
2.ServletRequest:Defines an object to assist a servlet in sending a response to the client. The
  servlet container creates a ServletResponse object and passes 
  it as an argument to the servlet's service method.

 而在相对应的HttpServletResponse和HttpServletRequest无非是处理具体有关HTTP协议的接口.可是在应用服务器Tomcat中是如何产生相对应的对象的呢??我们看看究竟实现类是哪个类??

public class ServletDemo1 extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		this.doPost(request, response);
	}
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		System.out.println(response.getClass().getName());
	}
}
Output:
        org.apache.catalina.connector.ResponseFacade

下面一张图简单介绍响应对象和请求对象如何在Tomcat容器中实现:

2014-07-09 Java Web的学习(4)-----Response和Request_第1张图片

上图是 Tomcat 创建的 Request 和 Response 的类结构图。
Tomcat一接受到请求首先将会创建 org.apache.coyote.Request 和 org.apache.coyote.Response,这两个类是 Tomcat 内部使用的描述一次请求和相应的信息类它们是一个轻量级的类,它们作用就是在服务器接收到请求后,经过简单解析将这个请求快速的分配给后续线程去处理,所以它们的对象很小,很容易被 JVM 回收。
接下去当交给一个用户线程去处理这个请求时又创建 org.apache.catalina.connector.Request 和 org.apache.catalina.connector.Response 对象。
这两个对象一直穿越整个 Servlet 容器直到要传给 Servlet,传给Servlet的是Request和Response的门面类 RequestFacade 和RequestFacade,这里使用门面模式的目的——封装容器中的数据。

一次请求对应的Request和Response的类转化如下图所示:

2014-07-09 Java Web的学习(4)-----Response和Request_第2张图片

2.HTTPServletResponse Interface

Extends the ServletResponse interface to provide HTTP-specific functionality in sending a response. For example, it has methods to access HTTP headers and cookies.The servlet container creates an HttpServletRequest object and passes it as an argument to the servlet's service methods 
(doGet, doPost, etc).

  Tomcat实现HTTPServletResponse 接口的Response对象代表一次请求的响应,这个对象中封装了向客户端发送数据、发送响应头,发送响应状态码的方法.接口中方法具体可以查看Servlet API.基本上是有关HTTP协议的响应消息方法.

2014-07-09 Java Web的学习(4)-----Response和Request_第3张图片

省略相关方法.........

利用response对象的几个常用示例:

1.向客户端输出中文数据
2.解决中文文件下载
3.控制客户端不要缓冲
4.发送HTTP头,控制页面定时刷新或者跳转到其他组件(Servlet/JSP/HTML...)
5.通过HTTP头,实现请求重定向.

  实现核心代码如下:

1.1向客户端输出中文数据(字节流输出),默认采用本地编码输出(响应).如果要以其他编码格式响应,有三种实现方法.

package com.itheima.response;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class OutputStreamDemo1 extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		this.doPost(request, response);
	}
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String str = "中国是一个伟大的国家";
		//默认本地编码,GBK编码格式发送给浏览器.而浏览器默认用gb2312解码
//		response.getOutputStream().write(str.getBytes());
		//数据以utf-8编码格式发送给浏览器.
//		response.getOutputStream().write(str.getBytes("utf-8"));
		//解决方案:
		//1.手动修改浏览器解码方式.IE页面中任意右击----->编码----->Unicode(utf-8)
		//2.在程序修改响应头信息...Content-Type:text/html;charset=utf-8
		//注意:在修改头信息按常理应当放在第一行中,必须先设置响应头,后才能得到输出流,向输出流输出数据
//		response.setHeader("Content-Type", "text/html;charset=utf-8");
//		response.getOutputStream().write(str.getBytes("utf-8"));
		//?为什么不使用close()方法关闭资源流,因为Tomcat应用服务器在响应之后会自动为程序关闭OutputStream流 
		//3.使用<meta>标签模仿响应头
//		response.getOutputStream().write("<meta http-equiv=Content-Type content=text/html;charset=utf-8>".getBytes());
//		response.getOutputStream().write((str+"1111").getBytes("utf-8"));
		//4.使用response对象中setContentType设置浏览器以哪种方式解码
		response.setContentType("text/html;charset=utf-8");
		response.getOutputStream().write((str+"2222").getBytes("utf-8"));
	}
}

1.2向客户端输出中文数据(字符流输出).默认是使用iso-8859-1编码。注意:setContentType功能很强大..

package com.itheima.response;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class PrintWriterDemo1 extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		this.doPost(request, response);
	}
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String str = "美国式范德萨进口量发大水了金卡";
		//由于向浏览器输出字符流,默认是使用iso-8859-1编码.而浏览器可能用别的码表解码数据.
//		response.getWriter().write(str);     //???????????????
		//1.告知浏览器用什么编码.  2.通知服务器输出用什么编码   
		//作用相当于以上两条代码response.setCharacterEncoding("utf-8")
		//           response.setHeader("Content-Type", "text/html;charset=utf-8");
		response.setContentType("text/html;charset=utf-8");
		//向浏览器表明程序是使用utf-8编码格式输出的.
//		response.setCharacterEncoding("utf-8");
		response.getWriter().write(str);
	}
}

2.解决中文文件下载.URLEncoder.encode("文件名","编码格式");

public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String name="中国.gif";
		response.setHeader("Content-Disposition","attachment;filename="+URLEncoder.encode(name,"utf-8")+"");
		response.setHeader("Content-Type", "application/octet-stream");
		InputStream in = new FileInputStream(this.getServletContext().getRealPath("/WEB-INF/classes/中国.gif"));
		OutputStream out = response.getOutputStream();
		int len = -1;
		byte[] buf = new byte[1024];
		while((len=in.read(buf))!=-1){
			out.write(buf, 0, len);
		}
		in.close();
		out.close();
	}

3.控制客户端不要缓冲

response.addHeader("Pragma", "no-cache"); 
response.setHeader("Cache-Control", "no-cache"); 
response.setHeader("Expires", "0");

4.发送HTTP头,控制页面定时刷新或者跳转到其他组件(Servlet/JSP/HTML...)

public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		response.setHeader("Refresh", "3;url="+this.getServletContext().getContextPath()+"/index.jsp");
		response.getWriter().write("注册成功,3秒后会自动跳转到主页<br/>"+"如果没有跳转,<a href=#>请点击</a>");
	}

5.通过HTTP头,实现请求重定向.

        response.setStatus(302);
	response.setHeader("Location", this.getServletContext().getContextPath()+"/index.jsp");
	或者
	response.sendRedirect(location);

   请求重定向示意图:可以查看PPT里(幻灯片放映模式).

3.HTTPServletRequest Interface

Defines an object to provide client request information to a servlet. The servlet container creates a ServletRequest object and passes it as an argument to the servlet's service method.A ServletRequest object provides data including parameter name and values, attributes, and an input stream. Interfaces that extend ServletRequest can provide additional protocol-specific data 
(for example, HTTP data is provided by HttpServletRequest)

HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,开发人员通过这个对象的方法,可以获得客户这些信息。对于相关方法可以,查看API.几乎都是get开头的方法.因为从浏览器发送过来,需要服务器程序获取,并且拿来处理和操作.

2014-07-09 Java Web的学习(4)-----Response和Request_第4张图片

同样,省略。。。。。。

而利用request对象开发常用示例:

1.获得客户机请求头
2.获取客户机请求参数(重要).
3.请求转发和包含(在转发中传递request域数据)

   第一个示例省略,重要是第二个开发示例。。常用.

2.将请求参数封装到JavaBean。利用BeanUtils第三方框架,填充数据.注意:复杂类型(引用型对象)需要注册对应的转换器

        /**
	 * 将HTTP协议请求相关信息填充到JavaBean 使用第三方开发架包直接实现.开发时常用
	 * @param request
	 * @param clazz
	 * @return bean
	 */
	public static <T> T request2Bean(HttpServletRequest request, Class<T> clazz) {
		try {
			T t = clazz.newInstance();
			// 封装复杂类型时,需要注册说明.
			ConvertUtils.register(new DateLocaleConverter(), Date.class);
			// 封装到Bean中.
			BeanUtils.populate(t, request.getParameterMap());
			return t;
		} catch (Exception e) {
			new RuntimeException(e);
		}
		return null;
	}

在第三种方式也是常用的.但是当你了解到转发和包含原理之后.实验起来很简单的..其中包含是不包括头信息的。。。

而转发的示例图:可以查看自己的PPT,不是偷懒,而是PPT中的画的太形象..转发是一次请求...

2014-07-09 Java Web的学习(4)-----Response和Request_第5张图片

2014-07-09 Java Web的学习(4)-----Response和Request_第6张图片

request中处理请求参数中文处理:

2014-07-09 Java Web的学习(4)-----Response和Request_第7张图片

注意:URL的路径问题:/代表当前应用.URL一般被服务器使用的话可以直接/,而如果浏览器使用的话,则需要/应用名.

       例如:URL:/myapp/servlet/ServletDemo1------->服务器用:/servlet/ServletDemo1

                                                                   -------->浏览器用:/myapp/servlet/ServletDemo1

参考资料:

http://docs.oracle.com/cd/E17802_01/products/products/servlet/2.5/docs/servlet-2_5-mr2/





你可能感兴趣的:(2014-07-09 Java Web的学习(4)-----Response和Request)