SlideShare ist ein Scribd-Unternehmen logo
1 von 56
Downloaden Sie, um offline zu lesen
刊
    号   本期推荐
        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">
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期
Csdn Java电子杂志第1期

Weitere ähnliche Inhalte

Andere mochten auch

Echinoderms
EchinodermsEchinoderms
EchinodermsTamara
 
Maximum Social Media Recruitment NL V1 20100211
Maximum Social Media Recruitment NL V1 20100211Maximum Social Media Recruitment NL V1 20100211
Maximum Social Media Recruitment NL V1 20100211Patrick Boonstra
 
Shri Laxmi Narayan Dr. Shriniwas Kashalikar
Shri Laxmi Narayan Dr. Shriniwas KashalikarShri Laxmi Narayan Dr. Shriniwas Kashalikar
Shri Laxmi Narayan Dr. Shriniwas Kashalikarbanothkishan
 
Photoshop_BlendingPhotos
Photoshop_BlendingPhotosPhotoshop_BlendingPhotos
Photoshop_BlendingPhotostutorialsruby
 
Happy New Year Dr Shriniwas Janardan Kashalikar
Happy New Year Dr  Shriniwas Janardan KashalikarHappy New Year Dr  Shriniwas Janardan Kashalikar
Happy New Year Dr Shriniwas Janardan Kashalikarbanothkishan
 
MRSA VACCINE/HIT REGIONAL KILLER BOYDEN GRAY
MRSA VACCINE/HIT REGIONAL KILLER BOYDEN GRAYMRSA VACCINE/HIT REGIONAL KILLER BOYDEN GRAY
MRSA VACCINE/HIT REGIONAL KILLER BOYDEN GRAYPrayer Warriors Institute
 
The Financial Director Cost Control Checklist
The Financial Director Cost Control ChecklistThe Financial Director Cost Control Checklist
The Financial Director Cost Control ChecklistAlan Birse
 
New Study Of Gita Nov 10 Dr Shriniwas J Kashalikar
New Study Of Gita Nov 10 Dr  Shriniwas J  KashalikarNew Study Of Gita Nov 10 Dr  Shriniwas J  Kashalikar
New Study Of Gita Nov 10 Dr Shriniwas J Kashalikarbanothkishan
 
FSC-CIGARETTES-TOXIC-DECEPTIVE-PRACTICES-CRIMINAL-FRAUD-GASEOUS-ACTIVATORS-5-...
FSC-CIGARETTES-TOXIC-DECEPTIVE-PRACTICES-CRIMINAL-FRAUD-GASEOUS-ACTIVATORS-5-...FSC-CIGARETTES-TOXIC-DECEPTIVE-PRACTICES-CRIMINAL-FRAUD-GASEOUS-ACTIVATORS-5-...
FSC-CIGARETTES-TOXIC-DECEPTIVE-PRACTICES-CRIMINAL-FRAUD-GASEOUS-ACTIVATORS-5-...Prayer Warriors Institute
 
How To Enter University
How To Enter UniversityHow To Enter University
How To Enter Universityseyedraadi
 
B L O S S O M W I T H S T R E S S M A N A G E M E N T D R S H R I N I W...
B L O S S O M  W I T H  S T R E S S  M A N A G E M E N T   D R  S H R I N I W...B L O S S O M  W I T H  S T R E S S  M A N A G E M E N T   D R  S H R I N I W...
B L O S S O M W I T H S T R E S S M A N A G E M E N T D R S H R I N I W...banothkishan
 
Y O G A A N D S U P E R J O Y D R
Y O G A  A N D  S U P E R J O Y  D RY O G A  A N D  S U P E R J O Y  D R
Y O G A A N D S U P E R J O Y D Rbanothkishan
 
Achieve WordPress Blogging Success
Achieve WordPress Blogging SuccessAchieve WordPress Blogging Success
Achieve WordPress Blogging SuccessG9 Media
 
Namasmaran And Stress Dr. Shriniwas J. Kashalikar
Namasmaran And Stress Dr. Shriniwas J. KashalikarNamasmaran And Stress Dr. Shriniwas J. Kashalikar
Namasmaran And Stress Dr. Shriniwas J. Kashalikarbanothkishan
 
How to Create a University Entrepreneurship Program entry on SmallBusiness.com
How to Create a University Entrepreneurship Program entry on SmallBusiness.comHow to Create a University Entrepreneurship Program entry on SmallBusiness.com
How to Create a University Entrepreneurship Program entry on SmallBusiness.comSmallBusiness.com
 
shelleyrae_PS_refineedge
shelleyrae_PS_refineedgeshelleyrae_PS_refineedge
shelleyrae_PS_refineedgetutorialsruby
 
M E A N I N G O F C O N C E P T U A L S T R E S S D R
M E A N I N G  O F  C O N C E P T U A L  S T R E S S  D RM E A N I N G  O F  C O N C E P T U A L  S T R E S S  D R
M E A N I N G O F C O N C E P T U A L S T R E S S D Rbanothkishan
 

Andere mochten auch (18)

Echinoderms
EchinodermsEchinoderms
Echinoderms
 
Maximum Social Media Recruitment NL V1 20100211
Maximum Social Media Recruitment NL V1 20100211Maximum Social Media Recruitment NL V1 20100211
Maximum Social Media Recruitment NL V1 20100211
 
Shri Laxmi Narayan Dr. Shriniwas Kashalikar
Shri Laxmi Narayan Dr. Shriniwas KashalikarShri Laxmi Narayan Dr. Shriniwas Kashalikar
Shri Laxmi Narayan Dr. Shriniwas Kashalikar
 
Photoshop_BlendingPhotos
Photoshop_BlendingPhotosPhotoshop_BlendingPhotos
Photoshop_BlendingPhotos
 
Happy New Year Dr Shriniwas Janardan Kashalikar
Happy New Year Dr  Shriniwas Janardan KashalikarHappy New Year Dr  Shriniwas Janardan Kashalikar
Happy New Year Dr Shriniwas Janardan Kashalikar
 
MRSA VACCINE/HIT REGIONAL KILLER BOYDEN GRAY
MRSA VACCINE/HIT REGIONAL KILLER BOYDEN GRAYMRSA VACCINE/HIT REGIONAL KILLER BOYDEN GRAY
MRSA VACCINE/HIT REGIONAL KILLER BOYDEN GRAY
 
The Financial Director Cost Control Checklist
The Financial Director Cost Control ChecklistThe Financial Director Cost Control Checklist
The Financial Director Cost Control Checklist
 
New Study Of Gita Nov 10 Dr Shriniwas J Kashalikar
New Study Of Gita Nov 10 Dr  Shriniwas J  KashalikarNew Study Of Gita Nov 10 Dr  Shriniwas J  Kashalikar
New Study Of Gita Nov 10 Dr Shriniwas J Kashalikar
 
FSC-CIGARETTES-TOXIC-DECEPTIVE-PRACTICES-CRIMINAL-FRAUD-GASEOUS-ACTIVATORS-5-...
FSC-CIGARETTES-TOXIC-DECEPTIVE-PRACTICES-CRIMINAL-FRAUD-GASEOUS-ACTIVATORS-5-...FSC-CIGARETTES-TOXIC-DECEPTIVE-PRACTICES-CRIMINAL-FRAUD-GASEOUS-ACTIVATORS-5-...
FSC-CIGARETTES-TOXIC-DECEPTIVE-PRACTICES-CRIMINAL-FRAUD-GASEOUS-ACTIVATORS-5-...
 
How To Enter University
How To Enter UniversityHow To Enter University
How To Enter University
 
B L O S S O M W I T H S T R E S S M A N A G E M E N T D R S H R I N I W...
B L O S S O M  W I T H  S T R E S S  M A N A G E M E N T   D R  S H R I N I W...B L O S S O M  W I T H  S T R E S S  M A N A G E M E N T   D R  S H R I N I W...
B L O S S O M W I T H S T R E S S M A N A G E M E N T D R S H R I N I W...
 
Y O G A A N D S U P E R J O Y D R
Y O G A  A N D  S U P E R J O Y  D RY O G A  A N D  S U P E R J O Y  D R
Y O G A A N D S U P E R J O Y D R
 
12 2 Contracts
12 2 Contracts12 2 Contracts
12 2 Contracts
 
Achieve WordPress Blogging Success
Achieve WordPress Blogging SuccessAchieve WordPress Blogging Success
Achieve WordPress Blogging Success
 
Namasmaran And Stress Dr. Shriniwas J. Kashalikar
Namasmaran And Stress Dr. Shriniwas J. KashalikarNamasmaran And Stress Dr. Shriniwas J. Kashalikar
Namasmaran And Stress Dr. Shriniwas J. Kashalikar
 
How to Create a University Entrepreneurship Program entry on SmallBusiness.com
How to Create a University Entrepreneurship Program entry on SmallBusiness.comHow to Create a University Entrepreneurship Program entry on SmallBusiness.com
How to Create a University Entrepreneurship Program entry on SmallBusiness.com
 
shelleyrae_PS_refineedge
shelleyrae_PS_refineedgeshelleyrae_PS_refineedge
shelleyrae_PS_refineedge
 
M E A N I N G O F C O N C E P T U A L S T R E S S D R
M E A N I N G  O F  C O N C E P T U A L  S T R E S S  D RM E A N I N G  O F  C O N C E P T U A L  S T R E S S  D R
M E A N I N G O F C O N C E P T U A L S T R E S S D R
 

Ähnlich wie Csdn Java电子杂志第1期

淘宝网前端应用与发展
淘宝网前端应用与发展淘宝网前端应用与发展
淘宝网前端应用与发展taobao.com
 
常用Js框架比较
常用Js框架比较常用Js框架比较
常用Js框架比较Adam Lu
 
rebar erlang 2
rebar erlang 2rebar erlang 2
rebar erlang 2致远 郑
 
程序组介绍Ver2.0
程序组介绍Ver2.0程序组介绍Ver2.0
程序组介绍Ver2.0vtmers2012
 
《Linux运维趋势》2012年5月号 总第19期
《Linux运维趋势》2012年5月号 总第19期《Linux运维趋势》2012年5月号 总第19期
《Linux运维趋势》2012年5月号 总第19期51CTO
 
那些mockup沒告訴你的事@WebConf.tw 2013
那些mockup沒告訴你的事@WebConf.tw 2013那些mockup沒告訴你的事@WebConf.tw 2013
那些mockup沒告訴你的事@WebConf.tw 2013Adam Wang
 
.Net网络编程入门
.Net网络编程入门.Net网络编程入门
.Net网络编程入门magicshui
 
twMVC#42 讓我們用一種方式來開發吧
twMVC#42 讓我們用一種方式來開發吧twMVC#42 讓我們用一種方式來開發吧
twMVC#42 讓我們用一種方式來開發吧twMVC
 
[2008]网站重构 -who am i
[2008]网站重构 -who am i[2008]网站重构 -who am i
[2008]网站重构 -who am iTwinsen Liang
 
Top100summit前端的云时代支付宝前端平台架构 王保平
Top100summit前端的云时代支付宝前端平台架构  王保平Top100summit前端的云时代支付宝前端平台架构  王保平
Top100summit前端的云时代支付宝前端平台架构 王保平drewz lin
 
淘宝网前端开发面试题
淘宝网前端开发面试题 淘宝网前端开发面试题
淘宝网前端开发面试题 Lumend
 
Architect 201003-by-info q
Architect 201003-by-info qArchitect 201003-by-info q
Architect 201003-by-info qgavin shaw
 
React.js what do you really mean?
React.js what do you really mean?React.js what do you really mean?
React.js what do you really mean?昱安 周
 
Insider Dev Tour - Taipei Productive and Fun Web Development with NodeJS and ...
Insider Dev Tour - Taipei Productive and Fun Web Development with NodeJS and ...Insider Dev Tour - Taipei Productive and Fun Web Development with NodeJS and ...
Insider Dev Tour - Taipei Productive and Fun Web Development with NodeJS and ...jasonzheng50
 
2016 前端潮玩意兒
2016 前端潮玩意兒2016 前端潮玩意兒
2016 前端潮玩意兒Maxis Kao
 
Html5研究小组《微周刊》第28期
Html5研究小组《微周刊》第28期Html5研究小组《微周刊》第28期
Html5研究小组《微周刊》第28期chloeguo
 
Non-MVC Web Framework
Non-MVC Web FrameworkNon-MVC Web Framework
Non-MVC Web FrameworkFred Chien
 
Ruby rails分享
Ruby rails分享Ruby rails分享
Ruby rails分享Cam Song
 
從 Java programmer 的觀點看 ruby
從 Java programmer 的觀點看 ruby從 Java programmer 的觀點看 ruby
從 Java programmer 的觀點看 ruby建興 王
 

Ähnlich wie Csdn Java电子杂志第1期 (20)

淘宝网前端应用与发展
淘宝网前端应用与发展淘宝网前端应用与发展
淘宝网前端应用与发展
 
常用Js框架比较
常用Js框架比较常用Js框架比较
常用Js框架比较
 
rebar erlang 2
rebar erlang 2rebar erlang 2
rebar erlang 2
 
程序组介绍Ver2.0
程序组介绍Ver2.0程序组介绍Ver2.0
程序组介绍Ver2.0
 
《Linux运维趋势》2012年5月号 总第19期
《Linux运维趋势》2012年5月号 总第19期《Linux运维趋势》2012年5月号 总第19期
《Linux运维趋势》2012年5月号 总第19期
 
那些mockup沒告訴你的事@WebConf.tw 2013
那些mockup沒告訴你的事@WebConf.tw 2013那些mockup沒告訴你的事@WebConf.tw 2013
那些mockup沒告訴你的事@WebConf.tw 2013
 
.Net网络编程入门
.Net网络编程入门.Net网络编程入门
.Net网络编程入门
 
twMVC#42 讓我們用一種方式來開發吧
twMVC#42 讓我們用一種方式來開發吧twMVC#42 讓我們用一種方式來開發吧
twMVC#42 讓我們用一種方式來開發吧
 
[2008]网站重构 -who am i
[2008]网站重构 -who am i[2008]网站重构 -who am i
[2008]网站重构 -who am i
 
Top100summit前端的云时代支付宝前端平台架构 王保平
Top100summit前端的云时代支付宝前端平台架构  王保平Top100summit前端的云时代支付宝前端平台架构  王保平
Top100summit前端的云时代支付宝前端平台架构 王保平
 
淘宝网前端开发面试题
淘宝网前端开发面试题 淘宝网前端开发面试题
淘宝网前端开发面试题
 
Architect 201003-by-info q
Architect 201003-by-info qArchitect 201003-by-info q
Architect 201003-by-info q
 
React.js what do you really mean?
React.js what do you really mean?React.js what do you really mean?
React.js what do you really mean?
 
Insider Dev Tour - Taipei Productive and Fun Web Development with NodeJS and ...
Insider Dev Tour - Taipei Productive and Fun Web Development with NodeJS and ...Insider Dev Tour - Taipei Productive and Fun Web Development with NodeJS and ...
Insider Dev Tour - Taipei Productive and Fun Web Development with NodeJS and ...
 
2016 前端潮玩意兒
2016 前端潮玩意兒2016 前端潮玩意兒
2016 前端潮玩意兒
 
Html5研究小组《微周刊》第28期
Html5研究小组《微周刊》第28期Html5研究小组《微周刊》第28期
Html5研究小组《微周刊》第28期
 
Non-MVC Web Framework
Non-MVC Web FrameworkNon-MVC Web Framework
Non-MVC Web Framework
 
Ruby rails分享
Ruby rails分享Ruby rails分享
Ruby rails分享
 
從 Java programmer 的觀點看 ruby
從 Java programmer 的觀點看 ruby從 Java programmer 的觀點看 ruby
從 Java programmer 的觀點看 ruby
 
42qu thrift1
42qu thrift142qu thrift1
42qu thrift1
 

Mehr von yiditushe

Spring入门纲要
Spring入门纲要Spring入门纲要
Spring入门纲要yiditushe
 
J Bpm4 1中文用户手册
J Bpm4 1中文用户手册J Bpm4 1中文用户手册
J Bpm4 1中文用户手册yiditushe
 
性能测试实践2
性能测试实践2性能测试实践2
性能测试实践2yiditushe
 
性能测试实践1
性能测试实践1性能测试实践1
性能测试实践1yiditushe
 
性能测试技术
性能测试技术性能测试技术
性能测试技术yiditushe
 
Load runner测试技术
Load runner测试技术Load runner测试技术
Load runner测试技术yiditushe
 
J2 ee性能测试
J2 ee性能测试J2 ee性能测试
J2 ee性能测试yiditushe
 
面向对象的Js培训
面向对象的Js培训面向对象的Js培训
面向对象的Js培训yiditushe
 
Flex3中文教程
Flex3中文教程Flex3中文教程
Flex3中文教程yiditushe
 
开放源代码的全文检索Lucene
开放源代码的全文检索Lucene开放源代码的全文检索Lucene
开放源代码的全文检索Luceneyiditushe
 
基于分词索引的全文检索技术介绍
基于分词索引的全文检索技术介绍基于分词索引的全文检索技术介绍
基于分词索引的全文检索技术介绍yiditushe
 
Lucene In Action
Lucene In ActionLucene In Action
Lucene In Actionyiditushe
 
Lucene2 4学习笔记1
Lucene2 4学习笔记1Lucene2 4学习笔记1
Lucene2 4学习笔记1yiditushe
 
Lucene2 4 Demo
Lucene2 4 DemoLucene2 4 Demo
Lucene2 4 Demoyiditushe
 
Lucene 全文检索实践
Lucene 全文检索实践Lucene 全文检索实践
Lucene 全文检索实践yiditushe
 
Lucene 3[1] 0 原理与代码分析
Lucene 3[1] 0 原理与代码分析Lucene 3[1] 0 原理与代码分析
Lucene 3[1] 0 原理与代码分析yiditushe
 
7 面向对象设计原则
7 面向对象设计原则7 面向对象设计原则
7 面向对象设计原则yiditushe
 
10 团队开发
10  团队开发10  团队开发
10 团队开发yiditushe
 
9 对象持久化与数据建模
9  对象持久化与数据建模9  对象持久化与数据建模
9 对象持久化与数据建模yiditushe
 
8 Uml构架建模
8  Uml构架建模8  Uml构架建模
8 Uml构架建模yiditushe
 

Mehr von yiditushe (20)

Spring入门纲要
Spring入门纲要Spring入门纲要
Spring入门纲要
 
J Bpm4 1中文用户手册
J Bpm4 1中文用户手册J Bpm4 1中文用户手册
J Bpm4 1中文用户手册
 
性能测试实践2
性能测试实践2性能测试实践2
性能测试实践2
 
性能测试实践1
性能测试实践1性能测试实践1
性能测试实践1
 
性能测试技术
性能测试技术性能测试技术
性能测试技术
 
Load runner测试技术
Load runner测试技术Load runner测试技术
Load runner测试技术
 
J2 ee性能测试
J2 ee性能测试J2 ee性能测试
J2 ee性能测试
 
面向对象的Js培训
面向对象的Js培训面向对象的Js培训
面向对象的Js培训
 
Flex3中文教程
Flex3中文教程Flex3中文教程
Flex3中文教程
 
开放源代码的全文检索Lucene
开放源代码的全文检索Lucene开放源代码的全文检索Lucene
开放源代码的全文检索Lucene
 
基于分词索引的全文检索技术介绍
基于分词索引的全文检索技术介绍基于分词索引的全文检索技术介绍
基于分词索引的全文检索技术介绍
 
Lucene In Action
Lucene In ActionLucene In Action
Lucene In Action
 
Lucene2 4学习笔记1
Lucene2 4学习笔记1Lucene2 4学习笔记1
Lucene2 4学习笔记1
 
Lucene2 4 Demo
Lucene2 4 DemoLucene2 4 Demo
Lucene2 4 Demo
 
Lucene 全文检索实践
Lucene 全文检索实践Lucene 全文检索实践
Lucene 全文检索实践
 
Lucene 3[1] 0 原理与代码分析
Lucene 3[1] 0 原理与代码分析Lucene 3[1] 0 原理与代码分析
Lucene 3[1] 0 原理与代码分析
 
7 面向对象设计原则
7 面向对象设计原则7 面向对象设计原则
7 面向对象设计原则
 
10 团队开发
10  团队开发10  团队开发
10 团队开发
 
9 对象持久化与数据建模
9  对象持久化与数据建模9  对象持久化与数据建模
9 对象持久化与数据建模
 
8 Uml构架建模
8  Uml构架建模8  Uml构架建模
8 Uml构架建模
 

Csdn Java电子杂志第1期

  • 1. 号 本期推荐 Struts 最佳实践 J2EE模板技术 Java 创 对话:Web技术的思考 2004.12 J2EE Web框架汇总 E M A G . C S D N . N E T
  • 2. Java eMag I’m loving it James Gosling, Inventor of Java Te
  • 4. 篇首寄语 带着满身的风尘,笔者从 提升水平,才有可能逐渐摆脱 上海回到了北京。这时,我们 位于产业链末端的尴尬境地。 的第一期Java电子杂志也即将面 CSDN电子杂志正是希望为所有 世了。 中国程序员提供一个交流的平 台,我们的Java电子杂志也正是 在刚刚落幕的BEA eWorld 思想激烈碰撞的产物。也许它 2004大会上,笔者有幸见到了 还有很多不足之处,但我们毕 BEA的多位技术专家和高层管 竟上路了。 理人士。作为CSDN的代表,我 向他们提出了同一个问题:对 作为一个职业编辑,看着 中国软件开发者的印象如何? Java电子杂志的几位业余编辑制 中国程序员还有什么差距?有 作这份杂志是件饶有兴味的事 趣的是,他们无一例外地告诉 情。我本可以给他们更多的帮 笔者:中国程序员的技术能力 助,但我更愿意给他们少许建 和聪明才智令人折服;但中国 议,然后看着他们自己摸索前 程序员最大的缺陷在于经验和 进。其实不仅这份杂志,我们 交流。 大家的技术之路、职业之路又 何尝不是在不断的挫折和迂回 是的,经验和交流,这 中摸索前进?所以,希望每个 是我们最欠缺的。据统计, 看到这份电子杂志的人都尽可 北美的职业程序员平均年龄为 能地参与进来,不管是提出意 37.5岁,而中国大约为26岁。相 见和建议、写作投稿、或是加 比之下,我们少了10年的实践 入编辑团队,甚至哪怕只是给 经验,所以我们的技术、我们 我们一些精神上的鼓励,请你 的软件行业才显得那么稚嫩, 参与进来,让这份杂志也能在 那么不成熟。而年轻往往又同 我们所有人的交流与协作中不 时伴随着气盛,所以我们才看 断进步。 到了那么多的争吵、那么多的 浮躁。 希望我们的Java电子杂志会 越来越好。希望我们每个人的 为了弥补10年的差距,我 前途都会越来越好。 主编的话 们只能寄望于更多、更主动的 交流。只有大家都能把自己的 透明 实践经验和知识积累与所有同 行分享,我们才有可能更快地 2004年12月18日凌晨·北京
  • 5. 目 录 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所拥有。
  • 6. 关于我们 熊节 [ 透明 ] 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。
  • 7. 关于我们 石红军[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 联系方式 全新组合 首次亮相 希望可以得到您的支持和鼓励。也欢迎您加入到我们的队伍 中来,共同开创我们自己的技术天地
  • 8. 好书推荐 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
  • 9. 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等著名的脚本语言也 译。
  • 10. 热情 Passion JAVA M A G A Z I N E _ F R O M _ C S D N . N E T
  • 11. 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宣 布
  • 12. 专业 Professional JAVA M A G A Z I N E _ F R O M _ C S D N . N E T
  • 13. 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
  • 14. 技术 Technology JAVA M A G A Z I N E _ F R O M _ C S D N . N E T
  • 15. 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声明和映射和映射的部 分如下:
  • 16. 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
  • 17. 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响应中包含另外一个资源
  • 18. 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中
  • 19. 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规范以及一些成熟框架的源码。
  • 20. 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连接数据库。
  • 21. 法。 代码如下: 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 之标签库篇.
  • 22. 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了) 了责任了。但也别得意,他在显示逻辑处理上功
  • 23. 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或
  • 24. 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) {
  • 25. 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 '"
  • 26. 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-
  • 27. 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支持多级配
  • 28. 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)
  • 29. 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)把结果数据传
  • 30. 您 的 知 识 库 加 点 油 Java 我 们 期 待 eMag 着 您 的 加 入 ! 请和我们联系 投稿信箱emag_java@csdn.net 杂志主页http://emag.csdn.net/Default.aspx?tabid=57
  • 31. 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">