Struts解决了许多Web应用程序开发中的常见问题。基于Struts应用程序框架构造的应用程序,除了可以复用业已证明可用的解决方案外,同时也可以使得开发人员更加关注应用程序的特性。Struts是由Apache软件基金会支持的开源软件。
本书完整介绍了Struts框架结构,涵盖了设计、数据校验、数据库访问、动态页面生成、本地化、Struts配置以及其他一些重要的方面。书中还介绍了如何同时使用JSP标签和Velocity模板,并仔细介绍了Struts体系结构以及Struts控制流,同时也说明了如何扩展Struts框架结构。
书中还明确指出了Struts 1.0和1.1版本间的区别,同时还通过实例说明了Struts 1.0应用程序向Struts 1.1应用程序转换的技术。本书还介绍了很多已得到证明的设计技术、模式和策略,而这些内容在其他书中是很难找到的。
主要内容
■ Struts 1.0和Struts 1.1
■ Jakarta Scaffold工具包
■ HTTP、Java Servlet和JSP标签库
■ 基于Servlet的应用程序设计
■ 设计和开发模式
■ Jakarta Validator和Tile包
■ Velocity模板
■ 动态的Web程序设计
■ 使用数据库以及数据服务
■ 各种各样的例子
无
到2000年的时候,Java已经是一个成熟的语言了。早期版本中的那些问题被解决,同时一些很有趣的开发工具和类库也开始出现在市场上。我当时已经有过数年开发基于Web应用程序的经验。和许多其他程序员一样,最开始开发Web应用程序的时候是使用JavaScript和Perl语言。这种组合具有强大的功能,但是维护它简直就是一个噩梦。后来又使用过ColdFusion,它同样具有强大的功能但是对于我的客户而言,它太贵了。我曾经还试过FileMaker Pro,这是一个很有趣的工具,但是它过于专业化了。
我当时做的这一系列的Web应用程序的主要客户是一个公共的广播电台。该电台的主要经济支柱是每年的拍卖活动。本地的供应商提出自己的商品和服务,而人们通过广播电台来投标同时来支持该电台。当然,对于那些高端的拍卖品,例如手工艺品、汽车、度假产品、名人签名等等,我们同时也会在网站上贴出他们对应的图片。
在1998的时候,对于那些高端拍卖品,我们使用JavaScript和Perl语言开发的一个应用程序来进行“预投标“。那些真正的投标还是通过电台的实况投标活动进行。应用程序真正要做的仅仅是得到开始投标的价格。到1999年的时候,我们开始同时通过在线以及电话投标两种形式了。每一年的时候,因为发现原来使用的平台并不能完全符合我的要求,我都不得不使用另外的平台来使得发布被拍卖的产品。
对于当时正在使用的Apache服务器很满意,因此我花费了一些时间来研究刚刚诞生的Jakarat站点。在那个站点上,我发行了Struts。最开始的时候,我甚至都觉得Struts项目可能已经不是一个活动的项目了。但是它的文档看起来是一个很有潜力的项目。因此,我订阅了它的邮件列表来看看是否还有人工作在该项目上。该项目的文档中附带了一个例子应用程序,因此我独自一个人来试试该例子程序。试图来搞清楚该框架结构到底干什么。这项研究工作最终变成了“对于Struts应用程序的介绍“这样一篇文档,在其中通过一系列的截屏来说明例子应用程序是如何工作。我将该文章发表在邮件列表上,其他一些订阅了该邮件列表的人指出我在文章中的一些小错误。
我继续订阅该邮件列表,在可能的情况下帮助其他人同时也得到其他人的帮助。该邮件列表的使用人数极具上升。到年底的时候,Struts的体系架构师Cragi McClanahan希望有人可以帮助他完成Struts1。0版本的文档工作。我被Struts小组选中来完成该文档工作。到2001年的时候,我们终于成功发布了Struts1。0。
在这以后,我开始了“More About Struts“的页面。在最开始的时候,我仅仅是用它来存放那些我编写的和Struts相关的材料。然后我又在其中添加了指向其他人编写的关于Struts的材料。慢慢地,越来越多关于Struts的文章出现了。我的关于Struts的资源列表的页面也越来越大,越来越受到欢迎。因此我将它移到Struts的主站点上。现在,它包含了一系列的页面,指向我们知道的全部和Struts相关的东西上。
Strus的邮件列表中包含了很多很有用的东西。特别在开始的时候,Craig也经常通过它来给出实现细节上以及体系结构上的指导。但是,现在想在归档后的邮件列表中找到合适的回答已经变成了一个挑战。因此,我又开始通过对于邮件列表里面每一个问题进行归纳,找到最好的部分。这项工作最后成为了一个相当大的关于Struts的“FAQ“。在2001年的六月,JGurn决定对于Struts也设定一个论坛和FAQ,因此我们将该FAQ移交给JGurn,但是我还是负责该FAQ。
同时,许多出版社也开始注意到Struts。很多出版社向我约稿。在咨询了其他的Struts社团后,我们最终觉得和Manning出版社一起合作。和Apache一样,Manning对于开源项目也是有着长期的承诺。尽管我们期望使得这本书尽快面世,但是我们也期望能够保证本书尽可能成为最好的。
结果就是我们现在看见的《Struts in Action》。在其实是一本合作的结晶。David Winterfeldt,Struts Validator的创始人,很热心地负责了关于Validator的章节。同样,Cedric Dumoulin,Tiles的创始人,也负责Tiles的章节。George Franciscus负责第一章,也是最关键的一章。第一章就是专门针对那些刚刚进入该领域的新手的。我们甚至请Craig为我们写了序言(Craig更喜欢写程序)。当然,其他的Struts开发人员和整个社区,都在不同的阶段审阅了本书的手稿。我们在此对于那些建议表示感谢。
我们就要进入使用Struts的第三个年头了。现在我们不会每年都重写一次,我们将每年改进它。
Ted Husted
Fairport 纽约
本书是很多资深的Struts开发人员艰苦工作的结晶。Ted,Cedric,George和David通过他们出色的工作来通过该书说明Struts是如何工作的,以及如何在实际工作中使用Struts。如果你是一个使用Struts的新手,则本书可以使得你更快地更容易地掌握Struts框架结构以及将它使用到自己的实际项目中去。对于那些已经很了解Struts的程序员而言,通过阅读本书,还是可以发现一些新的东西。
我是在20世纪90年代末期开始对基于Web的应用程序感兴趣。当时我已经掌握了一门计算机语言(Java),它解决了高级编程中一个很重要的问题-程序员不需要考虑如何动态地释放已经被分配的内存。
在开始的时候,我所期望去做的仅仅是使得构造基于Web应用程序的程序员的生活轻松一些。而Struts的出乎意料地流行说明了不仅仅是Struts视图解决的问题不仅仅我一个人碰到过。Struts解决了很多普遍存在的问题。
当JSP的最初规范出台的时候(0.91和0.92),在该文档中一个引人入胜的概念在于两种不同的构造基于JSP的应用程序的基本设计风格。模式一的特性是表单提交的结果是由产生该表单的servlet或者JSP页面来处理。这种设计风格使得我们将表现层逻辑(创建表单的代码)和商业层逻辑(用来对输入数据进行校验以及处理输入的数据)混和在一起。当项目里面的程序员仅仅具有一方面的技能(或者是稍微懂一些程序设计的页面设计人员,或者是仅仅懂一些HTML的Java开发人员)的时候,经常使用这种设计方法。同时,当项目的时间很紧张(例如,原形系统需要在下个星期一的时候运行否则不能够得到投资基金的支持),使用该方式也很有用。但是经验告诉我,模式一的设计方法会导致在以后的系统维护和增强都很困难。
与此相反,模式二的设计方法是将表单提交的数据交给一个控制器模块。控制器模块将数据转发给合适的商业逻辑模块来处理数据。商业逻辑模块和数据库打交道,同时还获取要进一步和用户打交道使用的数据。然后,控制器模块将创建响应页面的工作交给表现层模块来处理。表现层模块的唯一功能就是创建响应页面。
你可能认为使用模式二风格的程序可能要更加复杂-特别对于一个简单的应用程序而言,这种复杂性会使得项目没有办法进行。实际上,基于模式二创建的应用程序并不比基于模式一创建的应用程序需要更多的时间。但是使用模式二创建应用程序的好处会很快显示出来。如果我们基于一个恰当的体系结构来创建应用程序,则对于一个层次进行的主要修改并不会(或者很少)对于其他层次有影响。这样我们就可以立刻重用那些并不受到影响的层次中的逻辑。
在我对于基于Web应用程序的体系结构进行这样探索的时候,我的职业生涯也同时带我进入了一个很有趣的方向。当时我在一个为美国长途汽车工业提供信息服务的公司工作,该公司期望将他们的服务也扩展到欧洲。这就使得他们的应用程序需要具有处理多种语言和国际化的能力。我很快地编写了一个简单的控制器servlet来使得我们可以实现简单的MVC体系结构,但是并不奏效,因为我们需要的是可以进行语言选择的控制器。
我在国际化中最开始的工作就是沿着JSP1.1提供的新的JSP标签来创建“用户使用界面“。该工作最终演变成了如今Struts中的<bean:message>标签。
在这之后,我加入了Sun公司。在Tomcat上工作。(作为Tomcat4中Catalina容器的设计师)。该开发工作中的一大部分是开源项目Apache的一部分。当Sun在1999年将其对于JSP和Servlet的参考实现贡献给Apache后,我们关于servlet容器的开发就是Jakarta项目的一部分。但是,当时我对于模式二中原始的应用程序设计方式并不满意,因此我决心做些什么。
尽管我对于如何解决该问题有着很好的想法,但是真正的代码直到2000年的Memorial Day假日的时候才出来。(我妻子一定对此感到很委屈,因为我带着我的笔记本和全家人一起去Oregon海滩度过那个假期)。而ActionForm的第一个版本就是在那个假期里面出现的。而该想法很明显解决了很多设计上有趣的问题。除此之外,在表现层以及商业逻辑组件上定义逻辑上的名字,和通过一个中心地方的配置文件来集中管理这些名字,可以解决开发人员在对该两层进行开发时候的合作以及避免对一层的修改影响另外一层的问题。
我在Tomcat项目上的经历使我知道开源项目开发的好处,因此很自然我将Struts贡献给了开源社区。这个选择以及Struts自身优美地解决了一些开发基于Web应用程序中的根本问题的能力,使得Struts以令人吃惊地速度被人们所使用。成千上万的程序员下载了Struts,通过了学习曲线,通过Struts的邮件列表开始问问题(也得到回答),然后成功地使用Struts构造应用程序。
当然,不可能通过我一个人的力量来实现全部这些功能。Ted,Cedric,David以及其他Struts委员会中曾经以及现在的成员,还有George以及Struts开发团队,才使得Struts框架结构能够比我一个人能够做到的更加成功。对于他们,我致以我发自内心的感谢。对于你们,本书的读者,我希望你们会发现你们对于Struts的技术和API上花的时间是值得的。
Craig McClanahan
Ted Husted:Ted Husted: 是一名咨询师,也是公认的Struts权威。他还是jGuru Struts论坛的管理员以及Struts开发小组的核心成员。
黄若波 程峰 程繁科:暂无简介
第一部分 Struts起步
第1章 概述1
11 本书的目的1
111 Struts的开发人员1
112 为什么说Struts是开源软件2
113 为什么被称为Struts2
12 应用程序框架的概念2
13 必备知识3
131 HTTP3
132 通用网关接口4
133 Java servlet5
134 JSP6
135 JSP标签7
136 JavaBean8
137 Model 29
14 Struts概述9
141 构造一个简单的应用程序11
142 准备工作11
143 如何完成整个练习12
144 回顾17
15 总结20
第2章 研究Struts体系结构21
21 言众人所言21
22 为什么使用Struts21
221 历史的回顾21
222 Struts介绍22
223 Struts控制层22
224 使用Struts开发Web应用程序26
23 为什么需要框架结构26
231 Web——麻烦的源头26
232 servlet解决方案27
233 Servlet框架结构28
234 黑盒和白盒系列29
24 Struts、Model 2和MVC29
241 MVC的演变29
242 Model 2的产生30
243 应用程序层——独立的视图层31
244 Struts如何实现Model 2、MVC和分层32
25 Struts控制流33
251 流程概述33
252 更微小的细节35
253 Struts的性能37
26 Struts的强项和弱点38
261 Struts的缺点38
262 Struts的优点40
27 总结41
第3章 构造一个简单的应用程序42
31 从基础了解Struts42
32 简述登录应用程序的流程43
321 起步43
322 将会使用的页面43
323 欢迎页面44
324 登录页面44
325 再次进入欢迎页面45
326 退出欢迎页面45
327 特性摘要45
33 解剖登录应用程序46
331 浏览器中欢迎页面的代码46
332 欢迎页面的JSP源代码47
333 欢迎页面的配置信息49
334 浏览器中登录页面的代码50
335 登录页面对应的配置部分52
336 LogonSubmit的源代码52
337 LogonForm的源代码53
338 LogonAction的源代码55
339 LogoffAction的源代码60
34 构造一个应用程序62
341 定义需求62
342 计划应用程序63
343 计划源代码树结构65
344 安装自己的开发工具65
345 建立buildxml文件66
346 建立webxml文件66
347 建立strutsconfigxml文件67
348 测试部署68
349 构造我们的欢迎页面69
3410构造登录页面70
3411构造常量类71
3412构造其他的类72
3413创建用户目录72
3414配置ActionErrors73
3415编译和测试登录页面73
3416修改欢迎页面74
3417Struts的Action:ForwardAction75
35 总结76
第4章 配置Struts组件77
41 三个XML文件和一个属性文件77
42 Web应用程序部署描述文件78
421 webxml文件78
422 ActionServlet的参数80
43 Struts配置81
431 细节82
432 管理修改83
433 原则:隐藏变化83
44 Struts配置元素84
441〈globalexceptions〉85
442〈formbeans〉86
443〈globalforwards〉87
444〈actionmappings〉88
445〈controller〉89
446〈messageresources〉90
447〈plugin〉90
448〈datasources〉91
449 编写自己的子类92
4410Struts配置文件的一个框架92
45 应用程序的资源文件94
46 Ant文件95
47 配置Struts的核心97
471 安装Java和Servlet容器97
472 安装一个开发环境98
473 安装Struts的核心文件98
48 配置Tiles框架结构98
49 配置Struts Validator99
410使用Struts空白应用程序100
411配置模块化的应用程序102
4111 分而治之102
4112 前缀化页面104
4113 更新配置文件104
412 共享Struts的JAR文件104
413 总结105
第二部 分提出自己的框架结构
第5章 处理ActionForm107
51 输入垃圾,输出珠宝107
52 多面手ActionForm110
521 使用ActionForm来填充自己的域110
522 使用ActionForm作为数据缓存111
523 使用ActionForm作为数据校验器112
524 使用ActionForm作为类型转换器112
525 使用ActionForm作为数据传递对象112
526使用ActionForm作为防火墙113
53 ActionForm的设计结果114
531 ActionForm可能和业务逻辑层对象共享名字114
532 ActionForm可能减少定制的代码量114
533 ActionForm可以封装辅助函数115
534 ActionForm可以内含其他bean115
54 ActionForm的其他类型116
541 Mapbacked ActionForm116
542 DynaActionForm117
55 哪些情况下不使用ActionForm118
551 为什么ActionForm不是一个Map对象118
552 为什么ActionForm不是一个简单的JavaBean118
553 为什么ActionForm不是一个接口119
56 使用ActionForm119
561 实现业务层逻辑120
562 内含可改变的数据对象121
563 设置不可改变数据对象122
564 设置可改变的数据对象123
565 使用工厂方法123
566 传递一个Map对象124
567 通过反射传递数据126
568 使用接口类130
57 BaseForm131
571 SessionLocale131
572 Dispatch132
573 自动填充132
574 BaseMapForm132
58 总结133
第6章 使用ActionForward对象134
61 ActionForward的功能134
62 ActionForward如何工作135
63 本地转发和全局转发136
64 运行时刻参数137
641 在页面中增加参数137
642 在Action类中添加参数138
65 动态转发138
66 导航条内容不变的原因138
67 编写自己的ActionForward139
68 总结140
第7章 ActionMapping的设计141
71 了解ActionMapping141
711 ActionMapping bean142
712 ActionMapping目录142
72 ActionMapping属性143
721 path属性143
722 forward属性144
723 include属性144
724 type属性144
725 className属性144
726 name属性145
727 roles属性145
728 scope属性145
729 validate属性145
7210input属性145
7211parameter属性146
7212attribute属性147
7213prefix和suffix属性147
7214unknown属性147
73 内部组件148
731 本地转发148
732 本地异常148
74 编写自己的ActionMapping148
75 总结149
第8章 使用Action对象150
81 准备,设定,行动150
82 使用Action对象150
821 Action是什么151
822 何时调用Action152
823 Action可以做什么153
824 Action到底是什么157
83 标准的Action158
831 标准的桥接Action159
832 标准的基本Action161
84 级联Action165
85 Scaffold Action167
851 仅仅和转发相关的Action167
852 辅助Action172
86 基本的View Action174
87 辅助Action类使用的技术175
871 可选择的转发176
872 先调用177
873 捕获级联的异常177
874 灵活的错误信息转发179
875 提示成功消息180
876 可变换的视图180
877 使用反射技术来调用方法181
878 使用反射来调用类181
88 使用灵活转发182
89 总结186
第9章 扩展ActionServlet187
91 ActionServlet的地位187
92 RequestProcessor189
921 process方法190
922 processRoles190
93 ExceptionHandler192
94 插件193
95 总结193
第三部 分构造自己的页面
第10章 显示动态内容195
101 标签——就是你195
1011 JSP标签库——有什么优点195
1012 Struts和JSTL198
1013 Struts标签库和MVC199
102 使用扩展标签库200
1021 扩展标签是如何工作的200
1022 如何安装扩展标签202
1023 扩展标签库不是什么203
103 Struts标签库204
1031 Struts标签库的常用功能205
1032 bean标签206
1033 html标签208
1034 logic标签210
104 使用Struts标签213
1041 Struts的标签213
1042 基础213
1043 技术220
1044 可用的控件231
105 不同的视图232
1051 Struts和JSP232
1052 servlet上下文232
1053 除了JSP以外233
106 总结233
第11章 使用Tiles开发应用235
111 管理布局235
1111 用动态模板进行分层235
1112 运用模板的结果236
1113 使用模板236
1114 集成模板、Tiles和Struts237
112 创建一个layout模板238
1121 tile是什么240
1122 部署Tiles模板241
1123 添加样式表242
1124 模板和MVC243
113 Tiles Definition243
1131 声明Definition243
1132 JSP声明244
1133 配置文件声明247
1134 把Definition作为ActionForward249
114 Tile 属性250
1141 useAttribute250
1142 importAttribute251
1143 put251
1144 putList和add253
115 把一个应用程序转化为Tiles253
1151 设置Tiles框架253
1152 测试默认配置254
1153 浏览页面254
1154 使用〈tiles:insert〉重构页面256
1155 把〈tiles:insert〉标签析取到Definition中262
1156 模式化基础layout265
1157 把Definition精练为基础类和扩展类266
1158 形成例程267
1159 对移植的管理267
116 总结268
第12章 验证用户输入270
121 只有看见时我才知道270
1211 我们不能拒绝的输入270
1212 Web层的校验271
1213 使用校验器的结果272
122 Struts Validator简述273
123 基本校验器280
1231 required校验器281
1232 mask校验器281
1233 range校验器282
1234 maxLength校验器283
1235 minLength校验器283
1236 byte、short、integer、long、float和double校验器283
1237 date校验器283
1238 creditCard校验器284
1239 email校验器284
124 资源包284
1241 默认的资源包285
1242 默认校验器消息285
1243 定制化的校验器消息286
125 配置文件286
126 校验器的JSP标签287
127 ValidatorForm和ValidatorActionForm290
128 本地化的校验器291
129 可插入的校验器291
1210技术292
12101 多页面校验293
12102 取消按钮293
12103 定制化的消息293
12104 相关联域294
12105 联合使用校验器和validate方法295
1211移植应用程序到Struts Validator296
12111 安装配置Validator框架结构296
12112 测试默认的配置297
12113 回顾你的校验方法297
12114 扩展ValidatorForm或者Scaffold BaseForm298
12115 选择一个校验器来进行移植工作298
12116 添加formset、form和field元素299
12117 在ApplicationResources中添加新的选项300
12118 调用Struts校验器301
12119 测试和重复301
121110删除ActionForm子类302
1212总结303
第13章 内容本地化305
131 用另外一个名字305
1311 为什么进行本地化306
1312 Java的国际化功能306
132 Struts的国际化组件310
1321 Session中的Locale属性310
1322 MessageResources311
1323 默认的资源包311
1324 ActionErrors313
1325 ActionMessages313
1326 区域敏感的JSP标签314
133 本地化Struts应用程序318
1331 允许本地化318
1332 使用框架结构Locale对象319
1333 将标签和消息存放在属性文件中320
1334 创建语言相关的属性文件320
1335 在可以本地化模块中指定恰当的键值321
1336 其他模块使用〈bean:message〉321
134 本地化其他模块321
1341 本地化Struts Validator321
1342 本地化Tiles322
1343 本地化集合322
135 总结323
第14章 使用数据服务功能325
141 起步325
1411 从层次的角度看JDBC325
1412 介绍数据服务326
142 研究业务层327
1421 Struts——使用自己的模式327
1422 定义业务对象327
1423 设计业务对象328
1424 设计结果329
1425 混合业务方法和Action(不推荐)329
1426 一个简单的例子330
143 在Struts中使用ProcessBeans和JDBC330
1431 介绍ProcessBean331
1432 作为数据传递对象的ProcessBean332
1433 填充ProcessBean333
1434 执行ProcessBean333
1435 访问数据服务334
1436 使用典型的流程335
1437 对业务行为进行编码336
1438 使用ProcessBean作为持久层338
1439 使用其他的持久层338
144 使用result对象339
145 使用辅助Action340
146 使用Lucene341
147 使用内容摘要345
1471 Digester和RSS346
1472 获取和生成数据346
1473 RSS摘要347
148 在Struts中使用EJB349
1481 Session Facade350
1482 数据传递对象350
1483 实现模式350
149 总结351
第四部 分以实例介绍Struts
第15章 Artimus:实例研究353
151 框架的框架353
152 Scaffold——工具的产生354
153 关于Artimus354
154 部署描述文件(webxml)356
1541 配置Artimus357
1542 应用程序的属性357
1543 连接适配器358
1544 启动属性358
1545 其他配置设定358
1546 安全设定358
1547 受保护的URL359
1548 授权用户359
1549 鉴证策略359
155 ArtimusServlet359
1551 子类361
1552 串标志符361
1553 扩展点361
156 应用程序与SQL属性文件362
157 indexjsp363
158 全局转发363
159 /find/Recent365
1591 扩展bean368
1592 superexecute368
1593 getArticles368
1594 AccessfindByLast与ResultList368
1595 ProcessResult369
1596 ProcessAction370
1510 tilesxml与Articlejsp371
15101 useAttribute373
15102 baseStyle373
15103 标题373
15104 Tiles373
1511 resultjsp375
15111 图例376
15112 isResult376
15113 RESULT377
1512 article actions380
1513 viewjsp382
15131 headline383
15132 content383
15133 contributor384
1514 formjsp385
15141 article content386
15142 contributed/contributor387
15143 article ID387
15144 validation387
1515 /do/Menu389
15151 logon390
15152 菜单391
15153 我们的控件392
15154 saveResult方法392
15155 我们的结果集392
1516 menujsp393
15161 /find/Hours394
15162 /menu/Find395
15163 /find/Last396
15164 /menu/Contributor396
15165 /menu/Manager397
1517 总结397
第16章 Redux:迁移到Struts 11398
161 下一步:Struts 11398
1611 Struts 11特征集399
1612 我们可使用的特征401
162 改变基础402
1621 Struts 11中的Tiles402
1622 Struts 11中的Validator405
1623 Struts 11中的ReloadAction406
1624 对webxml和strutsconfigxml的其他变更406
1625 messagejsp(版本11)406
1626 formjsp(版本11)407
1627 MenuCreate(版本11)409
1628 继续前进409
163 可自由选择的修改410
1631 DynaActionForm格式410
1632 基于Action的安全机制411
1633 修改Action路径413
1634 Struts 11中的应用程序资源414
164 总结414
第17章 Velocity:替换JSP416
171 转移到Velocity模板416
172 变化导致了应用程序框架结构的出现416
173 为什么需要Velocity416
1731 Velocity轻便、快捷而且通用417
1732 Velocity可以很好地与其他软件协作417
1733 Velocity简单但是功能强大417
174 在Web应用程序中使用Velocity418
1741 将Velocity与servlet资源一起使用418
1742 联合使用Velocity和上下文属性419
1743 Velocity如何与Struts协同工作420
1744 VelocityStruts工具包420
1745 Struts View工具421
175 我们的登录模板421
176 建立VelocityViewServlet424
1761 安装VelocityViewServlet424
1762 部署Velocity servlet424
1763 工具箱配置文件425
177 设置strutsconfig426
178 总结427
附录
附录A 设计模式429
附录B Struts配置文件的API435
附录C 标签库快速参考446
术语表450
参考文献456