Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 53 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
53
Dung lượng
469,73 KB
Nội dung
<tiles-definitions> <! Base Tile Definition from the previous section > <definition name=".baseDef" path="/WEB-INF/jsp/tiles/template.jsp"> . . . </definition> <definition name=".homePage" extends=".baseDef"> . . . </definition> <definition name=".postComment" extends=".baseDef"> <put name="title" value="Post a Comment"/> <put name="content" value="/WEB-INF/jsp/tiles/postCommentContent.jsp"/> </definition> <definition name=".postStory" extends=".baseDef"> <put name="title" value="Post a Story"/> <put name="content" value="/WEB-INF/jsp/tiles/postStoryContent.jsp"/> </definition> <definition name=".searchForm" extends=".baseDef"> <put name="title" value="Search JavaEdge"/> <put name="content" value="/WEB-INF/jsp/tiles/searchFormContent.jsp"/> </definition> <definition name=".searchForm" extends=".baseDef"> <put name="title" value="Search JavaEdge"/> <put name="content" value="/WEB-INF/jsp/tiles/searchFormContent.jsp"/> </definition> <definition name=".signUp" extends=".baseDef"> <put name="title" value="Become a JavaEdge Member"/> <put name="content" value="/WEB-INF/jsp/tiles/signUpContent.jsp"/> </definition> <definition name=".storyDetail" extends=".baseDef"> <put name="title" value="View a specific story"/> <put name="content" value="/WEB-INF/jsp/tiles/storyDetailContent.jsp"/> </definition> </tiles-definitions> CHAPTER 6 ■ BUILDING FLEXIBLE FRONT-ENDS WITH THE TILES FRAMEWORK 243 Ch06_7389_CMP3 9/27/06 11:30 AM Page 243 Extending a Tiles Definition It is possible to declare a new Tiles definition that inherits all of the attributes of an existing Tiles definition and then adds new attributes that are unique to that tile. This is often done when you want to write a page that has the same basic look and feel as all the rest of the pages in an application, but has some additional visual elements that are unique. Let’s say that the marketing department has decided that they want to try and underwrite some of the costs of the JavaEdge site by selling ad space immediately below the header on the main page. However, the marketing department is also considering adding ads to other pages in the JavaEdge application at some later point in the future. The easy approach would be to modify the homePageContent.jsp file to include the ad information. However, this is not very reusable because every time the marketing department wants to add more pages with ads, the advertisement code added to the homePageContent.jsp would need to be replicated. A more flexible approach would be to use the inheritance and extensibility features found in Tiles definitions to build a hierarchy of definitions. The root Tiles definition for the JavaEdge application is still the .baseDef definition. All of the pages in the JavaEdge application, except for the home page, would use this definition. A new definition is going to be created for the JavaEdge home page that will extend the .baseDef definition. This new definition, which will be called .baseWithOneAd, will include a new attribute parameter that defines what HTML or JSP file is going to be used for the ad that is going to be placed in the JavaEdge application. Figure 6-5 shows the relationship between the .baseDef definition, the .baseWithOneAd definition, and the pages that implement these definitions. Figure 6-5. Building a base definition CHAPTER 6 ■ BUILDING FLEXIBLE FRONT-ENDS WITH THE TILES FRAMEWORK244 Ch06_7389_CMP3 9/27/06 11:30 AM Page 244 To implement the Tiles definition hierarchy shown previously, the following steps need to be taken: • The template.jsp that is being used by the JavaEdge application needs to be modified to include additional attributes that are only going to be implemented by the .baseWithOneAd Tiles definition. •A new Tiles definition needs to be implemented in the tiles-defs.xml file that inherits and extends the attributes defined in .baseDef. • The .homePage Tiles definition needs to be modified to use the .baseWithOneAd defini- tion instead of the .baseDef definition. Modifying the template.jsp File All of the attributes defined in the template.jsp file are being passed values from the individual pages using the .baseDef Tiles definition. Every individual JavaEdge page that uses the .baseDef definition must override the attribute values defined in the definition. If the page does not override these values, the page will be rendered using the default values from the definition. Implementing the condition that some pages in the JavaEdge application support adver- tisements requires a new attribute be added to the template.jsp page. This attribute, called adone, holds the path to a JSP file that contains the advertisement. The template.jsp file with the adone attribute declared is shown here: <%@ taglib uri="/taglibs/struts-tiles" prefix="tiles" %> <html> <head> <title><tiles:getAsString name="title"/></title> </head> <body> <p> <tiles:insert attribute="header"/> <tiles:insert attribute="adone" ignore="true"/> <tiles:insert attribute="content"/> <tiles:insert attribute="footer"/> </body> </html> Typically when a Tiles definition uses a template, each attribute declared in the template must have a value passed into it. If a value is not passed into it, the Tiles framework will raise an exception. However, with the introduction of the advertisement requirement, there is now an attrib- ute, adone, in the template.jsp file that does not need to have a value passed to it by every Tiles definition using the template. CHAPTER 6 ■ BUILDING FLEXIBLE FRONT-ENDS WITH THE TILES FRAMEWORK 245 Ch06_7389_CMP3 9/27/06 11:30 AM Page 245 To make the adone attribute nonmandatory, the ignore XML attribute is added to the attribute’s <tiles:insert> tag: <tiles:insert attribute="adone" ignore="true"/> The ignore XML attribute, when set to true, tells the Tiles framework to not throw an exception if the Tiles definition using the template does not pass a value for this attribute using a <tiles:put> tag. If the ignore XML attribute is set to false or is omitted altogether, every attribute defined in the template JSP must have a corresponding <tiles:put> tag defined in the Tiles definition implementing the template. Now that the template.jsp has been modified, let’s look at setting up the inheritance hierarchy for the JavaEdge Tiles definitions in the tiles-defs.xml file. Adding the New Definition to tiles-defs.xml Having one Tiles definition extend the attributes of another definition is straightforward. Shown here is the tiles-defs.xml file rewritten with an additional Tiles definition, .baseWithOneAd, added to it: <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration//EN" "http://struts.apache.org/dtds/tiles-config.dtd"> <tiles-definitions> <definition name=".baseDef" path="/WEB-INF/jsp/tiles/template.jsp"> <put name="title" value="Base Template Page"/> <put name="header" value="/WEB-INF/jsp/tiles/header.jsp"/> <put name="content" value="/WEB-INF/jsp/tiles/baseContent.jsp"/> <put name="footer" value="/WEB-INF/jsp/tiles/footer.jsp"/> </definition> <definition name=".baseWithOneAd" extends=".baseDef"> <put name="adone" value="/WEB-INF/jsp/tiles/baseAd.jsp"/> </definition> . . . </tiles-definitions> The .baseWithOneAd Tiles definition looks very similar to the .baseDef definition. Both Tiles definitions use a <definition> tag to declare the definition. Both definitions also declare attributes the definitions are going to pass to the template via the <put> tag. The key difference between the two different definitions is that the .baseWithOneAd definition does not use the path attribute to declare the path of the JSP file it is going to pass attribute values to. Instead, the .baseWithOneAd definition uses the extends attribute to indi- cate that it is inheriting all of the attributes from the .baseDef definition: <definition id=".baseWithOneAd" extends=".baseDef"> CHAPTER 6 ■ BUILDING FLEXIBLE FRONT-ENDS WITH THE TILES FRAMEWORK246 Ch06_7389_CMP3 9/27/06 11:30 AM Page 246 By using the extends attribute, the .baseWithOneAd definition automatically inherits all of the attribute parameters declared in the .baseDef definition. The .baseWithOneAd definition can choose to override the attribute values declared in the .baseDef definition by redeclaring them via a <put> tag. Also remember, additional attributes can be added that are specific to the child definition. The .baseWithOneAd Tiles definition has declared that it is going to pass a value to the adone attribute in the template.jsp file: <tiles:put name="adone" value="/WEB-INF/jsp/tiles/baseAd.jsp"/> Since the adone attribute is being declared in the .baseWithOneAd definition, only the JavaEdge pages using this definition will have the ad content included on the page. Modifying the .homePage Definition At this point, the .homePage definition can now be modified to use the .baseWithOneAd instead of the .baseDef Tiles definition: <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration//EN" "http://struts.apache.org/dtds/tiles-config.dtd"> <tiles-definitions> <definition name=".baseWithOneAd" extends=".baseDef"> . . . </definition> <definition name=".homePage" extends=".baseWithOneAd"> <put name="title" value="Todays Top Stories"/> <put name="content" value="/WEB-INF/jsp/tiles/homePageContent.jsp"/> <put name="adone" value="/WEB-INF/jsp/tiles/ad.jsp"/> </definition> . . . </tiles-definitions> Let’s look at the JavaEdge home page with the newly added ad at the top of the page. Bring up a web browser and go to http://localhost:8080/JavaEdge/execute/tiles/homePageSetup. You should see the advertisement at the top of the screen immediately below the menu bar, as shown in Figure 6-6. The home page will be the only application that has this advertise- ment on it. However, it would be extremely easy to add the advertisement to other pages in the JavaEdge application. All that is required is to modify the extends attribute on the page to which you want to add the advertisement to use the .baseWithOneAd definition rather than the .baseDef definition. CHAPTER 6 ■ BUILDING FLEXIBLE FRONT-ENDS WITH THE TILES FRAMEWORK 247 Ch06_7389_CMP3 9/27/06 11:30 AM Page 247 Figure 6-6. The JavaEdge application with an ad on the screen The .homePage definition overrides attributes from the two different definitions, .baseDef and .baseWithOneAd. However, the .homePage definition has no knowledge that the title and content attributes come from the .baseDef definition. Instead, as far as the .homePage definition is concerned, these attribute declarations are derived only from the .baseWithOneAd definition. The reason for this is that the Tiles inheri- tance model is a single-tree model. This means a definition can only inherit attributes from a single parent definition. The Tiles framework does not support multitree inheritance, in which a definition can inherit from multiple definitions that have absolutely no relationship to one another. If you want a tile to inherit attributes from multiple definitions, the definitions must be organized into a hierarchical relationship where each definition inherits its attributes in a chain. The bottom of this chain will be the definition that is going to inherit all of the attributes. ■Note It should be noted that while Tiles inheritance allows a great deal of flexibility in building the look and feel of a page, overusing and developing complex and/or deep inheritance hierarchies can cause per- formance problems and turn maintaining pages for the site into an absolute nightmare. We suggest never having a Tiles inheritance hierarchy more than two or three levels deep. If you find yourself creating overly deep inheritance hierarchies, you should consider cre- ating multiple base definitions based on the different distinct page types in your application. Mapping Tiles Definitions to Action Forwards Placing the Tiles definitions in a single file eliminates almost half of the JSP pages needed to build the JavaEdge application. However, the tiles-defs.xml file does not indicate how your Struts applications are supposed to actually navigate to the individual JSP pages. The question becomes, How does Struts map these Tiles definitions to JSP pages that can be reached from the Struts framework? CHAPTER 6 ■ BUILDING FLEXIBLE FRONT-ENDS WITH THE TILES FRAMEWORK248 Ch06_7389_CMP3 9/27/06 11:30 AM Page 248 Struts uses the Tiles plug-in to map an XML-based Tiles definition to a Struts Action Forward defined in the application’s struts-config.xml file. To map a Tiles definition to a Struts Action Forward, the developer needs to use the value in the <definition> tag’s name attribute in the <forward> tag for the Action. For example, to refactor the JavaEdge’s /homePageSetup action to redirect the end user to the .homePage Tiles definition, the <action> tag for the /homePageSetup Struts action needs to be rewritten as shown here: <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://struts.apache.org/dtds/struts-config_1_2.dtd"> <struts-config> . . . <action-mappings> <action path="/homePageSetup" type="com.apress.javaedge.struts.homepage.HomePageSetupAction" unknown="true"> <forward name="homepage.success" path=".homePage"/> </action> . . . </action-mappings> </struts-config> The key tag that needs to be modified is the <forward> tag. The path attribute in the <forward> tag must point to the name of the Tiles definition the user is going to be redirected to. With the Struts plug-in configured, the Struts framework will check to see if there is a Tiles definition defined that maps to the name specified in the path attribute. If the Struts framework finds a match, it will assemble the contents of the page from its different component pieces and forward the user to the assembled page. ON NAMING TILES The “.” naming convention that is being used by all of the JavaEdge Tiles definitions is not mandatory. You can still use “/” and a more traditional path structure to name the application’s individual Tiles definitions. However, even the refactored JavaEdge application uses Action Forwards that are not Tiles-based. Many of the Action Forwards in the JavaEdge application point to “pre-Actions” that do some work and then redi- rect the user to a Tiles-based JSP page. Using the “.” notation for Tiles-based actions and the “/” notation for Struts-based Actions helps keep the struts-config.xml file manageable and easy to follow. The idea of using the “.” notation for Tiles-based Forwards is not ours. Cedric Dumoulin, one of the authors of Struts in Action (Ted Husted et al., Manning Publications Company, ISBN: 1-930-011050-2), first put forth this idea. We adopted it for our own Struts projects and have found it works well. CHAPTER 6 ■ BUILDING FLEXIBLE FRONT-ENDS WITH THE TILES FRAMEWORK 249 Ch06_7389_CMP3 9/27/06 11:30 AM Page 249 The homePageSetup Struts action does not submit any form data. However, when using XML-based Tiles definitions and Struts actions that submit form data, make sure that the input parameter on the action is mapped to the name of the Tiles definition for the page rather than the JSP where the data was entered. For example, in the /login action shown here, the input parameter is set to the .homePage definition: <action path="/login" input=".homePage" name="loginForm" scope="request" validate="true" type="com.apress.javaedge.struts.login.Login"> <forward name="login.success" path="/execute/homePageSetup"/> </action> It is easy to overlook setting the input parameter to point to the Tiles definition. Missing this can result in hours of fun and debugging. Shown here are the rest of the JavaEdge action mappings converted to use XML-based Tiles definitions: <action path="/storyDetailSetup" type="com.apress.javaedge.struts.storydetail.StoryDetailSetupAction"> <forward name="storydetail.success" path=".storyDetail"/> </action> <action path="/signUpSetup" type="com.apress.javaedge.struts.signup.SignUpSetupAction" name="signUpForm" scope="request" validate="false"> <forward name="signup.success" path=".signUp"/> </action> <action path="/signUp" input=".signUp" name="signUpForm" scope="request" validate="true" type="com.apress.javaedge.struts.signup.SignUp"> <forward name="signup.success" path="/execute/homePageSetup"/> </action> <action path="/postStorySetup" type="com.apress.javaedge.struts.poststory.PostStorySetupAction" name="postStoryForm" scope="request" validate="false"> CHAPTER 6 ■ BUILDING FLEXIBLE FRONT-ENDS WITH THE TILES FRAMEWORK250 Ch06_7389_CMP3 9/27/06 11:30 AM Page 250 <forward name="poststory.success" path=".postStory"/> </action> <action path="/postStory" input=".postStory" name="postStoryForm" scope="request" validate="true" type="com.apress.javaedge.struts.poststory.PostStory"> <forward name="poststory.success" path="/execute/homePageSetup"/> </action> <action path="/postCommentSetup" type="com.apress.javaedge.struts.postcomment.PostCommentSetupAction" name="postCommentForm" scope="request" validate="false"> <forward name="postcomment.success" path=".postComment"/> </action> <action path="/postComment" type="com.apress.javaedge.struts.postcomment.PostComment" name="postCommentForm" scope="request" validate="false"> <forward name="postcomment.success" path="/execute/homePageSetup"/> </action> <action path="/SearchSetup" type="com.apress.javaedge.struts.search.SearchFormSetupAction" name="searchForm" scope="request" validate="false"> <forward name="search.success" path=".searchForm"/> </action> <action path="/Search" type="com.apress.javaedge.struts.search.Search" input=".searchForm" name="searchForm" scope="request" validate="false"> <forward name="search.success" path=".searchForm"/> </action> CHAPTER 6 ■ BUILDING FLEXIBLE FRONT-ENDS WITH THE TILES FRAMEWORK 251 Ch06_7389_CMP3 9/27/06 11:30 AM Page 251 Summary This chapter went through the basics of using the Tiles framework to build a flexible presenta- tion tier that can easily be modified as the business needs of your organization evolve. Some of the material that was covered in this chapter includes the following: •Configuring Struts to use the Tiles framework: •Configuring the struts-config.xml file (or in the examples for this chapter, the struts-config-tiles.xml file) to activate the Tiles plug-in •Configuring the Tiles plug-in to recognize where the tiles-defs.xml file is located and what level of debugging the Tiles plug-in should carry out • Laying out the skeleton tiles-defs.xml file. •Writing a simple JSP page to leverage the <tiles> tag libraries. •Exploring how Tiles definitions can be used to build the JavaEdge applications. This chapter looked at the two different types of Tiles definitions (JSP-based and XML- based) and how they could be used to do the following: •Group together related page attributes into unique entities that could be reused across multiple screens •Demonstrate how to override individual attributes in a definition to allow cus- tomization of the basic look and feel of an individual page or tile •Use XML-based Tiles definitions to centralize all of the screen layouts into a single file that can be easily managed and modified • Leverage the inheritance and extensibility features of XML-based Tiles definitions to add new elements to an existing application screen •Modifying the struts-config-tiles.xml file so that XML-based Tiles definitions can be used in a Struts Action Forward rather than the traditional JSP page. Our advice is not to get caught up in the pure mechanics of the Tiles framework. It is more important to understand how the Tiles framework can help a development team avoid the Tight-Skins and Hardwired antipatterns. The Tiles framework allows the development team to break the presentation layer into discrete and reusable components that can be managed from a single location. Let’s quickly review some of the changes made to the JavaEdge application during the course of this chapter. It should become pretty apparent that we made some fundamental changes to the application’s structure without having to rewrite a great deal of code. • Reconfigured the application to use a completely different set of JSP files without having to modify any of the existing files: By modifying the JavaEdge’s web.xml file to point to a new Struts configuration file (struts-config-tiles.xml file), you could move the JavaEdge application to a new presentation framework (Tiles) without having to touch any of the existing application source code. CHAPTER 6 ■ BUILDING FLEXIBLE FRONT-ENDS WITH THE TILES FRAMEWORK252 Ch06_7389_CMP3 9/27/06 11:30 AM Page 252 [...]... import import org .apache. struts. action.ActionMapping; org .apache. struts. action.DynaActionForm; org .apache. struts. action.ActionForward; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; org .apache. struts. action.ActionErrors; org .apache. struts. action.ActionError; org .apache. struts. action.ActionServlet; org .apache. struts. util.MessageResources; import com .apress. javaedge.common.VulgarityFilter;... rules to the framework 265 Ch07_7389_CMP3 266 9/27/ 06 1:10 PM Page 266 CHAPTER 7 ■ DYNAMIC FORMS AND THE STRUTS VALIDATOR FRAMEWORK The Jakarta Commons Validator Framework The Validator framework used in Struts did not originate in the Struts project Rather, the Validator framework is part of the Apache Jakarta Group’s Commons project (http://jakarta apache. org/commons) The Struts development team... import import import org .apache. struts. action.ActionMapping; org .apache. struts. validator.DynaValidatorForm; org .apache. struts. action.ActionForward; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; javax.servlet.http.HttpSession; org .apache. struts. action.ActionErrors; org .apache. struts. action.ActionError; org .apache. struts. action.ActionServlet; org .apache. struts. util.MessageResources;... package com .apress. javaedge .struts. poststory; import java.util.Vector; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import import import import import org .apache. struts. action.Action; org .apache. struts. action.ActionForm; org .apache. struts. action.ActionForward; org .apache. struts. action.ActionMapping; org .apache. struts. action.DynaActionForm;... email Validates that the field entered is a properly formatted e-mail address intRange Validates whether an integer is within a particular range floatRange Validates whether a float is within a particular range doubleRange Validates whether a double is within a particular range 267 Ch07_7389_CMP3 268 9/27/ 06 1:10 PM Page 268 CHAPTER 7 ■ DYNAMIC FORMS AND THE STRUTS VALIDATOR FRAMEWORK The validation.xml... will get to shortly) package com .apress. javaedge.common; import import import import import import import javax.servlet.http.HttpServletRequest; org .apache. commons.validator.Field; org .apache. commons.validator.ValidatorAction; org .apache. struts. action.ActionErrors; org .apache. commons.validator.GenericValidator; org .apache. commons.validator.ValidatorUtil; org .apache. struts. validator.Resources; import... development frameworks to enforce the D.R.Y principle Starting with Struts version 1.1 and higher, you can use two new features of the framework to solve the problems of repetitive code in implementing ActionForm classes and validating the data contained within them 255 Ch07_7389_CMP3 2 56 9/27/ 06 1:10 PM Page 2 56 CHAPTER 7 ■ DYNAMIC FORMS AND THE STRUTS VALIDATOR FRAMEWORK These two features are Dynamic... extends the Struts import org .apache. struts. action.DynaActionForm class rather than the Struts org .apache struts. action.ActionForm class: public class PostStoryDynaForm extends DynaActionForm { } The DynaActionForm class extends the ActionForm The DynaActionForm class is used to tell the Struts framework that the class is a Dynamic Form and that its attributes need to be read from the struts- config.xml... JavaEdge struts- config.xml file: The tag goes at the end of your struts- config.xml file It defines the fully qualified Java class that represents the plug-in point between Struts and the third-party software The ... entirely on unit testing, it does have some great chapters covering the topic 261 Ch07_7389_CMP3 262 9/27/ 06 1:10 PM Page 262 CHAPTER 7 ■ DYNAMIC FORMS AND THE STRUTS VALIDATOR FRAMEWORK Once a Dynamic Form’s tag and its corresponding tags have been declared, you’ve done all the work you need to do to tell Struts to use a dynamic ActionForm class The postStoryContent.jsp page that . org .apache. struts. action.Action; import org .apache. struts. action.ActionForm; import org .apache. struts. action.ActionForward; import org .apache. struts. action.ActionMapping; import org .apache. struts. action.DynaActionForm; import. org .apache. struts. action.ActionErrors; import org .apache. struts. action.ActionError; import org .apache. struts. action.ActionServlet; import org .apache. struts. util.MessageResources; import com .apress. javaedge.common.VulgarityFilter; public. PostStoryDynaForm class: package com .apress. javaedge .struts. poststory; import org .apache. struts. action.ActionMapping; import org .apache. struts. action.DynaActionForm; import org .apache. struts. action.ActionForward; import