UI design with Tiles and Struts
使用HTML和JSP表示视图的几种方案
摘要
每个Web应用开发者必须组织像header、body和footer等这样的页面元素,现在有很多的技术来实现这种组织,当然每种都有各自的优缺点。本文展示了7中可能的解决方案,并且重点揭示了使用Tiles和Struts相集成的方式来灵活的组织页面元素。先用几个简单的例子演示了组织页面元素的问题,然后使用JSP的内建机制,如include来清晰的解决这些问题。然后过渡到使用Tiles框架,学习如何使用Tiles和Stuts相结合来组织页面元素.
原文在
http://www.javaworld.com/javaworld/jw-01-2002/jw-0104-tilestrut.html,写的很详细。大家可以学习一下老外是怎么写技术文章的,文章结构很好,并且技术阐述的也很清楚。值得大家学习。
上面的文章没有了,现在发现了下面的一篇,贴出来分享。
The Model-View-Controller (MVC) framework is a proven and convenient way to generate organized, modular applications that cleanly separate logic, style, and data. In the Java world, Struts is one of the best-known and most talked about open source embodiments of MVC. Struts contributors have recently enhanced the project's core functionality and improved the view support, incorporating the Tiles view component framework to strengthen support for component-based development, to increase reuse, and to enhance consistency. In this article, Wellie Chao explains why the Struts and Tiles combination is a terrific package of tools for creating Web applications and shows you how to get started using it, with a focus on changes since Struts 0.9.
When I started learning how to create software back in the mid-80s, my first couple of months were spent writing monolithic code with linear flow and embedded display, logic, and data. It seemed the most obvious way at the time. With experience, I learned to package code into objects, separate data from logic, refactor common code, and practice other accepted tenets of good programming.
Web developers embrace MVC
Fast forward to 1994, when mainstream adoption of Web application development had only just begun. Because of the immaturity of the Web, developers had few tools to help them build Web software. As a result, applications mixed HTML code with application logic in ad hoc solutions. Understandably, UI design changes and business logic updates were both difficult and expensive in large applications because the tightly coupled presentation and logic obfuscated both elements, leading to errors and slow progress. Also, the mixed code necessitated knowledge of UI design on the part of developers or a close working relationship between developer and graphic designer that often made for inefficient use of time.
The introduction of JSP technology and tags ameliorated the change problem somewhat because logic and display could be separated. UI designers could productively work on display while developers could focus on logic. However, this approach still suffered shortcomings. Notably, certain operations -- common ones, too -- were still hard to develop. The validating form is the classic example. As many of you know, the process of form validation goes something like this:
- Display form; wait for user to fill it out and submit data.
- Check for valid field values; redisplay form if there are errors.
- Process data entered by user, perhaps storing it in a database.
- Display new page with results of processing or next step (probably another form) for user.
If you're only using JSP pages for this process, you'll find it difficult to route control from one page to another in a way that preserves manageability down the road when the code needs to be changed again. Do you place step 4 in the same page as step 3? If you use separate JSP pages, how do you keep track of which pages link to others, and what do you do when you want to change a page's filename or location? Furthermore, when step 2 detects an error in a field, how do you redisplay the original form with an error message but preserve the values the user has already filled in? Struts, an open-source Model-View-Controller framework, makes life easier for developers by helping with all of these issues.
This article does not discuss the MVC platform in depth. For that, see Malcolm Davis's developerWorks article entitled "Struts, an open-source MVC implementation." This article you're reading now discusses changes to Struts since Malcolm's article was published, including the Tiles library. For the code walkthrough, this article covers only the steps required for a minimal setup with Jakarta Tomcat 4.0 (Catalina). Please consult the manuals with your application server if you do not use Tomcat.
Background on Struts and Tiles
Craig McClanahan, the technical lead on the Apache Tomcat project, started the Struts project as a way to scratch an itch. It has grown quite popular as the preferred and officially sanctioned open-source implementation of a Model-View-Controller framework. It enjoys support from both Sun and IBM in the form of distribution with shipping products. Because Craig is active in development of both Tomcat and Struts, Struts will continue to be highly compatible with the reference implementation for the JSP and Servlet specifications, and thus highly compatible with all J2EE application servers.
Malcolm Davis's developerWorks article on Struts covers functionality through Struts 0.9; for brevity's sake, I will discuss only changes and Struts topics that he didn't cover. The current release version of Struts is 1.0.2, but there is a beta version, labeled 1.1-b1, that has been available since March 19, 2002. Because the beta version represents a code freeze in which only bug fixes are being worked on, there is an extremely good chance that the final version of 1.1 will be out shortly, a sentiment that has been echoed on the Struts mailing lists. Therefore, any new projects making use of Struts should probably begin on the 1.1 code base, and that is what I will cover.
Useful additions to the Struts framework since version 0.9 include improved form validation functionality, the ability to specify form elements via XML declarations, and the ability to dynamically define bean properties. Probably the most prominent addition, however, has been the incorporation of the Tiles templating library into the Struts distribution.
Have you ever wanted an easier way to create a set of pages (or perhaps a whole application) with a consistent user interface -- the same navigation bar, header, footer, and so on -- on every page? What about a way to display portlet-like rectangles of content within a larger page of content? The Tiles framework lets you accomplish both tasks and more. Through a central XML file defining screens and a set of tags that can be embedded in JSP pages to insert static and dynamic content, the Tiles framework allows you to build componentized views and assemble them as you like, thus aiding flexibility, reusability, consistency, and maintainability.
Struts and Tiles interact well because the developers of the two projects have recognized their complementary nature and decided to cooperate. A developer can specify a Tiles page definition as the target view (a forward in Struts parlance) of a Struts action. Because both Struts and Tiles conform to the JSP tag library specifications, Struts tags and Tiles tags can be intermixed in JSP pages.
You are likely itching to try out the Tiles framework and see exactly what it can do.
Struts and Tiles are aids for Web development, so you'll need to set up a Web container to experiment with them; the process for setting up Tomcat as your container and then the Struts and Tiles packages is described in the next section, in step-by-step fashion. These instructions also show you how to install this article's sample code. Once you've finished with that, you're ready to continue with the article. The Example 1 application doesn't take advantage of Struts and Tiles; it demonstrates the page-centric approach. By comparing it with Example 2, you'll see how much more structured and manageable Struts and Tiles can make your Web development. Finally, Example 3 demonstrates how straightforward it is to add functionality to a Struts and Tiles Web application that's already up and running.
Installing Struts and Tiles
The following instructions have been tested on Linux with the J2SE 1.4 SDK, Ant 1.4.1, Tomcat 4.0.3, and Struts 1.1-b1. If you encounter difficulties with different versions of these packages, you may want to change to the versions specified here to get acquainted with Struts and Tiles setup and development.
- If you do not have the J2SE 1.4 SDK (the Java 2 Platform, Standard Edition 1.4 Software Development Kit), get it from http://java.sun.com/j2se/1.4.2/download.html and follow the instructions included with the package to install it. You will need the SDK as opposed to the JRE, but you can choose to get the Forte/SDK combination.
- Make certain you have an environment variable called
JAVA_HOME
that is set to the location where the J2SE 1.4 SDK is installed.
- If you do not have Ant 1.4, get the binary distribution from http://archive.apache.org/ and unpack it. Make sure that you get the binary (as opposed to the source) distribution for this and all other packages in these setup instructions; otherwise, you will have to compile the packages before using them. Also, add the Ant bin directory to your path.
- Get the latest Tomcat binary distribution from http://jakarta.apache.org/site/downloads/index.html and unpack it. The filename should be something like jakarta-tomcat-4.0.5-LE-jdk14.tar.gz. To allow easy reference to it later in these instructions, let's arbitrarily call the path to the installation directory (up to and including the Tomcat directory) TOMCAT_HOME. This will be something like /home/wchao/jakarta-tomcat-4.0.5-LE-jdk14 on a UNIX system or c:\jakarta-tomcat-4.0.5-LE-jdk14 on a Windows system.
- Get the Struts 1.1-b1 beta release from http://jakarta.apache.org/site/downloads/index.html and unpack it (not in TOMCAT_HOME). We will call this directory STRUTS_INSTALL. This will be something like /home/wchao/jakarta-struts-1.1-b1 on a UNIX system or c:\jakarta-struts-1.1-b1 on a Windows system.
- Download the struts-tiles-examples.tgz and unpack it. It will create three directories: ex1, ex2, and ex3. We will call these directories EX1_INSTALL, EX2_INSTALL, and EX3_INSTALL, respectively.
- Change directory to TOMCAT_HOME/bin.
- Start up the Tomcat server by typing
./startup.sh
(if you are running UNIX) or ./startup.bat
(if you are running Windows).
- Verify that Tomcat is up and running properly by pointing your Web browser to http://localhost:8080/examples. The Examples application is shipped with Tomcat by default. If it doesn't work, then something went wrong with Tomcat; see the Tomcat documentation to resolve the issue.
|
Hello, World: A first attempt
To take a look at our first example, follow these steps:
- Change to the EX1_INSTALL directory.
- Edit the build.xml file and fill in an appropriate value for
tomcat.install.dir
. The value can either be an absolute or a relative path, although if you are inexperienced with how Ant works, it is probably best to use an absolute path.
- Type
ant deploy
. This will build the first example application into a WAR file ready for deployment, then deploy it to Tomcat. If you get an error indicating that Ant could not be found, see step 3 in the "Installing Struts and Tiles" section and make certain that Ant is in your path.
- Point your Web browser to http://localhost:8080/ex1. You should see a "Hello, World" page.
The Example 1 Web application is a very simple illustration of common Web application functionality. All but the simplest of applications require a consistent user interface from page to page. Usually this means that all pages have a common logo, top banner, top or left navigation bar, body, and footer. In Example 1, I have purposely hard-coded the common items in each page to demonstrate a point. Beginners at Web application development typically add new pages of functionality by copying and pasting existing code into new documents. It is easy to see how this approach can quickly become unwieldy. With every addition, the process of changing common page elements, such as a menu or a logo, takes longer and is more prone to error. Clearly, the copy-and-paste approach is a terrible model for any application that will grow beyond a few pages.
Astute readers will realize that JSP technology provides functionality to include content from other servlets and pages. Why don't we just use the <jsp:include/> tag to incorporate common elements? That would certainly make those elements easier to change. If you need to change the menu, just change the file containing the menu. All other pages use the <jsp:include/> tag to pull in the content from the menu, so they automatically pick up the changes. But this approach falls short when the actual layout needs to change or when files and directories need to be reorganized. When you decide to change the layout under a page-centric model, you must make a change to every single page, because even though access to the common elements has been centralized, the HTML code describing the layout itself (what the elements are and where they are positioned) is still present in each page. Similarly, when you decide to change the filename or the location of a file that contains content for one of the common elements, you must change every single file that uses the element in question. The reason? Every file addresses each common element by a fixed physical filename rather than a logical object name. Thus, you must update every reference to the physical filenames. These problems are addressed by Tiles view components.
If you look closely at index.jsp and form1.jsp, the two JSP files comprising the application, another drawback will be apparent: the error handling is quite awkward. The error handling code is in form1.jsp, where I must repeat the display code and add code to insert the values the user entered in the previous form screen (index.jsp). If the user profile fields ever change, or if the display of the input form ever changes, I must update code in two places. I could combine the error handling portion of form1.jsp with the initial form display in index.jsp, but I would still need to do extra work to set the field values to empty strings upon the initial form load, and I would still need to have a physical filename for the final static display of the user profile, which means that the application structure would remain fragile when change occurred. This drawback of awkward form handling is addressed by Struts form automation.
Table 1 below summarizes the benefits and shortcomings of the JSP-based, page-centric Web application model illustrated by the Example 1 application.
Table 1. Overview of the JSP-based approach
Advantage | Explanation |
It is easy to get started. | Just set up Tomcat and start writing code. There is no central file to keep synchronized or lengthy initial configuration of a library. Connections are specified by each individual JSP page or servlet. |
Disadvantage | Explanation |
It is hard to reuse presentation in different parts of application. | You can use <jsp:include/> tags to some extent, but they don't work so well in managing change. |
Common input and data processing tasks are mundane and repetitive. | Error handling is a common problem with plain JSP pages. Also, having to manually populate form values and manually retrieve those values from the request object is time-consuming and mundane work. |
Business logic and presentation are tightly coupled, with code for both mixed together. | If you look over index.jsp and form1.jsp, you'll see that the Java code is mixed with the HTML code. The code is ugly, it is error prone, and it makes isolated Java coding or user interface development really difficult. You end up having to know both HTML and Java coding to work on the page. |
There is no centralized description of application flow or behavior. | There's no way to get a complete sense of the application and how the operations flow together except by looking at each and every page. This is a recipe for confusion, errors, and frustration as a project gets bigger and bigger. |
|
Hello, World: New and improved
Now, let's look at the Struts and Tiles version of the example Web application we just saw. Perform the following steps:
- Change to the EX2_INSTALL directory.
- Edit the build.xml file and fill in appropriate values for
struts.install.dir
and tomcat.install.dir
.
- Type
ant deploy
. This will build the second example application into a WAR file ready for deployment, then deploy it to Tomcat. If you see an error about not being able to copy files, check to make sure that the struts.install.dir
and tomcat.install.dir
properties were set appropriately in step 2.
- Point your Web browser to http://localhost:8080/ex2. You should see a "Hello, World" page.
| Explanation of directory structure and files There are quite a few files under EX2_INSTALL/src/web, and at first glance you might find them all a bit confusing. Here's a little guidance.
The profileInput.jsp and profileOutput.jsp pages serve as the content for panel3 , the main body of the page; they drive this particular application. I have the different components of the page under tiles-components , and the HTML code for the layout is under tiles-layouts . I like this organization because it lets me have different layouts for different user roles and keep all the view components in one central place. Tiles will let you arrange your files any way you want as long as you specify how things are organized in the tiles-defs.xml file, so use whatever works best for you. |
|
If you've looked in the EX2_INSTALL directory, you're probably saying, "What's going on here? There are a lot more files." As with most technologies that impose more order and structure, with Struts and Tiles there is a startup cost in the form of administrative files. For a small project of a few pages, this additional overhead may not make sense. As the project grows, however, the Struts and Tiles approach really begins to shine. Let's take it piece by piece. I won't cover EX2_INSTALL/src/WEB-INF/web.xml; although this file is substantially different from its Example 1 counterpart, most of the lines are boilerplate, and understanding the settings isn't so important for beginning development.
In EX2_INSTALL/src/WEB-INF/struts-config.xml, the important changes since the earlier article on Struts are the use of DynaActionForm
in the <form-beans/> section and the use of tiles as targets in the <action-mappings/> section. In previous versions of Struts, you had to define a Java class for every form bean that you used. You could share form beans between different HTML forms only if they shared fields. Overall, the requirement of a Java class for every form bean was a big pain. Now you can specify the form bean's properties in the struts-config.xml file, and presto! The bean is automatically created without need for a separate file housing a Java class. The dynamic form beans are treated like Hashtable
objects with strongly typed objects for values. As for action mappings, the ability to specify a tile as a target was a completely logical addition once the decision was made to incorporate the Tiles library into the Struts distribution. You can see the tile targets (tile.profileInput and tile.profileOutput) in the action mapping for the profile form. The tiles are specified in the input attribute and the path attribute. Note that the ability to specify a tile target remedies the problem of changing filenames and locations mentioned in my analysis of the page-centric model: tile targets are virtual or logical names rather than physical names.
Now for the exciting part. Let's look at EX2_INSTALL/src/WEB-INF/tiles-defs.xml.
Tiles are specified in <definition/> tags. You can name the definitions anything you want, and the name attribute does not have to be a substring match of the path attribute. I have chosen the name rootLayout
for the first definition to indicate that it is the base layout that pages in the application will follow. Note the path: /tiles-layout/rootLayout.jsp. If you look at /tiles-layout/rootLayout.jsp under EX2_INSTALL/src/web, you will see how simple and clean the layout is. A user interface designer would love it. Note also that it contains no code, so the user interface designer can make changes without worrying about breaking anything.
The <tiles:insert/> tags in rootLayout.jsp correspond to the <put/> tags within the rootLayout
definition in tiles-defs.xml. Note that the <tiles:insert attribute="x"/> tags each have an attribute representing a logical name. Each logical name maps to a name and value specified using a <put name="x" value="y"/> tag in the <definition/> tag within tiles-defs.xml. By using logical rather than physical names in the rootLayout.jsp page and by consolidating physical names in tiles-defs.xml, we make changes to filenames and project filesystem organization manageable.
The real savings in time and the most significant increase in adaptability comes with inheritance of layouts, another Struts feature. In tiles-defs.xml, the section below the "Page definitions" banner has two pages: tile.profileInput and tile.profileOutput. The names are arbitrary and you don't need the tile. prefix if you don't like it (though the name you use must match targets specified in the struts-config.xml file). The names should match the path attribute in the <forward name="x" path="y"/> tags in struts-config.xml. The names should also match the input attribute in the <action ... input="" .../> tags in struts-config.xml. The extends
attribute in the <definition name="x" extends="y"/> tag is where the magic that delivers agility to user interface development happens. By specifying a master layout and extending it, you have the flexibility of not only changing common elements like topBanner
, topMenu
, panel1
, panel2
, and other components, but also the freedom to put different elements on the page and change where they are located. For instance, you could add panel4
, a tile to display the local weather, below panel2
on the left side of the page. As long as the weather code does not require any input from the user or interaction with other components on the page, you could make the addition of panel4
without any changes whatsoever to the application business logic, or even any changes to JSP pages other than rootLayout.jsp.
Let's try adding panel4
with weather information to the application to see how easy it is. To save you time, I've already created the JSP file with the content and HTML code for the weather component in a file called panel4.jsp
in EX2_INSTALL/src/web/tiles-components. There are two changes you will need to make:
- In EX2_INSTALL/src/WEB-INF/tiles-defs.xml, find the code shown in Listing 1 and edit it to add the <put/> tag for panel4, as shown in Listing 2:
Listing 1. Original tiles-defs.xml code
<definition name="rootLayout" path="/tiles-layouts/rootLayout.jsp">
<put name="titleString" value="CHANGE-ME"/>
<put name="topBanner" value="/tiles-components/topBanner.jsp"/>
<put name="topMenu" value="/tiles-components/topMenu.jsp"/>
<put name="panel1" value="/tiles-components/panel1.jsp"/>
<put name="panel2" value="/tiles-components/panel2.jsp"/>
<put name="panel3" value="CHANGE-ME"/>
<put name="footer" value="/tiles-components/footer.jsp"/>
<put name="footerDebug" value="/tiles-components/footerDebug.jsp"/>
</definition>
|
Listing 2. New tiles-defs.xml code
<definition name="rootLayout" path="/tiles-layouts/rootLayout.jsp">
<put name="titleString" value="CHANGE-ME"/>
<put name="topBanner" value="/tiles-components/topBanner.jsp"/>
<put name="topMenu" value="/tiles-components/topMenu.jsp"/>
<put name="panel1" value="/tiles-components/panel1.jsp"/>
<put name="panel2" value="/tiles-components/panel2.jsp"/>
<put name="panel4" value="/tiles-components/panel4.jsp"/>
<put name="panel3" value="CHANGE-ME"/>
<put name="footer" value="/tiles-components/footer.jsp"/>
<put name="footerDebug" value="/tiles-components/footerDebug.jsp"/>
</definition>
|
- In EX2_INSTALL/src/web/tiles-layouts/rootLayout.jsp, find the code shown in Listing 3 and edit it to add a <br> tag and the code to insert
panel4
, as shown in Listing 4:
Listing 3. Original rootLayout.jsp code
<td width="35%">
<!-- ============================================================ -->
<!-- Begin panel1 -->
<tiles:insert attribute="panel1"/>
<!-- End panel1 -->
<!-- ============================================================ -->
<br>
<!-- ============================================================ -->
<!-- Begin panel2 -->
<tiles:insert attribute="panel2"/>
<!-- End panel2 -->
<!-- ============================================================ -->
</td>
|
Listing 4. New rootLayout.jsp code
<td width="35%">
<!-- ============================================================ -->
<!-- Begin panel1 -->
<tiles:insert attribute="panel1"/>
<!-- End panel1 -->
<!-- ============================================================ -->
<br>
<!-- ============================================================ -->
<!-- Begin panel2 -->
<tiles:insert attribute="panel2"/>
<!-- End panel2 -->
<!-- ============================================================ -->
<br>
<!-- ============================================================ -->
<!-- Begin panel4 -->
<tiles:insert attribute="panel4"/>
<!-- End panel4 -->
<!-- ============================================================ -->
</td>
|
Note: the Example 3 application in EX3_INSTALL is just Example 2 with the changes above made; you can use this code if you get into trouble.
Now, there are a few steps you need to follow to make Tomcat recognize the new files:
- Change to the TOMCAT_HOME/bin directory.
- Shut down the Tomcat server by typing ./shutdown.sh (if you are running Unix) or ./shutdown.bat (if you are running Windows).
- Change directory to EX2_INSTALL.
- Type
ant undeploy
to remove the ex2.war file and the unpacked ex2 directory from the Tomcat webapp directory.
- Type
ant deploy
.
- Change to the TOMCAT_HOME/bin directory.
- Start up the Tomcat server by typing
./startup.sh
(if you are running Unix) or ./startup.bat
(if you are running Windows).
- Point your Web browser to http://localhost:8080/ex2. Reload on your browser to ensure that you aren't viewing a cached copy of the Example 2 Web application. You should see a new "Hello, World" page with the weather component.
Table 2 below summarizes the benefits and shortcomings of the MVC-based Struts and Tiles Web application model, as illustrated by the Example 2 application.
Table 2. Overview of the Struts and Tiles approach
Disadvantage | Explanation |
High learning curve, more moving parts to deal with. | It takes longer to get started with Struts and Tiles than with plain JSP pages, partly because there are more files to deal with and additional configuration needed. |
Advantage | Explanation |
Easier maintenance, greater modularity. | The Tiles framework makes it very easy to add and remove view components and to rearrange things. Struts performs a similar function for behavior and business logic. |
Prebuilt solutions for common input and output tasks. | With Struts, you can accept forms and handle errors automatically and in a structured manner. The Tiles framework lets you easily assemble different panes of output into an integrated whole. |
Easy to work on business logic and the UI in parallel. | Because the business logic is separate from the presentation, a graphic designer can work on the HTML for the user interface while a Java developer works on the Java code for the business logic. |
Centralized mapping of actions, forms, and screens. | The central mapping of actions, forms, and screens provided by the struts-config.xml file and the tiles-defs.xml file makes understanding the whole application much easier, especially if the application is large. |
|
More complex uses of Struts and Tiles
Space does not permit me to discuss other useful aspects of the Struts and Tiles package in depth, but I do want to touch on them briefly so you can get a sense of what Struts and Tiles can do. Perhaps these can be the topics of future articles if there is sufficient demand.
You will note that in both the examples in this article, I coded some basic validation of the first name, last name, favorite color, and birthdate. Simple validation of the sort I employed could actually be performed by Struts using its format validation, thus saving time spent coding Java statements. It is possible, for instance, to check for empty strings, to check that a string matches a date, or to check for a match with some other regular expression. You will find it very handy to use format validation as a first-level check with which your program can eliminate obvious errors before checking for adherence to more complex business logic rules. Struts provides a validator package that is configured via a validator.xml descriptor in the WEB-INF directory. I have not included the validator package in the two examples; if you would like to try it out, it's included with the Struts 1.1-b1 bundle.
Another useful feature of the Struts and Tiles package is integration with container-managed security. Many of you are using application servers such as IBM WebSphere or JBoss. These servers facilitate authentication and authorization by handling many of the routine tasks involved in security, freeing you from having to code them. Struts allows you to conditionally display different bits of bean data to different users based on user role, which is determined by automatically querying the container. Similarly, the Tiles framework allows you to conditionally display different view components to different users based on user role, again determined by automatically querying the container. I use these features in my own applications to display different menus to administrators, regular users, or guests.
Finally, I have not touched on internationalization in my examples, but it is a real concern for people building large applications that will ultimately be published in multiple languages. Struts lets you create message resource properties files that specify text for labels, titles, and other output. If you have populated a message resource properties file with all outputs in several different languages, you can change all widgets and hard-coded text to the appropriate language with a simple change of the language setting, even on the fly.