View Composition and Page Layout

You may well be thinking, "This is all very well, but the example HTML is very simple. In our site we need to use headers, footers, and navigation bars, not just a single content page".

View structure can get far more complex than the simple HTML document model we've seen. However, as I'll try to demonstrate, this doesn't pose a problem for MVC design or our approach to views.

All the templating technologies we've discussed allow us to compose views from multiple dynamic and static blocks. In JSP, for example, this is done via the include directive and include standard action, while both WebMacro and Velocity provide include directives.

There are two basic approaches, which I'll term content page inclusion and template page inclusion. In content page inclusion, each page of content includes other elements: often, a header and footer. In template page inclusion, a layout or template page includes pages of content as required. The one layout page may be used for an entire application, including different content wells, headers, footers etc. in different contexts. Multiple templates can be easily defined if necessary.

Template page inclusion is much more flexible than content page inclusion. It allows a model in which page fragments are components, which the template page is responsible for assembling. It also allows easy global changes to page structure, simply by changing the template page. With content page inclusion, we will need to change many individual pages to make a consistent change.

Since JSP 1.2 rectified the serious problems with the JSP 1.1 dynamic include mechanism, JSP has provided good support for template page inclusion. However, a higher level of abstraction is really needed. Struts, for example, provide the "template" tag library to handle this.

The present framework addresses template page inclusion through the use of static attributes on views. Static attributes are data available to views that doesn't need to come from the model provided by the controller. Thus they may be presentation-specific, and may provide valuable support for template pages. Static attributes will be overridden by model values with the same name, and so can also be used to provide default values.

Let's illustrate the point by looking at a JSP implementation of a simple layout that involves a header and footer.

Content page inclusion would mean that each page included a header and footer, like this:

    <%@ include file= "header.jsp" %>    Content well content for this page    <%@ include file= "footer.jsp" %> 

Note that as we know the name of the included page in each case, we can use JSP static includes (via a directive rather than the <jsp:include> standard action). This is a simple and intuitive approach, but it's not usually viable for large and complex web applications. While changes to the included header and footer JSP pages would automatically affect all pages including them, what if we wanted to add additional template content in a separate included JSP? Such changes would require the modification of all JSP pages. The basic problem is that each JSP contains the same, redundant, layout information.

In contrast, template page inclusion would involve a single template that would include the header and footer and the content well, which would vary at runtime. Page layout would be defined once only, in the template. A simple template might look like this:

    <%@ include file= "header.jsp" %>    <jsp:include page="<%=contentWell%>" />    <%@ include file="footer.jsp" %> 

The contentWell variable would need to be provided to the template page as a request attribute or by some other method. Note that a JSP dynamic include is the only option when we don't know what page we need to include. This simple example uses static includes for the header and footer, but of course any of the includes could be parameterized.

Note 

The dynamic versus static include issue was far more important in JSP 1.0 and 1.1 than in JSP 1.2, as the <jsp:include> action always flushed the buffer, which wasn't always acceptable. JSP 1.2 removes this limitation. This means that there's now only a minor speed penalty for using dynamic (rather than static) includes.

Each content well page would contain just the output relevant to its business purpose. This content, however, would need to be legal HTML at the point at which it appeared in the template, placing some restrictions on layout composition using this technique.

Now let's look at a realistic implementation of template page inclusion using static attributes to provide the necessary information to the template. Remember that the com.interface21.web.servlet.view.AbstractView class, from which all our views are derived, gives us the ability to set string static attributes in a CSV string. We can set three static attributes: header (the URL within the WAR of the header); contentWell (the URL of the content well); and footer (the URL of the footer). These static attribute values will be available to all templates, whatever the dynamic model, and define the layout of the composed view.

This inherited support means that we can use the InternalResourceView as with any JSP. When we use template page inclusion, we switch the URL in the view definition to that of the template page, but set the original URL (/welcome.jsp) as the value of the content well static attribute. Note that the footer is a static HTML resource, as this approach works with any resource inside a WAR:

    welcomeView.attributesCSV= header=[/jsp/header.jsp],\              contentWell=[/welcome.jsp],\              footer=[/jsp/footer.htm] 

The first and last character of each attribute value is ignored to allow the, or = characters to be included within it if necessary. While the present example uses [ and ] characters to enclose each value, any other pair of characters could be used. Note the use of the \ character as described in java.util.Properties documentation to break up a single property value for readability.

These three static attribute values will appear in our model as though they were data provided by the controller. This means that, when we use JSP, they will be available as request attributes, and that we can declare JSP beans of type string to access them.

The file /jsp/template.jsp in our sample application is the template file. After disabling automatic session creation (which should be the first task in any JSP), it declares the three beans:

    <%@ page session=" false" %>    <jsp:useBean         type=" java.lang.String"        scope="request"    />    <jsp:useBean         type="java.lang.String"        scope="request"    />    <jsp:useBean         type="java.lang.String"        scope="request"    /> 

Now it's trivial to use these values to structure the output and control the inclusion of the constituent parts:

    <html>    <head>    <title>Could also parameterize this</title>    </head>
   <jsp: include page="<%=header%>" />
    <hr>
   <jsp: include page="<%=contentWell%>" />
    <hr>    <font size="2">
    <jsp: include page="<%=footer%>" />
    </font>    </body>    </html> 

Let's try this template page with the welcome page from the sample application. The view definition in /WEB-INF/classes/views.properties used to be as follows:

    welcomeView.class=com.interface21.web.servlet.view.InternalResourceView    welcomeView.url=/welcome.jsp 

Now - without any change to controller or model code or welcome.jsp - our welcome page will appear like this:

click to expand

Note 

In practice, we would need to ensure that included page components didn't include <html> or <body> tags, so this is a slight oversimplification.

This approach - using a view implementation and "static attributes" - has a significant advantage over custom tag based view composition such as the Struts template tag library provides or that used in the Java Pet Store sample application (which are both based on the same concepts) in that it will work with view technologies other than JSP, such as WebMacro and Velocity.

Note 

It's also possible to combine the output of multiple views in Java code, rather than using a template technology. For example, the RequestDispatcher interface provides an include() method as well as the forward() method we've seen so far, which could be used by a custom View implementation to include the output of multiple JSP pages or other resources within a WAR. Alternatively, we could provide a CompositiveView implementation of the View interface that output the result of rendering several views - possibly of different types - in succession (I have successfully used the composite view approach with JSP 1.1 to get around the limitations of dynamic includes).

However, JSP 1.2, Velocity and other templating technologies make view composition so easy that it's hard to justify doing it in Java.

Important 

When view composition is involved - as in the use of a template page - the details should be concealed in view code. They are not the concern of controllers or models.

Whichever J2EE view technology you choose, remember to follow the same principle of separation of presentation from content in the markup layer itself. If using XML and XSLT, this won't be an issue. When generating HTML, make sure that the HTML uses CSS stylesheets to ensure that dynamically generated content is kept apart from rendering information.



Expert One-on-One J2EE Design and Development
Microsoft Office PowerPoint 2007 On Demand
ISBN: B0085SG5O4
EAN: 2147483647
Year: 2005
Pages: 183

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net