Java Web框架汇总
Upcoming SlideShare
Loading in...5
×
 

Java Web框架汇总

on

  • 4,663 views

 

Statistics

Views

Total Views
4,663
Views on SlideShare
4,659
Embed Views
4

Actions

Likes
1
Downloads
60
Comments
0

1 Embed 4

http://www.uniquesoft.cn 4

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Java Web框架汇总 Java Web框架汇总 Document Transcript

    • 刊 号 本期推荐 Struts 最佳实践 J2EE模板技术 Java 创 对话:Web技术的思考 2004.12 J2EE Web框架汇总 E M A G . C S D N . N E T
    • Java eMag I’m loving it James Gosling, Inventor of Java Te
    • echnology
    • 篇首寄语 带着满身的风尘,笔者从 提升水平,才有可能逐渐摆脱 上海回到了北京。这时,我们 位于产业链末端的尴尬境地。 的第一期Java电子杂志也即将面 CSDN电子杂志正是希望为所有 世了。 中国程序员提供一个交流的平 台,我们的Java电子杂志也正是 在刚刚落幕的BEA eWorld 思想激烈碰撞的产物。也许它 2004大会上,笔者有幸见到了 还有很多不足之处,但我们毕 BEA的多位技术专家和高层管 竟上路了。 理人士。作为CSDN的代表,我 向他们提出了同一个问题:对 作为一个职业编辑,看着 中国软件开发者的印象如何? Java电子杂志的几位业余编辑制 中国程序员还有什么差距?有 作这份杂志是件饶有兴味的事 趣的是,他们无一例外地告诉 情。我本可以给他们更多的帮 笔者:中国程序员的技术能力 助,但我更愿意给他们少许建 和聪明才智令人折服;但中国 议,然后看着他们自己摸索前 程序员最大的缺陷在于经验和 进。其实不仅这份杂志,我们 交流。 大家的技术之路、职业之路又 何尝不是在不断的挫折和迂回 是的,经验和交流,这 中摸索前进?所以,希望每个 是我们最欠缺的。据统计, 看到这份电子杂志的人都尽可 北美的职业程序员平均年龄为 能地参与进来,不管是提出意 37.5岁,而中国大约为26岁。相 见和建议、写作投稿、或是加 比之下,我们少了10年的实践 入编辑团队,甚至哪怕只是给 经验,所以我们的技术、我们 我们一些精神上的鼓励,请你 的软件行业才显得那么稚嫩, 参与进来,让这份杂志也能在 那么不成熟。而年轻往往又同 我们所有人的交流与协作中不 时伴随着气盛,所以我们才看 断进步。 到了那么多的争吵、那么多的 浮躁。 希望我们的Java电子杂志会 越来越好。希望我们每个人的 为了弥补10年的差距,我 前途都会越来越好。 主编的话 们只能寄望于更多、更主动的 交流。只有大家都能把自己的 透明 实践经验和知识积累与所有同 行分享,我们才有可能更快地 2004年12月18日凌晨·北京
    • 目 录 9. Web技术史话 CSDN eMag项目 Java电子杂志 15. Servlet规范简介 主办 CSDN.NET 官方站点 http://www.csdn.net 20. 主编 透明 责任编辑 awaysrain Struts最佳实践 anders totodo jerrykey 27. 大阿福 剑 一笑 Java Web 框架汇总 枯木 站点支持 emag.csdn.com 39. Java 模板技术 44. Rich Client 技术简介 48. 对话:Web技术的思考 49. JPetStore项目分析: 一个典型的J2EE应用 版权声明 本刊所有文章版权属作者所 Web层的实现 有,未经允许,不得以任何 方式转载、复制或翻印。 CSDN和eMag标示为csdn. net所拥有。
    • 关于我们 熊节 [ 透明 ] CSDN网站Java频道主编,J2EE架构师,Java程序员 联系方式 xiongjie@csdn.net 个人Blog http://gigix.blogdriver.com 擅长的技术领域 Java编程和系统架构 个人作品 翻译《最后期限》、《重构》、《软件工艺》、《与熊共 舞》等书 林仪明[anders] 翼华科技(厦门)有限公司 联系方式 yimlin@163.com 擅长的技术领域 Java Web应用开发/.Net Web应用开发 张凯峰[大阿福] IT技术爱好者,现就职于国内一大型软件公司 联系方式 QQ:1836566 擅长的技术领域 J2SE 个人作品 《谁动了我的电脑》主编 Introduce 陈玉泉[枯木 cyqxyz] 普通程序员,喜编程,常乐此不疲;好读书,却不求甚 解,故但凡神交于各方名士,仅有小得,而无大成;胸存 点墨,而心无大志,惟愿宁静淡泊而已。 联系方式 cyqxyz@163.com cyqxyz@msn.com 个人Blog http://cyqxyz.china-pub.com 擅长的技术领域 J2SE、Servlet、JSP。
    • 关于我们 石红军[awaysrain,绝对零度] csdn Web开发大版主,scjp,熟悉web开发技术,对java有浓厚的兴 趣。曾有三年的统计行业软件经验,最近在一家软件公司做 电子商务方面的工作。 联系方式:xiaohong1999@sina.com,hongjunshi@gmail.com 个人Blog:http://blog.csdn.net/awaysrain 擅长的技术领域:web开发 戴悦 大连灵溢信息咨询有限公司技术部负责人。 联系方式:Jerrykey1980@hotmail.com 擅长的技术领域:精通JAVA网络程序开发,了解J2EE,了解Struts,精通 Mysql、SQL Server数据库 张礼[totodo] 从事企业应用,有3年的开发经历 联系方式 totodo@vip.sina.com 擅长的技术领域 j2ee相关。 [ ] Introduce 联系方式 全新组合 首次亮相 希望可以得到您的支持和鼓励。也欢迎您加入到我们的队伍 中来,共同开创我们自己的技术天地
    • 好书推荐 The Java Developers Guide to Core J2EE Patterns, Second Java编程艺术 Edition 原版进口 原书名:The Art of Java Eclipse 原版进口 Core J2EE Patterns, Second 链接:http://www.dearbook. The Java Developers Guide to Edition com.cn/book/viewbook.aspx?pn Eclipse 链接:http://www.dearbook. o=TS0027258&indexPageForw com.cn/book/viewbook. ard=1 链接:http://www.dearbook. aspx?pno=TS0026897 作者:[美]Herbert Schildt, James com.cn/book/viewbook. Holmes 作者:Alur, Deepak/ Malks, 译者:邓劲生 aspx?pno=TS0026898 Dan/ Crupi, John 出版社:清华大学出版社 作者:Shavor, Sherry/ 出版社:Pearson 版别版次:2004年9第1版第1次 原出版社: Pearson Education 印刷 D’Anjou, Jim/ Fairbrother, ISBN书号:0131422464 ISBN书号:7-302-09054-8 Scott/ Kehn, Dan/ Kellerman, John/ McCarthy, Pat 出版社:Pearson ISBN书号:0321159640
    • Web技术史话 Web技术史话 Anders*小明 荒芜年代 1990-1992 帝国时代和封建诸侯 1993-1996 工业文明 1996-1999 多元文化 2000-2004 新技术革命——XML及其相关 大事记 1. 荒芜年代 1990-1992 CGI1.0草案。 陆续加入了CGI编程语言的行 列。1996年微软带来了ASP。 1990年,HTML标记的出 web开发终于迎来了它的第 现。 二次重大飞跃。伴随着CGI, 关键字:脚本语言。 带来web的动态处理能力。 这标志着Web开发时代的到 CGI就是这个时代的国王。这 技术特性:脚本代码和页面 来,B/S模型开始在之后的岁 个国度下的人们编写着一个个 显示混合,面向过程,解释程 月中,不断的发展壮大,攻城 CGI程序,把标准输入重定向 序,线程运行,调试困难。 略地蚕食着传统C/S的领域。 为http请求,处理请求数据, 把标准输入重定向http响应。 3. 工业文明 1996-1999 如同所有的新生事物一样, C语言一度统治了这个世界。 在web的史前岁月,web的开 1997年,Sun公司推出 发技术在html标记诞生后,无 关键字:CGI。 Servlet规范。Java阵营终于迎来 论是在服务端还是客户端都缓 了自己的web英雄。1998年, 慢的发展着。在相当长的一个 技术特性:实现了客户端 JSP技术诞生。Servlet和JSP的 时间内,它并未象今天这样辉 和服务端的动态交互,在程序 组合(还可以加上JavaBean技 煌。甚至于只是静态的文本标 代码写html标记,面向过程的 术)让Java开发者同时拥有了 识。 开发方式,应用程序,多进程 类似CGI程序的集中处理功 运行。 能和类似PHP的HTML嵌入 关键字:HTML。 功能,此外,Java的运行时编 C语言的帝国在短暂的 译技术也大大提高了Servlet和 技术特性:静态文本显示, 辉煌后,迅速灭亡。1994年 JSP的执行效率 表现力和交互能力不足。 Rasmus Lerdorf举起PHP大旗打 响革命第一战,1995年第一个 关键字:servlet,jsp。 2. 帝国时代和封建诸侯 1993- 用Perl写得程序诞生,很快, 1996 Perl在CGI编程领域的风头就盖 技术特性:代码和页面显 过了它的前辈C语言。随后, 示混合,线程运行,运行时编 1993年,NCSA提出了 Python等著名的脚本语言也 译。
    • 热情 Passion JAVA M A G A Z I N E _ F R O M _ C S D N . N E T
    • Web技术史话 1998年, Sun发布了EJB Web开发模型从Model 1 发展为 2003年微软提出XAML。 1.0标准。1999年,Sun正式发 Model 2(MVC)。 布了J2EE的第一个版本。紧接 关键字:rich client 着,遵循J2EE标准,为企业级 无论是开始的CGI,还是后来 应用提供支撑平台的各类应 的ASP,PHP甚至是Servlet都是页 技术特性:以DHTML、CSS和 用服务软件争先恐后地涌现了 面控制器模式,每个页面都知道 A c t i v e X 、 A p p l e t 所 代 表 的 Thin 出来。(同时2001年微软发布 本页面所需数据控制对象。基于 Client技术交互能力毕竟有限,人们 ASP.NET技术) Servlet发展了一批前端控制器模型 需要更丰富的交互能力,这催生了 系统,所有请求都转发到一个统一 Rich Client技术——利用XML描述 关键字:企业开发。 的控制程序上,经过处理后把数据 客户端界面,而不仅仅是HTML或 转发到某个特定页面上,Java下的 DHTML;同时引入新的交互方式 技术特性:Web开发从简单 Struts,Spring MVC和Turbine等都 Web Services。Mozilla下XUL技术 的信息展示变成企业电子商务 是代表。 以及微软的XAML都是代表。 应用,融入了系统开发中。开 发视角从单一的页面转向全站管 MVC的发展也演变出了——推 6. 新 技 术 革 命 —— 理;开发的关注点也从单一页面实 技术与拉技术。 XML及其相关 现转向系统功能实现,页面只是作 为用户交互的表现层存在系统中, 以Struts,Spring MVC和 1998年,W3C正式发布了XML 依然重要但已经不是唯一的关注 Turbine为 代 表 的 是 推 技 术 。 而 1.0标准。XML语言对信息的格式 点。 Tapestry和微软的ASP.NET则带来 和表达方法做了最大程度的规范, 了拉技术。 应用软件可以按照统一的方式处理 所有XML信息。 伴随着推技术和拉技术的发 客户端技术: 展,在视图技术发展出不同方向: 1999年 , W3C制 定 出 了 XSLT标 准 , 用 以 将 XML信 息 转 1996年 和 1997年 是 客 户 端 推技术的需求下,模板技术 换 为 HTML等 不 同 的 信 息 展 现 形 技术的重要年份,在这两年中 开始红火地发展起来,Velocity和 式;同年其研究小组提出了RDF( 产生影响深远的技术:W3C提出 JDynamic就 是 的 代 表 。 无 论 是 Resource Description Framework) 了 C S S 的 建 议 标 准 ; Netscape推 ASP下的模板技术,PHP模板技术 标准草案。RDF在XML语法的基础 出 自 己 的 html扩 展 , 支 持 还是新的开发模型的引入包括前端 上,规定了元数据的存储结构和相 JavaApplets和JavaScript,同 控制器和新页面控制器,都使用同 关的技术标准。 时引入了QuickTime插件;IE支 一处理技术——占位符动态替换技 持 DHTML和ActiveX控件的功能; 术。模板引擎在解释模板时通过占 2000年 , W3C发 布 SOAP( Macromedia推出Flash。 位别名在内存查找对应的数据,并 Simple Object Access Protocol)协 替换到视图中。当然,不同模板技 议的1.1版。2001年,W3C发布了 关键字:动态交互。 术,其模板语言是和其对模板文件 WSDL(Web Services Description 的处理都是不一样的。 Language)协议的1.1版。SOAP协 技术特性:在比与服务器动态 议 和 WSDL协 议 共 同 构 成 了 Web 交互晚了多年后,客户端自身与用 而在拉技术的带领下,引 Service的基础。 户交互能力得到大大加强。不仅如 入Web开发组件技术。Java下的 此,applet和activex(特别是微 Tapestry框架,JetSpeed所代表的 2001年 , W3C又 开 始 着 手 软xmlhttp)以及后来的mozilla的 Portal和Sun公司大力推广的JSF, 制定OWL(OWL Web Ontology xmlhttprequest更带来了客户端从 以及微软的ASP.Net都大力发展了 Language) 标 准 。OWL语言是一 被动与服务端交互到具有主动交互 Web Component的开发模型。 种 基 于 XML的 语 言 , 它 比 RDF更 能力。 加深入、细致地描述信息内容。 2003年 , W3C成 立 了 语 义 化 Web 5. 多元文化 2000-2004 Service研究小组(Semantic Web 客户端技术: Services Interest Group),研究在 2001年,Struts1.0发布。 Web Service中加入语义技术的相 2000年, Mozilla发布XUL0.6; 关 问 题 。 2004年 2月 , W3C宣 布
    • 专业 Professional JAVA M A G A Z I N E _ F R O M _ C S D N . N E T
    • Web技术史话 RDF和OWL标准正式成为W3C的建 1996年Netscape 2.0版中支 1996年Microsoft借鉴PHP的 议方案。 持JavaApplets和JavaScript 思想,在其Web服务器IIS 3.0中 引入了ASP技术 1996年W3C提出了CSS的建 议标准,同年,IE 3.0引入了 1997年CGI1.2也被纳入了议 7. 大事记 对CSS的支持 事日程 1990 HTML标记出现 1996年W3C在SGML语言的基 1997年Servlet技术问世 础上,提出了XML语言草案 1993年CGI 1.0的标准草案 1998年JSP技术诞生 由NCSA提出 1997年Microsoft发布了IE 4.0,支持 DHTML 1998年W3C正式发布了XML 1994年Rasmus Lerdorf发 1.0标准 明了专用于Web服务端编程的 1996年插件开发方式开 PHP语言 始风靡了浏览器的世界。 2000年W3C发布SOAP( Netscape 2.0引入了对 Simple Object Access 1995年Java诞生 QuickTime插件的支持, 同年 Protocol)协议的1.1版 IE 3.0正式支持在HTML页面中 1995年NCSA开始制定CGI 插入ActiveX控件的功能 2001年ASP.NET技术诞生 1.1标准 1996年Macromedia收购了 1995年第一个用Perl写成的 FutureWave,并将Jonathan CGI程序问世 Gay的发明改名为Flash
    • 技术 Technology JAVA M A G A Z I N E _ F R O M _ C S D N . N E T
    • Servlet规范简介 Servlet规范简介 awaysrain web框架是如何注入到Servlet中的 Web框架一般是通过一个Servlet提供统一的请求入口,将指定的资源映射到这个servlet,在这个servlet中进行 框架的初始化配置,访问Web页面中的数据,进行逻辑处理后,将结果数据与的表现层相融合并展现给用户。 WEB框架想要在符合Servlet规范的容器中运行,同样也要符合Servlet规范。 将一个WEB框架注入到一个servlet中,主要涉及到Servlet规范中以下部分:  部署描述符  映射请求到Servlet  Servlet生存周期  请求分发 部署描述符 部署描述符就是位于WEB应用程序的/WEB-INF目 录下的web.xml的XML文件,是WEB应用程序不可分割 的部分,管理着WEB应用程序的配置。部署描述符在 应用程序开发人员,应用程序组装人员,应用程序部署 人员之间传递WEB应用程序的元素和配置信息。 在WEB应用程序的部署描描述符中以下类型的配 置和部署信息是所有的servlet容器必须支持的:  ServletContext初始化参数  Session配置  Servlet声明  Servlet映射  应用程序生存周期监听器  Filter的定义和映射  MIME类型的映射  欢迎文件列表  错误文件列表 出现在部署描述符中的安全信息可以不被支持, 除非这个Servlet容器是J2EE规范实现的一部分。 所 有 正 确 的 WEB应 用 程 序 部 署 描 述 符 (Servlet2.3规范)必须包含下面的DOCTYPE声明: <!DOCTYPE web-app PUBLIC “-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN” “http://java.sun. com/dtd/web-app_2_3.dtd”> 下面说明在部署描述符中是如何进行Servlet声明 和映射的,这个DTD的全部内容可以在下面这个地 址获得: http://java.sun.com/dtd/web-app_2_3.dtd 在这个DTD中有关Servlet声明和映射和映射的部 分如下:
    • Servlet规范简介 <!-- catalog的Servlet,它的实现类为com.mycorp. The servlet element contains the CatalogServlet,并且带有一个catalog参数,参数 declarative data of a 值为Spring,所有向/catalog/*的请求都被映射到 servlet. If a jsp-file is specified and the 名称为catalog的Servlet。 load-on-startup element is present, then the JSP should be precompiled and loaded. Used in: web-app 映射请求到Servlet --> <!ELEMENT servlet (icon?, servlet-name, 接收到一个请求后,WEB容器要确定转到哪一个 display-name?, description?, WEB应用程序。被选择的应用程序的最长的上下文路 (servlet-class|jsp-file), init-param*, 径必须和请求的URL开始部分匹配。URL匹配的部分 load-on-startup?, runas?, 是映射到Servlet的上下文路径。 security-role-ref*)> WEB容器下一步必须按照下面的程序定位处理请 <!-- 求的Servlet。 The servlet-class element contains the 用来映射到Servlet的路径是请求对象的URL减 fully qualified class name 去上下文的路径。下面的URL路径映射规则按顺序执 of the servlet. 行,容器选择第一个成功的匹配并且不在进行下一 Used in: servlet 个匹配: -->  容器试着对请求的路径和Servlet的路径 <!ELEMENT servlet-class (#PCDATA)> 进行精确匹配,如果匹配成功则选择这个 <!-- Servlet。 The servlet-mapping element defines a  容器会循环的去试着匹配最长的路径前缀: mapping between a servlet 把’/’当作路径分隔符,按照路径树逐级 and a url pattern 递减的完成,选择最长匹配的Servlet。 Used in: web-app  如 果 这 个 U R L 路 径 的 最 后 有 扩 展 名 (比 --> 如.jsp),Servlet容器会试着匹配处理这个 <!ELEMENT servlet-mapping (servlet-name, 扩展名的Servlet。 url-pattern)>  如果前面的没有与前面三条规则相匹配的 <!-- Servlet,容器会试着为资源请求提供适 The servlet-name element contains the 当的资源,如果有“默认”的Servlet定义 canonical name of the 给这个应用程序,那么这个Servlet会被使 servlet. Each servlet name is unique within 用。 the web application. Used in: filter-mapping, servlet, servlet- 容器必须使用一个大小写敏感的匹配方式。 mapping 在部署描述符中,用下面的语法定义映射: -->  一个以’/’开始并且以’/*’结束的字符 <!ELEMENT servlet-name (#PCDATA)> 串用来映射路径。  一个以’*.’为前缀的字符串用来映射扩展 根据以上DTD,一个典型的Servlet的声明的格式如 名。 下:  一个只包含’/’的字符串指示着这个应用 <servlet> 程序“默认”的Servlet,在这种情况下, <servlet-name>catalog</servlet-name> servlet的路径是请求的URI减去上下文路 <servlet-class>com.mycorp.CatalogServlet</ 径,并且这个路径是null。 servlet-class>  所有其他的字符只用来精确匹配。 <init-param> 如果容器内置JSP容器,那么*.jsp被映射到 <param-name>catalog</param-name> 这个容器,并允许JSP页面在需要的时候被执行。 <param-value>Spring</param-value> 这种映射叫做隐含映射。如果WEB应用程序中定义 </init-param> 了*.jsp的映射,那么这个映射有比隐含映射高的优 </servlet> 先级。 一个典型的Servlet映射如下: WEB容器允许显式的声明隐含映射以获得优先 <servlet-mapping> 级,例如,*.shtml的隐含映射可以在服务器上被映 <servlet-name>catalog</servlet-name> 射为包含功能。 <url-pattern>/catalog/*</url-pattern> 映射实例: </servlet-mapping> path pattern servlet /foo/bar/* servlet1 /baz/* servlet2 通过上面的方法,我们就声明了一个名称为 /catalog servlet3 *.bop servlet4
    • Servlet规范简介 下面是实际请求映射的结果 这个接口定义了初始化一个servlet,服务请求和从 incoming path servlet handling request 容器中移除servlet的方法。他们按照下面的顺序执 /foo/bar/index. servlet1 行: html 1. servlet被实例化后,用init方法进行初始化 /foo/bar/index. servlet1 2. 客户端的任何请求都调用service方法 bop /baz servlet2 3. servlet被移除服务,调用destroy方法销毁 /baz/index.html servlet2 /catalog servlet3 /catalog/index. “default” servlet html /catalog/ servlet4 racecar.bop /index.bop servlet4 请注意/catalog/index.html 和/catalog/ racecar.bop这两种情况,因为是精确匹配,所以并 没有映射到处理/catalog的servlet。 Servlet生存周期 servlet的生存周期如下图: 在 介 绍 Servlet的 生 存 周 期 之 前 需 要 先 介 绍 一 下 javax.servlet.Servlet接口。所有的Servlet必须实现或者间 接实现这个接口,我们通常可以通过继承javax.servlet. 请求分发 GenericServlet或者javax.servlet.http.HttpServlet.类来实现 这个接口。 请求分发可以让一个Servlet把请求分配到另外一个 这个接口中定义了下面5种方法: 资源,RequestDispatcher接口提供了实现他的机制。可 public void init(ServletConfig config); 以通过下面两种方式从ServletContext中获得一个实现了 public ServletConfig getServletConfig(); RequestDispatcher接口的对象: public void service(ServletRequest req, • getRequestDispatcher ServletResponse res); • getNamedDispatcher public String getServletInfo(); getRequestDispatcher方法接受一个指向目标资源的 public void destroy() ; URL路径 RequestDispatcher rd = getServletContext(). init()方法 getRequestDispatcher(“/catalog”); init方法在容器器装入Servlet 时执行,Servlet容器 在实例化后只调用一次init方法, init方法必须在 getNamedDispatcher方法接受一个Servlet名称参 servlet接收到任何请求之前完成。 数,这个名称是在部署描述符中<servlet-name>元素指 这个方法通常用来进行一些资源的管理和初始化, 定的那个名称。 如从配置文件读取配置数据,读取初始化参数,初 RequestDispatcher rd = getServletContext(). 始化缓冲迟等一次性的操作。 getNamedDispatcher (“catalog”); getServletConfig()方法 GetServletConfig方法返回一个 ServletConfig 对 象,该对象用来返回这个Servlet的初始化信息和启 RequestDispatcher接口有两个方法,允许你在调用 动参数。返回的是传递到init方法ServletConfig。 的servlet完成初步处理后把请求响应分配到另外一个资 Service()方法 源, Service方法是应用程序逻辑的进入点,是servlet方 forward()方法: 法的核心,WEB容器调用这个方法来响应进入 public void forward(ServletRequest request, 的请求,只有servlet成功被init()方法初始化后, ServletReponse reponse) throws SwerletException,IOExce Service方法才会被调用。 ption getServletInfo()方法 forward方法上让你把请求转发到另外的Servlet或者 这个方法返回一个字符串对象,提供有关servlet 的 jsp或者html等资源,由这个资源接下来负责响应。如: 信息,如作者、版本等。 RequestDispatcher rd = getServletContext(). destroy()方法 getRequestDispatcher(“/catalog”); destroy方法在容器移除Servlet 时执行,同样只执行 rd. forward(request,response); 一次。这个方法会在所有的线程的service()方法执 行完成或者超时后执行,调用这个方法后,容器不 include()方法: 会再调用这个servlet的方法,也就是说容器不再把 public void include (ServletRequest request, 请求发送给这个Servlet。 这个方法给servlet释放 ServletReponse reponse) throws SwerletException,IOExce 占用的资源的机会,通常用来执行一些清理任务。 ption include方法让你的Servlet响应中包含另外一个资源
    • Servlet规范简介 生成内容 的controller组件 com.opensymphony.webwork. RequestDispatcher rd = getServletContext(). dispatcher.ServletDispatcher来处理。这个担任 getRequestDispatcher(“/catalog”); 控制器组件的Servlet在他的service()方法中在根据 rd. include(request,response); 请求的路径解析出对应的action来进行处理。 通 过 上 面 的 的 处 理 , 实 现 了 将 web请 求 转 到 了 webwork中的控制器 ServletDispatcher。不止是 webwork,实现MVC的web框架都需要进行类似的处理来 将web请求转入到自己的controller.以便进行进一步的处 结合WebWork的具体分析 理。 WebWork是由OpenSymphony组织开发实现MVC模 式的J2EE Web框架。在介绍完servlet规范的相关内容 Servlet生存周期 后,我们看看WebWork是如何注入到一个Servlet中的, 假设我们有一个上下文环境为“/WebWorkdDemo”的 ServletDispatcher这个Servlet的存周期可以 WEB应用。 如下: 1) 在 服 务 器 启 动 的 时 候 , 容 器 首 先 实 例化 ServletDispatcher 部署描述符 2) 实例化完成后,将调用init()方法,在init方 法中执行了以下操作: 在部署描述符中,我们需要进行如下配置:  初始化Velocity引擎 <servlet>  检查是否支持配置文件重新载入功能。 <servlet-name>webwork</servlet-name> 如果支持,每个request请求都将重新装 <servlet-class>com.opensymphony. 载xwork.xml配置文件,在开发时非常方 w e b w o r k . d i s p a t c h e r . 便。 ServletDispatcher</servlet-class>  设置一些文件上传的信息,比如:上传临 </servlet> 时目录,上传的最大字节等。 …… 3) 每 次 请 求 都 调 用 s e r v i c e ( ) 方 法 ,在 <servlet-mapping> service方法中执行了以下方法 <servlet-name>webwork</servlet-name>  通过request请求取得action的命名空间 <url-pattern>*.action</url-pattern>  根据servlet请求的Path,解析出要调用该请 </servlet-mapping> 求的Action的名字(actionName) 我们声明了一个名为webwork的Servlet和*.  创 建 Action上 下 文 ( extraContext), action到这个Servlet的映射,这个Servlet就是 遍历HttpServletRequest、HttpSession、 ServletContext 中的数据,并将其复制到 webwork中的controller,担任MVC框架中非常重 Webwork的Map实现中,至此之后,所有 要的控制器角色。 数据操作均在此Map结构中进行,从而将 内部结构与Servlet API相分离。  以 上 述 信 息 作 为 参 数 , 调用 映射请求到Servlet ActionProxyFactory创 建 对 应 的 ActionProxy实 例 。 ActionProxyFactory 在XWork的配置文件xwork.xml中有如下片段: 将根据Xwork 配置文件(xwork.xml) <action name=”demo” class=” webworkapp. 中 的 设 定 , 创 建 A c t i o n P r o xy 实 例 , DemoAction”> ActionProxy中包含了Action的配置信息( <result name=”success” 包括Action名称,对应实现类等等)。 type=”dispatcher”>  执行proxy的execute()方法 4) 容器移除Servlet 时执行destroy(),在 <param name=”location”>/demo.jsp</ ServletDispatcher这个Servlet中并没有 param> 重写destroy方法,在移除Servlet时,将什 </result> 么也不做。 </action> 这样我们由http://localhost:8080/ WebWorkDemo/demo.action这个URL向服务 请求分发 器发出请求时,WEB容器首先确定转到哪一个 WEB应用程序,容器将请求URL和上下文环境 WebWork提供了多种活灵活视图展现方式,例如还 进行匹配后知道将转到/WebWorkdDemo这个 是我们上面在xwork.xml中的配置: WEB应用。 接下来容器会在/WebWorkdDemo这个应用的部 署 描 述 符 中 进 行 查 找 处 理 这 个 请 求 的 servlet, 根 据 后缀 *.action 找到名称为webwork这个Servlet,这 样 根 据 部 署 描 述 符 , 这 个 请 求 被 映 射 到 webwork中
    • Servlet规范简介 <action name=”demo” class=” webworkapp. DemoAction”> <result name=”success” type=”dispatcher”> <param name=”location”>/demo.jsp</ eMag :Java杂志 param> </result> </action> 第二期征稿启事 根据以上配置当DemoAction的返回值 为"success"时的处理类型为"dispatcher",当 CSDN社 区 电 子 杂 志 项 目 是 全 社 区 的 项 目 , result的type为"dispatcher"时,通过javax.servlet. Java电子杂志只有依靠大家的支持,才能够发展下 RequestDispatcher的forward()或include()方法将处 去。因此,现在面向全社区征集Java电子杂志第二期 理结果和表现层融合后展现给用户 的相关稿件。 我们可以看看WebWork提供的dispatcher类 本启事主要描述了Java杂志第二期的主题以及稿 型Result Type的实现类 com.opensymphony 件内容要求。这是我们的近期目标。我们同时还给出了 .webwork.dispatcher.ServletDispatcherResult中的 一些备选主题,供大家选择。这是我们的长期目标。围 绕着这些主题的文章,会陆续出现在第二期以后的各期 代码片断: Java杂志中。所以,您完全可以选择自己感兴趣的方 HttpServletRequest request = ServletActionContext. 向来投稿。一旦您的稿件被我们采用,您将会得到我们 getRequest(); 对文章作者的奖励。如果您的稿件没有被我们采用,我 HttpServletResponse response = ServletActionContext. 们也会及时地通知您。 getResponse(); Java杂 志 第 二 期 的 主 题 是 : “ 深 入 剖 析 J2SE RequestDispatcher dispatcher = request.getRequestDisp 1.5新特性”。 atcher(finalLocation); 我们的计划是:精选一些J2SE 1.5新特性,然后 组织一系列文章分别加以深入的剖析和阐述。 if (dispatcher == null) { 我们选择的特性如下: response.sendError(404, “result ‘” + finalLocation + “’ 1、元数据。 not found”); 2、Generic Types。 return; 3、自动装箱和拆箱。 } 4、循环方法的加强。 5、静态引入。 if (!response.isCommitted() && (request. 6、格式化输入/出。 getAttribute(“javax.servlet.include.servlet_path”) == 7、可变参数列表。 null)) { 8、并发工具,线程处理API。 request.setAttribute(“webwork.view_uri”, 9、监控和管理相关的内容,包括JMX MBeans, finalLocation); JVMTI等等。 request.setAttribute(“webwork.request_uri”, request. 10、客户端的改进,比如Swing相关的改进。 getRequestURI()); 11、XML支持的改进。 12、支持补充字符。 dispatcher.forward(request, response); 13、增强的JDBC RowSets支持。 } else { 当然,肯定还存在一些您认为很有趣,但却没有在 dispatcher.include(request, response); 这里列出来的特性。没有关系,您完全可以把您的文章 } 发给我们,我们深表欢迎,并会有专人负责审核您的文 ServletDispatcherResult类 的 从 章。 ServletActionContex中 得 到 HttpServletRequest和 我们的备选主题有: HttpServletResponse,然后调用request.getRequestDisp 1、容器 atcher(finalLocation)方法得到一个RequestDispatcher实 2、分布式组件 例,如果返回的是null,则输出404页面未找到的错 3、数据持久化 误,否则将调用dispatcher.forward(request, response)或者 4、Remoting和EAI dispatcher.include(request,w response)进行请求分发,将 欢迎大家为我们踊跃投 处理结果和表现层融合后展现给用户。 您可以先参考一下我们的《CSDN电子杂志作 南》 相关奖励措施敬请留意即将颁布的《CSDN社区电 子杂志项目奖励制度》。 结束语 通过以上的介绍,我们对web框架是如何注入 到servlet中有了简单的了解,如果想更深入的研究,可 以阅读Servlet规范以及一些成熟框架的源码。
    • Struts 最佳实践 totodo 背景: 4. 请做单元测试( 对于Struts 可采用 从本期的电子杂志内容介绍中,大家已经看 StrutsTestCase)。 到了web发展的整个历史, Struts 自从 2001 6月 5. 请了解,阅读 sun 的命名规范。 1.0 Release之后经历了漫长的春秋,有着庞大的用 户群体, 并且IBM, Tomcat Web控制台都采用了 1.Struts 之对象使用篇 Struts Framework.. Struts 版本换了好多了,,如果你只是使用最 Web框架有好多种选择,并不一定要使用 基本的Form,Action相信0.5 就够了,目前最为 Struts, 但如果你正刚开始使用的话,希望下面的一 流行的是1.1因此我们尽量使用1.1给我们带来的 些实践能给你带来帮助, 仅此而已。 所以,请原 便捷。 谅,本文没有什么实例代码, 因为今天早上,我的好 推荐: 友Leemassn 跟我说,这东西已经烂掉了:-( ,所以相 每写个应用都用继承 BaseAction ,和BaseForm 信阅读此文的读者对Struts基本用法已经有了一 (BaseAction 最好是继承LookupDispatchAction, 定了解, 业余时间和能力有限,以下写的内容 BaseForm 最好是继承ValidatorActionForm,这两 也均属纸上谈兵。也希望能抛砖引玉。 个都是从1.1开始有的) 正确是导向,才是使用Web Framework的真正 ValidatorActionForm也是继承ActionForm , 目的。倒并不是因为Struts 耳濡目染的多了,我们 因为1.1有了PlugIn,当你使用ValidatorPlugIn使 才一定要使用Struts ,并不是MVC就一定要使用 得你的FormBean具备了验证能力啦.   Struts ,当你能灵活游刃于粒度良好的数据持久 Validator也能算的上是Struts中比较精粹的一 层,业务层,展示层,清晰的划分好你的业务对 个东东,它能做到对你FormBean里的每个数据 象,规划好WEB数据的展现,能为你的Web应 类型做判断,实现了资源绑定,并且你可以自定 用留下可扩展的接口时候,这时候你已经比需要 义一些规则放在框架里使用,相信它会你的应用 特定的Framework了, 而Struts 只是为这些都做 程序增光不少。 自带了一些常用的基本数据类 了考虑,让你的MVC变得容易实现。 型校验,你可直接使用。 无论项目大或小,复杂或者简单,使用Struts的 由于要介绍的太多,具体使用方法可参见 一些建议: Apache 的Validator 项目,在Struts中,只需要在 1. 请选用支持广泛的JDO 或者Hibernate,或 Struts-config.xml里增加 者iBates,来做你的数据持久层。 2. 请加入Struts-el标签,(丰富你标签显示 <plug-in classname="org.apache.struts.validator. 时所需要逻辑)。 ValidatorPlugIn"> <set-property 3. 请尽可能通过JNDI连接数据库。
    • 法。 代码如下: protected Map getKeyMethodMap() { Map map = new HashMap(); map.put("button.add", "add"); map.put("button.delete", "delete"); return map; } public ActionForward add(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // do add return mapping. findForward("success"); } public ActionForward delete(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) property="pathnames" throws IOException, ServletException { value="/WEB-INF/validator-rules.xml,/WEB- // do delete INF/validation.xml"/> return mapping.findForward("success"); </plug-in> } (1.1 也同也有了 DynaActionForm,它的 JSP中: 作用就是不需要你写专门的ActionForm类,而 在Struts-Config文件中,但实际开发中,我们并 <html:form action="/test"> 不是简单的一个Form,我们可能要给Form做验 <html:submit property="action"> <bean:message key="button.add"/> 证,做初始化,还要增添一些方法,所以并不建 </html:submit> 议大量使用DynaActionForm) <html:submit property="action"> LookupDispatchAction 继承DispatchAction, <bean:message key="button.delete"/> 自己多加两个方法,就是getKeyMethod(),localM </html:submit> ap() ,它能帮你从本地submit的资源文件读取, </html:form> 比如submit 的名字是add或者delete,而你只管执 行submit就可以, 就能找到你的add方法delete方 2.Struts 之标签库篇.
    • Struts最佳实践 相信Struts是很讲究复用的 能还是很弱。 标签库主要还是用做View的,所以,在设计 推荐: ActionForm的时候大可大胆设计,别担心他们不 尽量使用EL标签(也可以引入JSTL):主要 能在jsp页面上很好的显示, 该是Date类型就 用于复杂的逻辑判断。 是,也可以使用List,Map ,这样的符合类型,也可 举个简单例子: 以是其他对象的引用,因为他们都能很方便的在 <logic:present name="yourForm" property="a"> ….< logic:present > 页面上显示。 虽然标签库也提供了逻辑判断,上面判断了 例:如果Test1Form包含了 各种Model对象, Class Test1Form extends ValidatorActionForm{ a属性是否存在, Student student //有Students 有id,name等属 但你又想知道a 是否等于1,怎么样头痛了 性 吧,换成el 那就是: Teach teach  //Teach对象有id, classid等属 <c:if test='${yourForm.a =="1" }'> ....</c:if> 性 List classes //一组Classes 对象 Classes又含 有 classid等属性 (不过也不要怀念你以前使用纯JSP的美好日 Test2Form test2form //另外一个ActionForm 子,JSP由于表达能力过强,(等于是Java代码的 有 attr2 等field 脚本显现),就担心你用它也过多的业务逻辑代 .... 码,使得你的程序难以阅读和维护。) }    [ 补充一些:对于前台的显示,,Struts标签不 得不说是似乎已经成了一根鸡肋, 美丽,容易操 那么,在JSP页面中你可以这样子: 作的的界面,往往要以来于其他技术,Struts的标签 <html:form action="/test1"> 使用的最大的目的也是为了方便于数据显示, 美 <bean:define name=”test1Form” 丽复杂操作还是要依赖你的Html与JavaScript]。 property=”test2Form” id=”test2” type=”com.yourcompony.Test2Form” /> 3.Struts之异常处理篇. <html:text name=”test2” property=”test2. 异常处理的基本原则: catch之后记录日志, attr2” /> 并且做处理,不能处理,则抛出。 <html:text name=”id” 基本上来讲,Struts 给异常处理提供了较为 property=”student.id”><html:text name=”name” property=”teach.name”> 完善的框架. <html:text name=”classid” 按道理讲,当一个系统正式交付的时候,,我 property=”classes[0].classid”> 们还让用户看到那些 一大串英文字母是一种极 </html:form > 端粗暴的行为, 所以,我们从两头抓起。 推荐: 先承认这样子的代码很难看,但只是想说 1 . 使 用 v a l i d a t i o n F o r m 做 可 验 证 的确 明,对于标签库,他能展示任何request中的对 formBean , 当然你也可以使用你积累下来比较丰 象,以及其引用对象。 富的javascript,而validationForm的好处就是,他 还有一个原则,如果上层标签中给一个对象 能帮你能在服务器端验证,如果应用系统对于数 定义id,那么那个id将被下层标签中作为name 来 据的校验教为严格,正应该使用FormBean。 引用,并且得到它的所有属性。 看本例中 Bean: 2..Action处理中,在try catch 使用saveMessage define 里的test2 (同样常见的在Iterator标签里也 或者saveErrors() 经常指定ID来被下面的标签引用。) (Struts1.2开始抛弃了ActionErrors,全部是 Struts对于对象的展示,普通的标签库算是尽 ActionMessages了) 了责任了。但也别得意,他在显示逻辑处理上功
    • Struts最佳实践 这里就不得不说到一些构架上的一些东西了. } Struts Action中处理的异常,已经不该是你的原始 if(! error.isEmpty()){ saveErrors(request,errors); 异常了.在你的Dao层要抛出DataException,而在 …. 你的业务层,需要捕获到,作为你的自定义异常抛 出,这样你在struts里捕获到的异常才是友好的,且 至于显示嘛,直接使用<html:errors/>就 是有意义的. OK了.但是你要觉得没有空白的地方显示,也 我们都知道往往Dao那一层都是抛 可以使用类的。 的一个统一的异常比如DataExpcetion, <html:messages id="message"> HibernteException之类的。 <script>window.alert('<bean:write 然后到你的业务处Service调用DAO的方法时 name="message"/>')</script> </html:messages> 候,就能就捕获DataExpcetion, 因为在Serivce那 一层(你的业务层),你总归是知道自己要做什 或者以红色醒目字显示: 么,因此应该Service的业务方法里,再抛出一个 自定义的业务异常,带上你 <html:messages id="msg" message="true"> <font color="red"> 比如在业务处理,添加一个学生过程,如果 <bean:write name="msg"/> 假设是StudentServiceImpl.java </font> </html:messages> public void doAddStudent(Student student) throws DupKeyExption,StudentException{    try{ 对于,全局的异常,那你最好forward一个 if((Student)getObject(student,student. gloable-forward 的 errorPage.jsp之类的JSP getId()).getId()==student.getId()){ (注:Struts1.2开始,抛弃了ActionErrors了, throw new DupKeyExcption(“该 统一使用使用ActionMessages了,对于 学生已经存在"); } 题外话: WEB应用系统大部分异常只是 studentDao.add(); 起到了一个传递错误信息的作用,因此把他们 }catch(DataException e){ 叫做Messge也是更为贴切,ActionErrors是继承 logger.debug(“错误信息:",e); ActionMessage的,用法也是和ActionMessages一 throws new StudentException(“增加 学生失败”); 样, 似乎显得多余,Struts体积已经够庞大了, } Errors这样一个孩子也就这样在1.2里夭折了。) } 如果你将异常定义的级别教好,使用 那么在Action中调用该业务处理方法就应该 <global-exceptions> <exception 是: handler="com.yourcorp.CustomizedExcepti try { onHandler" service.doAddStudent(); key="global.error.message" }catch (DupikeyException e1){ path="/error.jsp" //重复添加了 scope="request"     errors.add("message",new type="java.lang.Exception"/> ActionError("student.error.dupkey")); </global-exceptions> }catch (Exception e) { //添加失败 logger.error(e.getMessage()); 4 Struts 之 扩展篇 errors.add("message",new Struts 的Plugin 给Struts应用程序算是留了一到 ActionError("student.error.add")); e.printStackTrace(); 后门,扩展Struts 可以由此窃入 forward = “glablefaild”; Plugin 能使得你的web应用程序在startup或
    • shutdown 的时候,能完成一部分操作. 它是基于配 置的,你可以很方便的外挂一些应用程序。配置 /** 文件将在启动时载入,并且完成实例化。 * Initializes the <code>SessionFactory</code>. 比如HibernatePlugin,代码引之hibernate. * @param servlet the <code>ActionServlet</ org/105.htm code> instance under which the * plugin will run. public class HibernatePlugIn implements PlugIn * @param config the <code>ModuleConfig</ { code> for the module under which public static final String SESSION_FACTORY_ * the plugin will run. KEY */ = SessionFactory.class.getName(); public void init(ActionServlet servlet, private static Log _log = LogFactory. ModuleConfig config) getLog(HibernatePlugIn.class); throws ServletException { _servlet = servlet; private boolean _storedInServletContext = true; _config = config; private String _configFilePath = "/hibernate.cfg. xml"; initHibernate(); } private ActionServlet _servlet = null; private ModuleConfig _config = null; /** private SessionFactory _factory = null; * Initializes Hibernate with the config file found at /** * <code>configFilePath</code>. */ * Destroys the <code>SessionFactory</code> private void initHibernate() throws instance. ServletException { */ Configuration configuration = null; public void destroy() { URL configFileURL = null; ServletContext context = null; _servlet = null; _config = null; try { configFileURL = HibernatePlugIn.class. try { getResource(_configFilePath); _log.debug("Destroying SessionFactory..."); context = _servlet.getServletContext(); _factory.close(); if (_log.isDebugEnabled()) { _log.debug("Initializing Hibernate from " + _configFilePath + "..."); _log.debug("SessionFactory destroyed..."); } } catch (Exception e) { _log.error("Unable to destroy SessionFactor configuration = (new Configuration()). y...(exception ignored)", configure(configFileURL); _factory = configuration. e); buildSessionFactory(); } } if (_storedInServletContext) {
    • Struts最佳实践 _log.debug("Storing SessionFactory in + storedInServletContext + "'..."); ServletContext..."); } _storedInServletContext context.setAttribute(SESSION_ = new Boolean(storedInServletContext). FACTORY_KEY, _factory); booleanValue(); } } } } catch (Throwable t) { _log.error("Exception while initializing 基于配置实例化的工具有好多,引入 Hibernate."); SpringFramework,它能为你做不少工作,可以 _log.error("Rethrowing exception...", t); 配置化的实现 数据连接获取, DAO,Serivice的 throw (new ServletException(t)); 获取,自动事务,一切也都能梆在Struts中完成 } 现。 } 具体参考SpringFramework。 /** * Setter for property configFilePath. * @param configFilePath New value of property 5. 测试篇 configFilePath. Struts通过传统的手工输入进行测试, 效 */ 率教低, 请尽量使用单元测试 public void setConfigFilePath(String configFilePath) { 基本使用如下: if ((configFilePath == null) || (configFilePath. trim().length() == 0)) { public class StudentActionTest extends throw new IllegalArgumentException( MockStrutsTestCase { "configFilePath cannot be blank or public StudentActionTest(String arg0) { null."); super(arg0); } } if (_log.isDebugEnabled()) { public static void main(String[] args) { _log.debug("Setting 'configFilePath' to '" junit.textui.TestRunner.run(UserActionTest. + configFilePath + "'..."); class); } } _configFilePath = configFilePath; public void setUp() throws Exception { } super.setUp(); setContextDirectory(new File(“E:webapp /** webContext”)); * Setter for property storedInServletContext. } * @param storedInServletContext New value of protected void tearDown() throws Exception { property storedInServletContext. super.tearDown(); */ } public void setStoredInServletContext(String //测试方法 storedInServletContext) { public void testAdd() { if ((storedInServletContext == null) setRequestPathInfo("/student"); || (storedInServletContext.trim(). addRequestParameter("method","add"); length() == 0)) { actionPerform(); //执行 storedInServletContext = "false"; verifyForward("success"); //验证 } } } if (_log.isDebugEnabled()) { _log.debug("Setting 'storedInServletContext' to '"
    • Java Web框架汇总 王海龙 Tomcat的Server.xml文件中定义了网络请求路 0.简介 径到主机本地文件路径的映射。比如,<context path="/yourapp" docBase="yourapp_dir/webapp"/> 本文介绍 Java Web Framework的基本工作 原理,和一些常用的开源Web MVC Framework 我们来看一下,一个HTTP Request-Response (Struts, Web Work, Tapestry, Echo, JSF, Maverick, Cycle的处理过程。 Spring MVC, Turbine, Cocoon, Barracuda)。 HTTP Request URL一般分为三段:host, Web开发的最重要的基本功是HTTP; context, path。 JavaWeb开发的最重要的基本功是Servlet Specification。HTTP和Servlet Specification对于 如http://yourhost/yourapp/en/index.html这 Web Server和Web Framework的开发实现来说, 个URL,分为host=yourhost, context=yourapp, 是至关重要的协议规范。 path=en/index.html三段。其中,Context部分由 request.getContext()获得,path部分由request. 应用和剖析开源Web Framework,既有助于 getServletPath()获得(返回结果是“/en/index. 深入掌握HTTP& Servlet Specification, 也有助于了 html”)。 解一些现代的B/S Web框架设计思想,如MVC, 事件处理机制,页面组件,IoC,AOP等。在这 yourhost主机上运行的Tomcat Web Server接 个现代化的大潮中,即使Servlet规范本身也不能 收到这个URL,根据Context定义,把yourapp这 免俗,不断引入Filter、Listener等现代框架设计 个网络路径映射为yourapp_dir/webapp,并在此 模式。同是Sun公司出品的JSF更是如此。 目录下定位en/index.html这个文件,返回到客户 端。 关于MVC模型、项目简介、配置文件、入门 示例等基础知识,网上已经有大量的重复资料信 如果我们这个URL更换为http://yourhost/ 息,本文不再赘述。 yourapp/en/index.jsp,这个时候Tomcat会试 图把yourapp_dir/webapp/en/index.jsp文件编译成 文中会提到一些相关的开源项目,和一些编 Servlet,并调用运行这个Servlet。 程思想,如有需要,可以用相关的关键字在网上 搜索,获取基本的背景知识。 我们再把这个URL更换为http://yourhost/ yourapp/en/index.do。 本文力图言简意赅,突出重点。着重描述其 他资料没有提到、或很少提到的较重要内容,如 注意,戏剧化的事情就发生在这个时候, 运行原理、主流用法,相关知识,关键特性等。 Servlet规范中最重要的类RequestDispatcher登场 了。RequestDispatcher根据WEB-INF/web.xml配 置文件的定义,调用对应的 Servlet来 处 理 en/ 1. Java Web工作原理 index.do这个路径。 [编者按:本部分内容在本期杂志《Servlet规范简 假设web.xml里面有这样的定义 介》有更详细介绍] <servlet> <servlet-name>DispatchServlet</servlet-
    • Java Web 框架汇总 name> 量得多的接口定义,通常只有一两个方法,如 <servlet-class>yourapp.DispatchServlet</ execute(perform), validate等。 servlet-class> </servlet> 我们知道,URL->Servlet映射,定义在Web. <servlet-mapping> xml配置文件里,但MVC框架通常会有另外一个 <servlet-name>DispatchServlet</servlet- 定义URL-> Action映射的配置文件。 name> <url-pattern>*.do</url-pattern> 入口Dispatcher Servlet根据URL -> Action的映 </servlet-mapping> 射关系,把请求转发给Action。 那 么 , RequestDispatcher会 调 用 yourapp. Action获得输入参数,调用商业逻辑,并把 DispatchServlet类处理这个路径。 结果数据和View标识给(Model & View)返回 给Dispatcher Servlet。 如 果 web.xml没 有 定 义 对 应 en/ index.do这 个 路 径 的 Servlet, 那 么 Dispatcher Servlet根据这个View 标识,定位 To m c a t 返 回 “ 您 请 求 的 资 源 不 存 在 ” 相应的View Template Path,把处理转交给View( RequestDispatcher用于Web Server中,也可以 JSP +TagLib, Velocity, Free Marker, XSL等)。 用于应用程序中进行处理转向,资源定位。比 如,我们在处理en/index.do的代码中调用, View一般通过request.getAttribute()获得结 果数据,并显示到客户端。至于是谁把结果数 request.getRequestDispatcher(“cn/index.jsp”). 据设置到request.attribute里面,有两种可能: forward(request, response), 就可以转交另外的资 Action或Dispatcher Servlet。 源cn/index.jsp来处理。 几乎所有的 Web Framework 都需要定 2. Struts 义 自 己 的 D i s p a t c h作 用 的 S e r v l e t, 并 调 用 RequestDispatcher进行转向处理。 http://struts.apache.org/ 阅读Web Framework源代码,有两条主要线 Struts是目前用户群最大、开发厂商支持最多 索,(1)根据web.xml找到对应的Servlet类;(2)搜 的开源Web Framework。 索包含“RequestDispatcher”词的代码文件。 Struts劳苦功高,为普及MVC框架作出了 我们看到,request, response 这 两 个参 不可磨灭的贡献。显赫的声望,趋于老化的 数,被RequestDispatcher在各种Servlet之间传 厚重结构,令Struts成为很多现代Web 来传去(JSP也是Servlet)。 Framework参照、挑战的目 所 以 , request的 标。 setAttribute()和 getAttribute()方 法 Struts应 用 是Servlet之间传送 主 要 包 括 3件 事 数据的主要方式。 情: 配置struts- config.xml文件,实 在MVC结构中, 现Action类,实现 一般的处理流程如 View;还有一些高 下: 级扩展用法。下面 分别讲述。 处 理 H T T P Request的基本单位一 1. 配置struts- 般称为Action,是一个 config.xml文件: 比Servlet轻 Struts支持多级配
    • Java Web 框架汇总 置文件,具体用法和限制,详见Struts文档。 Welcome.vm"/> 这里只讨论struts-config.xml主流配置的内 容。:-) web.xml的定义如下 (1) URL Path到Action的映射。 <servlet> 如<action path="/LogonSubmit" type="app. <servlet-name>velocity</servlet-name> LogonAction" ... /> <servlet-class>org.apache.velocity.tools.view. Struts的入口Servlet是ActionServlet。 servlet.VelocityViewServlet</servlet-class> ActionServlet需要此信息把URL Path调用对 </servlet> 应的Action类处理。 <servlet-mapping> 在Struts运行期间,一 应用和剖析开源Web 个URL Path,只存在一个 Framework,既有助于 <servlet- 对应的Struts Action实 name>velocity</servlet- 例。所有的该URL Path的 深入掌握HTTP& Servlet name> 请求,都经过这同一个 Specification, 也有助于了解 Struts Action实例处理。 <url-pattern>*.vm</url- 所以Struts Action必须线 一些现代的B/S Web框架设 pattern> 程安全。 计思想,如MVC,事件处 </servlet-mapping> 想想看,其实这个要求 理机制,页面组件,IoC, 并不过分,Action只是一 这时,request. 个处理程序,不应该保存 AOP等。 getRequestDispatcher(“/ 跨HTTP请求的状态数据, pages/Welcome. 按理来说,也应该做成线 vm”)会调用VelocityViewServlet,由 程安全的。 VelocityViewServlet负责装并驱动运行/ pages/Welcome.vm这个模板文件。 (2) Template Name到View Template Path的 映射。 这里面有一个问题,如果调用的是 DispatchRequester.include()方法, <forward name="success" path="/pages/ 那么如何才能把pages/Welcome.vm传给 Welcome.jsp"/> VelocityViewServlet呢? Action类返回一个Template Name, 如前所说,RequestDispatcher传递的参数 ActionServlet根据这个Template Name获得对 只有两个,request和response。那么只能通过 应的View Template Path,然后调用 request attribute。正是为了解决这个问题, Servlet2.3规范之后,加入了javax.servlet. request.getRequestDispatcher(“View include.servlet_path这个属性。 Template Path”),把处理转向路径对应 的Servlet。在这个例子中,是转向/pages/ 参见VelocityViewServlet的代码( Welcome.jsp编译后的Servlet。 velocity-tool开源项目) // If we get here from RequestDispatcher.include(), 我们来看一个一个Velocity的例子。 getServletPath() <include name="success" path="/pages/ // will return the original (wrong)
    • Java Web 框架汇总 URI requested. The following special TagLib,其中最重要的就是Struts HTML TagLib。 // attribute holds the correct path. See section 8.3 of the Servlet html:form tag则是整个HTML Tag的核心,其 它的如html:input, html:select等tag,都包含 // 2.3 specification. 在html:form tag里面。 String path = (String)request. html:form tag用来映射Form Bean(也可以 getAttribute("javax.servlet.include. 通过适当定义,映射其他的bean,但使用上会有 servlet_path"); 很多麻烦)。html:form tag包含的其他Struts html tag用来映射Form Bean的属性。 从这里我们可以看出,为什么通晓Servlet Specification对于通晓Web Framework至关重 Struts Bean TagLib的用法比较臃肿,一般 要。 情况下可以用JSTL代替。当然,如果需要用到 bean:message tag实现国际化,那又另当别论。 (3) Form Bean的定义 Struts Tile TagLib用于页面布局。开源 如<form-bean name="logonForm" type="app. Portal项目Liferay使用了Struts Tile TagLib做 LogonForm"/> 为布局控制。 Struts Form Bean需要继承ActionForm类。 4.高级扩展用法 Form Bean类,主要有三个作用: 用户可以重载Struts的一些控制类,引入自 [1]根据bean的定义,利用reflection机制, 己的一些定制类。详见Struts文档。 自动把request参数转化为需要的数据类型,填 入到bean的属性当中。ActionForm类名中虽然有 本文不是Struts专题,只讲述最重要的主流 Form这个词,但不仅能够获取Form提交后的HTTP 用法,其它边边角角的,不再赘述。 Post参数,也可以获取URL后缀的HTTP Get参 数。 3. WebWork [2]输入验证。用户可以配置validation. xml,定义各属性的验证规则。 http://www.opensymphony.com/webwork/ [3]当作View Object来用。用户需要熟练 WebWork由于灵活的可插拔特性,受到很多资 掌握Struts HTML TagLib的用法,才能把Form 深程序员的欢迎。似乎很有可能大肆流行起来。 Bean的属性正确显示出来。 WebWork项目建立在XWork项目上。 (4)其他定义。详见Struts文档。不再赘述。 入口Servlet是WebWork项目中定义的 ServletDispatcher,而Action在XWork项目中定 2.实现Action。 义。 Action类从Form Bean或直接从request中 XWork Action接口的execute()方法没有 获得输入参数,调用商业逻辑,把结果数据 参数,不像Struts Action那样接受request, (也许会包装成View Object),用request. response参数,所以XWork Action能够脱离 setAttribute()放到request中,最后返回一个 Web环境被直接调用,便于单元测试。 用ForwardMapping类包装的Template Name。 这里引入了一个问题。没有了request参 3.实现View。 数,那么XWork Action如何获得request parameters作为输入数据?又通过什么桥梁( Struts View的标准实现方法是JSP + Struts Struts用request.setAttribute)把结果数据传
    • 给 您 的 知 识 库 加 点 油 Java 我 们 期 待 eMag 着 您 的 加 入 ! 请和我们联系 投稿信箱emag_java@csdn.net 杂志主页http://emag.csdn.net/Default.aspx?tabid=57
    • Java Web 框架汇总 送到View层? Servlet Filter的工作机制一般,所有注入的 Interceptor方法会先于Actio方法运行。 在Web Work 中,只能通过 Action 本身的 getter,setter属性来传送输入参数和输出结 我们来看一下Action和Interceptor的地位: 果。 Action没有参数,无法获得ActionContext;而 Interceptor接受的ActionInvoication参数拥有 比如,我们有这样一个实现了XWork 包括ActionContext在内的所有重要信息。 Action接口的类, 这种权力分配的不平等,注定了Action的作 YourAction implements Action{ 用非常有限,只限于调用商业逻辑,然后返回一 个成功与否标志。所有与外部Web世界打交道、 int productId = null; 协调内部工作流程的重担,都责无旁贷地落在 Interceptor的肩上。 String productName = null; public void setProductId(int 我们可以设想一个极端的例子。我们声 productId){this.productId = productId;} 明一批不做任何事情的空Action,我们只是 需要它们的空壳类名;我们制作一批对应的 public String getProductName(){return Interceptor,所有的转发控制、商业逻辑都在 productName;} Interceptor上实现,然后把Interceptor都注入 public String execute(){ 到对应的空Action。这在理论上是完全可行的。 productName = findNameById(productId); 在Web海洋的包围中,Action可少, return “success”; Interceptor不可少。Action是一个孤岛,如果没 } 有外来盟友Interceptor的协助,只能在自己的 } 小范围内独立作战(比如Unit Test),而对整 体大局的作战目标无法产生影响。 这个类里面的productId将接受request输入 参数,productName是输出到页面显示的结果。 下面我们来看一下Action是如何在 Interceptor的全程监管下工作的。 比如,这样的请求,http://yourhost/ yourapp/MyAction.action?productId=1 在WebWork中,我们需要如下配置XWork. xml。 Web Work会把1填到YourAction的productId里 面,然后执行execute()方法,JSP里的语句 <xwork> <ww:property value=“productName”>会把 <!-- Include webwork defaults (from YourAction的productName显示在页面上。 WebWork-2.1 JAR). --> <include file="webwork-default.xml" 如果一个Web Framework采用了这种屏蔽 /> Action的request, response参数的设计方式, <!-- Configuration for the default 一般也同时会采用这种Action和输入输出数据 package. --> 结合成一体的解决方式。类似的情形也存在于 <package name="default" Tapestry和Maverick中,后面会讲到。 extends="webwork-default"> 当WebWork ServletDispatcher接收到HTTP <!-- Default interceptor stack. --> Request的时候,首先把所有相关的信息(包 括request, response, session, servlet config, <default-interceptor-ref name=" servelt context, 所有request参数)等存放到 defaultStack" /> AcationContext中,然后根据Interceptor配 <!-- Action: YourAction. --> 置信息,生成一个YourAction的动态代理类对 <action name="youraction" 象。实际上运行的正是这个代理对象,如同 class="yourapp.YourAction">
    • Java Web 框架汇总 <result name="success" 进行截获处理。虽然实际上,Servlet Filter截 type="dispatcher"> 获的是Servlet,但某些情况下,可以达到和截 YourAction.jsp 获一批Action的同样效果。 </result> </action> 比如,在Web Work中,我们可以为所有admin </package> package的Action,加入一个Interceptor,当检 </xwork> 查到当前Session的用户没有admin权限时,统一 返回一个警告页面:您没有足够的权限执行这个 webwork-default.xml里面的相关定义如下: 操作。 <interceptors> 我们看到也可以为所有URL Pattern 为 <interceptor name="validation" “admin/*.action” 的URL定义一个Servlet class="com.opensymphony.xwork.validator. Filter,当检查到当前Session的用户没有 ValidationInterceptor"/> admin权限时,统一返回一个警告页面:您没有 <interceptor name="static-params" 足够的权限执行这个操作。 class="com.opensymphony.xwork.interceptor. StaticParametersInterceptor"/> WebWork的Interceptor配置是相当灵活的, <interceptor name="params" class="com. 相当于对Action实现了AOP。Interceptor相当于 opensymphony.xwork.interceptor. Aspect,基类AroundInterceptor的before(), ParametersInterceptor"/> after()方法相当于Advice。 <interceptor name="conversionError" class="com.opensymphony.webwork. 另外,XWork也提供了从XML配置文件装 interceptor.WebWorkConversionErrorInterce 配Component的机制,相当于实现了对于 ptor"/> Component的IoC。 <interceptor-stack name="defaultStack"> <interceptor-ref name="static- 提到AOP和IoC,顺便多讲两句。Spring params"/> AOP能够截获所有Interface,不限于某个特定接 <interceptor-ref name="params"/> 口;Spring框架支持所有类型的IoC,不限于某 <interceptor-ref 种特定类型。 name="conversionError"/> </interceptor-stack> 要知道,AOP, IoC可是现在最时髦的东西, </interceptors> 一定不要错过啊。:D 从 上 述 的 配 置 信 息 中 可 以 看 出 , 相关概念导读(如果需要,请用如下关键字 YourAction执行execute()方法的前后,会被 搜索网络): defaultStack所定义的三个Intercepter截获。 这些Interceptor的任务之一就是把输入参数设 AOP -- Aspect Oriented Programming -- 面 置到Action的对应属性当中。 向方面编程。 如果我们需要加入对YourAction的属性的 IoC – Inversion of Control --控制反转 验证功能,只要把上述定义中的validation Interceptor加入到defaultStack中就可以了。 Dynamic Proxy -- 动态代理,JDK1.4引入的 当然,实际工作还没有这么简单,一般来说,还 特性。还可以进一步参考CGLib, ASM等开源项 要为每个进行属性验证的Action的都配置一份 目。 validation.xml。 WebWork直接支持所有主流View-- XWork Interceptor能够在Package和Action XSL,Velocity, FreeMarker,JSP。WebWork还提 级别上,进行截获处理。 供了自己的TagLib。“直接支持”的意思是说, 不用像Struts那样,使用Velocity的时候,还需 Servlet Filter能够在URL Patten级别上, 要引入辅助桥梁Velocity-tool。
    • Java Web 框架汇总 WebWork中用到一种功能和XPath类似的对象 Component处理。 寻径语言ONGL,是一个开源项目。ONGL同样用在 下面要介绍的Tapestry项目中。 这些特殊信息通常包含在URL参数或Hidden Input里面,必要的时候,还需要生成一些Java Opensymphony下还有一个SiteMesh项目, Script。Tapestry,Echo,JSF都是这种原理。 通过Servlet Filter机制控制布局。可以和 WebWork组合使用。 Tapestry的例子如下: <a href="#" jwcid="@DirectLink" 4. Tapestry parameters="ognl:currentItem.itemId" listener="ognl:listeners.showItem"> http://jakarta.apache.org/tapestry/ [编者按:OGNL是一种利用java对象setter和 Tapestry近来突然火了起来,令我感到吃惊。 getter方法来访问其属性的表达式语言,Tepestry项 也许是JSF带来的Page Component风潮令人们开 目及很多项目使用了该技术。更详细链接http://www. 始关注和追逐Tapestry。 ognl.org/] Ta p e s t r y 的 重 要 思 想 之 一 就 是 P a g e JSF用TagLib实现页面组件,也提供了类似 Component。 的CommandLink和CommandButton Tag。其中对 应Tapestry listener的Tag属性是action。后面会讲 前 面 讲 到 , XWork能够 自动把 request参数 解。 映射到Action的属性当中。Tapestry走得更远, 甚 至 能 够 根 据 request参 数 , 映 射 到 Action( Tapestry的模板标签是HTML标签的扩展,具 Tapestry里面称为Page)的方法,并把request参 有良好的“所见即所得”特性,能够直接在浏览 数映射为Page方法需要的参数,进行正确的调 器中正确显示,这也是Tapestry的一个亮点。 用。就这样,Tapestry不仅把输入输出数据,而 且把事件方法也绑定到了Page上面。 在Tapestry框架中,Action的概念已经非常模 糊,而换成了Page的概念。而Tapestry Page是拥 有属性和事件的页面组件,其中的事件处理部相 5. Echo 当于Action的职责,而属性部分起着Model的作 http://sourceforge.net/projects/echo 用。 Echo提供了一套类似Swing的页面组件,直 除了使用Page和其它的Tapestry页面组件,用 接生成HTML。 户也可以自定义页面组件。 从程序员的角度看来,用 Echo编写 Web程 这种页面组件/属性事件的编程模型,受到一 序,和用Swing编写Applet一样,属于纯面向组 些程序员的欢迎。当然,这种编程模型并不是没 件事件编程,编程模型也以Event/Listener结构为 有代价的,每个Tapestry模板文件都需要一个对 主体。 应的.page文件。这些.page文件定义了页面组件 的属性、事件、Validator等信息。 Echo没有Dispatcher Servlet,也没有定义 URL->Action映射的配置文件。 我们来看一下B/S结构中,组件的属性、事 件和HTTP Request绑定的基本原理。一个能够 Echo的Action就是实现了ActionListener接 发出请求的页面组件(比如Link和Button),在 口 ( 参 数 为 ActionEvent) 的 Servlet( 继 承 输出自己的HTML的时候,需要输出一些特殊的 EchoServer类)。 信息来标志本组件的属性/事件,这样下次HTTP Request来的时候,会把这些信息带回来,以便 所以,Echo直接由Web Server根据web.xml配 Web Framework加以辨认识别,发给正确的Page 置的URL -> Servlet的映射,进行转发控制。
    • Echo也没有明显的View层,Echo在页面组件 方面走得更远,所有的HTML和JavaScript都由框 架生成。你不必(也没有办法)写HTML,只需 要(也只能)在Java代码中按照类似Swing编程 方式,生成或操作用户界面。用户也可以定制自 己的Echo组件。 Echo的UI Component的实现,采用了两 个重要的模式。一个是Peer(Component -> ComponentPeer)模式,一个是UI Component -> Renderer模式。 虽 然 Echo的 API更 类 似 于 Swing, 但 实 现 上 却 采 用 更 接 近 于 AWT的 Peer模 式 。 每 个 Component类 ( 代 表 抽 象 的 组 件 , 比 如 Button),都有一个对应的ComponentPeer类( 代表实际的组件,比如windows桌面的Button, Linux桌面的Button,HTML Button等)。 先别急,这个事情还没有完。虽然 ComponentPeer落实到了具体的界面控件,但是 它还是舍不得显示自己,进一步把显示工作交给 一个Renderer来执行。 UI Component 有可能对应 Model, 比 如 , 在 Echo里 面 , Button类 对 应 一 个 Event, Listener。 Tag包 含 componentType和 ButtonUI(继承了ComponentPeer)类,而这个 rendererType两个属性,用来选择对应的的UI ButtonUI类会把最终显示交给ButtonRender来处 Component和Renderer。 理。 JSF的应用核心无疑是JSF TagLib。JSF 据说多了这么一步,能够让显示控制更加灵 TagLib包含了对应所有重要HTML元素的Tag, 活丰富。比如,同一个Renderer可以处理不同的 而且Input Tag可以直接包含Validator Tag或者 UI Component,同一个UI Component也可以交给 Validator属性,来定义验证手段。 不同的Renderer处理。 我们通过JSF携带的cardemo例子,来看JSF的 JSF的页面组件也采用了UI Component -> 处理流程。 Renderer模式,后面会讲到。 (1) carDetail.jsp有如下内容: 6. JSF <h:commandButton action="#{carstore. buyCurrentCar}" value="#{bundle.buy}" /> http://java.sun.com/j2ee/ javaserverfaces/index.jsp 可以看到,这个button的submit action和 carstore.buyCurrentCar方法绑定在一起。我们在 http://wwws.sun.com/software/ Tapestry里面曾经看到过类似的情景。 communitysource/jsf/download.html download source (2) carstore在faces-config.cml中定义: JSF的 中 心 思 想 也 是 页 面 组 件 /属 性 事 件 。 <managed-bean> 一般来说,JSF的页面组件是一个三件套{ UI <managed-bean-name> carstore </ Component, Tag, Renderer}。 managed-bean-name>
    • navigation to confirmChoices.jsp </description> <from-outcome>confirmChoices</from- outcome> <to-view-id>/confirmChoices.jsp</ to-view-id> </navigation-case> </navigation-rule> (5)于是转到页面confirmChoices.jsp。 除了Interceptor之外,JSF几乎包含了现代 Web Framework应该具备的所有特性:页面组 件,属性事件,IoC (ManagedBean),Component -> Renderer,类似于Swing Component的Model- Event-Listener。 也许设计者认为,众多庞杂的模式能够保证 JSF成为一个成功的框架。Portal开源项目eXo就 是建立在JSF框架上。 可 以 看 出 这 样 一 个 趋 势 , 现 代 We b Framework认为B/S结构的无状态特性和HTML界 <managed-bean-class> carstore.CarStore 面是对编程来说是需要极力掩盖的一个缺陷,所 </managed-bean-class> 以尽量模拟C/S结构的组件和事件机制,以吸引 <managed-bean-scope> session </ 更多的程序员。 managed-bean-scope> </managed-bean> 7. Maverick (3) carstore.CarStore类中的buyCurrentCar方法 如下: http://mav.sourceforge.net/ public String buyCurrentCar() { Maverick是一个轻量而完备的MVC Model 2框架。Maverick的Action不叫Action,直截了当 getCurrentModel().getCurrentPrice(); 的称作Controller。 return "confirmChoices"; Controller只接受一个ControllerContext参数。 request,response, servlet config, servelt context等 } 输入信息都包装在ControllerContext里面,而且 Model也通过ControllerContext的model属性返 回。整个编程结构清晰而明快,令人赞赏。 (4) confirmChoices转向在faces-config.cml中定 义: 但这个世界上难有十全十美的事情,由于 ControllerContext只有一个model属性可以传递数 <navigation-rule> 据,程序员必须把所有需要的数据都打包在一个 <from-view-id>/carDetail.jsp</from- 对象里面设置到model属性里。这种麻烦自然而 view-id> 然会导致这样的可能用法,直接把Controller本 <navigation-case> 身设置为model,这又回到了Controller(Action)和 <description> Model一体的老路。 Any action that returns "confirmChoices" on carDetail.jsp should cause
    • Java Web 框架汇总 Spring以一招IoC名满天下,其AOP也方兴未 艾。“Spring出品,必属精品”的观念已经深入 人心。我这里多说也无益,强烈建议读者去阅读 Spring Doc & Sample & Code本身。 前面讲到,WebWork也把所有的输入信息 9. Turbine 都 包 装 在 ActionContext里 面 , 但 Action并 没 有 权 力 获 取 。 而 在 Maverick中 , Controller对 http://jakarta.apache.org/turbine/ 于 ControllerContext拥 有 全 权 的 控 制 , 两 者地位不可同日而语。当然,由于参数 Turbine是一个提供了完善权限控制的坚实框 ControllerContext包含request,reponse之类信 架(Fulcrum子项目是其基石)。Turbine的个人 息,这也意味着,Maverick Controller不能像 用户不多,但不少公司用户选择Turbine作为框 WebWork Action那样脱离Web环境独立运行。 架,开发一些严肃的应用(我并没有说,用其它 框架开发的应用就不严肃^_^)。Portal开源项目 当然,这也并不意味着任何结构性 JetSpeed建立在Turbine上。 缺陷。程序的结构由你自己控制,你 完 全 可 以 把 需 要 单元测试的 那 部 分 从 Turbine用RunData来传递输入输出数据。如 We b 环 境 脱 离 开 来 , 放 到 B u s i n e s s 层 。 同Maverick的ControllerContext,RunData是整 如 同 WebWork, Maverick直 接 支 持所 个Turbine框架的数据交换中心。除了request, 有的主流View。Maverick的配置文件采Struts, response等基本信息,RunData直接包括了User/ Cocoon两家之长,URL -> Action -> View映射 ACL等权限控制相关的属性和方法,另外还包 的主体结构类似于Struts,而View定义部分对 括Action Name和Target Template Name等定位属 Transform的支持则类似于Cocoon。如: 性。 <command name="friends"> Module是 Turbine里 面 除 了 RunData之 外 的 <controller class="org.infohazard. 又 一 个 核 心 类 , 是Turbine框 架 的 基 本 构 件 , friendbook.ctl.Friends"/> Action是Module,Screen也是Module。Turbine提 <view name="success" path="friends.jsp"> 供了LoginUser和LogoutUser两个Action作为整个 <transform path="trimInside.jsp"/> 系统的出入口。而其余流量的权限控制则由类似 </view> 于Servlet Filter机制的Pipeline控制。 </command> Turbine Pipeline的编程模型和Servlet Filter一 模一样:Turbine Pipeline的Valve就相当于Servlet 8. Spring MVC Filter,而ValveContext则相当于Filter Chain。 还 有 更 相 近 的 例 子 , Tomcat源 代 码 里 面 也 有 http://www.springframework.com/ Valve和ValueContext两个类,不仅编程模型一 样,而且名字也一样。 Spring MVC是我见过的结构最清晰的MVC Model 2实现。 权限控制贯穿于Turbine框架的始终。要用好 Turbine,首先要通晓子项目Fulcrum 的Security部 Action不叫Action,准确地称做Controller; 分的权限实现模型。 Controller接收request, response参数,干脆利落地 返回ModelAndView(其中的Model不是Object类 Fulcrum Security的权限实体包括四个-- User, 型,而是Map类型)。 Group, Role, Permission。 其它的Web Framework中, Action返回值一 实体之间包含{Role,Permission}和{ Group, 般都只是一个View Name;Model则需要通过其 User, Role}两组关系。 它的途径(如request.attribute,Context参数,或 Action本身的属性数据)传递上去。 {Role,Permission}是多对多的关系,一个
    • Java Web 框架汇总 Role可以具有各种Permission;{ Group, User, url=jdbc:mysql://127.0.0.1/newapp Role}之间是多对多的关系,一个Group可包含多 个User,并可以给User分配不同的Role。 services.DatabaseService.database.newapp. username=turbine 权限模型的实现同样采用Peer模式,Entity -> EntityPeer, Entity -> ManagerPeer。 services.DatabaseService.database.newapp. password=turbine Entity和EntityManger代表抽象的模型概念, 而EntityPeer和ManagerPeer代表具体的实现。 用户可以根据模型,提供不同的实现, 这说明,权限控制实现由数据库提供,需要 比如,用内存结构中实现,用数据表结构实 根据权限模型创建如下数据表: 现,与Windows NT权限验证机制结合,与 OSWorkflow的权限控制模型结合,等等。其 TURBINE_USER,TURBINE_ROLE, 中,用数据表结构实现,又可以选择用Torque实 TURBINE_GROUP, 现,或者用Hibernate实现。(Torque是Turbine的 O/R Mapping子项目) TURBINE_PERMISSION,TURBINE_ ROLE_PERMISSION, 例如,Falcrum.property配置文件包含如下 Security相关选项: TURBINE_USER_GROUP_ROLE。 # -------------------------------------------------------- ----------- # SECURITY SERVICE # ------------------------------------------------------- ------------ 10. Cocoon http://cocoon.apache.org services.SecurityService.user.class=org.apache. fulcrum.security.impl.db.entity.TurbineUser Cocoon项目是一个叫好不叫做的框架。采用 XML + XSLT Pipeline机制,Java程序只需要输出 services.SecurityService.user.manager=org. XML数据,Cocoon框架调用XSL文件把XML数 apache.fulcrum.security.impl.db.DBUserManager 据转换成HTML、WML等文件。 services.SecurityService.secure.passwords. Cocoon强大灵活的XSL Pipeline配置功能, algorithm=SHA XSLT的 内 容 /显 示 分 离 的 承 诺 , 一 直 吸 引 了 不少程序员fans。怎奈天不从人愿,由于复杂 # ------------------------------------------------------- 度、速度瓶颈、XSL学习难度等问题的限制, ------------ Cocoon一 直 主 要 限 于 网 站 发 布 出 版 领 域 , 向 CMS和Portal方向不断发展。另外,Cocoon开发 # DATABAS E S E R V I C E 了XSP脚本和Cocoon Form技术。 # ------------------------------------------------------- Cocoon的sitemap.xmap配置文件比较复杂, ------------ 与其它的Web Framework差别很大。 services.DatabaseService.database.newapp. 主体Pipelines配置部分采用Pattern Match的方 driver=org.gjt.mm.mysql.Driver 式,很像XSL语法,也可以类比于Web.xml里面 Servlet Mapping的定义。比如,一个典型的URL- services.DatabaseService.database.newapp. >Action的映射定义看起来是这个样子:
    • Java Web 框架汇总 <map:pipelines> HTML或WML模板文件,静态编译成DOM结 构的Java类,作为页面组件。XMLC会根据 <map:pipeline> HTML元素的id定义,生成相应DOM结点的简 便操作方法。 <map:match pattern="*-dept.html"> Barracuda的事件类也需要用Barracuda Event <map:act set="process"> Builder工具把event.xml编译成Java类,引入到工 程中。Barracuda直接用Java类的继承关系映射事 <map:parameter name="descriptor" 件之间的父子层次关系。比如,ChildEvent是 ParentEvent的子类。 value="context://docs/department- form.xml"/> Barracuda的事件分为两类:Request Events( Control Events)和Response Events(View <map:parameter name="form-descriptor" Events)。 value="context://docs/department- Barracuda事件处理过程很像Windows系统消 form.xml"/> 息队列的处理机制。 <map:generate type="serverpages" src="docs/ (1) Barracuda根据HTTP Request生成Request confirm-dept.xsp"/> Event,放入到事件队列中。 <map:transform src="stylesheets/apache. (2) EventDispatcher检查事件队列是否为空, xsl"/> 如果为空,结束。如果非空,按照先进先出的方 式,从事件队列中取出一个事件,根据这个事件 <map:serialize/> 的类型,选择并调用最合适的EventListener,参 数Event Context包含事件队列。 </map:act> “ 根 据 事 件 类 型 , 选 择 最 合 适 的 <map:generate type="serverpages" EventListener对象”的过程是这样的:比如, src="docs/{1}-dept.xsp"/> <map:transform src="stylesheets/apache. EventDispatcher从时间队列里取出来一个事 xsl"/> 件,类型是ChildEvent;Barracuda首先寻找注 <map:serialize/> 册了监听ChildEvent的EventListener,如果找不 </map:match> 到,再上溯到ChildEvent的父类ParentEvent,看 </map:pipeline> 哪些EventListener对ParentEvent感兴趣。 </map:pipelines> 详细过程参见Barracuda 的DefaultEventDispa- tcher类。 11. Barracuda (3) EventListener根据Event Context包含的 http://barracudamvc.org/Barracuda/index.html request信息,调用商业逻辑,获得结果数据, 然后根据不同情况,把新的事件加入到Event Barracuda是一个HTML DOM Component + Context的事件队列中。 Event/Listener结构的框架。 (4)控 制 交 还 给 EventDispatcher, 回 到 第 根据模板文件或配置文件生成静态Java类, (2)步。 并在代码中使用这些生成类,是Barracuda的一 大特色。 Barracuda需 要 用 XMLC项 目 把 所 有 的
    • Java 模板技术 Anders*小明 一、起源与现状: 这一切都是因为在Model 1中并没有分离视 关于Template和JSP的起源还要追述到Web开 图和控制器。完全分离视图和控制器就成了必 发的远古年代,那个时候的人们用CGI来开发 须。这就是Model 2。它把Model 1中未解决的问 web应用,在一个CGI程序中写HTML标签。 题——分离对组件(业务逻辑)的调用工作,把 在这之后世界开始朝不同的方向发展: 这部分工作移植到了控制器。现在似乎完美了, sun公司提供了类似于CGI的servlet解决方案,但 不过等等,原来的控制器从页面中分离后,页面 是无论是CGI还是servlet都面对同一个问题:在 所需的数据怎么获得,谁来处理页面显示逻辑? 程序里写html标签,无论如何都不是一个明智 两个办法:1. 继续利用asp,php或者jsp等机制, 的解决方案。于是sun公司于1999年推出了JSP技 不过由于它们是运行在web环境下的,他们所要 术。而在另一个世界里,以PHP和ASP为代表的 显示的数据(后端逻辑产生的结果)就需要通过 scriptlet页面脚本技术开始广泛应用。 控制器放入request流中;2. 使用新手法——模板 不过即便如此,问题并没有结束,新的问题 技术,使用独立的模板技术由于脱离的了web环 出现了:业务和HTML标签的混合,这个问题不 境,会给开发测试带来相当的便利。至于页面所 仅导致页面结构的混乱,同时也使代码本身难以 需数据传入一个POJO就行而不是request对象。 维护。 模板技术最先开始于PHP的世界,出现了 于是来自起源于70年代后期的MVC模式被 PHPLIB Template和FastTemplate这两位英雄。不 引入开发。MVC的三个角色:Model——包含 久模板技术就被引入到java web开发世界里。目 除UI的数据和行为的所有数据和行为。View是 前比较流行的模板技术有:XSTL,Velocity, 表示UI中模型的显示。任何信息的变化都由 JDynamiTe,Tapestry等。另外因为JSP技术毕竟 MVC中的第三个成员来处理——控制器。 是目前标准,相当的系统还是利用JSP来完成页 在之后的应用中,出现了技术的第一次飞 面显示逻辑部分,在Sun公司的JSTL外,各个第 跃:前端的显示逻辑和后端的业务逻辑分离, 三方组织也纷纷推出了自己的Taglib,一个代表 COM组件或EJB或CORBA用于处理业务逻辑, 是struts tablib。 ASP、JSP以及PHP被用于前端的显示。这个就是 二、 模板技术分析: Web开发的Model 1阶段(页面控制器模式)。 模板技术从本质上来讲,它是一个占位符动态 不过这个开发模式有很多问题: 替换技术。一个完整的模板技术需要四个元素: 1、页面中必须写入Scriptlet调用组件以获得 0. 模板语言,1. 包含模板语言的模板文件,2. 拥 所必需的数据。 有动态数据的数据对象,3. 模板引擎。以下就具 2、处理显示逻辑上Scriptlet代码和HTML代 体讨论这四个元素。(在讨论过程中,我只列举 码混合交错。 了几个不同特点技术,其它技术或有雷同就不重 3、调试困难。JSP被编译成servlet,页面上的 复了) 调试信息不足以定位错误。 模板语言:
    • Java 模板技术 模板语言包括:变量标识和表达式语句。根 据表达式的控制力不同,可以分为强控制力模板 JDynamiTe 语言和弱控制力模板语言。而根据模板语言与 变量定义:用{}包装 表达式语句:写在注释格式(<!-- )中 HTML的兼容性不同,又可以分为兼容性模板语 弱控制语言 言和非兼容性模板语言。 兼容语言 模板语言要处理三个要点: 标量标记。把变量标识插入html的方法很 XSLT 多。其中一种是使用类似html的标签;另一种是 变量定义:xml标签 使用特殊标识,如Velocity或者JDynamiTe;第三 表达式:xsl标签 种是扩展html标签,如tapestry。采用何种方式有 强控制语言:外部引用:import,include 着很多考虑,一个比较常见的考虑是“所见即所 条件控制:if, choose…when… 得”的要求。 otherwise 非兼容语言 条件控制。这是一个很棘手的问题。一个简 单的例子是某物流陪送系统中,物品数低于一定 Tapestry 值的要高亮显示。不过对于一个具体复杂显示逻 采用component的形式开发。 辑的情况,条件控制似乎不可避免。当你把类似 变量定义(组件定义):在html标签中加上jwcid 于<IF condition=”$count <= 40”><then><span 表达式语句:ognl规范 class=”highlight”>count </span></then></ 兼容语言 IF>引入,就象我们当初在ASP和PHP中所做得 一样,我们将不得不再一次面对scriptlet嵌入网 模板文件: 页所遇到的问题。我相信你和我一样并不认为这 模板文件指包含了模板语言的文本文件。 是一个好得的编写方式。实际上并非所有的模板 模板文件由于其模板语言的兼容性导致不同 技术都使用条件控制,很多已有的应用如PHP上 结果。与HTML兼容性的模板文件只是一个资 中的以及我曾见过一个基于ASP.NET的应用, 源文件,其具有良好的复用性和维护性。例如 当然还有Java的JDynamiTe。这样网页上没有任 JDynamiTe的模板文件不但可以在不同的项目中 何逻辑,不过这样做的代价是把高亮显示的选择 复用,甚至可以和PHP程序的模板文件互用。而 控制移交给编程代码。你必需做个选择。也许 如velocity的非兼容模板文件,由于其事实上是 你也象我一样既不想在网页中使用条件控制, 一个脚本程序,复用性和可维护性大大降低。 也不想在代码中写html标记,但是这个显示逻辑 拥有动态数据的数据对象: 是无可逃避的(如果你不想被你的老板抄鱿鱼 模板文件包含的是静态内容,那么其所需的 的话),一个可行的方法是用CSS,在编程代码 动态数据就需要另外提供。根据提供数据方式的 中决定采用哪个css样式。特别是CSS2技术,其 不同可以分为3种: selector机制,可以根据html类型甚至是element的 Map:利用key/value来定位。这个是最常见的 attributes来apply不同的样式。 技术。如velocity的VelocityContext就是包含了 迭代(循环)。在网页上显示一个数据表 map对象。 单是一个很基本的要求,使用集合标签将不 Example.vm: 可避免,不过幸运的是,它通常很简单,而 Hello from $name in the $project project. 且够用。特别值得一提的是PHP的模板技术和 JDynamiTe技术利用html的注释标签很简单的实 Example.java: 现了它,又保持了“所见既所得”的特性。 VelocityContext context = new VelocityContext(); 下面是一些技术的比较: context.put("name", "Velocity"); context.put("project", "Jakarta"); Velocity DOM:直接操作DOM数据对象,如XSLT利用 变量定义:用$标志 XPath技术。 表达式语句:以#开始 POJO:直接利用反射取得DTO对象,利用 强控制语言:变量赋值:#set $this = "Velocity" 外部引用:#include ( $1 ) JavaBean机制取得数据。如Tapestry。 条件控制:#if …. #end 模板引擎: 非兼容语言 模板引擎的工作分为三步: 1. 取得模板文件并确认其中的模板语言符合 规范。 比如velocity,确定#if有对应得#end等。 Xml+xslt的模型中,xml文件标签是否完整等。
    • Java 模板技术 在完成这些工作后,模板引擎通常会把模板文件 renderPage(writer)方法,该方法调用page的 解析成一颗节点树(包含模板文件的静态内容节 renderPage方法。 点和模板引擎所定义的特殊节点)。 Page执行renderPage时,首先判断是否有 2. 取得数据对象。 listener的请求,如果有则处理listener请求;然后 该数据对象一般通过程序传递引用实 调用BaseComponentTemplateLoader的process方法 现。现有的大量框架在程序底层完成,处理方 把模板文件载入并形成一个component节点树, 式也各自不同,有两种技术分别为推技术和拉 依次执行节点的renderComponent方法。 技术。推技术:controller调用set方法把动态数据 每个component对象将通过ongl的机制取得 注入,模板引擎通过get方法获得,典型代表: 对象属性。并把该值写入输入流。 Struts;拉技术:模板引擎根据配置信息,找到 例如:insert component 与view对应的model,调用model的get方法取得 protected void renderComponent(IMarkupWrit 数据,典型代表:Tapestry。 er writer, IRequestCycle cycle) { 3. 合并模板文件(静态内容)和数据对象( if (cycle.isRewinding()) 动态内容),并生成最终页面。 return; 合并的机制一般如下,模板引擎遍历这 Object value = getValue(); 颗节点树的每一个节点,并render该节点,遇到 if (value == null) 静态内容节点按正常输入,遇到特殊节点就从数 return; 据对象中去得对应值,并执行其表达式语句(如 String insert = null; 果有的话)。 Format format = getFormat(); 以下详细说明: if (format == null) { Velocity insert = value.toString(); Template template = Velocity.getTemplate("test. } else{ wm"); try{ Context context = new VelocityContext(); insert = format.format(value); context.put("foo", "bar"); } context.put("customer", new Customer()); catch (Exception ex) { template.merge(context, writer); throw new ApplicationRuntimeException( 当调用Velocity.getTemplate 方法时,将调用 Tapestry.format("Insert.unable-to-format",value),this, ResourceManger的对应方法。 getFormatBinding().getLocation(), ex); } ResourceManger先查看该模板文件是否在 } cache中,如果没有就去获取,生成resource对象 String styleClass = getStyleClass(); 并调用process()方法,确定该模板是否有效,如 if (styleClass != null) { 果有效,则在内存中生成一个Node树。 writer.begin("span"); 当调用template.merge()时,遍历这颗 writer.attribute("class", styleClass); Node树,并调用每个Node的render方法。对于 renderInformalParameters(writer, cycle); 模板中的变量和对象Node,还将调用execute()方 } if (getRaw()) 法,从context中取得value。 writer.printRaw(insert); 注:ResourceManger在runtimeresource包下, else Node在runtimeparsernode包下 writer.print(insert); Tapestry if (styleClass != null) Tapestry比较麻烦,先介绍一下http请求的处 writer.end(); // <span> 理过程。 } 当httprequest请求到达时。该请求被 getValue为取得insert的value属性。 ApplicationServlet捕获,随后ApplicationServlet通 过getEngine取到对应的Engine,通过该engine的 三、JSP技术分析 getService拿到对应的service,调用其service方法 1. JSP技术: 执行http请求。 JSP,一个伪装后的servlet。web server会 每个service通过RequestCycle对象的 对任何一个jsp都生成一个对应jsp类,打开这 getPage方法取得Page对象,并将其设置为 个类,就会发现,jsp提供的是一个代码生成 该Cycle对象的active Page。之后service调用 机制,把jsp文件中所有的scriptlet原封不动的 renderResponse方法执行输出。 copy的到生成的jsp类中,同时调用println把所有 renderResponse调用page的getResponseWr 的html标签输出。 iter(output)取得writer对象,并把它传给cycle. Test.jsp:
    • Java 模板技术 <html> out.write("<body>rn"); <head><title>jsp test</title></head> out.write("<table width="226" border="0" <body> cellspacing="0" cellpadding="0">rn "); <table width="226" border="0" cellspacing="0" out.write("<tr><td><font face="Arial " cellpadding="0"> size="2" color="#000066"> rnt "); <tr><td><font face="Arial" size="2" out.write("<b class="headlinebold">The jsp color="#000066"> test file"); <b class="headlinebold">The jsp test out.write("</b>rnt "); file</b> out.write("</tr></td></font>rnt "); </tr></td> </font> out.write("</table>rn"); </table> out.write("<body>rn"); <body> out.write("</html>"); </html> } catch (Throwable t) { Test_jsp.java: out = _jspx_out; package org.apache.jsp; if (out != null && out.getBufferSize() != 0) import javax.servlet.*; out.clearBuffer(); import javax.servlet.http.*; if (pageContext != null) pageContext. import javax.servlet.jsp.*; handlePageException(t); import org.apache.jasper.runtime.*; } finally { if (_jspxFactory != null) _jspxFactory.releasePage public class Test _jsp extends HttpJspBase { Context(pageContext); private static java.util.Vector _jspx_includes; } public java.util.List getIncludes() { } return _jspx_includes; } } public void _jspService(HttpServletRequest request, 2. Taglib技术: HttpServletResponse response) Taglib作为jsp之上的辅助技术,其工作本 throws java.io.IOException, ServletException 质依托与jsp技术,也是自定义标签翻译成java代 { 码,不过这次和jsp略有不同,它还要经过几个 JspFactory _jspxFactory = null; 过程。 javax.servlet.jsp.PageContext pageContext = null; 先来看一下,实现一个tag的2个要点: HttpSession session = null; 1. 提供属性的set方法,此后这个属性 ServletContext application = null; 就可以在jsp页面设置。以jstl标签为例 c:out ServletConfig config = null; value=""/,这个value就是jsp数据到tag之间的 JspWriter out = null; 入口。所以tag里面必须有一个setValue方法, Object page = this; 具体的属性可以不叫value。例如setValue(String JspWriter _jspx_out = null; data){this.data = data;}。这个“value”的名称是 在tld里定义的。取什么名字都可以,只需tag里 try { 提供相应的set方法即可。 _jspxFactory = JspFactory.getDefaultFactory(); 2. 处理 doStartTag 或 doEndTag 。这两个方法 response.setContentType("text/html;charset=ISO- 是 TagSupport提供的。 还是以c:out value=""/为 8859-1"); 例,当jsp解析这个标签的时候,在“<”处触 pageContext = _jspxFactory.getPageContext(this, 发 doStartTag 事件,在“>”时触发 doEndTag request, response, null, true, 8192, true); 事件。通常在 doStartTag 里进行逻辑操作,在 application = pageContext.getServletContext(); doEndTag 里控制输出。 config = pageContext.getServletConfig(); 在处理tag的时候: session = pageContext.getSession(); 0. 从tagPool中取得对应tag。 out = pageContext.getOut(); � 为该tag设置页面上下文。 _jspx_out = out; � 为 该 t a g 设 置 其 父 t a g , 如 果 没 有 就为 null。 out.write("<html>rn"); � 调用setter方法传入标签属性值tag,如果 out.write("<head><title>jsp test</title></ 该标签没有属性,此步跳过。 head> rn"); � 调用doStartTag方法,取的返回值。
    • Java 模板技术 � 如果该标签有body,根据doStartTag返 Body导致了taglib的出现了两个分支:Display 回值确定是否pop该标签内容。如果要 Tag和Control Tag, 前者在java code中嵌入了 pop其body,则:setBodyContent(),在 html标签,相当与一个web component,而后者 之后,doInitBody()。如果该标签没有 则是另一种模板脚本。 body,此步跳过。 � 调用doEndTag()以确定是否跳过页面剩 四、两种技术方案的比较: 下部分。 1. 技术学习难易度 � 最后把tag类返还给tagPool。 模板技术。使用模板技术,第一点就是必须 学习模板语言,尤其是强控制的模板语言。于是 tag类为: 模板语言本身的友好性变的尤为重要。以下依据 package my.customtags; 友好性,表现力以及复用性三点为主基点比较了 import javax.servlet.jsp.JspWriter; 一下几种模板技术。 import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.TagSupport; Velocity: public class Hidden extends TagSupport{ Turbine项目( http://jakarta.apach e . o r g / String name; Turbine)采用了velocity技术。 public Hidden(){ name = ""; } 1. 友好性不够。理由: 强控制类型,出 public void setName(String name){ this.name = 现页面显示控制代码和html混合。与Html的 name; } 不兼容,无法所见即所得。遇到大的HTML页 public void release(){ value = null; } 面,从一个 “#if”找到对应的 “#end”也是 public int doStartTag(){ return EVAL_BODY_ 很痛苦的一件事情。 INCLUDE;} 2. 表现力强。理由:强控制语言。 public int doEndTag() throws JspTagException{ 3. 复用性弱。理由:模板脚本和页面代码 try{ pageContext.getOut().write(", you are 混合。 welcome"); } catch(IOException ex){ throw new Jsp XSLT TagException("Error!"); } Cocoon项目(http://cocoon.apache.org/)采用 return EVAL_PAGE; XML + XSLT的方法。CSDN社区也是采用此 } 方案。 } 1. 内 容 和 显 示 风 格 分 离 , 这 点 X S L T 做的 最好。 Jsp页面: 2. 速度慢。理由:XSLT的使用XPath,由 <my:hidden name="testname"/> 于是要解析DOM树,当XML文件大时,速度 很慢。 生成的jsp代码: 3. 友好性不够。理由:由于没有HTML文 my.customtags.Hidden _jspx_th_my_hidden_11 = 件,根本看不到页面结构、显示风格和内容。 (my.customtags.Hidden) _jspx_tagPool_my_hidden_ XSL语法比较难以掌握,由于没有“所见即所 name.get(my.customtags.Hidden.class); 得”编辑工具,学习成本高。 _jspx_th_my_hidden_11.setPageContext(pageConte 4. 表现力强。理由:强控制语言。 xt); 5. 复用性弱。理由:xsl标签和html标签混 _jspx_th_my_hidden_11.setParent(null); 合。 _jspx_th_my_hidden_11.setName("testname"); int _jspx_eval_my_hidden_11 = _jspx_th_my_ hidden_11.doStartTag(); JDynamiTe if (_jspx_th_my_hidden_11.doEndTag() == javax. 1. 表现力中等。理由:弱控制语言。 servlet.jsp.tagext.Tag.SKIP_PAGE) 2. 友好性强。理由:所见即所得的效果。 return true; 在模板件中的ignore block在编辑条件下可展示 _jspx_tagPool_my_hidden_name.reuse(_jspx_th_ 页面效果,而在运行中不会被输出。 my_hidden_11); 3. 复用性强。理由:利用html标签。 return false; Taglib技术提供两个机制,Body和non-
    • Java 模板技术 Tapestry Rich Client技术简介 1. 友 好 性 中 等 。 理 由 : 整 个 T a p e s t r y 页面 awaysrain 文件都是HTML元素。但是由于component会 重写html标签,其显示的样子是否正确,将不 预测。 2. 表现力强。理由:强控制语言。 3. 复用性强。理由:扩展了HTML元素的 定义。 在JSP中大量的使用TagLib,能够使得JSP的 页面结构良好,更符合XML格式,而且能够 重用一些页面元素。但TagLib的编译之后的代 码庞大而杂乱。TabLib很不灵活,能完成的 事情很有限。TabLib代码本身的可重用性受到 TagSupport定义的限制,不是很好。 另外是,我 不得不承认的一件事是,TagLib的编写本身不是 正 如 前 文 所 介 绍 的 , 传 统 的 基 于 C/S的 一件愉快的事情,事实我个人很反对这种开发方 Windows应用程序总是让客户面临着一些感觉很 式。 是不爽的问题,如:部署问题、升级困难、维 护困难、安全问题,但是完全的WEB开发由于 2. 技术使用难易度 HTTP协议的无状态特性——浏览器和服务器总 模板技术:模板技术本身脱离了Web环 是在不停地执行Request和Response来营造一种 境,可以在不启动Web server得情况下进行开发 有状态、持续会话的假象,致使人们又开始怀恋 和测试,一旦出错详细的信息易于错误的定位。 具有更强运算能力、本地存储能力和更稳定的通 由于模板引擎的控制,页面中将只处理显示逻辑 讯能力的客户端程序了。 (尽管其可能很复杂) JSP技术:工作在Web环境下,开发测试 一定要运行web server。此外,一些TagLib能够 不得不说的是,宽带网络的出现在某种意 产生新的标签,页面的最终布局也必须在web环 义促成了Rich Client的诞生。通过快捷的发布, 境下才可以确定。测试时出错信息不明确,特别 特定的通讯协议标准,Rich Client正以不可阻挡 是TagLib得存在,极不容易定位。由于其本质是 的气势向人们重现着C/S模式下客户端程序的优 程序,很容易在其中写入业务逻辑,甚至于数据 势。 库连接代码,造成解耦的不彻底。 Rich Client的发布 3. 总结 模板技术更加专注于页面的显示逻辑,有效 帮助开发人员分离视图和控制器。在学习,开发 C/S架构下,客户端程序发布与维护一直比 和测试都更加容易。 较困难和繁琐。在版本更新以后,需要对客户的 JSP技术本身是一个早期的技术,本身并没 客户端程序进行逐个下载安装及配置更新,这 有提出足够的方式来分离视图和控制器。相反, 是一个体力活,而这也一直是使用户大量选择 我认为其本身是鼓励开发人员不做解耦,因为在 WEB程序的因素之一。 JSP代码中插入业务逻辑是如此的容易。 在Rich Client时代,由于宽带网络的便 利,在客户端尽尽需要从服务器端下载已经更新 好的程序运行,而不必理会繁琐的下载、安装和 配置的过程。 这里不得不提Java的是WebStart技术。 WebStart是让用户只需在网页上点击一个超 级链接就能运行一个Java桌面应用的技术。对于 一个拥有WebStart能力的Java应用来说,用户使
    • Rich Client 技术简介 用它就和使用WEB应用一样的简单,但它所具有 集成大量企业内遗留的系统的EAI(企业应用集 的界面能力和本地处理能力却是WEB应用无法望 成)项目中,它一直是首选的技术。 其项背的。 RMI可以是做CORBA的Java版本,但相比较而 具体的应用的技术知识可以从http://java. 言这是一个轻量级的版本了,对于服务器和客户 sun.com中寻找相关文档,这里不一一赘述。 端两边都用Java来实现的前提下,这是一个非常 好的选择。 Rich Client的通信机制 CORBA和RMI有一个共同的缺陷:通常不会在 系统80端口提供服务,所以这在具备网罗防火墙 除了快捷方便的发布外,Rich Client还需要 的情况下显得非常被动。 与服务器端建立一种快速、可靠、强大、易用 的通信交互机制。但我们开发WEB应用时,表 现层和业务服务层常常只是同一个进程中的不 XML-RPC 同对象,它们之间的交互不过是Java的方法调用 而已,当表现层逻辑被分发到世界各地的计算 为了解决在系统的80端口提供RPC的服务, 机上,客户端和服务器之间的交互就成了一个大 而又不影响正在执行的WEB服务,人们想出了用 问题——从前的C/S被淘汰,很大程度上归咎于 HTTP协议传输RPC包的办法。对于几乎是专门用 socket通信的复杂性。 于传输文本的HTTP协议,要在其上传输RPC封 包,最方便的方法莫过于把RPC封包编码成文本 现在,形形色色的RPC(远程过程调用, 形式——例如XML文件。XML-RPC(http://www. Remote Procedure Call)技术以独特的优势扮演 xml-rpc.com)是由美国UserLand公司指定的一 起了信使的角色。以下列举几种Rich Client可以 个RPC协议。它将RPC信息封包编码为XML,然后 采用的通信机制。 通过HTTP传输封包;它是一个简单的RPC协议, 只支持一些基本数据类型,不支持对象模型,这 CORBA和RMI 势必掣肘在客户端和服务器端之间传输复杂的对 象。 CORBA(通用对象请求代理体系结构, SOAP Common Object Request Broker Architecture) 曾经红极一时,它能够兼容各种操作系统平台的 SOAP即Simple Object Access 语言,强大的的可扩展性所带来的负面影响就 Protocol(简单对象访问协议)是在分散或分 是实现的复杂和繁琐。如果服务器端和客户端 布式的环境中交换信息的简单的协议,是一 都采用Java开发,那么CORBA所需要的语言无关 个基于XML的协议。它允许所有的操作在80端 的IDL就完全变成了画蛇添足。当然,对于需要 口上进行,从而也绕过了防火墙等问题。
    • 给 您 的 智 慧 库 加 点 货 Java 我 们 期 待 eMag 着 您 的 加 入 ! 请和我们联系 投稿信箱emag_java@csdn.net 杂志主页http://emag.csdn.net/Default.aspx?tabid=57
    • Rich Client 技术简介   SOAP规范中有三个基本组成部分: Laszlo开发的示例应用,展示了在Eclispe环境 S O A P 封 装 , 编 码 规 则 , 以及 下开发Laszlo应用的过程。demo的地址如下: 在 请 求 和 响 应 之 间 的 交 互 方 式 。 http://dl.alphaworks.ibm.com/technologies/   目前已有的基于JAVA提供SOAP功能 rcb/demo.html 的产品有:Apache SOAP, IBM SOAP4J等 要了解更多关于SOAP的信息,可以访问 http:// FLEX www.w3.org/TR/SOAP Flex是Macromedia公司开发的,用于 Hessian Rich client开发的环境,其原理是将MXML(the Macromedia Flex Markup Language)文件, 编 译 成S W F文 件 , 然后 显 示 在浏 览 器 中 , 并 利 Hessian(http://www.caucho.com)是由 用Web Service技术和服务器通信。从而利用 Resin应用服务器的开发商Caucho公司制定的一 Flash的强大功能,带来更丰富的用户体验。 个RPC协议,虽然它也是通过HTTP协议传输RPC封 F l e x 官 方 说 法 如 下 ( 摘 自 网络 包,但是它的RPC封包却是以二进制形式编码 上相关文章): 原 代 号 为 “ R o y a l e ”的 的,而且能够表现对象模型和异常体系,这就使 MacromediaFlex软件将把服务器软件、开发指 得Hessian比XML-RPC具有更高的效率。 南和其他工具组合在一起,使传统的网络应 用开发人员能够用Macromedia公司的Flash格 具体通信机制资料请读者参考网上内容和透 式创作软件单元。如从前报道的那样,该 明于2004年5期《程序员》杂志中《王朝复辟还 产品的重点是让那些使用Sun微系统公司的 是浴火重生》一文。 Java2企业版(J2EE)的开发人员能够创作出更 有吸引力、更容易导航的J2EE应用软件接口。 Rich Client开源开发平台Laszlo F l e x 将 使 J 2 E E 开 发 人 员 使 用 标 准 的文 本式开发工具来制作Flash应用程序,而不 必使用Macromedia公司以前出售的复杂的设 Laszlo是一个开源的Rich client开发环境。 计工具。Macromedia公司从今年年初开始, 使用Laszlo平台时,开发者只需编写名为LZX的 努力扩大Flash格式对于主流开发商的吸引 描述语言(其中整合了XML和JavaScript), 力,其目标是扩大Flash的用途,使其成为 运行在J2EE应用服务器上的Laszlo平台会将其 提供互联网应用和建立交互式网站的基础。 编译成FLASH文件并传输给客户端展示。单从 Macromedia公司计划在2004年上半年 运行原理来说,Laszlo与XUL(XML用户接口语 推 出 Fl e x服 务 器 软件 , 该 软件 的 价 格 目 前 还 言, XML User interface Language)、 没 有 确定 。 它的 初 级 版本 将 运 行于 J 2 E E 中 , XAML(“Longhorn”)标记语言很类似。但它的 并计划随后推出支持微软的.Net格式的版 最大优势在于:它把描述语言编译成FLASH,而 本。最初的支持者包括IBM公司,它将随自 FLASH是任何浏览器都支持的展示形式,从而一 己的WebSphere软件一起推广Flex的应用。 举解决了浏览器之间的移植问题。而且,在未来 需要了解更多Flex技术的朋友可以访问 的计划中,Laszlo还可以将LZX编译成Java或. Flex的主页:http://www.macromedia.com/ NET本地代码,从而大大提高运行效率。 software/flex/ 具体请参考http://www.openlaszlo.org。 Thinlet IBM AlphaWorks网站近日发布了用于开发 Thinlet是一个采用Applet解析XUL并提供 Laszlo应用程序的集成开发环境(实际上是一 相应界面的解析器,在事件发生时,调用用户自 个Eclipse插件),使J2EE开发者能够在他们熟 己的事件处理程序(java 程序),需要客户端浏 悉的Eclipse环境中快速开发基于Laszlo的rich 览器支持Applet。更多信息可以参考 http:// client应用程序。可以在下列地址下载该插件: www.thinlet.com/ http://alphaworks.ibm.com/tech/ ide4laszlo 此外,AlphaWorks网站还提供了一个用
    • 对话:Web技术的思考 透明/编著 本文的内容来自各种渠道,有朋友非正式的讨论与邮件往来,也有网络上 的各种资料,还有开发者们口耳相传的实践经验。为了方便读者,我不揣 冒昧将它们整理成对话的形式,并借了两个虚构人物(WebWork的爱好者 Weber和Struts的老用户Steven)之口来比较这两种流行的web框架, 希望对读者的选择有所帮助。 了,新加一个功能就会伤筋动骨,所以Struts老是有很多 Steven:嘿,Weber,你最近忙什么呢? 新特性要发布呢。 Weber:哦,我刚做了一个项目,用WebWork做的,感 Steven:是的。最近Struts又放出消息,未来的版本将 觉挺好。 增加对JSR-168 portlet的支持。 Steven:WebWork吗?我知道它,它有什么好的? Weber:这个问题在WebWork里根本就不成问题。只 要做一个portlet作为引擎,再修改几个配置,所有的 We b e r : 好 处 可 多 了 , 比 S t r u t s 强 太 多 了 。 你 用 WebWork action都可以原封不动地移植到portlet环 Struts那么久,难道就不觉得有什么不舒服的吗? 境,因为它们原本就是最普通的JavaBean,根本就不知 道外面的环境究竟是servlet环境还是portlet环境。由于 Steven: 恩 … … 确 实 有 一 些 。 比 如 说 , Struts的 action不依赖具体的运行环境,所以单元测试也很方便, ActionForm其实不太好用,有点不伦不类的,平白的在 直接把action new出来,把参数设置进去就可以测试 action和view之间引入了麻烦。Struts最近的设计也逐 了。 渐在淡化ActionForm的作用了。 Steven:说起测试嘛,抛开先富起来的地区不说,起码 Weber:是呀。而且Struts的不爽的地方还有接口比较 中国还有1/3的软件企业处在对TDD懵懂的阶段吧?还有 难看。action必须要实现继承,到现在也没有改为接口 1/3的企业在追捧CMM和一些瀑布模型的开发方法吧?那 继承。而且execute方法的接口也全是HttpServlet..., 么对于这些企业,Struts和WebWork在易测上的差异他 不能脱离servlet container,要测试还得提供mock的 们是感受不到的。当前的状态下,易测性并不是软件企业 request,真是麻烦。 技术选型的一个重点目标,那么Struts就有了其生存的土 壤。当然这就扯得有点远了。 Steven:Struts由于要重用action的实例,因此不得 不把所有状态从action里剔除,从而需要每次都传入 Weber:你说得很有道理。Struts好在够多的人支持、 request/response,这是一个典型的无状态设计,为 使用,让人觉得够稳定、保险、有保障。要是做个项目, pool和负载作了准备,理论上讲性能的延展性要更好一 很多老板一定说,我要的不是新技术,要的是稳定。所以 些。Struts由于每次都要处理request/response,所以 我现在也还常常在用Struts开发项目。 必须提供一些工具方法,于是Action不再是接口,而改 成一个class,这个设计在ood里也是常用的手法。如果 Steven:看来我也应该多了解一下WebWork。如果以后 没有这些接口,又怎么在servlet和action之间传递数据 采用TDD的开发方法,可测性的确是很重要的因素,那时 呢? 也许我就会选择用WebWork了。 Weber:这就是WebWork的设计精彩之处了。action都 Weber:还有一种折中的办法,就是改造Struts,给它 是普通的JavaBean,它们只实现自己的业务功能,其他 加上拦截器机制,然后再用拦截器来实现Dependency 基础设施级的功能——例如怎么与servlet交换数据—— Injection,这样可以把Struts变得跟WebWork一样易 都是用拦截器来实现的。正是因为有这个拦截器机制,所 用,而且又不会损失它原来的功能,实现起来也不算复 以WebWork才这么好用呢。 杂。 Steven:不过我看WebWork提供的功能还是比较少, Steven:确实不错。这么一来,我的工具箱里又多了一 比如它自己就没有数据校验的能力,必须要用别的工具来 种可选的方案了。 帮助校验。 附 录 : 关 于 Struts与 WebWork之 间 的 Weber:没错,但这种功能都可以用拦截器机制来做,你 技 术 比 较 , 请 看 下 列 两 个 地 址 : http:// 可以把这些拦截器抽象出来复用。所以WebWork本身不 udoo.51.net/mt/archives/000044.html 需要包含那么齐全的功能,它只提供了一个灵活的核心, http://wiki.opensymphony.com/display/WW/ 很多功能都可以做成插件插进去。而Struts就比较麻烦 Comparison+to+Struts
    • JPetStore项目分析:一个典型的 枯木 J2EE应用Web层的实现 关于JpetStore (http://www.jfox.cn/jpetstore/ http://www.ibatis.com/ jpetstore/jpetstore.html) JPetStore是Sun公司开发 的,在大众化的宠物商店 程序基础上完全重写的, 最早的基于J2EE平台的宠物 商店网络应用服务程序。 与其它的PetStore最本质的 不同是JPetStore使用了类似 Microsoft网络宠物商店的设 计,但是在骨子确是完全不一 样的网络服务构架,可以说这 种构架完全体现了Java程序在 网络应用方面的优势,故在此 以它为例,从Java的底层实现 方面来分析 J2EE在Web层的应 用。 系统架构概览 JPetStore以一个小型宠物 商店电子商务平台为原型向大 家展示了一个带有简单数据库 连接的J2EE Web层的应用,它 集成了Web层应用领域所必须 具备的要素,如:用户ID认 证、商品信息查询、商品信息 列表等等。总之,JPetStore是 一个集客户购物,下订单,管 理为一体的简单且典型的电子 商务的例子。 当然,现实中的系统不会 如此简单,大多数的系统要 和多个数据源和其他的EIS( 企业信息系统)相连通的, 有着比较复杂的数据库系统
    • JPetStore项目分析 的设计与连接。比如说,订单的提交可能是一 了处理的逻辑,它们代表了商业的数据,并且可 个公司,信用卡服务可能另外的公司,运送又 以对这些商业数据进行必要的操作;实体EJB代 是一个公司,这样的话,数据系统的设计就很 表了商业应用的实体,包括客户、地址、账目 复杂(一般来说这就需要专门的DBA进行数据库 等;会话EJB提供了一些方法,如用户登陆、输 的设计)。然而作为窥探J2EE的一个窗口,了解 出用户信息、管理购物车等;其它会话EJB提供 J2EE的运作,JPetStore足以胜任。 了一些通用的方法,如产生唯一标示符等。传 JPetStore划分成了多个模块,采取了松耦 统的JavaBean组件演变成了值对象,在EJB组件 合的设计架构,允许存在多个数据源及EIS进行 和应用间进行传递数据,成功地处理了各个对 信息交互。它的结构相对简单,总共包括4个部 象的封装,有效地降低了程序设计的难度。而 分: XML文档类则用来处理订单信息。 • 购物站点 这个例子的WAF是对J2EE蓝图Web层规范的 • 管理。如:销售统计,手工接受/拒绝订 一个有效实现。一个通用的Web层处理一般可以 单 划分为四个步骤(如图2所示): • 订单处理 ◆ 解释一个请求 通过JMS接受/处理订单消息   ◆ 执行一个商业逻辑处理 用java mail来通知客户   ◆ 选择下一个视图 通过JMS发订单给供应商   ◆ 产生这个视图 并修改订单数据库的相应信息 • 供应商 通过JMS接受订 单 派送货物给用户 提供一个基于 web的库存管理 维护库存数据库 系统架构解析 宠物商店的网站 服务采用自上而下的 构架,其最上层是由 WAF(Web Application Framework)控制应用屏幕的跳转,进而产生视    图2 WAF的Web层处理 图,然后再调用商业组件来实现流程的处理(整 体结构如图1所示)。  下面将分析宠物商店各个模块的设计 , 宠物商店主要的一些独立组成模 块(如图3所示):   ◆ 控制模块 用来分发请求到 各个业务处理逻辑、控制屏幕跳 转、处理对应的组件及用户   ◆ 登录和注册 控制模块由 WAF实现和扩展   ◆ 购物车模块 购物车跟踪用 户购物的过程   ◆ 登录模块 确定用户登陆的 页面 ◆ 消息模块 从宠物商店 到定单处理中心用来异步传输订 单  ◆ 类别模块 根据用户查 图1 JPet Store 总体框架结构 询需求提供一个类别视图  ◆ 客户模块 表示客户信息,如地址、 WAF提供众多Web应用所需的服务,其中 信用卡、联系方式等 包括请求过滤和分发、产生模板视图、可重用的 Taglib,以及屏幕流程控制等等。应用组件封装
    • JPetStore项目分析 图3 JPet Store 模块设计 在图3中,控制模块将控制所有的交互信息 可以在XML文件内看到一序列的Bean,其标 和执行信息,每个用户会话都有一个购物车与之 识如:<form-beans> </form-beans>或<bean> 相对应。 </bean>, 例如struts-config.xml中: 宠物商店的组件主要有以下几个部分: <form-beans>   ◆ EJB 代表了商业数据和商业逻辑的 <form-bean name="accountBean" 处理 type="com.ibatis.jpetstore.   ◆ JSP页面 定义了整个应用视图的框架 presentation.AccountBean"/> 模板(template.jsp),由模板组成的各个JSP页面文 <form-bean name="catalogBean" type="com. 件,以及各种被引用的图形文件 ibatis.jpetstore.presentation.   ◆ XML文件 用来定义屏幕、屏幕跳转 CatalogBean"/> 控制、绑定URL到某个HTML Action、定制 <form-bean name="cartBean" type="com. signOn以及J2EE的部署 ibatis.jpetstore.presentation.   ◆ Servlet过滤器 用来校验用户安全登陆和 CartBean"/> 输出的编码 <form-bean name="orderBean" type="com.   ◆ 异步信息发送组件 传输使用XML封装的 ibatis.jpetstore.presentation. 订单到订单处理中心 OrderBean"/> ◆ 安装程序 用来产生例子数据库。 </form-beans> JpetStore系统的实现 下面是jPetStore的Spring层的三个结构文件 前面介绍的是JpetStore所涉及的J2EE Web构架 及所实现的功能, 如图5所示: 方面的常识以及JpetStore系统构架的一些信息, Presentation Layer 接下来,让我们进一步来了解一下JpetStore系统 界面交互 的实现。 Business Layer 首先,来认识一下JpetStore实现代码整体文件 Domain Model 实现 框架(图4,见下页): Data Layer Dao 实现 下面让我们对其中的一些实现的 web.xml 技术进行更深入的探讨。JPetStore 程序包括基于 struts-config.xml Spring规范的数据源,DAO层和交互式页面。你
    • JPetStore项目分析 Dao.xml return (Account) queryForObject("getAccount ByUsername", username); JpetStroeDomain 的结构(如图6): } …… } JpetStroe Presentation定义了Formbean,例 如AccountBean.java就为Account.java实现了 Formbean。在进行构架分析之前,先来了解一 下MVC构架(如图6):MVC(Model/View/ Controller,MVC)构架允许一个开发者将一 个可视化接口连接到一个面向对象的设计中, 而同时还可以避免我们上面讨论的几个问题。 MVC通过创建下面三个层将面向对象的设计与 可视化接口分开: 模型(Model):模型包含完成任务所需要 的所有的行为和数据。模型一般由许多类组成并 且使用面向对象的技术来创建满足五个设计目标 的程序。 界面(View):一个界面就是一个程序的可 视化元素,如对话框、选单、工具条等。界面显 图6 JpetStrore业务类 示从模型中提供的数据,它并不控制数据或提供 除显示外的其它行为。一个单一的程序或模型一 其内部都是对一些涉及到的实体的属性进行 般有两种界面行为。界面从模型内的对象中显示 定义,并实现数据封装。如:Account.java 数据。这些对象的改变可以通过也可以不通过用 户的交互操作来完成。如:在一个Web浏览器中 public class Account implements Serializable { 负责接收页面的对象收集和装配栈中的信息,必 须有某种方式来让这些对象通知界面数据已经被 /* Private Fields */ 改变了。在模型变化时有两种方法来对界面进行 private String username; 更新。 private String password; 控制器(Controller):控制器将模型映射到 …… 界面中。控制器处理用户的输入,每个界面有一 /* JavaBeans Properties */ 个控制器。它是一个集接收用户输入、创建或修 public String getUsername() { 改适当的模型对象并将修改在界面中体现出来的 return username; 一种状态控制的集合体。控制器在需要时还负责 } 创建其它的界面和控制器。控制器一直决定哪些 public void setUsername(String username) { 界面和模型组件应该在某个给定的时刻是活动 this.username = username; 的,它一直负责接收和处理用户的输入,来自用 } } JpetStroe Persistence是对Domain业务的操作 的实现。包括接口(iface)和实现(sqlmapdao)。如 AccountDao.java和AccountSqlMapDao.java public interface AccountDao { public Account getAccount(String username); …… } public class AccountSqlMapDao extends BaseSqlMapDao implements AccountDao { …… public Account getAccount(String username) {
    • JPetStore项目分析 户输入的任何变化都被从控制器送到模型。 …… 通过以上的介绍,现在让我们来分析 /* Static Initializer */ JpetStore是如何实现MVC,并进行流程处理的。 首先是整个系统的配置,它是由一些xml文件来 static { 实现的。如: List langList = new ArrayList(); <form-beans> …… <form-bean name="accountBean" } type="com.ibatis.jpetstore. presentation.AccountBean"/> /* Constructors */ <form-bean name="catalogBean" type="com.ibatis.jpetstore. public AccountBean() { presentation.CatalogBean"/> account = new Account(); <form-bean name="cartBean" type="com. } ibatis.jpetstore.presentation. CartBean"/> /* JavaBeans Properties */ <form-bean name="orderBean" type="com. ibatis.jpetstore.presentation. public String getUsername() { OrderBean"/> return account.getUsername(); </form-beans> } 其次来看一看Controller层(在struts文件夹 …… 中),如:basebean.java public void validate() {//错误信息反馈 public abstract class BaseBean extends …… ActionForm { } …… } public void reset(ActionMapping mapping, JpetStore便是通过以上的基本技术来实现 ServletRequest request) { MVC的基础构架的。 stMap.put("errors",errorList); validate(); 小结 errorList = (List) requestMap. 从Java应用于Internet开发的发展历程来看, get("errors"); 可将其开发方法划分为三个阶段:第一阶段是 ActionErrors actionErrors = null; 将业务逻辑和表现逻辑完全集成在一起,采用 if (errorList != null && !errorList. HTML、JSP和Servlets技术开发;第二阶段是将 isEmpty()) { 业务逻辑和表现逻辑分开,采用HTML、JSP、 actionErrors = new ActionErrors(); Servlets、JavaBeans Compoments和Custom Tags技 actionErrors.add(ActionErrors.GLOBAL_ 术开发;第三个阶段是MVC设计模式(J2EE的 ERROR,new ActionError("global.error")); 开发方法)。透过JpetStore这个比较简单项目, } 我们就已经能够充分体验到了J2EE开发方法所带 return actionErrors; 来的便利性,难怪,在网络技术高速发展的今 } 天,新技术层出不穷,可J2EE开发技术始终占据 …… 着主流的霸主地位。 } 再来接触一下Formbean(在Presentation文件 夹中),如AccountBean.java public class AccountBean extends BaseBean { /* Constants */ private static final AccountService accountService = AccountService.getInstance(); …… /* Private Fields */ private Account account;
    • 业界动态 BEA eWorld现场报道:第一天 被各大厂商炒得沸沸扬扬,但开发者们普遍仍处 于观望阶段,希望看到在实际项目中应用SOA的 12月15日,上海阳光明媚,室外气温17度。BEA 架构示例。在未来两天的大会中,BEA将向开发 eWorld大会将于明天开幕。本次大会BEA高层悉 者们展示电信、金融、政府应用等行业的SOA应 数来华,可见对此次大会的重视程度。本次大会 用实例。 的主题有三个。第一,Diablo;第二,SOA;第 三,开发者关系。 另外,BEA开发者日活动将是此次大会的重头 戏之一。BEA一向在开发者群体中有不错的口 Diablo不是暗黑破坏神的游戏,是将于明天发 碑,这次来华的BEA高层除了创始人兼CEO庄 布的WebLogic Server 9.0的代号。12月7日在 思浩(Alfred Chuang)、全球产品执行副总裁黄 旧金山,BEA曾经把Oracle OpenWorld大会 卫文等人之外,还有CTO办公室首席技术专家 的一群演讲者拉到一家宾馆,向他们展示了 Michael Smith和负责开发者关系的Scott Regan等 Diablo的beta版本,也引起了这些技术专家们很 技术人士。CSDN网站将对这两位技术专家进行 大的兴趣。据来自各方面的零星消息称,新版 独家专访,就开发者感兴趣的新一代应用服务器 本的WebLogic应用服务器支持J2EE 1.4规范, 技术架构、BEA中国开发者活动策略、BEA中国 并且据称对SOA有特别优化的支持,实际上是 人才计划等话题展开讨论。请CSDN网友继续关 用基于JMS的消息存储和转发机制实现了WS- 注记者的后续报道。 ReliableMessaging规范——这是一个关于“提供 可靠异步消息”的web service规范。据BEA产品 开发你的Rich Client:IBM对Laszlo开源富 执行副总裁黄卫文(Wai Wong)声称,在这个 客户端平台提供支持 消息机制基础上搭建的企业服务总线(Enterprise Service Bus,ESB)在效率方面比以前的版本至 IBM AlphaWorks网站近日发布了用于开发 少有三到四倍的提升。正是因为有这样一个可靠 Laszlo应用程序的集成开发环境(实际上是一个 并且高效的消息总线,BEA一直推崇的SOA才能 Eclipse插件),使J2EE开发者能够在他们熟悉的 成其为现实,这也是为什么说Diablo这款应用服 Eclipse环境中快速开发基于Laszlo的rich client应 务器尤其适合SOA的原因。 用程序。可以在下列地址下载该插件: 另外,BEA尤其强调这款服务器的热部署( http://alphaworks.ibm.com/tech/ide4laszlo hot-deploy)能力。在本次eWorld大会的宣传 资料中,笔者看到一份题为“流体计算”( 此外,AlphaWorks网站还提供了一个用Laszlo开 Liquid Computing)的材料,极言BEA对于企业 发的示例应用,展示了在Eclispe环境下开发 应对快速变化的帮助,Diablo强大的热部署能力 Laszlo应用的过程。demo的地址如下: 应当是其中重要的技术环节。众所周知,过去 WebLogic处理EJB采用了“预编译”的做法,即 http://dl.alphaworks.ibm.com/technologies/rcb/ 首先用ant脚本自动根据业务代码生成home对象 demo.html 等EJB必要的代码,然后部署到应用服务器,这 种实现策略的一大缺陷就是无法实现有效的热 Laszlo是一个开源的rich client开发环境。使用 部署。此次BEA重点宣传Diablo的热部署能力, Laszlo平台时,开发者只需编写名为LZX的描述 再加上此前BEA招聘了AspectWerkz的两位核心 语言(其中整合了XML和JavaScript),运行在 开发者,令人不禁联想Diablo的核心是否采用了 J2EE应用服务器上的Laszlo平台会将其编译成 AOP技术,而彻底放弃了预编译的做法。这个 FLASH文件并传输给客户端展示。单从运行原 猜想在未来的两天内即将得到确认。 理来说,Laszlo与XUL、XAML很类似。但它的 最大优势在于:它把描述语言编译成FLASH, 除了Diablo的发布之外,SOA的应用也是本次大 而FLASH是任何浏览器都支持的展示形式,从 会的重点话题。在整个2004年,SOA的概念已经
    • 而一举解决了浏览器之间的移植问题。而且, http://jcp.org/aboutJava/communityprocess/edr/ 在未来的计划中,Laszlo还可以将LZX编译成 jsr252/ Java或.NET本地代码,从而大大提高运行效率。 近日Laszlo的CTO David Temkin接受了一个采 Google大举挖进Java人才 BEA首席架构师 访,对Laszlo的战略和发展做了更多的介绍: 投奔 http://news.com.com/David+vs.+Goliath+vs.+Gol 不久前,Google刚刚挖到了Joshua Bloch,他是 iath/2008-7344_3-5457982.html Effective Java的作者,他设计的Collections框架 也是迄今最受好评的类库框架之一。同时他 JSP 2.1和JSF 1.2规范发布预览版本 还是JSR175(A Metadata Facility for the JavaTM Programming Language)的首席专家。 J2EE的两种重要的表现层技术JSP和JSF发布了新 技术规范的预览版本,其中最重要的一点是两 紧接着,Google又把BEA的首席架构师Adam 者将表达式语言(Expression Language,EL)部 Bosworth拢入自己旗下。Bosworth在软件行业 分合二为一。在不久的将来,这两种技术有可 作为技术主管受到广泛的尊敬。在为新创企 能更进一步地彼此融合,成为一种统一的表现 业Crossgain(2001年被BEA收购)工作之前, 层技术。然而在J2EE社群的普遍观点中,如果单 Bosworth曾在微软任职数年,并成功地从事于一 单作为一种视图技术,JSP并不是最佳的选择, 些项目的开发,如微软的Access数据库。 Velocity和XSLT等基于模板的视图技术通常比 JSP更方便;而基于组件的JSF也面临广泛的信任 他的跳槽来得太突然了,两个月以前,他还在供 危机。两者的组合是否能得到业界的认可,还需 应商的“年度eWorld秀”中担任重要角色,并 要时间的检验。 他的主题演讲中介绍Alchemy项目----一个建 立下一代移动浏览器的计划。 以下是官方公告 Google的招兵买马计划一直在有条不紊的进行 我们很高兴向大家宣告,JavaServer Pages、JSR- 着,曾在SUN微系统工作的David Stoutamire, 245下开发的Faces.JavaServer Pages(JSP)2.1和 现在在Google工作。就在上星期,Neal JSR-252下开发的JavaServer Faces(Faces)1.2的 Gafter,SUN公司的javac主管,也离开SUN转向 新版规范的Early Draft Review发布。 Google。 JSP 2.1把Expression Language(EL)输出到它自 不仅是Java方面,Greg Stein,曾是CollabNet项 己各自分离的文档中,在技术上,这些文档是 目经理,管理Subversion 项目并且发布了他们的 JSP规范的子文档。这些统一的EL规范定义了一 SourceCast产品,现在在Google的博客软件组工 个更高层的java 包,javax.el。这个包与使用它的 作;Rob Pike,曾是贝尔实验室最初Unix团队成 技术之间完全独立,并且允许此技术将自身插 员之一,参与过Plan 9 和Inferno操作系统的开发, 入EL处理过程。更改的JSP规范遵从使用标准化 如今也投奔Google。 EL的规范。 Google一直渴求人才,对于开发者来说, 对于前面提到的JSR-252,这个规范并没什么新 Google也是一个充满吸引力的地方。他只雇佣 特性。Faces 1.2支持新的标准化EL,还包含一些 最棒的、最聪明的、近乎于天才的那些家伙, bug修复的相关规范。 在笼络人才这方面,也只有微软可与之媲美。 最近Java人才不断涌入Google究竟是巧合,或是 Faces和JSP在JSRs下的结盟带来了一些新功能, Google准备尝试基于Java做一些事情,我们拭目 也为将来的发展打下了坚实的基础。例如,在 以待。 同时使用Faces和JSP的web应用中,网页仅使 用JSP(不包含任何faces内容)来访问Managed Beans成为可能。在JSP规范的附录E中和Faces规 范的前言中都可以看到更改内容的细节。 JSP 2.1 EDR (JSR-245) http://jcp.org/aboutJava/communityprocess/edr/ jsr245/ Faces 1.2 EDR (JSR-252)
    • Java eMag I’m loving it