﻿<?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-kooyee ‘s blog-随笔分类-Ajax学习手记</title><link>http://www.blogjava.net/Javawind/category/24924.html</link><description /><language>zh-cn</language><lastBuildDate>Sat, 29 Mar 2008 08:06:05 GMT</lastBuildDate><pubDate>Sat, 29 Mar 2008 08:06:05 GMT</pubDate><ttl>60</ttl><item><title>[dojo] 在grails中使用dojo上传文件</title><link>http://www.blogjava.net/Javawind/archive/2008/03/29/189408.html</link><dc:creator>kooyee</dc:creator><author>kooyee</author><pubDate>Sat, 29 Mar 2008 01:44:00 GMT</pubDate><guid>http://www.blogjava.net/Javawind/archive/2008/03/29/189408.html</guid><wfw:comment>http://www.blogjava.net/Javawind/comments/189408.html</wfw:comment><comments>http://www.blogjava.net/Javawind/archive/2008/03/29/189408.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Javawind/comments/commentRss/189408.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Javawind/services/trackbacks/189408.html</trackback:ping><description><![CDATA[首先下载dojo和安装dojo plugin （grails 1.0以上）<br />
<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 src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #000000">&lt;</span><span style="color: #000000">g:javascript&nbsp;library</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">dojo</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">/&gt;</span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000">&lt;</span><span style="color: #000000">g:javascript</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />dojo.require(</span><span style="color: #000000">"</span><span style="color: #000000">dojo.io.IframeIO</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000">&lt;/</span><span style="color: #000000">g:javascript</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000">&lt;</span><span style="color: #000000">g:form&nbsp;url</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">[action:'submitToRemoteCall']</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;id</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">form2</span><span style="color: #000000">"</span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />enctype</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">multipart/form-data</span><span style="color: #000000">"</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />File:&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">input&nbsp;name</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">someFile</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;type</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">file</span><span style="color: #000000">"</span><span style="color: #000000">&gt;&lt;/</span><span style="color: #000000">input</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000">&lt;</span><span style="color: #000000">g:submitToRemote<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />value</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">Submit&nbsp;Upload</span><span style="color: #000000">"</span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />name</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">form2</span><span style="color: #000000">"</span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />action</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">submitToRemoteUpload</span><span style="color: #000000">"</span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />update</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">[success:'message',failure:'error']</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">/&gt;</span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000">&lt;/</span><span style="color: #000000">g:form</span><span style="color: #000000">&gt;</span></div>
注意 form中写入url属性， 而且form不要有hide类型的input，否则会调用XMLHttpRequest，而不用IframeIO<br />
<br />
在controller中写入<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 src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #000000">def&nbsp;submitToRemoteUpload&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000"><br />
<img id="Codehighlighter1_27_320_Open_Image" onclick="this.style.display='none'; Codehighlighter1_27_320_Open_Text.style.display='none'; Codehighlighter1_27_320_Closed_Image.style.display='inline'; Codehighlighter1_27_320_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_27_320_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_27_320_Closed_Text.style.display='none'; Codehighlighter1_27_320_Open_Image.style.display='inline'; Codehighlighter1_27_320_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /></span><span id="Codehighlighter1_27_320_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"  alt="" /></span><span id="Codehighlighter1_27_320_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />def&nbsp;f&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;request.getFile(</span><span style="color: #000000">'</span><span style="color: #000000">someFile</span><span style="color: #000000">'</span><span style="color: #000000">)<br />
<img id="Codehighlighter1_77_97_Open_Image" onclick="this.style.display='none'; Codehighlighter1_77_97_Open_Text.style.display='none'; Codehighlighter1_77_97_Closed_Image.style.display='inline'; Codehighlighter1_77_97_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_77_97_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_77_97_Closed_Text.style.display='none'; Codehighlighter1_77_97_Open_Image.style.display='inline'; Codehighlighter1_77_97_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" /></span><span style="color: #0000ff">if</span><span style="color: #000000">(f.empty)&nbsp;</span><span id="Codehighlighter1_77_97_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"  alt="" /></span><span id="Codehighlighter1_77_97_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />render&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">No&nbsp;file!</span><span style="color: #000000">"</span><span style="color: #000000"><br />
<img id="Codehighlighter1_104_318_Open_Image" onclick="this.style.display='none'; Codehighlighter1_104_318_Open_Text.style.display='none'; Codehighlighter1_104_318_Closed_Image.style.display='inline'; Codehighlighter1_104_318_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_104_318_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_104_318_Closed_Text.style.display='none'; Codehighlighter1_104_318_Open_Image.style.display='inline'; Codehighlighter1_104_318_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />}</span></span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000">&nbsp;</span><span id="Codehighlighter1_104_318_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"  alt="" /></span><span id="Codehighlighter1_104_318_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />def&nbsp;fileName&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;f.getOriginalFilename()<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />render(text:</span><span style="color: #000000">"</span><span style="color: #000000">&lt;html&gt;&lt;body&gt;&lt;textarea&gt;You&nbsp;called&nbsp;${actionName}&nbsp;in</span><span style="color: #000000"><br />
<img id="Codehighlighter1_209_224_Open_Image" onclick="this.style.display='none'; Codehighlighter1_209_224_Open_Text.style.display='none'; Codehighlighter1_209_224_Closed_Image.style.display='inline'; Codehighlighter1_209_224_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_209_224_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_209_224_Closed_Text.style.display='none'; Codehighlighter1_209_224_Open_Image.style.display='inline'; Codehighlighter1_209_224_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" /></span><span style="color: #000000">$</span><span id="Codehighlighter1_209_224_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"  alt="" /></span><span id="Codehighlighter1_209_224_Open_Text"><span style="color: #000000">{controllerName}</span></span><span style="color: #000000">&nbsp;with&nbsp;file&nbsp;$</span><span id="Codehighlighter1_237_246_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"  alt="" /></span><span id="Codehighlighter1_237_246_Open_Text"><span style="color: #000000">{fileName}</span></span><span style="color: #000000">&lt;/</span><span style="color: #000000">textarea</span><span style="color: #000000">&gt;&lt;/</span><span style="color: #000000">body</span><span style="color: #000000">&gt;&lt;/</span><span style="color: #000000">html</span><span style="color: #000000">&gt;</span><span style="color: #000000">"</span><span style="color: #000000">,</span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /></span><span style="color: #000000">contentType:</span><span style="color: #000000">"</span><span style="color: #000000">text/html</span><span style="color: #000000">"</span><span style="color: #000000">,&nbsp;encoding:</span><span style="color: #000000">"</span><span style="color: #000000">UTF-8</span><span style="color: #000000">"</span><span style="color: #000000">)<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />}</span></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span></div>
IframeIO的默认mimetype为text/plain，所以使用render （text：...）而且套嵌在&lt;textarea&gt;中<br />
<br />
如果要返回render view。 可以修改dojo的dojo.io.bind()，bind参数加上mimetype:"text/html"。form中的&lt;g:submitToRemote&gt;改为<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 src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #000000">&lt;</span><span style="color: #000000">input&nbsp;onclick</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">dojo.io.bind({url:'/test/index/submitToRemoteUpload',&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mimetype:'text/html',<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;load:function(type,data,evt){<strong>dojo.byId('message')innerHTML&nbsp;=&nbsp;data.body.innerHTML</strong>;},<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;error:function(type,error)&nbsp;{&nbsp;dojo.html.textContent(&nbsp;dojo.byId('error'),error.message);},<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;formNode:dojo.byId('form2')});return&nbsp;false</span><span style="color: #000000">"</span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;type</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">submit</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;name</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">form2</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;value</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">Submit&nbsp;Upload</span><span style="color: #000000">"</span><span style="color: #000000">&gt;</span></div>
<br />
<br />
<br />
<br />
<br />
<img src ="http://www.blogjava.net/Javawind/aggbug/189408.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Javawind/" target="_blank">kooyee</a> 2008-03-29 09:44 <a href="http://www.blogjava.net/Javawind/archive/2008/03/29/189408.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>推荐一篇好文章——Java Web开发构想 </title><link>http://www.blogjava.net/Javawind/archive/2008/01/26/177939.html</link><dc:creator>kooyee</dc:creator><author>kooyee</author><pubDate>Sat, 26 Jan 2008 11:18:00 GMT</pubDate><guid>http://www.blogjava.net/Javawind/archive/2008/01/26/177939.html</guid><wfw:comment>http://www.blogjava.net/Javawind/comments/177939.html</wfw:comment><comments>http://www.blogjava.net/Javawind/archive/2008/01/26/177939.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Javawind/comments/commentRss/177939.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Javawind/services/trackbacks/177939.html</trackback:ping><description><![CDATA[<p><span style="font-size: 24pt"><strong style="font-size: 18pt">1．背景、形势 </strong></span><br />
<br />
<br />
能够进行Web开发的编程语言和技术很多 <br />
<br />
(1) 动态解释语言 <br />
PHP; Perl; Python (Zope, Plone); Ruby (Ruby on Rails); <br />
<br />
(2) 编译语言 <br />
Java; .net <br />
<br />
Java Web开发远非一枝独秀： <br />
除了受到来自.net 这个重量级对手的最大挑战之外，更受到Zope, Ruby on Rail 等新式轻骑兵的冲击（当然，也继续受到老式轻步兵PHP, Perl的冲击）。 <br />
<br />
官方Java走的是复杂路线，Servlet -&gt; JSP -&gt; Taglib。.net走的也是复杂路线，依靠成熟友好的集成化开发环境取胜。Java阵营好容易应对过来，从纷纭复杂的各种开发框架基础上，发展出了重量级Web开发框架JSF，以及相应的集成化开发环境；渴望以此应对.net的攻势。胜负未分，前途未卜。这时，另一个方向又杀来了新式轻骑Zope, Ruby on Rail。 <br />
Python, Ruby等动态解释语言，面向对象特性更好，先天支持 动态绑定、AOP、函数式编程、&#8220;编程即配置&#8221;等时髦概念。开发速度更快，代码量更小，达到killer级别。 <br />
<br />
传统的HTML Web开发领域里面，Java已经是腹背受敌。领域外也展开了征战，Rich Client Architecture的兴起：AJAX(XMLHttp), Flash RIA, XUL, XAML, Smart Client（以及从前的ActiveX, Applet, Web Start）。 <br />
<br />
Web的发展趋势是 语义Web，最终目的是让整个Web成为一个巨大的数据库。 <br />
这意味着，未来的Web应用将更加的面向文本内容数据，更加搜索引擎友好 &#8211; Search Engine Friendly. <br />
二进制的客户端插件，如Flash RIA, ActiveX, Applet, Web Start等，虽然交互性能最好，但不是以文本内容数据为中心，搜索引擎不友好。所以，我只是保持适当关注。我更关注基于文本的UI表现，如HTML, XUL, XAML等。XUL, XAML还没有广泛流行，只是保持一种有兴趣的关注。 <br />
当下关注的重点，还是 XHTML + CSS + Javascript少量的 AJAX(XMLHttp)增加更好的交互性。 <br />
<br />
我一直认为：轻量、简洁、高效 才是硬道理。后面阐述我对Java Web开发的理解和构想。 <br />
<br />
<br />
</p>
<p><span style="font-size: 18pt"><strong>2. Web开发框架层次概述 <br />
<br />
</strong></span>从上到下，Web开发框架的层次如下： <br />
<br />
(1) HTML, JavaScript, CSS等页面资源。 <br />
(2) 页面模板层。 如JSP, Freemarker, Velocity, XSL，fastm等。用来生成HTML, JavaScript, CSS等页面资源。 <br />
(3) Web框架。把HTTP Request调度分派到对应的Service Entry。 <br />
(4) Business Logic. <br />
(5) O/R Mapping. <br />
(6) JDBC <br />
(7) DB <br />
<br />
根据我的经验，一个典型的Web应用中的代码比例如下： <br />
页面逻辑约占 50%，商业逻辑约占30%, O/R 约占20%。 <br />
<br />
但事实上，页面却是最不受重视的部分，从来都被认为是脏活，累活，杂活。典型的开发过程通常是这样： <br />
页面设计人员迅速的用Dreamweaver等生成一堆文本杂乱无章的页面，然后交给JSP程序员加入更加杂乱无章的Java代码和Taglib。 <br />
当页面布局风格需要改变的时候，页面设计人员用Dreamweaver等生成一堆新的页面。JSP程序员再重新加入更加杂乱无章的Java代码Taglib。 <br />
至于页面中的脚本逻辑调试，更是一门精深的工夫了。 <br />
<br />
根据社会规则，通常来说，工作内容越轻松，收入越高；工作内容越脏月累，收入越低；Web开发也是如此：做着最脏最累的活的页面程序员，工资一般比不上后台业务逻辑程序员。 <br />
<br />
开发框架通常会带来这样的结果：让简单的东西，变得更简单；让复杂的东西，变得更复杂。 <br />
这其中的原因在于： <br />
一般来说，一个应用中简单重复的东西占80%，复杂特殊的东西占20%。 <br />
简单重复的东西很容易摸清规律，进行包装，通用化。但是，在包装的同时，经常就阻挡住了底层的一些灵活强大的控制能力。在复杂特殊的需求中，确实又需要这些底层控制能力，那么为了绕开框架的限制，付出的努力要比不用框架 大得多。 <br />
打个比方，一个比较极端的例子。编译语言比汇编语言的开发效率高很多，但是却无法直接操作寄存器。当需要在编译语言中操作寄存器的时候，就非常的痛苦。比如Java，也许需要JNI，写C代码，还要在C代码里面嵌入汇编。编译、连接都很麻烦。 <br />
所以，一个框架的开发效率，就在于这个80%简单 与 20%复杂之间的平衡。 <br />
假如，不用框架来开发，简单的80%要消耗 80个资源数，复杂的20%要消耗20个资源数，总资源数是100；使用了某个框架，简单的80%只要消耗10个资源数，复杂的20%要消耗40个资源数，总资源数是50。那么，我们说，这个开发框架是有效率的。 <br />
<br />
我的思路是，同时应对复杂和简单。当然，为了应对复杂，简单的东西可能就应对得不那么好。比如，做这样一个开发框架，简单的80%要消耗20个资源数，复杂的20%要消耗10个资源数，总资源数是30。 <br />
这种开发框架是有可能实现的。而且是很有意义的。尤其是在复杂部分的比例提高的时候。越复杂的系统，这种开发框架就越有意义。 <br />
<br />
后面的关于Web各层开发的论述，主要就按照这个&#8220;应对复杂、让复杂更简单&#8221;的思路展开。<br />
<br />
</p>
<p><span style="font-size: 18pt"><strong>3．页面资源 </strong></span><br />
<br />
也许有人会说，页面资源，不就是HTML吗？太简单，太低极了，没劲。Dreamweaver、Frontpage多简单阿。随便找个人来用就可以了。文本内容乱糟糟不要紧，浏览器里面显示出来的效果好看就行。要增加炫的、酷的动画效果，那就写JavaScript呗。写在HTML里面，看看在IE里面能不能运行就可以了呗。 <br />
这也正是大多数公司开发页面资源的方式。因为页面的需求变化是最多、最快的，而页面的制作成本很低，人们不愿意在上面投入更多的资源。 <br />
<br />
我的看法是，万丈高楼平地起。应用程序的每一个部分都应该完善管理，结构优美。越是需求变化多的地方，越是脏乱差的地方，越应该加大力度处理好。 <br />
<br />
页面结构方面，Javaeye论坛的Dlee做了很多工作。 <br />
<br />
(1) 在 2005 年我们如何写 JavaScript <br />
<a href="http://forum.javaeye.com/viewtopic.php?t=12973" target="_blank"><font color="#004377">http://forum.javaeye.com/viewtopic.php?t=12973</font></a> <br />
(2)使用 Unordered Lists 制作的下拉菜单和树 <br />
<a href="http://forum.javaeye.com/viewtopic.php?t=12995" target="_blank"><font color="#004377">http://forum.javaeye.com/viewtopic.php?t=12995</font></a> <br />
<br />
<br />
从上面的Dlee的论述和给出的资料。可以看出，页面资源分为三部分： <br />
(1) XHTML。结构，Structure。 <br />
XHTML里面的Tag部分只应该包括 &lt;ul&gt; &lt;table&gt; &lt;p&gt; &lt;div&gt;&lt;span&gt;等结构布局Tag，或者&lt;strong&gt;&lt;emphasis&gt;表示语义的Tag。 <br />
XHTML里面不应该包括风格信息，比如字体、颜色、大小、粗细等，也不应该包括&lt;font&gt; &lt;b&gt; &lt;i&gt; &lt;h&gt; 等字体信息。 <br />
XHTML里面不应该包括Javascript的定义和调用。 <br />
<br />
(2) JavaScript。行为，behavior。 <br />
JavaScritp应该存在于一个独立于XHTML文件的独立文件中。这样可以做自动化单元测试。JavaScript应该只改变HTML DOM的结构和内容，而不应该改变它的风格。 <br />
<br />
(3) CSS。Style，风格。或者说，Presentation，表现。 <br />
前面说了，XHTML里面不应该包括JavaScript的调用。那么，XHTML的元素是如何JavaScript事件绑定起来？就是在CSS里面指定的。 <br />
当然，众所周知，CSS的本职工作是处理页面风格。 <br />
<br />
页面资源方面，我完全认同Dlee的观点。从技术和资源积累的长远目标看来，这方面的初期投入的回报将是非常丰厚的。 <br />
即使将来HTML消亡了，进入了XAML, XUL, RSS时代，这些结构清晰的各部分，重用的可能性都非常巨大。JavaScript + CSS + XML UI的这种经典设计思路，将留存很久。混杂成一团的HTML的命运只能是全盘被抛弃。 <br />
<br />
</p>
<p><span style="font-size: 18pt"><strong>4．页面模板层 <br />
<br />
</strong></span>页面模板层是指Server端运行的用来生成HTML（或JavaScript，CSS）的Server Side Template Engine。 <br />
这一层也是著名的脏乱差楼层。著名的HTML的Java代码污染事件，就发生在这个楼层。不仅JSP有这个问题，其他的template, 如freemarker, velocity, tapestry等含有逻辑的脚本，都不同程度上有HTML的Script Logic污染问题。 <br />
<br />
Dlee的做法很美。直接就不要页面模板层，不用Server Side Template Engine。直接用JavaScript更改HTML DOM的结构、内容、数据。同时，会用到少量的浏览器端XSL。 <br />
这样带来的结果，Template就是很干净纯粹的HTML，不含有任何Server Side Script。这个效果，和Servier Side Template 的 Jivan，XMLC达到的一样。只是一个是在浏览器端执行，一个是在Server端执行。 <br />
<br />
我研究比较了几乎所有的Server Side Template Engine，力图采众家之长，避众家之短，写了一个Server Side Template Engine -- fastm, 能够最优雅方便的实现页面模板层。关于fastm，我的Blog上有不少文章论述。 <br />
我的Blog，里面专门有个fastm 分类。 <br />
<a href="http://blog.csdn.net/buaawhl" target="_blank"><font color="#004377">http://blog.csdn.net/buaawhl</font></a> <br />
<a href="http://buaawhl.blogdriver.com/" target="_blank"><font color="#004377">http://buaawhl.blogdriver.com</font></a> <br />
<br />
Fastm发布在java.net上。 <br />
<a href="https://fastm.dev.java.net/" target="_blank"><font color="#004377">https://fastm.dev.java.net</font></a> <br />
<br />
<br />
我仍然对Server Side Template Engine持肯定态度。基于如下原因： <br />
(1) JavaScript代码量大、文件多的时候，不容易管理，不容易进行语法检查，不容易跟踪调试。 <br />
这里有人会争辩，Server Side Template Engine也用到了很多脚本阿，比如Freemarker, Velocity, 而且嵌在HTML中，怎么管理，怎么调试？即使是JSP，也是Java Code嵌在HTML里面，怎么管理，怎么调试？ <br />
这里我要说，Jivan, XMLC, fastm，Wicket等Template Engine的逻辑都是在Java Code里面。 <br />
<br />
(2) 用JavaScript生成文本内容，搜索引擎不友好。 <br />
一般的网络蜘蛛程序，只根据URL获取HTML文本，搜索里面的文本内容，而不会执行里面的JavaScript脚本。 <br />
<br />
(3) JavaScript代码重用还是有些局限 <br />
比如，有两个HTML文件，一个是Table布局，一个是List布局。 <br />
我有同样的一批数据，要在这两种布局中显示。 <br />
这时候，就要给这两个HTML分别写两套JavaScript。这里面的DOM层次，元素，属性都不同，再怎么定义ID，Class，也无法用完全相同的一套JavaScript处理。 <br />
这里有人会争辩，Server Side Template Engine也无法做到。别说JSP, Velocity, Freemarker等要在两套HTML里面嵌入相同的代码，就是Jivan, XMLC, Wicket也要分别写不同的两套Java Code，因为它们的XML DOM Node / Model View (Table, List) 都是不同的。 <br />
这里我要说。fastm可以做到只用一套代码逻辑。而且只有fastm可以。fastm的代码重用率是最高的。 <br />
<br />
关于Ajax(XMLHttp)，我的意见是必要时才用，而且最好采用粗粒度的用法 -- JavaScript发出一个URL请求，返回一整段HTML，直接替换到页面的某一块，而不是用JavaScript来做这样的把数据填充到HTML DOM中。如果你直接在浏览器里面输入那个URL，也可以获取那整段的HTML内容。 <br />
典型的应用场合是Portal。Portal页面的每个Portlet都含有这样的 Ajax(XMLHttp) javascript代码 -- 发出一个Portlet URL请求，返回一整段Portlet的内容，直接替换当前的Portlet块。 <br />
<br />
这样做的好处是： <br />
(1) 减少JavaScript代码的量和复杂度。 <br />
(2) 搜索引擎友好。网络蜘蛛程序可以辨别JavaScript中的URL，并根据这个URL，获取整段处理好的HTML文本，进行内容搜索。 <br />
有人可能会争辩：如果URL请求返回的是XML数据，不是整段处理好的HTML，搜索引擎也可以进行内容搜索。 <br />
这点我同意。前提是XML数据的内容是足够连贯的，而不是散落的。比如，你返回的XML数据是&#8220;中国&#8221;。这个&#8220;中国&#8221;要放在HTML中的一个{country}位置，{country}足球。这个时候，结果HTML的内容含有&#8220;中国足球&#8221;。而XML数据中只含有&#8220;中国&#8221;。如果用户用&#8220;中国足球&#8221;作为关键字来搜索，就找不到这个URL。 <br />
<br />
从前面给出的fastm资料的连接中，可以得知。如同Jivan, XMLC, Wicket一样，fastm的template里面不含有逻辑，所有的逻辑都写在Java里面。 <br />
有人会争辩说：页面逻辑写在Java里面，我改变了页面逻辑，还需要重新编译。这也太不方便了。Velocity, Freemarker, JSP就不用重新编译。 <br />
这里我的看法是：业务逻辑代码改变了，不也需要重新编译吗？页面逻辑就不是逻辑了吗？HTML里面的脚本怎么语法检查、跟踪调试？业务逻辑需要语法检查、跟踪调试，页面逻辑就不需要语法检查、跟踪调试了吗？ <br />
对方可能会说：在我的应用中，页面逻辑的改动需求非常频繁，而且这些页面逻辑非常简单，不需要语法检查、跟踪调试。 <br />
<br />
这里我的意见是： <br />
(1) 那就使用JSP, Velocity, Freemarker等脚本。 <br />
(2) fastm, Jivan, XMLC, Wicket的Java代码部分也可以写在脚本里面，比如，Server Side JavaScript, Jython(Python), Groovy, Bean Shell 等脚本语言都可以很方便的和Java相互调用。 <br />
<br />
<br />
fastm的生命周期将很长。 <br />
HTML, XUL, XAML都是，或将是可以在浏览器或可视化编辑工具里面显示的XML UI定义语言。Microsoft Office的Word, Excel, Powerpoint等格式都提供了相应的XML格式。这些XML文件都可以在Office里面显示，并编辑。 <br />
Adobe公司也提供了PDF的XML格式 -- XDP。可以在Adobe Designer里面显示并编辑。 <br />
由于fastm是Designer Friendly的XML UI所见即所得的模板技术。这方面具有很大的潜力。 <br />
根本不需要第三方花大力气专门做个IDE，来显示自定义的Tag。目标文件格式提供商自己的阅读编辑工具就可以直接用了，而且效果就是运行后产生的结果文件的效果。 <br />
<br />
即使没有可视化要求的场合。比如，Web Service需要的XML数据。fastm同样有用武之地。比如， <br />
&lt;!-- BEGIN DYNAMIC: users --&gt; <br />
&lt;user&gt; <br />
&lt;name&gt;{name}&lt;/name&gt; <br />
&lt;address&gt;{name}&lt;/address&gt; <br />
&lt;/user&gt; <br />
&lt;!-- END DYNAMIC: users --&gt; <br />
<br />
可以很容易的把一个Java Object List转化为XML数据。 <br />
<br />
另外，我不得不承认。浏览器端的JavaScript的页面逻辑，可移植性要高于Server Side Template Engine。因为Server Side Template Engine通常是特定语言相关的。 <br />
目前fastm是用Java实现的。由于实现很简单，移植到其它的语言，也很简单。如果是移植到Python, Ruby等动态解释语言，那就更简单了。我是有这个考虑，因为Zope, Ruby on Rails 的模板还是Logic 和 HTML混杂的，fastm这个思路有很大的用武之地。 <br />
<br />
前面讲了这么多。清理了两层有名的脏乱差的老大难的楼层 -- 页面资源层和页面模板层。让这两层变得和下面的楼层同样的优雅、清洁。 <br />
<br />
下面该讲到Web框架层了。在向下讲之前，由于前面提到了脚本，我想先插入一段关于&#8220;可配置&#8221;、&#8220;可编程&#8221;、&#8220;可热部署&#8221;、&#8220;脚本逻辑 vs XML Tag逻辑&#8221;的话题。把这个人们比较关心、讨论比较多的话题，先讲清楚。<br />
&nbsp;<br />
<br />
</p>
<p><span style="font-size: 18pt"><strong>5．可配置、可编程、可热部署、脚本逻辑 vs XML Tag逻辑 <br />
<br />
</strong></span>由于Java是编译语言，人们通常把变化的参数部分抽取出来，放到配置文件中。 <br />
这些配置文件通常是XML文件。这很好，没什么问题。XML很适合用来表达数据结构。 <br />
但是，对于某一种技术的狂热，通常引起对这种技术的过度使用，或者误用。 <br />
人们开始觉得，XML能够表达一切东西，包括for, if, else等逻辑。这方面的典型例子有 Workflow XML Definition，Logic TagLib, XSL Logic Tag等。 <br />
这点我不敢苟同。我的看法是，XML不适合表达逻辑，XML表达逻辑非常蹩脚。XML表达逻辑相当于自定义一门XML格式的脚本语言。 <br />
<br />
比如，Logic Tablib，很难自然的支持 if else, switch。只能蹩脚地支持一堆 &lt;logic:if&gt; &lt;logic:ifNot&gt; &lt;logic:exists&gt; &lt;logic:notExists&gt; &lt;logic:ifNull&gt; &lt;logic:notNull&gt;。 <br />
（注，好久没有接触过Taglib了。这些Tag Name都是凭以前的使用印象写的，也许名字不对，但表达这些意思的TagLib都还是有的） <br />
如果要表达if () else if() else 就更蹩脚了。要进行非常麻烦的嵌套。 <br />
<br />
再比如，XSL 支持if, else 也非常蹩脚。非要多出来一个层次才行。 <br />
&lt;xsl:choose&gt; <br />
&lt;xsl:when test="&#8230;"&gt; <br />
&#8230;. If &#8230;. <br />
&lt;/xsl:when&gt; <br />
&lt;xsl:otherwise&gt; <br />
&#8230; else &#8230; <br />
&lt;/xsl:otherwise&gt; <br />
&lt;/xsl:choose&gt; <br />
<br />
同样，如果要表达if () else if() else 就更蹩脚了。 <br />
&lt;xsl:choose&gt; <br />
&lt;xsl:when test="&#8230;"&gt; <br />
&#8230;. If &#8230;. <br />
&lt;/xsl:when&gt; <br />
&lt;xsl:otherwise&gt; <br />
&lt;xsl:choose&gt; <br />
&lt;xsl:when test="&#8230;"&gt; <br />
&#8230;. If &#8230;. <br />
&lt;/xsl:when&gt; <br />
&lt;xsl:otherwise&gt; <br />
&#8230; else &#8230; <br />
&lt;/xsl:otherwise&gt; <br />
&lt;/xsl:choose&gt; <br />
&lt;/xsl:otherwise&gt; <br />
&lt;/xsl:choose&gt; <br />
<br />
可以看到，XML Tag 表达逻辑，非常麻烦，可读性很差，完全是一种误用，没有半点优势。当然，逻辑简单的情况下，还是可以接受的。 <br />
有人会说：XML表达逻辑，可以免编译阿。 <br />
那么我说：语法检查呢，跟踪调试呢？ <br />
对方说：只是一些简单的逻辑，不需要语法检查、跟踪调试。 <br />
我说：如果只是为了免编译，前面列出的那么多的解释执行的脚本语言更适合。XML表达的逻辑，比Java等编译语言还要麻烦很多，而脚本语言比Java等编译语言简洁多了，可读性非常好，而且脚本语言和Java语言有很好的交互性，可以相互调用。重用、结构方面都具有优势。 <br />
<br />
有人会举出<strong>Spring</strong> IoC为例子，说：你看，<strong>Spring</strong> IoC的配置文件不都是XML格式吗？ <br />
我说： <br />
(1) <strong>Spring</strong> IoC的配置文件基本都是属性设置，Bean ID声明。没有逻辑。 <br />
(2) 我也不是很赞同<strong>Spring</strong> IoC在XML配置文件里面引用Java类的做法。这方面，其它的容器如 Pico, Nano都支持多种配置方式，其中包括了不少脚本方式。我觉得，在脚本里面定义生成Java Object，比在XML中要好。当然，Web.xml里面也引用了Java Class名字。但那是非常简单的情况。没有嵌套引用、属性赋值、构造参数等复杂的定义方式。XML适合描述一些通用的资源、数据、结构。比如，HTML, XUL, XAML，RSS就是XML用的恰当的例子。 <br />
<br />
所以，我的基本观点是这样。 <br />
(1) 纯数据，不用说，应该定义在XML中。 <br />
(2) 如果是系统中一些Java Object要用到的基本属性。比如，连接池大小等。定义在properties, XML, Script中都可以。如果定义中没有出现具体的Java Class名，倾向于定义在properties, XML文件中。如果出现了具体的Java Class名，倾向于定义在Script中。这个界限不那么明显，两者皆可。 <br />
(3) 复杂结构的Java Bean的构造生成，那是肯定会出现具体的Java Class名，应该定义在Script中。 <br />
<br />
关于&#8220;可配置 vs 可编程&#8221;，有一点要明确：只要是可编程的，一定是可配置的。但如果是可配置的，却不一定是可编程的。 <br />
这里的可编程，是指框架给程序员提供了API；可配置，是指框架给程序员提供了配置文件的格式写法。 <br />
&#8220;可编程&#8221;一定是&#8220;可配置&#8221;的。 <br />
(1) 用户至少可以自己定义配置文件，读取参数，调用API。 <br />
(2) 有那么多的解释脚本可以直接和Java互操作，完全可以直接用来当作配置文件，定义参数。 <br />
&#8220;可配置&#8221; 却不一定&#8220;可编程&#8221;的。 <br />
如果框架只给你提供了配置方式，而没有API，那意味着，你只能进行参数的静态配置。很难在动态期间改变这些参数了。你总不能尝试着用代码去改变配置文件的内容吧？即使你改动了，如果框架不进行文件的时间戳检查，就是一开始装载进来，就不再检查更改了，你不就一点办法都没有了吗？ <br />
比如，Struts Tiles的XML定义，你只能静态配置，你想在运行期间改变布局，没有办法。Site Mesh也是如此。而我们可以在运行期间任意操作XML DOM Node，别说布局了，任何东西都可以改变。 <br />
所以，一个框架首要注重的是提供API，而不是提供配置方式。这是一个重要的原则。 <br />
<br />
讨论完了&#8220;可编程&#8221;、&#8220;可配置&#8221;问题，我们来看&#8220;热部署&#8221;问题。 <br />
XML配置文件、脚本文件支持&#8220;热部署&#8221;当然要比编译语言程序的热部署容易得多。只要解释执行前，检查一下时间戳就可以了。要注意的问题，只是做好测试，因为没有编译期的语法检查。 <br />
不过，Java程序也是可以&#8220;热部署&#8221;的。只是稍微麻烦一点。典型的例子是JSP, EJB Jar等。JSP修改之后，会自动编译执行；EJB Jar丢到EJB Container里面，会被检测到并装载到JNDI命名空间。 <br />
编译语言Java程序的热部署的一个可能的技术难点是，Class或者Jar已经存在，如何监测到Class或者Jar的更改，并装载这个新版本，替换旧版本。 <br />
这个问题我具体没有研究过。从道理上讲，应该在Class Loader上下功夫。如果需要，可以参阅开源EJB Container的相关实现部分。Java还有一种&#8220;Hot Swap&#8221;技术，专门解决这个问题，可以搜索查阅一下。 <br />
<br />
这段小插曲，就到这里。下面讨论Web框架。<br />
&nbsp;<br />
<br />
</p>
<p><span style="font-size: 18pt"><strong>6．Web框架 <br />
<br />
</strong></span>Web框架层是一个清洁的楼层。很多优秀的程序员在这一层大展身手，做出了很多好作品。我感觉不错的有<strong>Spring</strong> MVC, Web Work。 <br />
对于Web应用来说，Web框架层是最重要的一层。SOA、Semantic Web等效果都要在这一层实现。 <br />
首先，我们来讨论，框架的编程结构。 <br />
<br />
我的Blog中有一篇《Java Web框架综述》的文章。讲解了一些流行的Web框架的编程结构，很多重复的内容不再赘述。 <br />
<a href="http://blog.csdn.net/buaawhl" target="_blank"><font color="#004377">http://blog.csdn.net/buaawhl</font></a> <br />
<br />
Java Web框架综述 <br />
<a href="http://blog.csdn.net/buaawhl/archive/2004/12/21/224069.aspx" target="_blank"><font color="#004377">http://blog.csdn.net/buaawhl/archive/2004/12/21/224069.aspx</font></a> <br />
<br />
<strong>Spring</strong> MVC的编程接口是最清晰的。大多数简单情况下，Web Work的用法是最简单有效的，编程结构比较特殊，可以说具有一定的变革意义。 <br />
<strong>Spring</strong> MVC的Controller接口相当于Struts Action，也具有Request, Response两个参数，虽然编程接口非常清晰优雅，但是本质上没有什么变化。 <br />
<strong>WebWork</strong>的Action则失去了Controller的身份，只相当于FormBean的身份，或者说相当于ActionBean的身份。<strong>WebWork</strong> Action不具有Request, Response两个参数，它只具有属性，并通过属性Setter获取HTTP Request的参数，通过属性getter把结果数据输出到HTTP Response。 <br />
可以说，<strong>WebWork</strong>的这个把握是相当到位的。95%以上的情况下，程序员是不需要Request, Response参数的。当需要这些参数的时候，<strong>WebWork</strong>并没有挡住路，可以通过实现RequestAware，ResponseAware等接口来获取，或者通过一个Thread Local获取。这种情况下，编程结构的约定，就不那么清晰了。 <br />
<br />
我从Canonical的帖子和Blog受到了很多启发。 <br />
<a href="http://canonical.blogdriver.com/" target="_blank"><font color="#004377">http://canonical.blogdriver.com</font></a> <br />
<br />
jsplet:对Model 2模式的批判 <br />
<a href="http://canonical.blogdriver.com/canonical/591479.html" target="_blank"><font color="#004377">http://canonical.blogdriver.com/canonical/591479.html</font></a> <br />
<br />
jsplet与<strong>webwork</strong>的概念对比 <br />
<a href="http://canonical.blogdriver.com/canonical/594671.html" target="_blank"><font color="#004377">http://canonical.blogdriver.com/canonical/594671.html</font></a> <br />
<br />
从级列理论看MVC架构 <br />
<a href="http://canonical.blogdriver.com/canonical/579747.html" target="_blank"><font color="#004377">http://canonical.blogdriver.com/canonical/579747.html</font></a> <br />
<br />
从Canonical的文章可以看出。JSPLet用JSP文件作为Dispatcher，然后在JSP里面注册并调用对应的Object。这个寻访Object的过程，完全是根据丰富的URL定义来做的。URL里面包括Object Scope, Object Name, Method Name, Method Parameters，天生就对事件机制有良好的支持。 <br />
<br />
Zope的一些做法也有异曲同工之妙。 <br />
Zope Object Publishing <br />
<a href="http://www.zope.org/Documentation/Books/ZDG/current/ObjectPublishing.stx" target="_blank"><font color="#004377">http://www.zope.org/Documentation/Books/ZDG/current/ObjectPublishing.stx</font></a> <br />
<a href="http://www.plope.com/Books/2_7Edition/ZopeArchitecture.stx#2-3" target="_blank"><font color="#004377">http://www.plope.com/Books/2_7Edition/ZopeArchitecture.stx#2-3</font></a> <br />
<br />
这种通过URL获取Published Object的服务的思路，是一种实现SOA效果的有效思路。 <br />
<br />
我们首先来看Web Service的现状。目前Web Service主要分为两大阵营。SOAP和REST。关于REST，请参阅 <br />
<a href="http://www.xfront.com/REST-Web-Services.html" target="_blank"><font color="#004377">http://www.xfront.com/REST-Web-Services.html</font></a> <br />
关于SOAP和REST的比较、互操作，网上有很多文章。如果需要请搜索查阅。 <br />
<br />
我个人比较倾向于REST风格的Web Service。 <br />
因为SOAP是一门固定的协议，如果用SOAP来编写Web Service程序，需要一个SOAP协议的解析库 ，也许还需要一些专门的&#8220;SOAP 数据 -- 编程语言&#8221;映射库，如同CORBA IDL的多语言映射一样。如果你要让自己的Web应用支持SOAP，你需要把发布的服务对象、方法都包装为SOAP协议，这需要一些编程语言相关的数据结构的映射工作。 <br />
REST则只是一种风格，而不是一个协议。中心思想是简单的通过丰富的URI定义 (如XLink + XPointer等) 获取资源。如果你要让自己的Web应用支持REST，那么很简单，只要在URI上下功夫就可以了，比如，多增加一个参数format=REST，在程序中多增加一种XML输出格式就可以了。（从道理上来说，SOAP也可以这么实现，但SOAP的输入和输出都要遵守SOAP协议，SOAP的输入参数一般都包装在SOAP信封里面） <br />
<br />
<br />
<br />
关于HTTP Get和Post，我表述一下自己的看法。 <br />
<br />
我认为，Web的精髓在于Get，而不是Post，在于获取服务器的输出，而不是输入到服务器。即，Web的精髓在于以小搏大，四两拨千斤。最经典的用法就是用一个URL，获取一个长篇的文本内容，这个内容里面充满了其他更多的资源连接。这也是超文本连接HTML发明的初衷。 <br />
至于HTTP Post，则是这上面的一个扩展。B/S结构如此流行，很多应用都要转移到Web上面，怎么办，应用总是交互的，总要让用户输入数据吧，就增加了HTTP Post协议。 <br />
<br />
HTTP Get经典、简单、有效。可以用丰富的URI定义把这个优势发挥到极致。这个实现也比较简单、优雅。就不多说了。主要的难点在于HTTP Post。下面的讨论主要应对&#8220;HTTP Post&#8221;这个复杂现象。<br />
&nbsp;<br />
HTTP Post从来就不让人们满意。当输入逻辑复杂到一定程度，表单数据的繁杂、凌乱、散落，到了服务器端很难组织起来。输入方面B/S结构确实和C/S结构难以匹敌。于是，出现了XMLHttp，能够把参数在浏览器里面组织成为一个统一的XML数据结构（或其他格式），发送到服务器端，一次解析出来。SOAP做这个方面，更是拿手好戏。所以，很多XMLHttp程序直接采用SOAP作为通信协议。而REST风格的HTTP Post则和HTML Form Post没有太大的本质区别。 <br />
<br />
REST在HTTP Get方面更胜一筹，SOAP在HTTP Post方面更胜一筹。可以根据Web应用的特点，根据HTTP Get / HTTP Post 页面的比例，选择适合的技术。 <br />
<br />
我们再进一步分析HTTP Post的数据内容。HTTP Post的数据，可能包含三种类型： <br />
(1) 需要存档在服务器的数据 <br />
比如，用户注册时候，输入的基本信息，用户名、密码、电子邮件等。这些信息要存放到服务器的数据库。 <br />
对于这种基本信息，HTTP Post，XMLHttp，SOAP处理起来，难度都不大，没有很大区别。 <br />
B2B的数据交换，也属于这个类别。用何种技术区别不大。一般采用SOAP，因为SOAP是一种流行的标准协议。 <br />
(2) 服务调用参数 <br />
比如，用户进行复合条件查询的时候，输入的查询条件。这个时候，HTTP Post处理起来就非常蹩脚。而XMLHttp，SOAP则具有很大的优势。可以把复杂的查询条件很好组织成XML数据，发送到服务器端统一处理。SOAP里面甚至可以定义对象名、方法名等详细的调用信息。 <br />
(3) 指令 <br />
这种情况比较少见。上面的参数类别中提到的&#8220;对象名、方法名等详细的调用信息&#8221;，和这个指令类别有些交叉。 <br />
假如一个SOAP调用方法里面的参数也是一个自定义的对象，这个自定义对象的属性数据在SOAP信息中进行了定义。到了服务器端之后，服务端程序首先调用这个自定义参数的构造函数，生成这个参数对象，然后调用对应的服务对象，把这个参数传给服务。这个过程可以看作是一个顺序指令：[1]构造参数[2]调用服务。 <br />
<br />
这只是最简单的情况。而目前的Web Service一般也就支持到这个程度。 <br />
我的看法是，一不做，而不休。既然都把调用信息定义到这个程度了，不如做的更彻底一些，全面完善的支持指令。这个指令则意味着逻辑。前面讲过了，我不赞成用XML Tag表示逻辑，而赞成脚本。这里比较适合的脚本是JavaScript，因为JavaScript比较通用，客户端、服务器端都可以解释执行。注意，这里和一般的做法正好相反：一般的Web应用总是把JavaScript从服务器传到浏览器里面执行，而这里是把JavaScript在浏览器里组织好，发给服务器端处理；这个JavaScript将会在服务器端执行，调用服务器端的对象。举个SOAP含有JavaScript指令的例子 (只是示意，非标准格式) ： <br />
&lt;soap envelope&gt; <br />
&lt;XML Data&gt; <br />
&lt;a&gt; <br />
&lt;b&gt;12&lt;/b&gt; <br />
&lt;/a&gt; <br />
&lt;c&gt; <br />
&lt;d&gt;21&lt;/d&gt; <br />
&lt;/c&gt; <br />
&lt;e&gt; <br />
&lt;e&gt;16&lt;/e&gt; <br />
&lt;/e&gt; <br />
&lt;/XML Data&gt; <br />
<br />
&lt;script&gt; <br />
final_result = default; <br />
result1 = service1.service(a.b); <br />
if(result1.ok){ <br />
result2 = service2.service(c.d); <br />
if(result2.ok) <br />
final_result = service3.service(e.f); <br />
} <br />
&lt;/script&gt; <br />
&lt; /soap envelope &gt; <br />
<br />
这个好处是： <br />
[1] 发布了更多的基本Service。给客户提供了更大的灵活度。 <br />
比如，这里就发布了3个Service。由用户自己组织逻辑。 <br />
按照传统的做法，上述流程将整个包装在服务器端执行。发布给用户的Service只有最外面的一个Service，而且高度耦合（if, else, if, else流程hard code在服务器端），不灵活，不通用。 <br />
这里的方法，就可以让客户端随意组织service1, service2, service3的调用顺序和方式。 <br />
[2] 减少了通信次数。 <br />
假如这段Script在客户端执行，那么和服务器要进行3次通信。 <br />
<br />
传统Web的权限控制一般在URL级别，这种script -&gt; server方式的权限控制则要在对象级别、方法级别、Code片断级别了，复杂很多，也许要大量应用Java的Code权限认证机制。 <br />
<br />
以上展开讨论了 Web Service, HTTP Get/Post。下面我们回到Web框架层。 <br />
前面说了，JSPLet给了我很大的启发。很多思路可以借鉴。 <br />
当然，我并不赞成用JSP作Dispatcher, Controller。(1) 因为JSP要编译成Servlet，而Servlet是Web Server管理的比较昂贵的资源。一个Web系统中JSP达到几千个，就会遇到性能瓶颈。(2) JSP中的代码重用很成问题。一般只能通过include file的方式。 <br />
可以借鉴的思路。(1) JSPLet 的入口是JSP文件，这一步的URL到处理程序的映射是Servlet/JSP Container自然支持的。这是免配置的。(2) 丰富的URL参数定义，良好的对象方法寻址能力。 <br />
<br />
我开发的开源Web框架lightweb，将具备如下特性： <br />
(1) 支持两个层次的编程接口。 <br />
interface Action { void service(request, response, servletContext); } <br />
这个Action比Struts Action, <strong>Spring</strong> MVC Controller高一个级别。相当于Dispatcher, 相当于JSPLet的JSP控制文件。这个用来做最外层的入口控制。 <br />
同时，也支持简单的JavaBean.method的直接调用。相当于<strong>WebWork</strong> Action，JSPLet Registered Object。这个用来做具体的事情。 <br />
<br />
(2) 支持丰富的对象寻址URI，比如http://my.com/myProject/myModule/myEntry.action?object=calculator&amp;method=add&amp;p1=1&amp;p2=3 <br />
这表示要通过 myEntry.acion这个入口，调用caculator.add(1, 2)方法。 <br />
如果用URL Rewriter可以美化为 <br />
<a href="http://my.com/myProject/myModule/myEntry/calculator/add/1/3" target="_blank"><font color="#004377">http://my.com/myProject/myModule/myEntry/calculator/add/1/3</font></a> <br />
看起来就很象XLink + XPointer了。 <br />
<br />
(3) 免配置。或者说极少的配置。 <br />
框架根据一定的匹配准则，把myModule/myEntry.action映射到 <br />
com.mycompany.mymodule.MyEntryAction 这个类的service方法。 <br />
这个service方法负责根据object, method的名字，寻找到对应的bean，并根据参数进行属性设置验证，并执行对应的bean.method。然后，把这个bean作为Model和template结合，输出结果。 <br />
同样，template的获取也是根据一定的匹配准则，根据myModule/myEntry找到 <br />
Mymodule/myentry.html 或者Mymodule/myentry/calculator.html。 <br />
<br />
这样的lightweb就能够同时对应简单和复杂。复杂控制的需求交给Action接口来做，简单的一般具体任务交给普通Java Bean去做。 <br />
Web框架层可以做的非常复杂，可以做的非常简单。Lightweb的目标，就是分成多个简单的部分；各部分合起来就能够完成从非常简单到非常复杂的需求。 <br />
接下来，我们来看O/R。 <br />
<br />
<br />
</p>
<p><span style="font-size: 18pt"><strong>7．O/R <br />
</strong></span><br />
Hibernate, EJB Entity Bean产品，JDO产品，iBatis是比较流行的几种O/R Mapping Framework。 <br />
我做的一些工作中，经常涉及到复杂的优化过的native SQL，并且涉及到大量的批量复杂逻辑处理，现有的O/R框架都不能满足功能和性能要求。 <br />
<br />
我做出这样一个lightor框架，思路借鉴了Martin Fowler的《企业架构模式》里面讲述的一些O/R的Row Mapper, Column Mapper等概念。 <br />
<br />
最经典的用法是： <br />
ResultSet rs = ps.executeQuery( a long complex native sql); <br />
//will return a lot of records <br />
A a = new A(); <br />
B b = new B(); <br />
IMapper aMapper = MapperService.getMapper(A.class); <br />
IMapper bMapper = MapperService.getMapper(B.class); <br />
<br />
While(rs.next()){ <br />
aMapper.populate(a, rs); <br />
bMapper.populate(b, rs); <br />
<br />
businessLogic(a, b); <br />
} <br />
<br />
可以看到，Lightor不需要一下子把所有纪录都放到一个Object List里面。完全可以随取随用。整个过程中，a, b只有一份，极大的节省了空间、时间，也极大的提高了开发效率，减少了重复代码。 <br />
没有任何一个其它O/R能够支持这种用法。这里面，lightor的mapper的populate方法需要ResultSet参数。一般的O/R不屑于这么做的，别说ResultSet，连Connection都想包装起来不给你看。 <br />
<br />
Lightor的设计思路也是同时应对简单和复杂。Lightor的Mapper实体部分是自动生成代码。类似于JDO的静态Enhance。不同的是，JDO静态Enhance直接修改bean class。而Lightor则不动原有的bean，只是多生成了对应的Mapper Source/Class。这种方式是最利于跟踪调试的。至于发布部署，和JDO的情况差不多，不如Hibernate的动态代码增强。 <br />
这里我很羡慕Python, Ruby等动态解释语言的 <br />
<br />
这一层我主要关注的是性能，缓存策略等等，而不是简便。我觉得，一个应用系统的瓶颈主要存在于O/R, DB层。不应该单纯为了追求OO结构的优雅，或者编程的方便，而牺牲了一些可能优化的地方。 <br />
<br />
关于Lightor的缓存策略, 我的Blog上有几篇文章。 <br />
<a href="http://blog.csdn.net/buaawhl" target="_blank"><font color="#004377">http://blog.csdn.net/buaawhl</font></a> <br />
<br />
数据库对象的缓存策略 <br />
<a href="http://blog.csdn.net/buaawhl/archive/2004/12/21/224184.aspx" target="_blank"><font color="#004377">http://blog.csdn.net/buaawhl/archive/2004/12/21/224184.aspx</font></a> <br />
<br />
分页 &amp; QueryKey &amp; 定长预取 <br />
<a href="http://blog.csdn.net/buaawhl/archive/2005/01/08/245005.aspx" target="_blank"><font color="#004377">http://blog.csdn.net/buaawhl/archive/2005/01/08/245005.aspx</font></a> </p>
<p><br />
<br />
<span style="font-size: 18pt"><strong>8．总结 <br />
</strong></span><br />
我理想中的Web开发架构是这样的： <br />
开发速度快，运行速度快，结构清晰优雅。 <br />
具体到每一层。 <br />
Web框架层主要追求 开发速度快。 <br />
O/R层主要追求 运行速度快。 <br />
页面资源层和页面模板层主要追求 结构清晰优雅。</p>
<img src ="http://www.blogjava.net/Javawind/aggbug/177939.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Javawind/" target="_blank">kooyee</a> 2008-01-26 19:18 <a href="http://www.blogjava.net/Javawind/archive/2008/01/26/177939.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>