﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-闵毓-随笔分类-Java开发</title><link>http://www.blogjava.net/shmily432685/category/4000.html</link><description>http://www.eshoo.com.cn &lt;a title="欢迎来到异客中国" href="http://www.eshoo.com.cn"&gt;欢迎来到异客中国&lt;/a&gt;</description><language>zh-cn</language><lastBuildDate>Thu, 06 Mar 2008 12:33:53 GMT</lastBuildDate><pubDate>Thu, 06 Mar 2008 12:33:53 GMT</pubDate><ttl>60</ttl><item><title>转载：Java远程通讯可选技术及原理 </title><link>http://www.blogjava.net/shmily432685/archive/2008/03/06/184249.html</link><dc:creator>闵毓</dc:creator><author>闵毓</author><pubDate>Thu, 06 Mar 2008 05:55:00 GMT</pubDate><guid>http://www.blogjava.net/shmily432685/archive/2008/03/06/184249.html</guid><wfw:comment>http://www.blogjava.net/shmily432685/comments/184249.html</wfw:comment><comments>http://www.blogjava.net/shmily432685/archive/2008/03/06/184249.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/shmily432685/comments/commentRss/184249.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/shmily432685/services/trackbacks/184249.html</trackback:ping><description><![CDATA[<div class="postText">在分布式服务框架中，一个最基础的问题就是远程服务是怎么通讯的，在Java领域中有很多可实现远程通讯的技术，例如：RMI、MINA、ESB、Burlap、Hessian、SOAP、EJB和JMS等，这些名词之间到底是些什么关系呢，它们背后到底是基于什么原理实现的呢，了解这些是实现分布式服务框架的基础知识，而如果在性能上有高的要求的话，那深入了解这些技术背后的机制就是必须的了，在这篇blog中我们将来一探究竟，抛砖引玉，欢迎大家提供更多的实现远程通讯的技术和原理的介绍。<br />
<strong style="font-size: 14pt; color: #ff6600"><br />
<span style="font-size: 18pt; color: #008000">基本原理</span></strong><br />
要实现网络机器间的通讯，首先得来看看计算机系统网络通信的基本原理，在底层层面去看，网络通信需要做的就是将流从一台计算机传输到另外一台计算机，基于传输协议和网络IO来实现，其中传输协议比较出名的有http、tcp、udp等等，http、tcp、udp都是在基于Socket概念上为某类应用场景而扩展出的传输协议，网络IO，主要有bio、nio、aio三种方式，所有的分布式应用通讯都基于这个原理而实现，只是为了应用的易用，各种语言通常都会提供一些更为贴近应用易用的应用层协议。<br />
<span style="font-size: 18pt; color: #008000"><strong><br />
应用级协议</strong></span><br />
远程服务通讯，需要达到的目标是在一台计算机发起请求，另外一台机器在接收到请求后进行相应的处理并将结果返回给请求端，这其中又会有诸如one way request、同步请求、异步请求等等请求方式，按照网络通信原理，需要实现这个需要做的就是将请求转换成流，通过传输协议传输至远端，远端计算机在接收到请求的流后进行处理，处理完毕后将结果转化为流，并通过传输协议返回给调用端。<br />
原理是这样的，但为了应用的方便，业界推出了很多基于此原理之上的应用级的协议，使得大家可以不用去直接操作这么底层的东西，通常应用级的远程通信协议会提供：<br />
1、为了避免直接做流操作这么麻烦，提供一种更加易用或贴合语言的标准传输格式；<br />
2、网络通信机制的实现，就是替你完成了将传输格式转化为流，通过某种传输协议传输至远端计算机，远端计算机在接收到流后转化为传输格式，并进行存储或以某种方式通知远端计算机。<br />
所以在学习应用级的远程通信协议时，我们可以带着这几个问题进行学习：<br />
1、传输的标准格式是什么？<br />
2、怎么样将请求转化为传输的流？<br />
3、怎么接收和处理流？<br />
4、传输协议是？<br />
不过应用级的远程通信协议并不会在传输协议上做什么多大的改进，主要是在流操作方面，让应用层生成流和处理流的这个过程更加的贴合所使用的语言或标准，至于传输协议则通常都是可选的，在java领域中知名的有：RMI、XML-RPC、Binary-RPC、SOAP、CORBA、JMS，来具体的看看这些远程通信的应用级协议：<br />
<strong><strong>--------------------------------------------------------------------------------------------------------------------------------------------------</strong><br />
RMI</strong><br />
RMI是个典型的为java定制的远程通信协议，我们都知道，在single vm中，我们可以通过直接调用java object instance来实现通信，那么在远程通信时，如果也能按照这种方式当然是最好了，这种远程通信的机制成为RPC（Remote Procedure Call），RMI正是朝着这个目标而诞生的。<br />
来看下基于RMI的一次完整的远程通信过程的原理：<br />
1、客户端发起请求，请求转交至RMI客户端的stub类；<br />
2、stub类将请求的接口、方法、参数等信息进行序列化；<br />
3、基于socket将序列化后的流传输至服务器端；<br />
4、服务器端接收到流后转发至相应的skelton类；<br />
5、skelton类将请求的信息反序列化后调用实际的处理类；<br />
6、处理类处理完毕后将结果返回给skelton类；<br />
7、Skelton类将结果序列化，通过socket将流传送给客户端的stub；<br />
8、stub在接收到流后反序列化，将反序列化后的Java Object返回给调用者。<br />
来看jboss-remoting对于此过程的一个更好的图示：<br />
<img height="225" alt="" src="http://www.blogjava.net/images/blogjava_net/bluedavy/jboss-remoting-arch.jpg" width="710" border="0" /><br />
根据原理来回答下之前学习应用级协议带着的几个问题：<br />
1、传输的标准格式是什么？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 是Java ObjectStream。<br />
2、怎么样将请求转化为传输的流？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;基于Java串行化机制将请求的java object信息转化为流。<br />
3、怎么接收和处理流？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;根据采用的协议启动相应的监听端口，当有流进入后基于Java串行化机制将流进行反序列化，并根据RMI协议获取到相应的处理对象信息，进行调用并处理，处理完毕后的结果同样基于java串行化机制进行返回。<br />
4、传输协议是？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Socket。<br />
<strong>--------------------------------------------------------------------------------------------------------------------------------------------------<br />
XML-RPC<br />
</strong>XML-RPC也是一种和RMI类似的远程调用的协议，它和RMI的不同之处在于它以标准的xml格式来定义请求的信息(请求的对象、方法、参数等)，这样的好处是什么呢，就是在跨语言通讯的时候也可以使用。<br />
来看下XML-RPC协议的一次远程通信过程：<br />
1、客户端发起请求，按照XML-RPC协议将请求信息进行填充；<br />
2、填充完毕后将xml转化为流，通过传输协议进行传输；<br />
3、接收到在接收到流后转换为xml，按照XML-RPC协议获取请求的信息并进行处理；<br />
4、处理完毕后将结果按照XML-RPC协议写入xml中并返回。<br />
图示以上过程：<br />
<img height="270" alt="" src="http://www.blogjava.net/images/blogjava_net/bluedavy/xmlrpc.jpg" width="527" border="0" /><br />
同样来回答问题：<br />
1、传输的标准格式是？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;标准格式的XML。<br />
2、怎么样将请求转化为传输的流？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;将XML转化为流。<br />
3、怎么接收和处理流？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通过监听的端口获取到请求的流，转化为XML，并根据协议获取请求的信息，进行处理并将结果写入XML中返回。<br />
4、传输协议是？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Http。<br />
<strong>--------------------------------------------------------------------------------------------------------------------------------------------------<br />
Binary-RPC<br />
</strong>Binary-RPC看名字就知道和XML-RPC是差不多的了，不同之处仅在于传输的标准格式由XML转为了二进制的格式。<br />
同样来回答问题：<br />
1、传输的标准格式是？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;标准格式的二进制文件。<br />
2、怎么样将请求转化为传输的流？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;将二进制格式文件转化为流。<br />
3、怎么接收和处理流？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通过监听的端口获取到请求的流，转化为二进制文件，根据协议获取请求的信息，进行处理并将结果写入XML中返回。<br />
4、传输协议是？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Http。<br />
<strong>--------------------------------------------------------------------------------------------------------------------------------------------------<br />
SOAP<br />
</strong>SOAP原意为Simple Object Access Protocol，是一个用于分布式环境的、轻量级的、基于XML进行信息交换的通信协议，可以认为SOAP是XML RPC的高级版，两者的原理完全相同，都是http+XML，不同的仅在于两者定义的XML规范不同，SOAP也是Webservice采用的服务调用协议标准，因此在此就不多加阐述了。<br />
<strong>--------------------------------------------------------------------------------------------------------------------------------------------------<br />
CORBA<br />
</strong><font face="arial,sans-serif" color="#000000">Common&nbsp;Object&nbsp;Request&nbsp;Broker&nbsp;Architecture（公用对象请求代理[调度]程序体系结构），是一组用来定义&#8220;分布式对象系统&#8221;的标准，由OMG(Object&nbsp;Menagement&nbsp;Group)作为发起和标准制定单位。CORBA的目的是定义一套协议，符合这个协议的对象可以互相交互，不论它们是用什么样的语言写的，不论它们运行于什么样的机器和操作系统。<br />
</font>CORBA在我看来是个类似于SOA的体系架构，涵盖可选的远程通信协议，但其本身不能列入通信协议这里来讲，而且CORBA基本淘汰，再加上对CORBA也不怎么懂，在此就不进行阐述了。<br />
<strong>--------------------------------------------------------------------------------------------------------------------------------------------------<br />
JMS<br />
</strong>JMS呢，是实现java领域远程通信的一种手段和方法，基于JMS实现远程通信时和RPC是不同的，虽然可以做到RPC的效果，但因为不是从协议级别定义的，因此我们不认为JMS是个RPC协议，但它确实是个远程通信协议，在其他的语言体系中也存在着类似JMS的东西，可以统一的将这类机制称为消息机制，而消息机制呢，通常是高并发、分布式领域推荐的一种通信机制，这里的主要一个问题是容错（详细见ErLang论文）。<br />
来看JMS中的一次远程通信的过程：<br />
1、客户端将请求转化为符合JMS规定的Message；<br />
2、通过JMS API将Message放入JMS Queue或Topic中；<br />
3、如为JMS Queue，则发送中相应的目标Queue中，如为Topic，则发送给订阅了此Topic的JMS Queue。<br />
4、处理端则通过轮训JMS Queue，来获取消息，接收到消息后根据JMS协议来解析Message并处理。<br />
回答问题：<br />
1、传输的标准格式是？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JMS规定的Message。<br />
2、怎么样将请求转化为传输的流？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;将参数信息放入Message中即可。<br />
3、怎么接收和处理流？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;轮训JMS Queue来接收Message，接收到后进行处理，处理完毕后仍然是以Message的方式放入Queue中发送或Multicast。<br />
4、传输协议是？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不限。<br />
基于JMS也是常用的实现远程异步调用的方法之一。<br />
<br />
<span style="font-size: 18pt; color: #008000"><strong>可选实现技术</strong></span><br />
当然，在上面的原理中并没有介绍到所有的java领域可选的远程通信协议了，例如还有EJB采用的ORMI、Spring自己定义的一个简单的Http Invoker等等。<br />
看完原理后我们再来看看目前java领域可用于实现远程通讯的框架或library，知名的有：JBoss-Remoting、Spring-Remoting、Hessian、Burlap、XFire(Axis)、ActiveMQ、Mina、Mule、EJB3等等，来对每种做个简单的介绍和评价，其实呢，要做分布式服务框架，这些东西都是要有非常深刻的了解的，因为分布式服务框架其实是包含了解决分布式领域以及应用层面领域两方面问题的。<br />
当然，你也可以自己根据远程网络通信原理(transport protocol+Net IO)去实现自己的通讯框架或library。<br />
那么在了解这些远程通讯的框架或library时，会带着什么问题去学习呢？<br />
1、是基于什么协议实现的？<br />
2、怎么发起请求？<br />
3、怎么将请求转化为符合协议的格式的？<br />
4、使用什么传输协议传输？<br />
5、响应端基于什么机制来接收请求？<br />
6、怎么将流还原为传输格式的？<br />
7、处理完毕后怎么回应？<br />
<strong>--------------------------------------------------------------------------------------------------------------------------------------------------<br />
JBoss-Remoting<br />
</strong>Jboss-remoting是由jboss编写的一个java领域的远程通讯框架，基于此框架，可以很简单的实现基于多种传输协议的java对象的RPC。<br />
直接来回答问题：<br />
1、是基于什么协议实现的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JBoss-Remoting是个通讯框架，因此它支持多种协议方式的通信，例如纯粹的socket+io方式、rmi方式、http+io方式等。<br />
2、怎么发起请求？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在JBoss-Remoting中，只需将需要发起的请求参数对象传入jboss-remoting的InvocationRequest对象即可，也可根据协议基于InvocationRequest封装符合需求的InvocationRequest对象。<br />
3、怎么将请求转化为符合协议的格式的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JBoss-Remoting基于Java串行化机制或JBoss自己的串行化实现来将请求转化为对象字节流。<br />
4、使用什么传输协议传输？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 支持多种传输协议，例如socket、http等。<br />
5、响应端基于什么机制来接收请求？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 响应端只需将自己的处理对象注册到JBoss-Remoting提供的server端的Connector对象中即可。<br />
6、怎么将流还原为传输格式的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JBoss-Remoting基于java串行化机制或jboss自己的串行化实现来将请求信息还原为java对象。<br />
7、处理完毕后怎么回应？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 处理完毕后将结果对象直接返回即可，jboss-remoting会将此对象按照协议进行序列化，返回至调用端。<br />
另外，jboss-remoting支持多种通信方式，例如同步/异步/单向通信等。<br />
<br />
<strong>--------------------------------------------------------------------------------------------------------------------------------------------------<br />
<a title="心得与体会" href="http://www.blogjava.net/shmily432685/admin/EditPosts.aspx?catid=4001" >spring in action</a>-Remoting<br />
</strong><a title="心得与体会" href="http://www.blogjava.net/shmily432685/admin/EditPosts.aspx?catid=4001" >spring in action</a>-remoting是Spring提供java领域的远程通讯框架，基于此框架，同样也可以很简单的将普通的spring bean以某种远程协议的方式来发布，同样也可以配置spring bean为远程调用的bean。<br />
1、是基于什么协议实现的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 和JBoss-Remoting一样，作为一个远程通讯的框架，Spring通过集成多种远程通讯的library，从而实现了对多种协议的支持，例如rmi、http+io、xml-rpc、binary-rpc等。<br />
2、怎么发起请求？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在Spring中，由于其对于远程调用的bean采用的是proxy实现，发起请求完全是通过服务接口调用的方式。<br />
3、怎么将请求转化为符合协议的格式的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Spring按照协议方式将请求的对象信息转化为流，例如Spring Http Invoker是基于Spring自己定义的一个协议来实现的，传输协议上采用的为http，请求信息是基于java串行化机制转化为流进行传输。<br />
4、使用什么传输协议传输？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 支持多种传输协议，例如rmi、http等等。<br />
5、响应端基于什么机制来接收请求？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 响应端遵循协议方式来接收请求，对于使用者而言，则只需通过spring的配置方式将普通的spring bean配置为响应端或者说提供服务端。<br />
6、怎么将流还原为传输格式的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;按照协议方式来进行还原。<br />
7、处理完毕后怎么回应？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 处理完毕后直接返回即可，spring-remoting将根据协议方式来做相应的序列化。<br />
<br />
<strong>--------------------------------------------------------------------------------------------------------------------------------------------------<br />
Hessian<br />
</strong>Hessian是由caucho提供的一个基于binary-RPC实现的远程通讯library。<br />
1、是基于什么协议实现的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 基于Binary-RPC协议实现。<br />
2、怎么发起请求？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;需通过Hessian本身提供的API来发起请求。<br />
3、怎么将请求转化为符合协议的格式的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Hessian通过其自定义的串行化机制将请求信息进行序列化，产生二进制流。<br />
4、使用什么传输协议传输？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Hessian基于Http协议进行传输。<br />
5、响应端基于什么机制来接收请求？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 响应端根据Hessian提供的API来接收请求。<br />
6、怎么将流还原为传输格式的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Hessian根据其私有的串行化机制来将请求信息进行反序列化，传递给使用者时已是相应的请求信息对象了。<br />
7、处理完毕后怎么回应？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 处理完毕后直接返回，hessian将结果对象进行序列化，传输至调用端。<br />
<br />
<strong>--------------------------------------------------------------------------------------------------------------------------------------------------<br />
Burlap<br />
</strong>Burlap也是有caucho提供，它和hessian的不同在于，它是基于XML-RPC协议的。<br />
1、是基于什么协议实现的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 基于XML-RPC协议实现。<br />
2、怎么发起请求？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;根据Burlap提供的API。<br />
3、怎么将请求转化为符合协议的格式的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将请求信息转化为符合协议的XML格式，转化为流进行传输。<br />
4、使用什么传输协议传输？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Http协议。<br />
5、响应端基于什么机制来接收请求？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 监听Http请求。<br />
6、怎么将流还原为传输格式的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 根据XML-RPC协议进行还原。<br />
7、处理完毕后怎么回应？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 返回结果写入XML中，由Burlap返回至调用端。<br />
<br />
<strong>--------------------------------------------------------------------------------------------------------------------------------------------------<br />
XFire、Axis<br />
</strong>XFire、Axis是Webservice的实现框架，WebService可算是一个完整的SOA架构实现标准了，因此采用XFire、Axis这些也就意味着是采用webservice方式了。<br />
1、是基于什么协议实现的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 基于SOAP协议。<br />
2、怎么发起请求？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;获取到远端service的proxy后直接调用。<br />
3、怎么将请求转化为符合协议的格式的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将请求信息转化为遵循SOAP协议的XML格式，由框架转化为流进行传输。<br />
4、使用什么传输协议传输？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Http协议。<br />
5、响应端基于什么机制来接收请求？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 监听Http请求。<br />
6、怎么将流还原为传输格式的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 根据SOAP协议进行还原。<br />
7、处理完毕后怎么回应？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 返回结果写入XML中，由框架返回至调用端。<br />
<br />
<strong>--------------------------------------------------------------------------------------------------------------------------------------------------<br />
ActiveMQ<br />
</strong>ActiveMQ是JMS的实现，基于JMS这类消息机制实现远程通讯是一种不错的选择，毕竟消息机制本身的功能使得基于它可以很容易的去实现同步/异步/单向调用等，而且消息机制从容错角度上来说也是个不错的选择，这是Erlang能够做到容错的重要基础。<br />
1、是基于什么协议实现的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 基于JMS协议。<br />
2、怎么发起请求？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;遵循JMS API发起请求。<br />
3、怎么将请求转化为符合协议的格式的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不太清楚，猜想应该是二进制流。<br />
4、使用什么传输协议传输？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 支持多种传输协议，例如socket、http等等。<br />
5、响应端基于什么机制来接收请求？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 监听符合协议的端口。<br />
6、怎么将流还原为传输格式的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 同问题3。<br />
7、处理完毕后怎么回应？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 遵循JMS API生成消息，并写入JMS Queue中。<br />
基于JMS此类机制实现远程通讯的例子有Spring-Intergration、Mule、Lingo等等。<br />
<br />
<strong>--------------------------------------------------------------------------------------------------------------------------------------------------<br />
Mina<br />
</strong>Mina是Apache提供的通讯框架，在之前一直没有提到网络IO这块，之前提及的框架或library基本都是基于BIO的，而Mina是采用NIO的，NIO在并发量增长时对比BIO而言会有明显的性能提升，而java性能的提升，与其NIO这块与OS的紧密结合是有不小的关系的。<br />
1、是基于什么协议实现的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 基于纯粹的Socket+NIO。<br />
2、怎么发起请求？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通过Mina提供的Client API。<br />
3、怎么将请求转化为符合协议的格式的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Mina遵循java串行化机制对请求对象进行序列化。<br />
4、使用什么传输协议传输？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 支持多种传输协议，例如socket、http等等。<br />
5、响应端基于什么机制来接收请求？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以NIO的方式监听协议端口。<br />
6、怎么将流还原为传输格式的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 遵循java串行化机制对请求对象进行反序列化。<br />
7、处理完毕后怎么回应？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 遵循Mina API进行返回。<br />
MINA是NIO方式的，因此支持异步调用是毫无悬念的。<br />
<br />
<strong>--------------------------------------------------------------------------------------------------------------------------------------------------<br />
EJB<br />
</strong>EJB最突出的在于其分布式，EJB采用的是ORMI协议，和RMI协议是差不多的，但EJB在分布式通讯的安全控制、transport pool、smart proxy等方面的突出使得其在分布式领域是不可忽视的力量。<br />
1、是基于什么协议实现的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 基于ORMI协议。<br />
2、怎么发起请求？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EJB调用。<br />
3、怎么将请求转化为符合协议的格式的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 遵循java串行化机制对请求对象进行序列化。<br />
4、使用什么传输协议传输？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Socket。<br />
5、响应端基于什么机制来接收请求？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 监听协议端口。<br />
6、怎么将流还原为传输格式的？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 遵循java串行化机制对请求对象进行反序列化。<br />
7、处理完毕后怎么回应？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 直接返回处理对象即可。<br />
<br />
在之前的分布式服务框架系列的文章中对于jndi有误导的嫌疑，在这篇blog中也顺带的提下jndi的机制，由于JNDI取决于具体的实现，在这里只能是讲解下jboss的jndi的实现了。<br />
在将对象实例绑定到jboss jnp server后，当远程端采用context.lookup()方式获取远程对象实例并开始调用时，jboss jndi的实现方法是从jnp server上获取对象实例，将其序列化回本地，然后在本地进行反序列化，之后在本地进行类调用。<br />
通过这个机制，就可以知道了，本地其实是必须有绑定到jboss上的对象实例的class的，否则反序列化的时候肯定就失败了，而远程通讯需要做到的是在远程执行某动作，并获取到相应的结果，可见纯粹基于JNDI是无法实现远程通讯的。<br />
但JNDI也是实现分布式服务框架一个很关键的技术点，因为可以通过它来实现透明化的远端和本地调用，就像ejb，另外它也是个很好的隐藏实际部署机制(就像datasource)等的方案。<br />
<br />
<span style="font-size: 18pt; color: #008000"><strong>总结</strong></span><br />
由上一系列的分析可知，在远程通讯领域中，涉及的知识点还是相当的多的，例如有：通信协议(Socket/tcp/http/udp/rmi/xml-rpc etc.)、消息机制、网络IO（BIO/NIO/AIO）、MultiThread、本地调用与远程调用的透明化方案（涉及java classloader、Dynamic Proxy、Unit Test etc.）、异步与同步调用、网络通信处理机制（自动重连、广播、异常、池处理等等）、Java Serialization (各种协议的私有序列化机制等)、各种框架的实现原理（传输格式、如何将传输格式转化为流的、如何将请求信息转化为传输格式的、如何接收流的、如何将流还原为传输格式的等等），要精通其中的哪些东西，得根据实际需求来决定了，只有在了解了原理的情况下才能很容易的做出选择，甚至可以根据需求做私有的远程通讯协议，对于从事分布式服务平台或开发较大型的分布式应用的人而言，我觉得至少上面提及的知识点是需要比较了解的。<br />
<br />
<strong style="font-size: 18pt; color: #008000">参考文档（感谢这些文章）</strong><br />
RMI原理及实现：<a href="http://www.yesky.com/274/1625274.shtml">http://www.yesky.com/274/1625274.shtml</a><br />
Java NIO原理和使用：<a href="http://www.jdon.com/concurrent/nio%D4%AD%C0%ED%D3%A6%D3%C3.htm">http://www.jdon.com/concurrent/nio%D4%AD%C0%ED%D3%A6%D3%C3.htm</a><br />
XML RPC协议：<a href="http://hedong.3322.org/archives/000470.html" target="_blank">http://hedong.3322.org/archives/000470.html</a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.mengyan.org/blog/archives/2005/07/12/30.html">http://www.mengyan.org/blog/archives/2005/07/12/30.html</a><br />
Spring技术应用中的远程服务详解：<a href="http://www.builder.com.cn/2007/1027/583384.shtml">http://www.builder.com.cn/2007/1027/583384.shtml</a><br />
JAVA RPC通信<span style="color: #000000">机制之SOAP：</span><a href="http://www.java114.com/content16/content3826.html">http://www.java114.com/content16/content3826.html</a> <br />
Java Remoting：Protocol BenchMarks：<a href="http://q.sohu.com/forum/5/topic/1148909" target="_blank">http://q.sohu.com/forum/5/topic/1148909</a><br />
Evalution of RMI Alternative：<a href="https://www.jfire.org/modules/phpwiki/index.php/Evaluation%20of%20RMI%20Alternative" target="_blank">https://www.jfire.org/modules/phpwiki/index.php/Evaluation%20of%20RMI%20Alternative</a><br />
Metaprotocol Taxonomy：<a href="http://hessian.caucho.com/doc/metaprotocol-taxonomy.xtp" target="_blank">http://hessian.caucho.com/doc/metaprotocol-taxonomy.xtp</a> <br />
什么是Webservice：<a href="http://www.vchome.net/dotnet/webservice/webservice15.htm">http://www.vchome.net/dotnet/webservice/webservice15.htm</a> </div><img src ="http://www.blogjava.net/shmily432685/aggbug/184249.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/shmily432685/" target="_blank">闵毓</a> 2008-03-06 13:55 <a href="http://www.blogjava.net/shmily432685/archive/2008/03/06/184249.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>tomcat+mysql+jbpm配置工作流（1）</title><link>http://www.blogjava.net/shmily432685/archive/2007/03/30/107517.html</link><dc:creator>闵毓</dc:creator><author>闵毓</author><pubDate>Fri, 30 Mar 2007 09:42:00 GMT</pubDate><guid>http://www.blogjava.net/shmily432685/archive/2007/03/30/107517.html</guid><wfw:comment>http://www.blogjava.net/shmily432685/comments/107517.html</wfw:comment><comments>http://www.blogjava.net/shmily432685/archive/2007/03/30/107517.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/shmily432685/comments/commentRss/107517.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/shmily432685/services/trackbacks/107517.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 初次研究工作流Jbpm配置与开发：<br>JDK142<br>tomcat 5.0<br>mysql 5.0.16<br>apache-ant-1.6.5<br>jbpm-starters-kit-3.1.4<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/shmily432685/archive/2007/03/30/107517.html'>阅读全文</a><img src ="http://www.blogjava.net/shmily432685/aggbug/107517.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/shmily432685/" target="_blank">闵毓</a> 2007-03-30 17:42 <a href="http://www.blogjava.net/shmily432685/archive/2007/03/30/107517.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解决java.lang.UnsupportedClassVersionError问题！！</title><link>http://www.blogjava.net/shmily432685/archive/2006/12/29/90651.html</link><dc:creator>闵毓</dc:creator><author>闵毓</author><pubDate>Fri, 29 Dec 2006 01:44:00 GMT</pubDate><guid>http://www.blogjava.net/shmily432685/archive/2006/12/29/90651.html</guid><wfw:comment>http://www.blogjava.net/shmily432685/comments/90651.html</wfw:comment><comments>http://www.blogjava.net/shmily432685/archive/2006/12/29/90651.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/shmily432685/comments/commentRss/90651.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/shmily432685/services/trackbacks/90651.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Eclipse解决java.lang.UnsupportedClassVersionError问题，只需要把项目用的JDK与你安装的JDK搞成版本一样就解决了．<br>步骤：右击你的项目－－＞属性－－＞Java Compiler，设置合适的版本！！&nbsp;&nbsp;<a href='http://www.blogjava.net/shmily432685/archive/2006/12/29/90651.html'>阅读全文</a><img src ="http://www.blogjava.net/shmily432685/aggbug/90651.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/shmily432685/" target="_blank">闵毓</a> 2006-12-29 09:44 <a href="http://www.blogjava.net/shmily432685/archive/2006/12/29/90651.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]Velocity处理Struts的验证信息</title><link>http://www.blogjava.net/shmily432685/archive/2006/08/07/62185.html</link><dc:creator>闵毓</dc:creator><author>闵毓</author><pubDate>Mon, 07 Aug 2006 06:57:00 GMT</pubDate><guid>http://www.blogjava.net/shmily432685/archive/2006/08/07/62185.html</guid><wfw:comment>http://www.blogjava.net/shmily432685/comments/62185.html</wfw:comment><comments>http://www.blogjava.net/shmily432685/archive/2006/08/07/62185.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/shmily432685/comments/commentRss/62185.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/shmily432685/services/trackbacks/62185.html</trackback:ping><description><![CDATA[<div class="postcontent">　　Velocity它那出色的模板引擎可以帮助我们减少很多不必要的编码工作，并使逻辑性代码更加优美地放置在了后台javabean中，从而渐渐成为java程序员们口的谈论的话题。更多的时候，我们把它与Struts联手作为web应用的表现层来使用。本文要讨论的话题是利用Velocity来处理Struts的验证信息。<br /><br />　　我们经常利用Struts的ActionForm提供的验证服务(validate)来检查页面上输入的信息。当输入的信息不符合检验标准时，返回一个装载了错误信息的错误对象，如下：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img id="Codehighlighter1_42_550_Open_Image" onclick="this.style.display='none'; Codehighlighter1_42_550_Open_Text.style.display='none'; Codehighlighter1_42_550_Closed_Image.style.display='inline'; Codehighlighter1_42_550_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_42_550_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_42_550_Closed_Text.style.display='none'; Codehighlighter1_42_550_Open_Image.style.display='inline'; Codehighlighter1_42_550_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" /><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> LoginForm </span><span style="COLOR: #0000ff">extends</span><span style="COLOR: #000000"> ActionForm </span><span id="Codehighlighter1_42_550_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_42_550_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> String name;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    <br /><img id="Codehighlighter1_111_141_Open_Image" onclick="this.style.display='none'; Codehighlighter1_111_141_Open_Text.style.display='none'; Codehighlighter1_111_141_Closed_Image.style.display='inline'; Codehighlighter1_111_141_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_111_141_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_111_141_Closed_Text.style.display='none'; Codehighlighter1_111_141_Open_Image.style.display='inline'; Codehighlighter1_111_141_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> setName(String name) </span><span id="Codehighlighter1_111_141_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_111_141_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />      </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.name </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> name;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    <br /><img id="Codehighlighter1_176_206_Open_Image" onclick="this.style.display='none'; Codehighlighter1_176_206_Open_Text.style.display='none'; Codehighlighter1_176_206_Closed_Image.style.display='inline'; Codehighlighter1_176_206_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_176_206_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_176_206_Closed_Text.style.display='none'; Codehighlighter1_176_206_Open_Image.style.display='inline'; Codehighlighter1_176_206_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> String getName() </span><span id="Codehighlighter1_176_206_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_176_206_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />      </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.name;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> ActionErrors validate(<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        ActionMapping mapping,<br /><img id="Codehighlighter1_304_548_Open_Image" onclick="this.style.display='none'; Codehighlighter1_304_548_Open_Text.style.display='none'; Codehighlighter1_304_548_Closed_Image.style.display='inline'; Codehighlighter1_304_548_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_304_548_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_304_548_Closed_Text.style.display='none'; Codehighlighter1_304_548_Open_Image.style.display='inline'; Codehighlighter1_304_548_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        HttpServletRequest request) </span><span id="Codehighlighter1_304_548_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_304_548_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />          </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 生成错误对象</span><span style="COLOR: #008000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">          ActionErrors errs </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> ActionErrors();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />          </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 名称不可为空</span><span style="COLOR: #008000"><br /><img id="Codehighlighter1_441_514_Open_Image" onclick="this.style.display='none'; Codehighlighter1_441_514_Open_Text.style.display='none'; Codehighlighter1_441_514_Closed_Image.style.display='inline'; Codehighlighter1_441_514_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_441_514_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_441_514_Closed_Text.style.display='none'; Codehighlighter1_441_514_Open_Image.style.display='inline'; Codehighlighter1_441_514_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" /></span><span style="COLOR: #000000">          </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.name </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">null</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">""</span><span style="COLOR: #000000">.equals(</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.name)) </span><span id="Codehighlighter1_441_514_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_441_514_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />            errs.add(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">name</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> ActionMessage(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">msg.name.empty</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">));<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />          }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />          <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />          </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> errs;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span></div><br />　　只要在struts-config.xml action的配置中加入input="/login.jsp"，并在页面上利用Struts 标签&lt;html:errors property="name"/&gt;就可以将ApplicationResources.properties中所定义的错误信息显示出来。这是Struts的传统做法。那么在Velocity中该如何处理这种情况呢？方法很简单，只要配置Velocity的toolbox.xml并将相应的.jar文件放在lib下面即可。关于toolbox.xml的详细配置请参见《<a id="viewpost1_TitleUrl" href="/shmily432685/archive/2006/08/07/62177.html"><font color="#366900">Velocity中使用Struts的国际化文件</font></a>》。通过该文我们知道了Velocity为Struts的错误信息提供了专用的类org.apache.velocity.tools.struts.ErrorsTool。还是上面的例子，我们只要将页面中的&lt;html:errors property="name"/&gt;改为$!{errors.get("name")}即可。 </div><img src ="http://www.blogjava.net/shmily432685/aggbug/62185.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/shmily432685/" target="_blank">闵毓</a> 2006-08-07 14:57 <a href="http://www.blogjava.net/shmily432685/archive/2006/08/07/62185.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]Velocity中使用Struts的国际化文件</title><link>http://www.blogjava.net/shmily432685/archive/2006/08/07/62177.html</link><dc:creator>闵毓</dc:creator><author>闵毓</author><pubDate>Mon, 07 Aug 2006 06:50:00 GMT</pubDate><guid>http://www.blogjava.net/shmily432685/archive/2006/08/07/62177.html</guid><wfw:comment>http://www.blogjava.net/shmily432685/comments/62177.html</wfw:comment><comments>http://www.blogjava.net/shmily432685/archive/2006/08/07/62177.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/shmily432685/comments/commentRss/62177.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/shmily432685/services/trackbacks/62177.html</trackback:ping><description><![CDATA[当利用Velocity和Struts一同开发web应用时，可能会遇到这样的问题，即.vm文件中无法使用Struts的标签。虽然Velocity的模板引擎以及它强大的语句可以使我们毫不犹豫地抛弃Struts的标签，但有时候，我们仍然需要在.vm文件中引用Struts的国际化文件ApplicationResources.properties，能否做到呢？答案是肯定的。以下是一个toobox.xml文件：<br /><div class="UBBPanel"><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #0000ff">&lt;?</span><span style="COLOR: #ff00ff">xml version="1.0"</span><span style="COLOR: #0000ff">?&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">toolbox</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">tool</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">key</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">link</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">key</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">scope</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">request</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">scope</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">class</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />       org.apache.velocity.tools.struts.StrutsLinkTool<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">class</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">tool</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">tool</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">key</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">msg</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">key</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">scope</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">request</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">scope</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">class</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />       org.apache.velocity.tools.struts.MessageTool<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">class</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">tool</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">tool</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">key</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">actionMsg</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">key</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">scope</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">request</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">scope</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">class</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />       org.apache.velocity.tools.struts.ActionMessagesTool<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">class</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">tool</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">tool</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">key</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">errors</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">key</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">scope</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">request</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">scope</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">class</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />       org.apache.velocity.tools.struts.ErrorsTool<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">class</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">tool</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">tool</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">key</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">form</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">key</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">scope</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">request</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">scope</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">class</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />       org.apache.velocity.tools.struts.FormTool<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">class</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">tool</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">tool</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">key</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">tiles</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">key</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">scope</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">request</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">scope</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">class</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />       org.apache.velocity.tools.struts.TilesTool<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">class</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">tool</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">tool</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">key</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">validator</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">key</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">scope</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">request</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">scope</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">class</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />       org.apache.velocity.tools.struts.ValidatorTool<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">class</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">tool</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">toolbox</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span></div><br />StrutsLinkTool：针对 Struts 的 LinkTool 专用版本，提供了 setAction() 和 setForward() 访问预先配置的活动映射。<br />MessageTool：提供对 Struts 国际化支持的访问，尤为特别的是依赖于语言的消息资源。<br />ErrorsTool：处理 Struts 错误消息，包括对国际化的支持。<br />FormTool：访问 Struts 的表单 beans。<br />TilesTool：提供对 Struts 1.1 Tiles 扩展支持的访问。<br />ValidatorTool：提供对 Struts 1.1 Validator 扩展的访问，生成代码验证表单输入字段。<br /><br />现在，我们有一个编译好了的文件：ApplicationResources_zh_CN.properties。它的内容如下：<br />name=六月天<br /><br />在.vm文件中，就可以这样写：<br />$!{msg.get(“name”)}<br /></div><img src ="http://www.blogjava.net/shmily432685/aggbug/62177.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/shmily432685/" target="_blank">闵毓</a> 2006-08-07 14:50 <a href="http://www.blogjava.net/shmily432685/archive/2006/08/07/62177.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>myeclipse中weblogic服务简介</title><link>http://www.blogjava.net/shmily432685/archive/2005/11/26/21511.html</link><dc:creator>闵毓</dc:creator><author>闵毓</author><pubDate>Sat, 26 Nov 2005 08:11:00 GMT</pubDate><guid>http://www.blogjava.net/shmily432685/archive/2005/11/26/21511.html</guid><wfw:comment>http://www.blogjava.net/shmily432685/comments/21511.html</wfw:comment><comments>http://www.blogjava.net/shmily432685/archive/2005/11/26/21511.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.blogjava.net/shmily432685/comments/commentRss/21511.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/shmily432685/services/trackbacks/21511.html</trackback:ping><description><![CDATA[<H2 class=diaryTitle>myeclipse配置weblogic&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </H2>
<P>
<P>
<P>weblogic安装参见</P>
<P><A href="http://zhangstar.blogbus.com/logs/2004/09/413796.html">http://zhangstar.blogbus.com/logs/2004/09/413796.html</A></P>
<P>
<P>MyEclipse默认的应用服务器为JBoss3，这里我们使用WebLogic8.1。启动Eclipse，选择“窗口\首选项”菜单，打开首选项对话框。展开MyEclipse下的Application Servers结点，点击JBoss 3，选中右面的Disable单选按钮，停用JBoss 3。然后点击WebLogic 8，选中右边的Enable单选按钮，启用WebLogic服务器。同时下面的配置如下： <BR>(1)BEA home directory：C:\BEA。假定WebLogic安装在D:\BEA文件夹中。 <BR>(2)WebLogic installation directory：C:\BEA\weblogic81。 <BR>(3)Admin username：用户名。 <BR>(4)Admin password：密码。 <BR>(5)Execution domain root：安装后，启动服务的路径。 <BR>(6)Execution domain name：mydomain。 <BR>(7)Execution server name：myserver。 <BR>(8)Hostname:PortNumber：localhost:7001。 <BR>(9)Security policy file：D:\BEA\weblogic81\server\lib\weblogic.policy。 <BR>(10)JAAS login configuration file：省略。 <BR>以上配置根据安装情况不同而不同。<BR>如图：<BR><IMG height=529 alt=myeclipse_weblogic.JPG src="http://www.blogjava.net/images/blogjava_net/shmily432685/subject/myeclipse_weblogic.JPG" width=759 border=0><BR>接着展开WebLogic 8结点，点击JDK，在右边的WLS JDK name处选择WebLogic 8的默认JDK。这里组合框中缺省为j2re1.4.2_03，即之前单独安装的jre。单击Add按钮，弹出WebLogic &gt; Add JVM对话框，在JRE名称处随便输入一个名字，如jre1.4.1_02。然后在JRE主目录处选择WebLogic安装文件夹中的JDK文件夹，如D:\BEA\jdk141_02，程序会自动填充Javadoc URL文本框和JRE系统库列表框。单击确定按钮关闭对话框。这时候就可以在WLS JDK name组合框中选择jre1.4.1_02了。之后还要在下面的Optional Java VM arguments，如-ms64m -mx64m -Djava.library.path="D:/BEA/weblogic81/server/bin" -Dweblogic.management.discover=false -Dweblogic.ProductionModeEnabled=false <BR>最后点击Paths，在右边的Prepend to classpath列表框中，通过Add JAR/ZIP按钮，加入D:\BEA\weblogic81\server\lib\weblogic.jar、D:\BEA\weblogic81\server\lib\webservices.jar。如果用到数据库，还需把数据库的驱动类库加进来，这里我们用WebLogic自带的SQL Server数据库驱动库D:\BEA\weblogic81\server\lib\mssqlserver4v65.jar。 <BR>至此，MyEclipse中WebLogic8的配置工作就算完成了。下面可以看看在Eclipse中能否启动WebLogic了？自从安装了MyEclipse之后，Eclipse工具栏中就会有一个Run/Stop Servers下拉按钮。点击该按钮的下拉部分，选择“WebLogic 8\Start”菜单，即开始启动WebLogic了。通过查看下面的控制台消息，就可以知道启动是否成功，或有什么异常发生。停止WebLogic可选择“WebLogic\Stop”菜单</P><img src ="http://www.blogjava.net/shmily432685/aggbug/21511.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/shmily432685/" target="_blank">闵毓</a> 2005-11-26 16:11 <a href="http://www.blogjava.net/shmily432685/archive/2005/11/26/21511.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>web.xml规则经过整理总结如下：</title><link>http://www.blogjava.net/shmily432685/archive/2005/11/11/19258.html</link><dc:creator>闵毓</dc:creator><author>闵毓</author><pubDate>Fri, 11 Nov 2005 02:29:00 GMT</pubDate><guid>http://www.blogjava.net/shmily432685/archive/2005/11/11/19258.html</guid><wfw:comment>http://www.blogjava.net/shmily432685/comments/19258.html</wfw:comment><comments>http://www.blogjava.net/shmily432685/archive/2005/11/11/19258.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/shmily432685/comments/commentRss/19258.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/shmily432685/services/trackbacks/19258.html</trackback:ping><description><![CDATA[<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">1、部署描述符文件就像所有</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">XML</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">文件一样，必须以一个</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">XML</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">头开始。这个头声明可以使用的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">XML</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">版本并给出文件的字符编码。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>2、DOCYTPE</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">声明必须立即出现在此头之后。这个声明告诉服务器适用的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">servlet</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">规范的版本（如</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">2.2</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">或</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">2.3</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">）并指定管理此文件其余部分内容的语法的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">DTD(Document Type Definition</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，文档类型定义</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">)</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR></SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">所有部署描述符文件的顶层（根）元素为</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">web-app</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。请注意，</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">XML</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素不像</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">HTML</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，他们是大小写敏感的。因此，</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">web-App</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">和</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">WEB-APP</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">都是不合法的，</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">web-app</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">必须用小写。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">1</SPAN>&nbsp;<SPAN style="COLOR: #000000">&lt;?</SPAN><SPAN style="COLOR: #000000">xml&nbsp;version</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">1.0</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">&nbsp;encoding</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">UTF-8</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">?&gt;</SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">2</SPAN>&nbsp;<SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">3</SPAN>&nbsp;<SPAN style="COLOR: #000000"></SPAN><SPAN style="COLOR: #000000">&lt;</SPAN><SPAN style="COLOR: #000000">web</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">app&nbsp;xmlns</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">http://java.sun.com/xml/ns/j2ee</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">&nbsp;xmlns:xsi</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">http://www.w3.org/2001/XMLSchema-instance</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">&nbsp;version</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">2.4</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">&nbsp;xsi:schemaLocation</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">http://java.sun.com/xml/ns/j2ee&nbsp;&nbsp;&nbsp;http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">&gt;</SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">4</SPAN>&nbsp;<SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">5</SPAN>&nbsp;<SPAN style="COLOR: #000000"></SPAN><SPAN style="COLOR: #000000">&lt;/</SPAN><SPAN style="COLOR: #000000">web</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">app</SPAN><SPAN style="COLOR: #000000">&gt;</SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">6</SPAN>&nbsp;<SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">7</SPAN>&nbsp;<SPAN style="COLOR: #000000"></SPAN></DIV>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt">2、 </SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">部署描述符文件内的元素次序</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 22pt; mso-char-indent-count: 2.0"><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">XML </SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素不仅是大小写敏感的，而且它们还对出现在其他元素中的次序敏感。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 22pt; mso-char-indent-count: 2.0"><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">XML</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">头必须是文件中的第一项，</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">DOCTYPE</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">声明必须是第二项，而</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">web- app</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素必须是第三项。在</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">web-app</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素内，元素的次序也很重要。服务器不一定强制要求这种次序，但它们允许（实际上有些服务器就是这样做的）完全拒绝执行含有次序不正确的元素的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">Web</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">应用。这表示使用非标准元素次序的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">web.xml</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">文件是不可移植的。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 22pt; mso-char-indent-count: 2.0"><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">下面的列表给出了所有可直接出现在</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">web-app</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素内的合法元素所必需的次序。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 22pt; mso-char-indent-count: 2.0"><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">此列表说明</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">servlet</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素必须出现在所有</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">servlet-mapping</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素之前。请注意，所有这些元素都是可选的。因此，可以省略掉某一元素，但不能把它放于不正确的位置。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l icon icon</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素指出</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">IDE</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">和</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">GUI</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">工具用来表示</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">Web</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">应用的一个和两个图像文件的位置。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l display-name display-name</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素提供</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">GUI</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">工具可能会用来标记这个特定的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">Web</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">应用的一个名称。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l description description</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素给出与此有关的说明性文本。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l context-param context-param</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素声明应用范围内的初始化参数。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l filter </SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">过滤器元素将一个名字与一个实现</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">javax.servlet.Filter</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">接口的类相关联。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l filter-mapping </SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">一旦命名了一个过滤器，就要利用</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">filter-mapping</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素把它与一个或多个</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">servlet</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">或</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">JSP</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">页面相关联。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l listener servlet API</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的版本</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">2.3</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">增加了对事件监听程序的支持，事件监听程序在建立、修改和删除会话或</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">servlet</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">环境时得到通知。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">Listener</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素指出事件监听程序类。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l servlet </SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">在向</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">servlet</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">或</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">JSP</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">页面制定初始化参数或定制</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">URL</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">时，必须首先命名</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">servlet</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">或</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">JSP</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">页面。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">Servlet</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素就是用来完成此项任务的。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l servlet-mapping </SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">服务器一般为</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">servlet</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">提供一个缺省的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">URL</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">：</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><A href="http://host/webAppPrefix/servlet/ServletName。但是，常常会更改这个URL，以便servlet可以访问初始化参数或更容易地处理相对URL。在更改缺省URL时，使用servlet-mapping元素。" target=_blank>http://host/webAppPrefix/servlet/ServletName<SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana"><SPAN lang=EN-US>。但是，常常会更改这个</SPAN></SPAN>URL<SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana"><SPAN lang=EN-US>，以便</SPAN></SPAN>servlet<SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana"><SPAN lang=EN-US>可以访问初始化参数或更容易地处理相对</SPAN></SPAN>URL<SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana"><SPAN lang=EN-US>。在更改缺省</SPAN></SPAN>URL<SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana"><SPAN lang=EN-US>时，使用</SPAN></SPAN>servlet-mapping<SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana"><SPAN lang=EN-US>元素。</SPAN></SPAN></A><BR>l session-config </SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">如果某个会话在一定时间内未被访问，服务器可以抛弃它以节省内存。可通过使用</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">HttpSession</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">setMaxInactiveInterval</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">方法明确设置单个会话对象的超时值，或者可利用</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">session-config</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素制定缺省超时值。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l mime-mapping </SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">如果</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">Web</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">应用具有想到特殊的文件，希望能保证给他们分配特定的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">MIME</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">类型，则</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">mime-mapping</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素提供这种保证。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l welcom-file-list welcome-file-list</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素指示服务器在收到引用一个目录名而不是文件名的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">URL</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">时，使用哪个文件。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l error-page error-page</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素使得在返回特定</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">HTTP</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">状态代码时，或者特定类型的异常被抛出时，能够制定将要显示的页面。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l taglib taglib</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素对标记库描述符文件（</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">Tag Libraryu Descriptor file</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">）指定别名。此功能使你能够更改</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">TLD</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">文件的位置，而不用编辑使用这些文件的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">JSP</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">页面。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l resource-env-ref resource-env-ref</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素声明与资源相关的一个管理对象。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l resource-ref resource-ref</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素声明一个资源工厂使用的外部资源。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l security-constraint security-constraint</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素制定应该保护的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">URL</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。它与</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">login-config</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素联合使用</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l login-config </SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">用</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">login-config</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素来指定服务器应该怎样给试图访问受保护页面的用户授权。它与</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">sercurity-constraint</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素联合使用。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l security-role security-role</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素给出安全角色的一个列表，这些角色将出现在</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">servlet</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素内的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">security-role-ref</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">role-name</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">子元素中。分别地声明角色可使高级</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">IDE</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">处理安全信息更为容易。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l env-entry env-entry</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素声明</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">Web</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">应用的环境项。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l ejb-ref ejb-ref</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素声明一个</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">EJB</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的主目录的引用。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana"><BR>l ejb-local-ref ejb-local-ref</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">元素声明一个</SPAN><SPAN lang=EN-US style="FONT-SIZE: 11pt; FONT-FAMILY: Verdana">EJB</SPAN><SPAN style="FONT-SIZE: 11pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的本地主目录的应用。<BR>3、</SPAN></P><img src ="http://www.blogjava.net/shmily432685/aggbug/19258.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/shmily432685/" target="_blank">闵毓</a> 2005-11-11 10:29 <a href="http://www.blogjava.net/shmily432685/archive/2005/11/11/19258.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>集成 Struts、Tiles 和 JavaServer Faces</title><link>http://www.blogjava.net/shmily432685/archive/2005/11/10/19073.html</link><dc:creator>闵毓</dc:creator><author>闵毓</author><pubDate>Wed, 09 Nov 2005 16:19:00 GMT</pubDate><guid>http://www.blogjava.net/shmily432685/archive/2005/11/10/19073.html</guid><wfw:comment>http://www.blogjava.net/shmily432685/comments/19073.html</wfw:comment><comments>http://www.blogjava.net/shmily432685/archive/2005/11/10/19073.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/shmily432685/comments/commentRss/19073.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/shmily432685/services/trackbacks/19073.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 将三种技术的功能、灵活性和可管理性集成到一起您是否想将 JavaServer Faces (JSF)的强大前端功能、Tiles 的内容格式编排优势和 Struts controller 层的灵活性都加入到您的J2EE Web 应用程序中？企业级 Java 专家 Srikanth Shenoy 和 Nithin Mallya 为您展示了如何将这三者的功能集成到一起。本文演示了如何在 Struts-F...&nbsp;&nbsp;<a href='http://www.blogjava.net/shmily432685/archive/2005/11/10/19073.html'>阅读全文</a><img src ="http://www.blogjava.net/shmily432685/aggbug/19073.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/shmily432685/" target="_blank">闵毓</a> 2005-11-10 00:19 <a href="http://www.blogjava.net/shmily432685/archive/2005/11/10/19073.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>面向Java开发人员的Ajax技术：构建动态的Java应用程序 </title><link>http://www.blogjava.net/shmily432685/archive/2005/10/20/16179.html</link><dc:creator>闵毓</dc:creator><author>闵毓</author><pubDate>Thu, 20 Oct 2005 10:19:00 GMT</pubDate><guid>http://www.blogjava.net/shmily432685/archive/2005/10/20/16179.html</guid><wfw:comment>http://www.blogjava.net/shmily432685/comments/16179.html</wfw:comment><comments>http://www.blogjava.net/shmily432685/archive/2005/10/20/16179.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/shmily432685/comments/commentRss/16179.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/shmily432685/services/trackbacks/16179.html</trackback:ping><description><![CDATA[<P id=subtitle><STRONG>Ajax 为更好的 Web 应用程序铺平了道路</STRONG></P>
<BLOCKQUOTE>在 Web 应用程序开发中，页面重载循环是最大的一个使用障碍，对于 Java™ 开发人员来说也是一个严峻的挑战。在这个系列中，作者 Philip McCarthy 介绍了一种创建动态应用程序体验的开创性方式。Ajax（异步 JavaScript 和 XML）是一种编程技术，它允许为基于 Java 的 Web 应用程序把 Java 技术、XML 和 JavaScript 组合起来，从而打破页面重载的范式。</BLOCKQUOTE>
<P>Ajax（即异步 JavaScript 和 XML）是一种 Web 应用程序开发的手段，它采用客户端脚本与 Web 服务器交换数据。所以，不必采用会中断交互的完整页面刷新，就可以动态地更新 Web 页面。使用 Ajax，可以创建更加丰富、更加动态的 Web 应用程序用户界面，其即时性与可用性甚至能够接近本机桌面应用程序。</P>
<P>Ajax 不是一项技术，而更像是一个 <I>模式</I> —— 一种识别和描述有用的设计技术的方式。Ajax 是新颖的，因为许多开发人员才刚刚开始知道它，但是所有实现 Ajax 应用程序的组件都已经存在若干年了。它目前受到重视是因为在 2004 和 2005 年出现了一些基于 Ajax 技术的非常棒的动态 Web UI，最著名的就是 Google 的 GMail 和 Maps 应用程序，以及照片共享站点 Flickr。这些用户界面具有足够的开创性，有些开发人员称之为“Web 2.0”，因此对 Ajax 应用程序的兴趣飞速上升。</P>
<P>在这个系列中，我将提供使用 Ajax 开发应用程序需要的全部工具 。在第一篇文章中，我将解释 Ajax 背后的概念，演示为基于 Java 的 Web 应用程序创建 Ajax 界面的基本步骤。我将使用代码示例演示让 Ajax 应用程序如此动态的服务器端 Java 代码和客户端 JavaScript。最后，我将指出 Ajax 方式的一些不足，以及在创建 Ajax 应用程序时应当考虑的一些更广的可用性和访问性问题。</P>
<P><A name=IDA1CAKB><SPAN class=atitle><FONT face=Arial size=4>更好的购物车</FONT></SPAN></A></P>
<P>可以用 Ajax 增强传统的 Web 应用程序，通过消除页面装入从而简化交互。为了演示这一点，我采用一个简单的购物车示例，在向里面添加项目时，它会动态更新。这项技术如果整合到在线商店，那么用户可以持续地浏览和向购物车中添加项目，而不必在每次点击之后都等候完整的页面更新。虽然这篇文章中的有些代码特定于购物车示例，但是演示的技术可以应用于任何 Ajax 应用程序。清单 1 显示了购物车示例使用的有关 HTML 代码，整篇文章中都会使用这个 HTML。</P>
<P><BR><A name="Listing 1"><B>清单1. 购物车示例的有关片断</B></A><BR>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TD><PRE><CODE class=section>
<FONT face="Lucida Console">&lt;!-- Table of products from store's catalog, one row per item --&gt;
&lt;th&gt;Name&lt;/th&gt; &lt;th&gt;Description&lt;/th&gt; &lt;th&gt;Price&lt;/th&gt; &lt;th&gt;&lt;/th&gt;
...
&lt;tr&gt;
  &lt;!-- Item details --&gt;
  &lt;td&gt;Hat&lt;/td&gt; &lt;td&gt;Stylish bowler hat&lt;/td&gt; &lt;td&gt;$19.99&lt;/td&gt;
  &lt;td&gt;
    &lt;!-- Click button to add item to cart via Ajax request --&gt;
    &lt;button onclick="addToCart('hat001')"&gt;Add to Cart&lt;/button&gt;
  &lt;/td&gt;
&lt;/tr&gt;
...

&lt;!-- Representation of shopping cart, updated asynchronously --&gt;
&lt;ul id="cart-contents"&gt;

  &lt;!-- List-items will be added here for each item in the cart --&gt;
  
&lt;/ul&gt;

&lt;!-- Total cost of items in cart displayed inside span element --&gt;
Total cost: &lt;span id="total"&gt;$0.00&lt;/span&gt;
</FONT></CODE></PRE></TD></TR></TBODY></TABLE><BR><A name=IDAJDAKB><SPAN class=atitle><FONT face=Arial size=4>Ajax 往返过程</FONT></SPAN></A></P>
<P>Ajax 交互开始于叫作 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 的 JavaScript 对象。顾名思义，它允许客户端脚本执行 HTTP 请求，并解析 XML 服务器响应。Ajax 往返过程的第一步是创建 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 的实例。在 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 对象上设置请求使用的 HTTP 方法（<CODE><FONT face=新宋体>GET</FONT></CODE> 或 <CODE><FONT face=新宋体>POST</FONT></CODE>）以及目标 URL。</P>
<P>现在，您还记得 Ajax 的第一个 <I>a</I> 是代表 <I>异步（asynchronous）</I> 吗？在发送 HTTP 请求时，不想让浏览器挂着等候服务器响应。相反，您想让浏览器继续对用户与页面的交互进行响应，并在服务器响应到达时再进行处理。为了实现这个要求，可以在 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 上注册一个回调函数，然后异步地分派 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE>。然后控制就会返回浏览器，当服务器响应到达时，会调用回调函数。</P>
<P>在 Java Web 服务器上，请求同其他 <CODE><FONT face=新宋体>HttpServletRequest</FONT></CODE> 一样到达。在解析了请求参数之后，servlet 调用必要的应用程序逻辑，把响应序列化成 XML，并把 XML 写入 <CODE><FONT face=新宋体>HttpServletResponse</FONT></CODE>。</P>
<P>回到客户端时，现在调用注册在 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 上的回调函数，处理服务器返回的 XML 文档。最后，根据服务器返回的数据，用 JavaScript 操纵页面的 HTML DOM，把用户界面更新。图 1 是 Ajax 往返过程的顺序图。</P>
<P><IMG src="http://www.wnetw.com/jclub_resources/technology/attachimages/1130485299342.gif"></P>
<P>现在您对 Ajax 往返过程有了一个高层面的认识。下面我将放大其中的每一步骤，进行更详细的观察。如果过程中迷了路，请回头看图 1 —— 由于 Ajax 方式的异步性质，所以顺序并非十分简单。</P>
<P><A name=IDAQFAKB><SPAN class=atitle><FONT face=Arial size=4>分派 XMLHttpRequest</FONT></SPAN></A></P>
<P>我将从 Ajax 序列的起点开始：创建和分派来自浏览器的 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE>。不幸的是，不同的浏览器创建 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 的方法各不相同。清单 2 的 JavaScript 函数消除了这些依赖于浏览器的技巧，它可以检测当前浏览器要使用的正确方式，并返回一个可以使用的 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE>。最好是把它当作辅助代码：只要把它拷贝到 JavaScript 库，并在需要 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 的时候使用它就可以了。</P>
<P><BR><A name=listing2><B>清单 2. 创建跨浏览器的 XMLHttpRequest</B></A><BR>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TD><PRE><CODE class=section>
<FONT face="Lucida Console">/*
 * Returns a new XMLHttpRequest object, or false if this browser
 * doesn't support it
 */
function newXMLHttpRequest() {

  var xmlreq = false;

  if (window.XMLHttpRequest) {

    // Create XMLHttpRequest object in non-Microsoft browsers
    xmlreq = new XMLHttpRequest();

  } else if (window.ActiveXObject) {

    // Create XMLHttpRequest via MS ActiveX
    try {
      // Try to create XMLHttpRequest in later versions
      // of Internet Explorer

      xmlreq = new ActiveXObject("Msxml2.XMLHTTP");

    } catch (e1) {

      // Failed to create required ActiveXObject

      try {
        // Try version supported by older versions
        // of Internet Explorer

        xmlreq = new ActiveXObject("Microsoft.XMLHTTP");

      } catch (e2) {

        // Unable to create an XMLHttpRequest with ActiveX
      }
    }
  }

  return xmlreq;
}
  </FONT></CODE></PRE></TD></TR></TBODY></TABLE><BR></P>
<P>稍后我将讨论处理那些不支持 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 的浏览器的技术。目前，示例假设清单 2 的 <CODE><FONT face=新宋体>newXMLHttpRequest</FONT></CODE> 函数总能返回 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 实例。</P>
<P>返回示例的购物车场景，我想要当用户在目录项目上点击 Add to Cart 时启动 Ajax 交互。名为 <CODE><FONT face=新宋体>addToCart()</FONT></CODE> 的 <CODE><FONT face=新宋体>onclick</FONT></CODE> 处理函数负责通过 Ajax 调用来更新购物车的状态（请参阅 <FONT color=#000033>清单 1</FONT>）。正如清单 3 所示，<CODE><FONT face=新宋体>addToCart()</FONT></CODE> 需要做的第一件事是通过调用清单 2 的 <CODE><FONT face=新宋体>newXMLHttpRequest()</FONT></CODE> 函数得到 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 对象。接下来，它注册一个回调函数，用来接收服务器响应（我稍后再详细解释这一步；请参阅 <FONT color=#000000>清单 6</FONT>）。</P>
<P>因为请求会修改服务器上的状态，所以我将用 HTTP <CODE><FONT face=新宋体>POST</FONT></CODE> 做这个工作。通过 <CODE><FONT face=新宋体>POST</FONT></CODE> 发送数据要求三个步骤。第一，需要打开与要通信的服务器资源的 <CODE><FONT face=新宋体>POST</FONT></CODE> 连接 —— 在这个示例中，服务器资源是一个映射到 URL <CODE><FONT face=新宋体>cart.do</FONT></CODE> 的 servlet。然后，我在 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 上设置一个头，指明请求的内容是表单 编码的数据。最后，我用表单编码的数据作为请求体发送请求。</P>
<P>清单 3 把这些步骤放在了一起。</P>
<P><BR><A name=listing3><B>清单 3. 分派 Add to Cart XMLHttpRequest</B></A><BR>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TD><PRE><CODE class=section>
<FONT face="Lucida Console">/*
 * Adds an item, identified by its product code, to the shopping cart
 * itemCode - product code of the item to add.
 */
function addToCart(itemCode) {

  // Obtain an XMLHttpRequest instance
  var req = newXMLHttpRequest();

  // Set the handler function to receive callback notifications
  // from the request object
  var handlerFunction = getReadyStateHandler(req, updateCart);
  req.onreadystatechange = handlerFunction;
  
  // Open an HTTP POST connection to the shopping cart servlet.
  // Third parameter specifies request is asynchronous.
  req.open("POST", "cart.do", true);

  // Specify that the body of the request contains form data
  req.setRequestHeader("Content-Type", 
                       "application/x-www-form-urlencoded");

  // Send form encoded data stating that I want to add the 
  // specified item to the cart.
  req.send("action=add&amp;item="+itemCode);
}
</FONT></CODE></PRE></TD></TR></TBODY></TABLE><BR></P>
<P>这就是建立 Ajax 往返过程的第一部分，即创建和分派来自客户机的 HTTP 请求。接下来是用来处理请求的 Java servlet 代码。</P>
<P><A name=IDA4AKKB><SPAN class=atitle><FONT face=Arial size=4>servlet 请求处理</FONT></SPAN></A></P>
<P>用 servlet 处理 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE>，与处理普通的浏览器 HTTP 请求一样。可以用 <CODE><FONT face=新宋体>HttpServletRequest.getParameter()</FONT></CODE> 得到在 POST 请求体中发送的表单编码数据。Ajax 请求被放进与来自应用程序的常规 Web 请求一样的 <CODE><FONT face=新宋体>HttpSession</FONT></CODE> 中。对于示例购物车场景来说，这很有用，因为这让我可以把购物车状态封装在 JavaBean 中，并在请求之间在会话中维持这个状态。</P>
<P>清单 4 是处理 Ajax 请求、更新购物车的简单 servlet 的一部分。<CODE><FONT face=新宋体>Cart</FONT></CODE> bean 是从用户会话中获得的，并根据请求参数更新它的状态。然后 <CODE><FONT face=新宋体>Cart</FONT></CODE> 被序列化成 XML，XML 又被写入 <CODE><FONT face=新宋体>ServletResponse</FONT></CODE>。重要的是把响应的内容类型设置为 <CODE><FONT face=新宋体>application/xml</FONT></CODE>，否则 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 不会把响应内容解析成 XML DOM。</P>
<P><BR><A name=listing4><B>清单 4. 处理 Ajax 请求的 servlet 代码</B></A><BR>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TD><PRE><CODE class=section>
<FONT face="Lucida Console">public void doPost(HttpServletRequest req, HttpServletResponse res)
                        throws java.io.IOException {

  Cart cart = getCartFromSession(req);

  String action = req.getParameter("action");
  String item = req.getParameter("item");
  
  if ((action != null)&amp;&amp;(item != null)) {

    // Add or remove items from the Cart
    if ("add".equals(action)) {
      cart.addItem(item);

    } else if ("remove".equals(action)) {
      cart.removeItems(item);

    }
  }

  // Serialize the Cart's state to XML
  String cartXml = cart.toXml();

  // Write XML to response.
  res.setContentType("application/xml");
  res.getWriter().write(cartXml);
}
</FONT></CODE></PRE></TD></TR></TBODY></TABLE><BR></P>
<P>清单 5 显示了 <CODE><FONT face=新宋体>Cart.toXml()</FONT></CODE> 方法生成的示例 XML。它很简单。请注意 <CODE><FONT face=新宋体>cart</FONT></CODE> 元素的 <CODE><FONT face=新宋体>generated</FONT></CODE> 属性，它是 <CODE><FONT face=新宋体>System.currentTimeMillis()</FONT></CODE> 生成的一个时间戳。</P>
<P><BR><A name=listing5><B>清单 5. Cart 对象的XML 序列化示例 </B></A><BR>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TD><PRE><CODE class=section>
<FONT face="Lucida Console">&lt;?xml version="1.0"?&gt;
&lt;cart generated="1123969988414" total="$171.95"&gt;
  &lt;item code="hat001"&gt;
    &lt;name&gt;Hat&lt;/name&gt;
    &lt;quantity&gt;2&lt;/quantity&gt;
  &lt;/item&gt;
  &lt;item code="cha001"&gt;
    &lt;name&gt;Chair&lt;/name&gt;
    &lt;quantity&gt;1&lt;/quantity&gt;
  &lt;/item&gt;
  &lt;item code="dog001"&gt;
    &lt;name&gt;Dog&lt;/name&gt;
    &lt;quantity&gt;1&lt;/quantity&gt;
  &lt;/item&gt;
&lt;/cart&gt;
</FONT></CODE></PRE></TD></TR></TBODY></TABLE><BR></P>
<P>如果查看应用程序源代码（可以从<FONT color=#000000>下载</FONT>一节得到）中的 Cart.java，可以看到生成 XML 的方式只是把字符串添加在一起。虽然对这个示例来说足够了，但是对于从 Java 代码生成 XML 来说则是最差的方式。我将在这个系列的下一期中介绍一些更好的方式。</P>
<P>现在您已经知道了 <CODE><FONT face=新宋体>CartServlet</FONT></CODE> 响应 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 的方式。下一件事就是返回客户端，查看如何用 XML 响应更新页面状态。</P>
<P><A name=IDAZDKKB><SPAN class=atitle><FONT face=Arial size=4>用 JavaScript 进行响应处理</FONT></SPAN></A></P>
<P><CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 的 <CODE><FONT face=新宋体>readyState</FONT></CODE> 属性是一个数值，它指出请求生命周期的状态。它从 0（代表“未初始化”）变化到 4（代表“完成”）。每次 <CODE><FONT face=新宋体>readyState</FONT></CODE> 变化时，<CODE><FONT face=新宋体>readystatechange</FONT></CODE> 事件就触发，由 <CODE><FONT face=新宋体>onreadystatechange</FONT></CODE> 属性指定的事件处理函数就被调用。</P>
<P>在<FONT color=#000000>清单 3</FONT>中已经看到了如何调用 <CODE><FONT face=新宋体>getReadyStateHandler()</FONT></CODE> 函数创建事件处理函数。然后把这个事件处理函数分配给 <CODE><FONT face=新宋体>onreadystatechange</FONT></CODE> 属性。<CODE><FONT face=新宋体>getReadyStateHandler()</FONT></CODE> 利用了这样一个事实：函数是 JavaScript 中的一级对象。这意味着函数可以是其他函数的参数，也可以创建和返回其他函数。<CODE><FONT face=新宋体>getReadyStateHandler()</FONT></CODE> 的工作是返回一个函数，检查 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 是否已经完成，并把 XML 响应传递给调用者指定的事件处理函数。清单 6 是 <CODE><FONT face=新宋体>getReadyStateHandler()</FONT></CODE> 的代码。</P>
<P><BR><A name=listing6><B>清单 6. getReadyStateHandler() 函数</B></A><BR>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TD><PRE><CODE class=section>
<FONT face="Lucida Console">/*
 * Returns a function that waits for the specified XMLHttpRequest
 * to complete, then passes its XML response to the given handler function.
 * req - The XMLHttpRequest whose state is changing
 * responseXmlHandler - Function to pass the XML response to
 */
function getReadyStateHandler(req, responseXmlHandler) {

  // Return an anonymous function that listens to the 
  // XMLHttpRequest instance
  return function () {

    // If the request's status is "complete"
    if (req.readyState == 4) {
      
      // Check that a successful server response was received
      if (req.status == 200) {

        // Pass the XML payload of the response to the 
        // handler function
        responseXmlHandler(req.responseXML);

      } else {

        // An HTTP problem has occurred
        alert("HTTP error: "+req.status);
      }
    }
  }
}
</FONT></CODE></PRE></TD></TR></TBODY></TABLE><BR>
<TABLE cellSpacing=0 cellPadding=0 width="40%" align=right border=0>
<TBODY>
<TR>
<TD width=10><FONT face="Lucida Console"><IMG height=1 alt="" src="http://www.ibm.com/i/c.gif" width=10></FONT></TD>
<TD>
<TABLE cellSpacing=0 cellPadding=5 width="100%" border=1>
<TBODY>
<TR>
<TD bgColor=#eeeeee><A name=IDA2FKKB><B>HTTP 状态码</B></A><BR>
<P>在清单 6 中，检查 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 的 <CODE><FONT face=新宋体>status</FONT></CODE> 属性以查看请求是否成功完成。<CODE><FONT face=新宋体>status</FONT></CODE> 包含服务器响应的 HTTP 状态码。在执行简单的 <CODE><FONT face=新宋体>GET</FONT></CODE> 和 <CODE><FONT face=新宋体>POST</FONT></CODE> 请求时，可以假设任何大于 200 （OK）的码都是错误。如果服务器发送重定向响应（例如 301 或 302），浏览器会透明地进行重定向并从新的位置获取资源；<CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 看不到重定向状态码。而且，浏览器会自动添加 <CODE><FONT face=新宋体>Cache-Control: no-cache</FONT></CODE> 头到所有 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE>，这样客户代码永远也不用处理 304（未经修改）服务器响应。</P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></P>
<P><A name=IDACHKKB><SPAN class=smalltitle><STRONG><FONT face=Arial size=3>关于 getReadyStateHandler()</FONT></STRONG></SPAN></A></P>
<P><CODE><FONT face=新宋体>getReadyStateHandler()</FONT></CODE> 是段相对复杂的代码，特别是如果您不习惯阅读 JavaScript 的话。但是通过把这个函数放在 JavaScript 库中，就可以处理 Ajax 服务器响应，而不必处理 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 的内部细节。重要的是要理解如何在自己的代码中使用 <CODE><FONT face=新宋体>getReadyStateHandler()</FONT></CODE>。</P>
<P>在<FONT color=#000033>清单 3</FONT>中看到了 <CODE><FONT face=新宋体>getReadyStateHandler()</FONT></CODE> 像这样被调用：<CODE><FONT face=新宋体>handlerFunction = getReadyStateHandler(req, updateCart)</FONT></CODE>。在这个示例中，<CODE><FONT face=新宋体>getReadyStateHandler()</FONT></CODE> 返回的函数将检查在 <CODE><FONT face=新宋体>req</FONT></CODE> 变量中的 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 是否已经完成，然后用响应的 XML 调用名为 <CODE><FONT face=新宋体>updateCart</FONT></CODE> 的函数。</P>
<P><A name=IDAVIKKB><SPAN class=smalltitle><STRONG><FONT face=Arial size=3>提取购物车数据</FONT></STRONG></SPAN></A></P>
<P>清单 7 是 <CODE><FONT face=新宋体>updateCart()</FONT></CODE> 本身的代码。函数用 DOM 调用检查购物车的 XML 文档，然后更新 Web 页面（请参阅 <A href="http://www-128.ibm.com/developerworks/cn/java/j-ajax1/#listing1"><FONT color=#996699>清单 1</FONT></A>），反映新的购物车内容。这里的重点是用来从 XML DOM 提取数据的调用。<CODE><FONT face=新宋体>cart</FONT></CODE> 元素的 <CODE><FONT face=新宋体>generated</FONT></CODE> 属性是在 <CODE><FONT face=新宋体>Cart</FONT></CODE> 序列化为 XML 时生成的一个时间戳，检查它可以保证新的购物车数据不会被旧的数据覆盖。Ajax 请求天生是异步的，所以这个检查可以处理服务器响应未按次序到达的情况。</P>
<P><BR><A name=listing7><B>清单 7. 更新页面，反映购物车的 XML 文档</B></A><BR>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TD><PRE><CODE class=section>
<FONT face="Lucida Console">function updateCart(cartXML) {

 // Get the root "cart" element from the document
 var cart = cartXML.getElementsByTagName("cart")[0];

 // Check that a more recent cart document hasn't been processed
 // already
 var generated = cart.getAttribute("generated");
 if (generated &gt; lastCartUpdate) {
   lastCartUpdate = generated;

   // Clear the HTML list used to display the cart contents
   var contents = document.getElementById("cart-contents");
   contents.innerHTML = "";

   // Loop over the items in the cart
   var items = cart.getElementsByTagName("item");
   for (var I = 0 ; I &lt; items.length ; I++) {

     var item = items[I];

     // Extract the text nodes from the name and quantity elements
     var name = item.getElementsByTagName("name")[0]
                                               .firstChild.nodeValue;
                                               
     var quantity = item.getElementsByTagName("quantity")[0]
                                               .firstChild.nodeValue;

     // Create and add a list item HTML element for this cart item
     var li = document.createElement("li");
     li.appendChild(document.createTextNode(name+" x "+quantity));
     contents.appendChild(li);
   }
 }

 // Update the cart's total using the value from the cart document
 document.getElementById("total").innerHTML = 
                                          cart.getAttribute("total");
}
</FONT></CODE></PRE></TD></TR></TBODY></TABLE><BR></P>
<P>到此，整个 Ajax 往返过程完成了，但是您可能想让 Web 应用程序运行一下查看实际效果（请参阅 <FONT color=#000000>下载</FONT> 一节）。这个示例非常简单，有很多需要改进之处。例如，我包含了从购物车中清除项目的服务器端代码，但是无法从 UI 访问它。作为一个好的练习，请试着在应用程序现有的 JavaScript 代码之上构建出能够实现这个功能的代码。</P>
<P><A name=IDA4JKKB><SPAN class=atitle><FONT face=Arial size=4>使用 Ajax 的挑战</FONT></SPAN></A></P>
<P>就像任何技术一样，使用 Ajax 也有许多出错的可能性。我目前在这里讨论的问题还缺乏容易的解决方案，但是会随着 Ajax 的成熟而改进。随着开发人员社区增加开发 Ajax 应用程序的经验，将会记录下最佳实践和指南。</P>
<P><A name=IDAEKKKB><SPAN class=smalltitle><STRONG><FONT face=Arial size=3>XMLHttpRequest 的可用性</FONT></STRONG></SPAN></A></P>
<P>Ajax 开发人员面临的一个最大问题是：在没有 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 可用时该如何响应？虽然主要的现代浏览器都支持 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE>，但仍然有少数用户的浏览器不支持，或者浏览器的安全设置阻止使用 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE>。如果开发的 Web 应用程序要部署在企业内部网，那么可能拥有指定支持哪种浏览器的权力，从而可以认为 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 总能使用。但是，如果要部署在公共 Web 上，那么就必须当心，如果假设 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 可用，那么就可能会阻止那些使用旧的浏览器、残疾人专用浏览器和手持设备上的轻量级浏览器的用户使用您的应用程序。</P>
<P>所以，您应当努力让应用程序“平稳降级”，在没有 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 支持的浏览器中也能够工作。在购物车的示例中，把应用程序降级的最好方式可能是让 Add to Cart 按钮执行一个常规的表单提交，刷新页面来反映购物车更新后的状态。Ajax 的行为应当在页面装入的时候就通过 JavaScript 添加到页面，只有在 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 可用时才把 JavaScript 事件处理函数附加到每个 Add to Cart 按钮。另一种方式是在用户登录时检测 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 是否可用，然后相应地提供应用程序的 Ajax 版本或基于表单的普通版本。</P>
<P><A name=IDANLKKB><SPAN class=smalltitle><STRONG><FONT face=Arial size=3>可用性考虑</FONT></STRONG></SPAN></A></P>
<P>关于 Ajax 应用程序的某些可用性问题比较普遍。例如，让用户知道他们的输入已经注册了可能是重要的，因为沙漏光标和 spinning 浏览器的常用反馈机制“throbber”对 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 不适用。一种技术是用“Now updating...”类型的信息替换 Submit 按钮，这样用户在等候响应期间就不会反复单击按钮了。</P>
<P>另一个问题是，用户可能没有注意到他们正在查看的页面的某一部分已经更新了。可以使用不同的可视技术，把用户的眼球带到页面的更新区域，从而缓解这个问题。由 Ajax 更新页面造成的其他问题还包括：“破坏了”浏览器的后退按钮，地址栏中的 URL 也无法反映页面的整个状态，妨碍了设置书签。请参阅 <FONT color=#000033>参考资料</FONT> 一节，获得专门解决 Ajax 应用程序可用性问题的文章。</P>
<P><A name=IDA4LKKB><SPAN class=smalltitle><STRONG><FONT face=Arial size=3>服务器负载</FONT></STRONG></SPAN></A></P>
<P>用 Ajax 实现代替普通的基于表单的 UI，会大大提高对服务器发出的请求数量。例如，一个普通的 Google Web 搜索对服务器只有一个请求，是在用户提交搜索表单时出现的。而 Google Suggest 试图自动完成搜索术语，它要在用户输入时向服务器发送多个请求。在开发 Ajax 应用程序时，要注意将要发送给服务器的请求数量以及由此造成的服务器负荷。降低服务器负载的办法是，在客户机上对请求进行缓冲并且缓存服务器响应（如果可能的话）。还应该尝试将 Ajax Web 应用程序设计为在客户机上执行尽可能多的逻辑，而不必联络服务器。</P>
<P><A name=IDAEMKKB><SPAN class=smalltitle><STRONG><FONT face=Arial size=3>处理异步</FONT></STRONG></SPAN></A></P>
<P>非常重要的是，要理解无法保证 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 会按照分派它们的顺序完成。实际上，应当假设它们不会按顺序完成，并且在设计应用程序时把这一点记在心上。在购物车的示例中，使用最后更新的时间戳来确保新的购物车数据不会被旧的数据覆盖（请参阅<FONT color=#000000>清单 7</FONT>）。这个非常基本的方式可以用于购物车场景，但是可能不适合其他场景。所以在设计时请考虑如何处理异步的服务器响应。</P>
<P><A name=IDATMKKB><SPAN class=atitle><FONT face=Arial size=4>结束语</FONT></SPAN></A></P>
<P>现在您对 Ajax 的基本原则应当有了很好的理解，对参与 Ajax 交互的客户端和服务器端组件也应当有了初步的知识。这些是基于 Java 的 Ajax Web 应用程序的构造块。另外，您应当理解了伴随 Ajax 方式的一些高级设计问题。创建成功的 Ajax 应用程序要求整体考虑，从 UI 设计到 JavaScript 设计，再到服务器端架构；但是您现在应当已经武装了考虑其他这些方面所需要的核心 Ajax 知识。</P>
<P>如果使用这里演示的技术编写大型 Ajax 应用程序的复杂性让您觉得恐慌，那么有好消息给您。由于 Struts、Spring 和 Hibernate 这类框架的发展把 Web 应用程序开发从底层 Servlet API 和 JDBC 的细节中抽象出来，所以正在出现简化 Ajax 开发的工具包。其中有些只侧重于客户端，提供了向页面添加可视效果的简便方式，或者简化了对 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> 的使用。有些则走得更远，提供了从服务器端代码自动生成 Ajax 接口的方式。这些框架替您完成了繁重的任务，所以您可以采用更高级的方式进行 Ajax 开发。我在这个系列中将研究其中的一些。</P>
<P>Ajax 社区正在快速前进，所以会有大量有价值的信息涌现。在阅读这个系列的下一期之前，我建议您参考 <FONT color=#000033>参考资料</FONT> 一节中列出的文章，特别是如果您是刚接触 Ajax 或客户端开发的话。您还应当花些时间研究示例源代码并考虑一些增强它的方式。</P>
<P>在这个系列的下一篇文章中，我将深入讨论 <CODE><FONT face=新宋体>XMLHttpRequest</FONT></CODE> API，并推荐一些从 JavaBean 方便地创建 XML 的方式。我还将介绍替代 XML 进行 Ajax 数据传递的方式，例如 JSON（JavaScript Object Notation）轻量级数据交换格式。</P>
<DIV></DIV></TD></TR></TBODY></TABLE>
<P></P><img src ="http://www.blogjava.net/shmily432685/aggbug/16179.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/shmily432685/" target="_blank">闵毓</a> 2005-10-20 18:19 <a href="http://www.blogjava.net/shmily432685/archive/2005/10/20/16179.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>