Tải bản đầy đủ

Tài liệu Struts in Action docx

Struts in Action

Struts in Action
Building web applications
with the leading Java framework
Ted Husted
Cedric Dumoulin
George Franciscus
David Winterfeldt
(74° w. long.)
For online information and ordering of this and other Manning books, go to
www.manning.com. The publisher offers discounts on this book when ordered in quantity.
For more information, please contact:
Special Sales Department
Manning Publications Co.
209 Bruce Park Avenue Fax: (203) 661-9018
Greenwich, CT 06830 email: orders@manning.com
©2003 by Manning Publications Co. All rights reserved.

No part of this publication may be reproduced, stored in a retrieval system, or transmitted,
in any form or by means electronic, mechanical, photocopying, or otherwise, without
prior written permission of the publisher.
Many of the designations used by manufacturers and sellers to distinguish their products
are claimed as trademarks. Where those designations appear in the book, and Manning
Publications was aware of a trademark claim, the designations have been printed in initial
caps or all caps.
Recognizing the importance of preserving what has been written, it is Manning’s policy to have
the books they publish printed on acid-free paper, and we exert our best efforts to that end.
The following figures were adapted from other Manning books: figure 2.1 from Swing by
Matthew Robinson and Pavel Vorobiev (figure 1.3); figures 2.8, 10.6, 11.1, and 11.2 from
Web Development with JavaServer Pages Second Edition by Duane Fields and Mark Kolb (figures 10.1,
10.5, 6.2, and 10.4). Figure 2.9 by Jean-Michel Garnier is reproduced with permission from the
Apache Software Foundation.
Manning Publications Co. Copyeditor: Liz Welch
32 Lafayette Place Typesetter: Tony Roberts
Greenwich, CT 06830 Cover designer: Leslie Haimes
ISBN 1-930110-50-2
Printed in the United States of America
12345678910– VHG – 05 04 03 02
struts_00_a.fm Page iv Tuesday, October 29, 2002 11:14 AM



Introduction 3

Exploring the Struts architecture 29

Building a simple application 59

Configuring Struts components 105



Coping with ActionForms 147

Wiring with ActionForwards 183

Designing with ActionMappings 193

Working with Action objects 207

Extending ActionServlet 255



Displaying dynamic content 267
brief contents

Developing applications with Tiles 319

Validating user input 365

Localizing content 409

Using data services with Struts 437



Artimus: pulling out the stops 475

Redux: migrating to Struts 1.1 533

Velocity: replacing JSPs 555
foreword xix
preface xxiii
acknowledgments xxvi
about this book xxviii


..................... 1
Introduction 3
1.1 What is this book about? 4
Who makes the Struts software? 4

Why is Struts open source? 5
Why is it called Struts? 5
1.2 What are application frameworks? 5
Other types of frameworks 6
1.3 Enabling technologies 6
Hypertext Transfer Protocol (HTTP) 7

Common Gateway
Interface (CGI) 8

Java servlets 9

JavaServer Pages 10
JSP tags 11

JavaBeans 12

Model 2 14
1.4 Struts from 30,000 feet 14
Building a simple application 16

development 16

Where the rubber meets the road 18
Looking back 24
1.5 Summary 28
Exploring the Struts architecture 29
2.1 Talking the talk 30
2.2 Why we need Struts 30
One step back, three steps forward 30

Enter Struts 31
Struts controller components 31

Developing a web
application with Struts 36
2.3 Why we need frameworks 37
The Web—a never-ending kluge 37

The servlet solution 38
Servlet frameworks 39

The whitebox-blackbox continuum 40
2.4 Struts, Model 2, and MVC 41
The evolution of MVC 41

The rise of Model 2 42
Application layers—decoupling the view 43
How Struts implements Model 2, MVC, and layers 44
2.5 Struts control flow 46
The big picture 47

The finer details 48
Is Struts performant? 52
2.6 The strengths and weaknesses of Struts 53
The weak points 54

Struts’ strong points 56
2.7 Summary 58
Building a simple application 59
3.1 Strut by Strut 60
Why a logon application? 61
3.2 Touring a logon application 61
Start here 61

Screens we’ll see 62

The welcome screen 62
The logon screen 62

The welcome screen, again 64
The welcome screen, good-bye 64

Feature roundup 65
3.3 Dissecting the logon application 65
The browser source for the welcome screen 65

The JSP source for
the welcome screen 66

The configuration source for the welcome
screen 69

The browser source for the logon screen 70
The configuration source for the logon screen 73
The LogonSubmit source 73

The LogonForm source 74
The LogonAction source 77

The LogoffAction source 83
3.4 Constructing an application 86
Defining the requirements 86

Planning the application 87
Planning the source tree 90

Setting up development tools 90
Setting up the build.xml file 92

Setting up the web.xml
file 92

Setting up the struts-config.xml file 92
Testing the deployment 94

Constructing our welcome page 95
Constructing the logon page 96

Constructing the Constants
class 98

Constructing the other classes 99

Creating the user
directory 99

Configuring the ActionErrors 100

and testing the logon page 101

Amending the welcome
page 101

The Struts ActionForward Action 102
3.5 Summary
Configuring Struts components 105
4.1 Three XMLs and a Properties file
The rest of the family 106
4.2 The web application deployment descriptor
The web.xml file 107

ActionServlet parameters 110
4.3 The Struts configuration
Details, details 113

Change management 115
The principle of Protected Variation 115
4.4 The Struts configuration elements
<global-exceptions> 118

<form-beans> 119
<global-forwards> 120

<action-mappings> 121
<controller> 123

<message-resources> 123
<plug-in> 124

<data-sources> 125
Rolling your own 126

A skeleton Struts config 127
4.5 The application resources file
4.6 The Ant build file
4.7 Configuring the Struts core
Installing Java and a Java servlet container 133
Installing a development environment 134
Installing the Struts core files 134
4.8 Configuring the Tiles framework
4.9 Configuring the Struts Validator
4.10 Getting started with the Struts Blank application
4.11 Configuring modular applications
Divide and conquer 140

Prefixing pages 142
Retrofitting a configuration 142
4.12 Sharing the Struts JAR
4.13 Summary


.......................... 145
Coping with ActionForms 147
5.1 Garbage in, treasure out 148
ActionForm requirements 150
5.2 The many faces of an ActionForm 151
The ActionForm as a field harvester 151

The ActionForm as a
data buffer 153

The ActionForm as a data validator 154
The ActionForm as a type transformer 155

The ActionForm as a
transfer object 155

The ActionForm as a firewall 156
5.3 ActionForm design consequences 157
ActionForms may share names 157

ActionForms may minimize
custom code 158

ActionForms may encapsulate helpers 158
ActionForms may nest other beans 158
5.4 ActionForm flavors 160
Map-backed ActionForms 160

DynaActionForms 162
5.5 Why isn’t an ActionForm... 162
Why isn’t an ActionForm just a Map? 163

Why isn’t an
ActionForm a plain JavaBean? 163

Why isn’t an ActionForm
an interface? 163
5.6 Debriefing ActionForms 164
Implementing a business-layer interface 166

Nesting a mutable
value object 167

Setting an immutable value object 168
Setting a mutable value object 169

Using a factory method 170
Passing a Map 171

Transferring values by reflection 173
Using an adaptor class 178
5.7 BaseForm 179
SessionLocale 180

Dispatch 180

Autopopulation 181
BaseMapForm 181
5.8 Summary 182
Wiring with ActionForwards 183
6.1 What ActionForwards do 184
6.2 How ActionForwards work 185
Forward versus redirect 185
6.3 Global and local forwards 187
6.4 Runtime parameters 188
Adding parameters in the page 188
Adding parameters in the Action class 188
6.5 Dynamic forwards
6.6 Why doesn’t the address bar change?
6.7 Rolling your own ActionForward
6.8 Summary
Designing with ActionMappings 193
7.1 Enter ActionMappings
The ActionMapping bean 195
The ActionMappings catalog 195
7.2 ActionMapping properties
The path property 197

The forward property 198
The include property 198

The type property 199
The className property 199

The name property 199
The roles property 199

The scope property 199
The validate property 200

The input property 200
The parameter property 201

The attribute property 202
The prefix and suffix properties 202

The unknown
ActionMapping 203
7.3 Nested components
Local forwards 203

Local exceptions 204
7.4 Rolling your own ActionMapping
7.5 Summary
Working with Action objects 207
8.1 Ready, set, action!
8.2 Getting it done with Action objects
What are Actions? 209

When are Actions called? 210
What do Actions do? 211

What does an Action look like? 217
8.3 The standard Actions
Standard bridge Action classes 219

Standard base Actions 222
8.4 Chaining Actions
Starting fresh 229
8.5 Scaffold Actions 229
Forward-only Actions 230

Helper Actions 236
8.6 Base View Actions 239
8.7 Helper Action techniques 240
Optional forwarding 241

Calling ahead 242
Catching chained exceptions 243

Smart error forwarding 245
Confirming success 246

Alternate views 247
Reflecting methods 247

Reflecting classes 248
8.8 Using smart forwarding 249
8.9 Summary 254
Extending ActionServlet 255
9.1 Where’s the beef? 256
The servlet’s Gang of Three 258
9.2 The RequestProcessor 259
The process method 260

processRoles 260
9.3 The ExceptionHandler 262
9.4 PlugIn 263
9.5 Summary 264


................................. 265
Displaying dynamic content 267
10.1 Tag—you’re it 268
JSP tags—what are they good for? 268

Struts and JSTL 271
Struts tags and MVC 273
10.2 Working with tag extensions 274
How are tag extensions written? 274

How are tag extensions
installed? 276

What tag extensions are not 278
10.3 The Struts taglibs 279
Features common to Struts tags 280

The bean tags 282
The html tags 285

The logic tags 287
10.4 Using Struts JSP tags 290
The Struts tag team 291

Fundamentals 291
Techniques 300

Successful controls 314
10.5 Alternate views 315
Struts and JSPs 315

Servlet contexts 315
Beyond JSPs 317
10.6 Summary 317
Developing applications with Tiles 319
11.1 Leveraging layouts 320
Layering with dynamic templates 320

consequences 321

Using templates 322
Combining templates, Tiles, and Struts 323
11.2 Building a layout template 324
But what is a tile? 326

Deploying a Tiles template 328
Adding a style sheet 329

Templates and MVC 330
11.3 Tiles Definitions 331
Declaring Definitions 331

JSP declarations 332
Configuration file declarations 335
Using Definitions as ActionForwards 338
11.4 Tile attributes 339
useAttribute 340

importAttribute 340

put 341
putList and add 343
11.5 Migrating an application to Tiles 343
Setting up the Tiles framework 344

Testing the default
configuration 344

Reviewing the pages 345
Refactoring a page with <tiles:insert> 348

Extracting the
<tiles:insert> tags into a Definition 355

Normalizing your
base layout 359

Refining your Definitions into base and
extended classes 360

Developing a routine 361
Managing the migration 362
11.6 Summary 363
Validating user input 365
12.1 I know it when I see it 366
Input we can’t refuse 366

Web-tier validations 367
Validator consequences 368
12.2 Overview of the Struts Validator 371
Logon example 374
12.3 Basic validators 379
The required validator 380

The mask validator 380
The range validator 381

The maxLength validator 382
The minLength validator 383

The byte, short, integer, long,
float, and double validators 383

The date validator 383
The creditCard validator 384

The email validator 384
12.4 Resource bundles 384
The default bundle 385

Default validator messages 385
Custom validator messages 386
12.5 Configuration files 387
12.6 Validator JSP tags 388
12.7 ValidatorForm and ValidatorActionForm 391
12.8 Localized validations 392
12.9 Pluggable validators 392
Creating pluggable validators 392
12.10 Techniques 394
Multipage validations 395

Cancel buttons 395

messages 396

Interrelated fields 397
Combining validators with the validate method 398
12.11 Migrating an application to the Struts Validator 399
Setting up the Validator framework 399

Testing the default
configuration 399

Reviewing your validations 400
Extending ValidatorForm or the Scaffold BaseForm 401
Selecting a validation to migrate 401

Adding the formset, form,
and field elements 403

Adding new entries to the
ApplicationResources 403

Calling the Struts Validator 404
Test and repeat 405

Removing the ActionForm subclass 406
12.12 Summary 408
Localizing content 409
13.1 By any other name 410
Why localize? 411

How Java internationalization works 412
13.2 Struts’ internationalized components 417
Session Locale attribute 417

MessageResources 418
The default resource bundle 419

ActionErrors 421
ActionMessages 421

Locale-sensitive JSP tags 422
13.3 Localizing a Struts application 427
Enabling localization 428

Using the framework Locale
object 430

Placing labels and messages in Properties files 431
Creating language-specified Properties files 431

Specifying an
appropriate key in localization-aware components 431

<bean:message> with other components 431
13.4 Localizing other components 432
Localizing the Struts Validator 432

Localizing Tiles 433
Localizing collections 433
13.5 Summary 435
Using data services with Struts 437
14.1 Stepping out 438
JDBC from a patterns perspective 438
Introducing our data services 440
14.2 Exploring the business layer 440
Struts—bringing your own Model 440

business objects 441

Designing business objects 442
Design consequences 443

Mixing business with
Actions (not) 443

A simple example 444
14.3 Using ProcessBeans and JDBC with Struts 445
Introducing ProcessBeans 446

ProcessBeans as transfer
objects 447

Populating ProcessBeans 448

ProcessBeans 448

Accessing data services 449

a typical flow 451

Coding a business activity 451
ProcessBeans as a persistence layer 454

Using other
persistence layers 455
14.4 Using result objects 455
ResultList methods 455
14.5 Using helper Actions 457
14.6 Using Lucene 458
searchProperties redux 459
14.7 Using content syndication 464
Digesting RSS 464

Retrieve and render 465
Syndicating RSS 466
14.8 Using EJBs with Struts 468
Session Facade 469

Data transfer objects 470
Implementation patterns 470
14.9 Summary 471


..................................... 473
Artimus: pulling out the stops 475
15.1 The framework’s framework 476
15.2 Scaffold—birth of a toolset 476
15.3 About Artimus 477
Building Artimus 479
15.4 The deployment descriptor (web.xml) 480
Configuring Artimus 482

Our application properties 482
Our connection adaptor 482

Our startup priority 483
Other configuration settings 483

Our security settings 483
The URLs we protect 483

The authorized users 484
Our authentication strategy 484
15.5 ArtimusServlet 484
Our subclass 486

Our String tokens 486
Our extension point 486
15.6 The application and SQL Properties files 487
15.7 index.jsp 488
15.8 Global forwards 489
15.9 /find/Recent 492
extends bean 494

super.execute 495

getArticles 495
Access.findByLast and ResultList 495

ProcessResult 497
ProcessAction 498
15.10 tiles.xml and Article.jsp 499
useAttribute 501

baseStyle 501

title 502

Tiles 502
15.11 result.jsp 504
The legend 506

isResult? 506

15.12 Article actions 510
15.13 view.jsp 513
headline 514

content 514

contributor 515
15.14 edit.jsp 516
Article content 518

Contributed / contributor 519
Article ID 519

Validation 519
15.15 /do/Menu 521
logon 523

menu 523

Our controls 525
saveResult 525

Our results 525
15.16 menu.jsp 526
/find/Hours 528

/menu/Find 528

/find/Last 529
/menu/Contributor 530

/menu/Manager 531
15.17 Summary 532
Redux: migrating to Struts 1.1 533
16.1 Next station, Struts 1.1 534
Struts 1.1 feature roundup 535

Features we can use 538
16.2 Baseline changes 538
Tiles in Struts 1.1 540

Validator in Struts 1.1 543
ReloadAction in Struts 1.1 544

Other baseline changes to
web.xml and struts-config.xml 544

message.jsp (1.1) 545
form.jsp (1.1) 546

MenuCreate (1.1) 547

Onward 548
16.3 Discretionary changes 548
Form to DynaActionForm 549

Action-based security 550
Action path changes 553
Application resources in Struts 1.1 553
16.4 Summary 554
Velocity: replacing JSPs 555
17.1 Moving to Velocity templates 556
17.2 Change makes the framework 556
17.3 Why we need Velocity 557
Velocity is light, fast, and versatile 557

Velocity works well with
others 557

Velocity is simple but powerful 557
17.4 Using Velocity with web applications 558
Using Velocity with servlet resources 559

Using Velocity with
context attributes 560

How Velocity works with Struts 561
The VelocityStruts toolkit 562

The Struts View tools 563
17.5 Our logon templates 563
17.6 Setting up VelocityViewServlet 566
Installing the VelocityViewServlet 566

Deploying the Velocity
servlet 567

The toolbox configuration file 568
17.7 Setting up struts-config 569
17.8 Summary 570
Design patterns 573
A.1 A brief history of design patterns 574
The Gang of Four 575

J2EE Blueprints 575
Core J2EE Patterns 576
A.2 Why patterns are important 576
A.3 What patterns won’t do 577
A.4 Struts—a Who’s Who of design patterns 577
The Service to Worker pattern 578

The Singleton pattern 579
The Session Facade pattern 579

Value Object / Value Object
Assembler patterns 579

The Composite View pattern 580
The Synchronizer Token pattern 580

The Decorator
pattern 581
The struts-config API 583
B.1 <struts-config> 584
<set-property> 585

<data-sources> 585
<data-source> 585

<global-exceptions> 586
<exception> 586

<form-beans> 587
<form-bean> 588

<form-property> 589
<global-forwards> 590

<forward> 590
<action-mappings> 591

<action> 592
<controller> 594

<message-resources> 596
<plug-in> 597
Taglib quick reference 599
glossary 605
references 614
index 624

You’re holding in your hands the result of the hard labor of some of Struts’
most important developers. Ted, Cedric, George, and David have done an
outstanding job of explaining how Struts works
how it is used in prac-
tice. If you’re a new developer,
Struts in Action
will make it much easier for
you to learn the framework and quickly put it to work on your own projects.
But even the most seasoned Struts developer is certain to learn something
new by reading this book.
I became interested in web application development in the late 1990s. I
was ready for a language that would let me address one of the most problem-
atic aspects of advanced development—the need to free up dynamically allo-
cated memory when I was through with it.
In the beginning, all I really hoped to accomplish was to make life a little
easier for a few developers building web applications. The incredible popu-
larity that Struts has achieved since then means that I wasn’t the only one
who struggled—Struts fills a very common need.
When the early public drafts of the JavaServer Pages specification (ver-
sions 0.91 and 0.92) became available, one of the intriguing concepts
embedded in these documents was the idea of two basic design styles for
based applications. A
Model 1
design is characterized by form submits that go
back to the servlet or
page that created the form. This design encourages
you to mix the
logic (used to create the form) with the
logic (used to validate the form input and process the requested transaction).
Such a design is often used when developers of only one skill set (either page
authors who know a little programming, or Java developers who know a little
) are available. It is also useful when time is of the essence (“The prototype
needs to work by next Monday or we don’t get our venture capital funding”).
Experience has taught us that Model 1 designs can be difficult to maintain and
enhance in the future.
In contrast, a Model 2 design submits forms to a controller component. The con-
troller component dispatches to an appropriate business-logic component to per-
form the requested transaction. The business-logic component interacts with the
database and acquires the information it needs for the next user interaction. The
controller component delegates the creation of the response page to a presentation
component whose sole purpose is to create that response.
You’re probably thinking that the Model 2 style sounds much more compli-
cated—perhaps even like overkill for simple applications. Indeed, creating an
application based on the Model 2 design does take longer than building the same
application in a Model 1 style. But the primary benefits show up quickly. If you’ve
created the proper architecture, major changes to one tier should have relatively
little (if any) impact on the other tier, and you can reuse the logic in the unaf-
fected tier immediately.
While all of this intellectual investigation of web application architectures was
going on, my professional career was leading me in interesting directions as well. I
was working for a company that provided information services to the long-haul
trucking industry in the United States, and we wanted to expand this service into
Europe. This created the need to deal with multiple languages and international-
ization. I quickly whipped up a simple controller servlet that let me implement
the basic
architecture, but it didn’t address, say, the need to include a Select
Language control.
Our first effort at internationalization started me down the path of creating
“user interface components” using the new custom tags facilities of
led ultimately to things like the
tag that is a part of Struts today.
Shortly after this, I joined Sun Microsystems to work with the Tomcat servlet
container (I was the primary architect of the Catalina servlet container that
is the basis of Tomcat 4). A large portion of this development took place in the
open source community at Apache, as part of the Jakarta Project—initiated when
Sun contributed the source code of what had been the servlet and
implementation to Apache in 1999. However, I was never happy with the state of
Model 2-oriented application designs, so I resolved to do something about it.
Although I had a pretty good idea of how to solve the remaining problems, the
actual code for Struts did not come into being until, much to the chagrin of my
wife, I took my laptop along with me to the 2000 Memorial Day weekend with my
family on the Oregon coast. The very first version of what became the ActionForm
was born that weekend, and it turned out to solve a number of interesting design
problems. In addition, the idea of defining logical names for the presentation and
business logic components—and centralizing the definition of those names in a
single configuration file—was clearly beneficial in solving the overlapping prob-
lems of coordination between the development of the two tiers and the goal of
insulating tiers from changes in the other.
Through my work on Tomcat I had recognized the benefits of open source
development so it was a natural choice to bring Struts to the world of open source
as well. This choice—and the elegance of how Struts deals with some of the most
basic problems of web application design—has resulted in acceptance that is truly
astounding. Thousands of developers have downloaded Struts, gone through the
learning curve, asked questions (and received answers) through the
mailing list, and have successfully deployed applications based on Struts all
over the world.
Of course, I was not able to accomplish all of this on my own. Ted, Cedric,
David, and all the other past and present Committers for the Struts project, along
with George and the community of Struts developers, have made the framework
far more useful than I ever could have done alone. To them, I offer my heartfelt
thanks. To you, the reader of this much-needed book, I hope that you find Struts a
useful addition to your arsenal, well worth the investment of time to learn its tech-
niques and
Craig McClanahan
Portland, Oregon

By 2000, Java had come of age. The dust from the early hype had settled and
some very interesting development tools and libraries were cropping up. I
had already been writing web applications for several years. Like many devel-
opers, I started with simple apps in JavaScript and Perl. A powerful combina-
tion, but a bear to maintain. Next came ColdFusion, which was much more
powerful but at the time too expensive for my client’s pocketbook. I even
tried FileMaker Pro, which was fun, but very, very proprietary.
My major client for this succession of web applications was a public broad-
casting station. The station’s major fund-raiser was (and still is) an annual auc-
tion. Local vendors donate goods and services, and people buy them at
auction to support the station. Of course, we were quick to post images of the
high-end items on the web site:
objets d’art
, a car, vacation packages, auto-
graphed items, and so forth.
In 1998, we used an application written with JavaScript and Perl to accept
“pre-bids” on the high-end items. The actual bidding on these items took
place in live television bid-downs. All the application really did was set the
starting bid price. In 1999, we accepted both online and phone bids right up
to when the item sold. Each year, I used a different platform to put the auction
online, because each year I found that the platform didn’t meet all my needs.
Since we were already satisfied users of the Apache
server, I
invested some time in wandering through the nascent Jakarta site, where I
discovered Struts. At first, I wasn’t even sure the project was still active. But
the documentation seemed promising, so I subscribed to the list to see if anyone
was home. An example application was already bundled with the documentation.
I started working my way through the example, trying to figure out the framework
as I went along. This journey turned into the “Walking Tour of the Struts Applica-
tion,” which describes how the example application works, screen by screen. I
posted the tour to the list, where some of the subscribers gently corrected my
understanding of the finer points.
I continued to follow the list, helping others when I could, and being helped
by those who had traveled this road before me. Traffic on the list grew steadily.
Toward the end of the year, Struts’ architect and lead developer, Craig McClana-
han, was looking for people to help with the documentation for the 1.0 release. I
was elected a Struts Committer in December 2000, and we finally shipped
Struts 1.0 in June 2001.
Along the way, I started my “More About Struts” page. At first, it was just a place
where I could keep the links to the Struts material I was writing. Then I began
adding links to the Struts “extensions” people had started to distribute, and then
to the many Struts articles that had begun to appear. My Struts Resources page
grew larger, and more popular, and so I moved it to the main Struts site. It is now
a set of several pages with links to everything known about the Struts universe.
The Struts list remained a treasure trove of helpful information, especially
since Craig himself was usually on hand to shed light on the implementation
details and architectural philosophy. But finding the best bits in the list archive
could be a challenge. So, I started a “threads page” within links to the best email
nuggets, which grew into a fairly large
. In June 2001, JGuru decided to open
a Struts forum and
, and we moved the main Struts
to JGuru, where I con-
tinue to manage it.
Around the same time, publishers started to take notice of Struts, and offers
began to arrive in my mailbox. After consulting with some of the other Struts
Committers, we eventually decided to work with Manning Publications. Like
Apache, Manning has a longstanding commitment to quality. While we wanted to
get a Struts book out as soon as we could, we also wanted to be sure that it would
be the best book possible.
The result is Struts in Action. It is very much a “team book.” David Winterfeldt,
the creator of the Struts Validator, was kind enough to draft our Validator chapter.
Likewise, Cedric Dumoulin, the creator of Tiles, drafted the Tiles chapter. George
Franciscus provided the critical chapter 1 of the book, which is designed to help
bring newbies into the fold. We even dragged a foreword out of Craig (who would
“rather be programming”). Of course, other Struts developers and Committers

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay