虽然咱们都是面向Servlet API的接口规范编程,可是仍是应该了解一下web服务器是如何实现它的(以tomcat为例).html
Servlet规范是这样定义相关的接口:java
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中是如何产生相对应的对象的呢??咱们看看究竟实现类是哪一个类??web
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容器中实现:apache
上图是 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的类转化以下图所示:
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协议的响应消息方法.编程
省略相关方法.........浏览器
利用response对象的几个经常使用示例:tomcat
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里(幻灯片放映模式).cookie
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开头的方法.由于从浏览器发送过来,须要服务器程序获取,而且拿来处理和操做.oracle
一样,省略。。。。。。
而利用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中的画的太形象..转发是一次请求...
request中处理请求参数中文处理:
注意: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/