- 浏览: 220869 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
Wangwei86609:
非常好的规则引擎框架,支持决策树和多线程运行规则https:/ ...
规则引擎 -
hzxlb910:
真详细,收藏哈
maven setting.xml配置说明 -
东方胜:
[b][/b]
脚本语言 Tcl -
345161974:
hyw520110 写道345161974 写道这个Visua ...
Visual Tcl Binary 完整版(完美中文支持) -
hyw520110:
345161974 写道这个Visual Tcl Binary ...
Visual Tcl Binary 完整版(完美中文支持)
译者 jarfield
博客 http://jarfield.iteye.com
获取参数
除非servlet 调用javax.servlet.http.HttpServletRequest 的getParameter 、getParameterMap 、getParameterNames 和getParameterValues 方法来读取请求参数,否则,我们都不需要解析query string 或HTTP 请求体(request body )。 因此,HttpRequest 类实现的这四个方法,都是先调用parseParameter 方法。
请求参数只需要被解析一次,而且也许只能被解析一次,因为如果请求参数是在请求体中,参数解析会导致SocketInputStream 到达字节流的末尾。HttpRequest 类使用boolean 成员parsed 来表示请求参数是否已经被解析。
如果是GET 请求,那么所有的请求参数都在query sting 中。如果是POST 请求,在请求体中也可以找到一些参数。所有参数以名/值对的形式存储在一个HashMap 中。Servlet 程序员能够以两种形式获取参数:Map (调用HttpServletRequest 的getParameterMap 方法)和名/值对。但是,这里有个“圈套”。Servlet 程序员不允许修改参数的值。因此,使用了一个特殊的HashMap :org.apache.catalina.util.ParameterMap 。
ParameterMap 类继承了java.util.HashMap ,并使用了一个boolean 成员locked 。只有locked 的值为false 时,名/值对才能被添加、修改和删除。否则,将会抛出一个IllegalStateException 异常。ParameterMap 的代码见Listing 3.6 。它重载了添加、修改和删除元素的方法。这些方法只能在locked 值为false 才能被调用。
Listing 3.6: The org.apache.Catalina.util.ParameterMap class.
- package org.apache.catalina.util;
- import java.util.HashMap;
- import java.util.Map;
- public final class ParameterMap extends HashMap {
- public ParameterMap() {
- super ();
- }
- public ParameterMap(int initialCapacity) {
- super(initialCapacity);
- }
- public ParameterMap(int initialCapacity, float loadFactor) {
- super(initialCapacity, loadFactor);
- }
- public ParameterMap(Map map) {
- super(map);
- }
- private boolean locked = false;
- public boolean isLocked() {
- return (this.locked);
- }
- public void setLocked(boolean locked) {
- this.locked = locked;
- }
- private static final StringManager sm =
- StringManager.getManager("org.apache.catalina.util");
- public void clear() {
- if (locked)
- throw new IllegalStateException(sm.getString("parameterMap.locked"));
- super.clear();
- }
- public Object put(Object key, Object value) {
- if (locked)
- throw new IllegalStateException
- (sm.getString("parameterMap.locked"));
- return (super.put(key, value));
- }
- public void putAll(Map map) {
- if (locked)
- throw new IllegalStateException
- (sm.getString("parameterMap.locked"));
- super.putAll(map);
- }
- public Object remove(Object key) {
- if (locked)
- throw new IllegalStateException
- (sm.getString("parameterMap.locked"));
- return (super.remove(key));
- }
- }
package org.apache.catalina.util; import java.util.HashMap; import java.util.Map; public final class ParameterMap extends HashMap { public ParameterMap() { super (); } public ParameterMap(int initialCapacity) { super(initialCapacity); } public ParameterMap(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); } public ParameterMap(Map map) { super(map); } private boolean locked = false; public boolean isLocked() { return (this.locked); } public void setLocked(boolean locked) { this.locked = locked; } private static final StringManager sm = StringManager.getManager("org.apache.catalina.util"); public void clear() { if (locked) throw new IllegalStateException(sm.getString("parameterMap.locked")); super.clear(); } public Object put(Object key, Object value) { if (locked) throw new IllegalStateException (sm.getString("parameterMap.locked")); return (super.put(key, value)); } public void putAll(Map map) { if (locked) throw new IllegalStateException (sm.getString("parameterMap.locked")); super.putAll(map); } public Object remove(Object key) { if (locked) throw new IllegalStateException (sm.getString("parameterMap.locked")); return (super.remove(key)); } }
现在,让我们看看parseParameters 方法是如何工作的。
由于请求参数既可以存在于query string 中,也可以存在于 HTTP请求体中,parseParameters 方法必须都检查query string 和请求体。一旦解析完成,就可以在parameters 成员变量中找到这些参数。因此该方法首先检查成员变量parsed 的值,如果之前已经解析过,parsed 的值就是true 。
if (parsed) return;
然后,parseParameters 方法声明创建一个名为results 的ParameterMap 变量,将它指向parameters 。如果parameters 为null ,就创建一个新的ParameterMap 对象。
ParameterMap results = parameters; if (results == null) results = new ParameterMap();
接着,parseParameters 方法打开ParameterMap 的锁,以便修改它。
results.setLocked(false);
下一步,parseParameters 方法检查编码,如果编码为空则赋予默认编码。
String encoding = getCharacterEncoding(); if (encoding == null) encoding = "ISO-8859-1";
接着,parseParameters 方法尝试解析query string 。参数解析是由org.apache.Catalina.util.RequestUtil 类的parseParameter 方法完成的。
- // Parse any parameters specified in the query string
- String queryString = getQueryString();
- try {
- RequestUtil.parseParameters(results, queryString, encoding);
- }
- catch (UnsupportedEncodingException e) {
- ;
- }
// Parse any parameters specified in the query string String queryString = getQueryString(); try { RequestUtil.parseParameters(results, queryString, encoding); } catch (UnsupportedEncodingException e) { ; }
下一步,parseParameters 方法尝试看看HTTP 请求体中是否包含参数。如果用户使用POST 方法发送请求,content length 大于0 ,并且content type 是application/x-www-form-urlencoded ,那么请求体中就会包含参数。解析请求体的代码如下。
- // Parse any parameters specified in the input stream
- String contentType = getContentType();
- if (contentType == null)
- contentType = "";
- int semicolon = contentType.indexOf(';');
- if (semicolon >= 0) {
- contentType = contentType.substring (0, semicolon).trim();
- }
- else {
- contentType = contentType.trim();
- }
- if ("POST".equals(getMethod()) && (getContentLength() > 0)
- && "application/x-www-form-urlencoded".equals(contentType)) {
- try {
- int max = getContentLength();
- int len = 0;
- byte buf[] = new byte[getContentLength()];
- ServletInputStream is = getInputStream();
- while (len < max) {
- int next = is.read(buf, len, max - len);
- if (next < 0 ) {
- break;
- }
- len += next;
- }
- is.close();
- if (len < max) {
- throw new RuntimeException("Content length mismatch");
- }
- RequestUtil.parseParameters(results, buf, encoding);
- }
- catch (UnsupportedEncodingException ue) {
- ;
- }
- catch (IOException e) {
- throw new RuntimeException("Content read fail");
- }
- }
// Parse any parameters specified in the input stream String contentType = getContentType(); if (contentType == null) contentType = ""; int semicolon = contentType.indexOf(';'); if (semicolon >= 0) { contentType = contentType.substring (0, semicolon).trim(); } else { contentType = contentType.trim(); } if ("POST".equals(getMethod()) && (getContentLength() > 0) && "application/x-www-form-urlencoded".equals(contentType)) { try { int max = getContentLength(); int len = 0; byte buf[] = new byte[getContentLength()]; ServletInputStream is = getInputStream(); while (len < max) { int next = is.read(buf, len, max - len); if (next < 0 ) { break; } len += next; } is.close(); if (len < max) { throw new RuntimeException("Content length mismatch"); } RequestUtil.parseParameters(results, buf, encoding); } catch (UnsupportedEncodingException ue) { ; } catch (IOException e) { throw new RuntimeException("Content read fail"); } }
最后,parseParameters 方法锁住ParameterMap ,设置parsed 成员的值为true ,并将results 赋值给parameters 。
// Store the final results results.setLocked(true); parsed = true; parameters = results;
创建HttpResponse 对象
HttpResponse 类实现了javax.servlet.http.HttpServletResponse 接口,跟随该类的还有一个门面类HttpResponseFacade 。Figure 3.3 展现了HttpResponse 和相关类的类图。
在第2 章,我们使用的HttpResponse 类仅包括部分功能。例如,它的getWriter 方法返回了一个java.io.PrintWriter 对象,该对象的print 方法并不会自动flush 。本章的应用将修复这个问题。为了理解如何修复的,你需要知道Writer 是什么。
在servlet 内部,你使用PrintWriter 来写入字符。你可以使用任何你希望的编码,但是字符总是作为字节流发送给浏览器。因此,第2 章中ex02.pyrmont.HttpResponse 类getWriter 方法的实现也就不奇怪了:
- public PrintWriter getWriter() {
- // if autoflush is true, println() will flush,
- // but print() will not.
- // the output argument is an OutputStream
- writer = new PrintWriter(output, true);
- return writer;
- }
public PrintWriter getWriter() { // if autoflush is true, println() will flush, // but print() will not. // the output argument is an OutputStream writer = new PrintWriter(output, true); return writer; }
看,我们是如何创建PrintWriter 对象的?传递一个java.io.OutputStream 实例作为参数。任何内容传递给PrintWriter 的print 或println 方法,都会被转成字节流,通过底层OutputStream 对象发送出去。
本章我们使用ex03.pyrmont.connector.ResponseStream 类的实例作为PrintWriter 的OutputStream 。注意,ResponseStream 类直接继承了java.io.OutputStream 类。
本章我们还使用继承了PrintWriter 的ex03.pyrmont.connector.ResponseWriter 类。ResponseWriter 类重写了所有的print 和println 方法,对这些方法的调用都会自动将输出flush 到底层的OutputStream 。因此,我们使用以ResponseStream 对象作为底层的ResponseWriter 实例。
我们本可以将一个ResponseStream 对象作为参数,实例化ResponseWriter 类。然而,我们使用java.io.OutputStreamWriter 对象桥接了ResponseWriter 对象和ResponseStream 对象。
有了OutputStreamWriter ,被写入的字符自动按照指定的字符集被编码成字节。这里使用的字符集,或者通过名称来指定,或者显式指定Charset 对象,或者使用平台默认的字符集。对write 方法的每次调用,都会对给定的字符进行编码转换。在写入底层输入流之前,转换后的字节先被累积在缓冲区中。缓冲区的大小可以指定,但对于大多数场景来说,默认大小已经足够了。
因此,getWriter 方法就按下面的代码来实现:
- public PrintWriter getWriter() throws IOException {
- ResponseStream newStream = new ResponseStream(this);
- newStream.setCommit(false);
- OutputStreamWriter osr =
- new OutputStreamWriter(newStream, getCharacterEncoding());
- writer = new ResponseWriter(osr);
- return writer;
- }
public PrintWriter getWriter() throws IOException { ResponseStream newStream = new ResponseStream(this); newStream.setCommit(false); OutputStreamWriter osr = new OutputStreamWriter(newStream, getCharacterEncoding()); writer = new ResponseWriter(osr); return writer; }
静态资源处理器和Servlet 处理器
ServletProcessor 类和第2 章的ex02.pyrmont.ServletProcessor 类是类似的。它们都只有一个方法:process 。然而,ex03.pyrmont.connector.ServletProcessor 的process 方法接受一个HttpRequest 对象和一个HttpResponse 对象,而不是Request 对象和Response 对象。下面是本章应用的process 方法原型:
public void process(HttpRequest request, HttpResponse response) {
另外,process 方法使用HttpRequestFacade 和HttpResponseFacade ,作为请求和响应的门面类。而且在调用了servlet 的service 方法后,还调用了HttpResponse 类的finishResponse 方法。
- servlet = (Servlet) myClass.newInstance();
- HttpRequestFacade requestPacade = new HttpRequestFacade(request);
- HttpResponseFacade responseFacade = new
- HttpResponseFacade(response);
- servlet.service(requestFacade, responseFacade);
- ((HttpResponse) response).finishResponse();
servlet = (Servlet) myClass.newInstance(); HttpRequestFacade requestPacade = new HttpRequestFacade(request); HttpResponseFacade responseFacade = new HttpResponseFacade(response); servlet.service(requestFacade, responseFacade); ((HttpResponse) response).finishResponse();
StaticResourceProcessor 类和ex02.pyrmont.StaticResourceProcessor 基本相同。
运行应用程序
要在Windows 运行该应用,在工作目录运行以下命令:
java -classpath ./lib/servlet.jar;./ ex03.pyrmont.startup.Bootstrap
在Linux 上,需要使用冒号来分隔两个库。
java -classpath ./lib/servlet.jar:./ ex03.pyrmont.startup.Bootstrap
要显示index.html ,使用下面的URL :
http://localhost:808O/index.html
要调用PrimitiveServlet,直接在浏览器中访问下面的URL:
http://localhost:8080/servlet/PrimitiveServlet
你会在浏览器中看到下面的内容:
Hello. Roses are red. Violets are blue.
提示:第2章中运行 PrimitiveServlet 时,并没有输出第二行。
你也可以调用第2 章中没有的ModernServlet 。URL 是:
http://localhost:8080/servlet/ModernServlet
提示: ModernServlet 的代码在工作目录的 webroot 目录下。
你可以在URL后面拼上一个query stirng ,来测试servlet 。Figure 3.4 显示了,以下面URL 运行ModernServlet 的输出结果:
http://localhost:8080/servlet/ModernServlet?userName=tarzan&password=pwd
Figure 3.4 : 运行ModernServlet
总结
本章你已经学习到了连接器 是如何工作的。本章构建的连接器 ,是Tomcat 4 默认连接器 的一个简化版本。正如你知道的,这个默认连接器 因为低效而被不推荐使用(deprecated )。例如,所有的HTTP 请求headers都被解析,即使servlet 从来没有使用它们。结果,默认连接器 运行速度缓慢,并被更快的Coyote 代替。Coyote 的代码可以从Apache基金会网站下载到。无论如何,默认连接器都是一个很好的学习工具,我们将在第4 章详细讨论它。
发表评论
-
pushlet
2012-05-31 14:56 1174基于pushlet的文件监控系统的研究与实现 http ... -
@Transactional spring 配置事务
2012-04-25 11:15 2094@Transactional spring 配置事 ... -
Spring的组件自动扫描机制
2012-04-09 17:47 0Spring将所有的bean都纳入到IOC中创建、管理和维护。 ... -
struts&rest
2012-04-03 00:11 798深入浅出REST http://www.infoq. ... -
文件转码
2011-11-16 09:55 2022工程项目太多,各工程或各文件编码不统一时,可运行本工具类,把工 ... -
安装和使用SpringIDE-------III
2011-07-29 10:40 8602. 编写类文件 · ... -
安装和使用SpringIDE-------II
2011-07-29 10:39 685显示图表,如图: 发表于 @ 2006 ... -
安装和使用SpringIDE
2011-07-29 10:36 1133这篇文章谈谈如何安装与使用SpringIDE。作为辅助Sp ... -
使用AJDT简化AspectJ开发
2011-07-29 10:05 1051面向方面编程(AOP)可用来解决当今的 许多 应用需求 ... -
利用Apache的CLI来处理命令行
2011-05-16 17:02 986CLI是Jakarta Commons中的一个子类。如果你仅仅 ... -
CGlib简单介绍
2011-04-28 08:37 864CGlib概述:cglib(Code Generation L ... -
Java ClassLoader
2011-04-25 18:24 1010当Java编译器编译好.class ... -
Template模式与Strategy模式
2011-04-20 16:23 686template method模式和stra ... -
Ibatis读写CLOB数据
2011-03-21 14:21 1051转载:http://www.iteye.com/topic/7 ... -
轻松构建和运行多线程的单元测试
2011-03-18 22:09 981背景 并行程序 并行程序是指控制计算机系统中两个或多个分别 ... -
Cairngorm3中文简介
2011-03-18 22:07 1029官方原文地址:http://opensource.adobe. ... -
ibator改造之返回数据库注释和数据库分页
2010-12-23 17:24 2238转载:http://www.iteye.com ... -
quatrz 任务监控管理 (2)
2010-10-28 23:28 1447在《Quartz 任务监控管理 (1)》http://www. ... -
Quartz任务监控管理 (1)
2010-10-28 23:27 1313转载:http://sundoctor.iteye.com/b ... -
Quartz 在 Spring 中如何动态配置时间
2010-10-28 23:25 1704转载: http://sundoctor.iteye.com ...
相关推荐
《How Tomcat Works》中文版一书详细剖析了Tomcat服务器的内部工作机制。该书基于Tomcat 4.1.12和5.0.18两个版本,深入讲解了其servlet容器的架构和运作原理,尤其是代号为Catalina的核心组件。 Tomcat是一个开源的...
《译How Tomcat Works(第二章)》这篇文章主要讲解了Apache Tomcat服务器的工作原理,它是一个开源的Java Servlet容器,广泛用于部署Web应用程序。在这一章中,我们将深入探讨Tomcat如何处理HTTP请求,以及其内部架构...
《How Tomcat Works》是一本深入探讨Apache Tomcat工作原理的书籍,中文版的提供使得国内开发者能够更方便地理解这一流行的开源Java Servlet容器。这本书不仅涵盖了Tomcat的基础知识,还详细解析了其内部机制,对于...
1. **架构概述**:Tomcat的架构基于服务器-客户端模型,主要由Catalina(Servlet容器)、 Coyote(HTTP/HTTPS连接器)和Jasper(JSP引擎)三个主要组件构成。Catalina处理Servlet,Coyote处理网络通信,Jasper编译和...
《How Tomcat Works》是一本深入解析Apache Tomcat工作原理的书籍,同时也包含了源码,为读者提供了理论与实践相结合的深入学习体验。Tomcat是一款广泛使用的开源Java Servlet容器,它是Apache软件基金会 Jakarta...
《How Tomcat Works中文版》这本书是一本深入探讨Apache Tomcat服务器工作原理的专著。Apache Tomcat服务器,或简称为Tomcat,是世界上广泛使用的Java Servlet容器和JavaServer Pages(JSP)引擎,负责处理基于Java...
### How Tomcat Works中文版深度解析 #### 一、引言与概述 《How Tomcat Works》是一本针对Apache Tomcat服务器内部工作机制进行深入剖析的专业书籍。本书详细介绍了Tomcat 4.1.12和5.0.18两个版本的内部结构与...
《How Tomcat Works》这本书是理解Apache Tomcat服务器工作原理的宝贵资源,它全面深入地讲解了这个流行的Java Servlet和JavaServer Pages(JSP)容器的内部机制。书中的20个章节涵盖了从基础概念到高级特性的广泛...
《How Tomcat Works》这本书深入浅出地介绍了Apache Tomcat这款广泛应用的Java Servlet容器的工作原理。Tomcat作为开源软件,是许多Web应用的基础,尤其在轻量级开发和测试环境中非常常见。以下是对Tomcat核心知识点...
《How Tomcat Works》这本书是理解Apache Tomcat服务器工作原理的重要资源,第三章主要探讨了Tomcat的架构和核心组件。以下是对这部分内容的详细解读: Tomcat作为一款开源的Java Servlet容器,其核心功能是解析...
《HowTomcatWorks》是一本深入解析Apache Tomcat工作原理的书籍,中文版的发布使得更多的中国开发者能够理解和掌握这款广泛应用的开源Java Servlet容器的工作机制。Tomcat是Apache软件基金会Jakarta项目的一部分,它...
《how tomcat works》是一本深入探讨Apache Tomcat内部工作原理的专业书籍。Apache Tomcat是一个开源的Java Servlet容器,它实现了Java Servlet和JavaServer Pages技术规范,提供了Java Web服务器的功能。对于Java ...
《How Tomcat Works》是一本深入探讨Apache Tomcat工作原理的书籍,包含了中英文两个版本。这本书对于理解Java Servlet和JavaServer Pages(JSP)容器的运作方式具有极高的价值,特别是对于那些想要深入理解Web应用...
《How Tomcat Works》是一本深入解析Apache Tomcat服务器内部工作原理的重要参考资料,它提供了对Tomcat架构的全面理解,包括其设计、配置和优化。这本书的中文版和英文版都为读者提供了便利,无论你是母语为中文...