Content Inclusion in the Book Viewer

The Book Viewer

The book viewer is rather limited in scope. It supports only a single book, which is a managed bean that we define in the faces configuration file. The name of that bean is book.

The book bean has these properties:

  • titleKey

  • image

  • numChapters

  • chapterKeys

The titleKey property represents a key in a resource bundle for the book's title. In the book viewer's properties file we have the key/value pair titleKey=Alice in Wonderland. When we display the book's title, we use the titleKey property, like this:

  <h:outputText value="#{msgs[book.titleKey]}"/>

The image property is a string. The application interprets that string as a URL and loads it in the book viewer's header like this:

  <h:graphicImage url="#{book.image}"/>

The chapterKeys property is a read-only list of keys, one for each chapter. The book viewer populates the book viewer's menu with corresponding values from a resource bundle:

  <h:dataTable value="#{book.chapterKeys}" var="chapterKey">      <h:commandLink>         <h:outputText value="#{msgs[chapterKey]}"/>         ...      </h:commandLink>   </h:dataTable>

The Book class uses the numChapters property to compute the chapter keys.

The implementation of the Book class is rather mundane. You can see it in Listing 8-3 on page 324. Here is how we define an instance of the Book class in faces-config.xml:

  <faces-config>      <!-- The book -->         <managed-bean>         <managed-bean-name>book</managed-bean-name>         <managed-bean-class>com.corejsf.Book</managed-bean-class>         <managed-bean-scope>request</managed-bean-scope>         <managed-property>            <property-name>titleKey</property-name>            <value>aliceInWonderland</value>         </managed-property>         <managed-property>            <property-name>image</property-name>            <value>cheshire.jpg</value>         </managed-property>         <managed-property>            <property-name>numChapters</property-name>            <property-class>java.lang.Integer</property-class>            <value>12</value>         </managed-property>      </managed-bean>   </faces-config>

There are many ways to implement page layout. In this section, we look at three options: a monolithic JSF page, inclusion of common content, and Tiles.

Note

We do not set the book's chapterKeys property in faces-config.xml. This is because the Book class creates that list of chapter keys for us. All we have to do is define the numChapters property.


Monolithic JSF Pages

A monolithic JSF page is perhaps the quickest way to implement the book viewer, shown in Figure 8-2. For example, here is a naive implementation:

  <!-- A panel grid, which resides in a form, for the entire page --%>   <h:panelGrid columns="2" style      columnClasses="menuColumn, chapterColumn">      <!-- The header, containing an image, title, and horizontal rule --%>      <f:facet name="header">         <h:panelGrid columns="1" style>            <h:graphicImage value="#{book.image}"/>            <h:outputText value="#{msgs[book.titleKey]}" styleClass='bookTitle'/>            <hr>         </h:panelGrid>      </f:facet>      <!-- Column 1 of the panel grid: The menu, which consists of chapter links --%>      <h:dataTable value="#{book.chapterKeys}" var="chapterKey"               style columnClasses="linksColumn">         <h:column>            <h:commandLink>               <h:outputText value="#{msgs[chapterKey]}"/>               <f:param name="chapter" value="#{chapterKey}"/>            </h:commandLink>         </h:column>      </h:dataTable>      <!-- Column 2 of the panel grid: The chapter content --%>      <c:import url="${param.chapter}.html"/>   </h:panelGrid>     

The book viewer is implemented with a panel grid with two columns. The header region is populated with an image, text, and HTML horizontal rule. Besides the header, the panel grid has only one row the menu occupies the left column and the current chapter is displayed in the right column.

The menu is composed of chapter links. By default, Book.getChapterKeys() returns a list of strings that looks like this:

  chapter1   chapter2   ...   chapterN

ChapterN represents the last chapter in the book. In the book viewer's resource bundle, we define values for those keys:

  chapter1=Chapter 1   chapter2=Chapter 2   ...

To create chapter links, we use h:dataTable to iterate over the book's chapter keys. For every chapter, we create a link whose text corresponds to the chapter key's value with this expression: #{msgs[chapterKey]}. So, for example, we wind up with "Chapter 1" ... "Chapter 12" displayed in the menu when the number of chapters is 12.

The right column is reserved for chapter content. That content is included with JSTL's c:import tag.

The directory structure for the book viewer is shown in Figure 8-4. The monolithic JSF version of the book viewer is shown in Listing 8-1 through Listing 8-5.

Figure 8-4. The directory structure of the book viewer


Note

Notice the f:param tag inside h:commandLink. The JSF framework turns that parameter into a request parameter named chapter when the link is activated. When the page is reloaded, that request parameter is used to load the chapter's content, like this:

  <c:import url="${param.chapter}"/>


Listing 8-1. book-viewer/web/book.jsp

  1. <html>   2.    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>   3.    <%@ taglib uri="http://java.sun.com/jsf/core"  prefix="f" %>   4.    <%@ taglib uri="http://java.sun.com/jsf/html"  prefix="h" %>   5.   6.    <f:view>   7.       <f:loadBundle basename="com.corejsf.messages" var="msgs"/>   8.       <head>   9.          <link href="styles.css" rel="stylesheet" type="text/css"/>  10.          <title><h:outputText value="#{msgs.bookWindowTitle}"/></title>  11.       </head>  12.  13.       <body>  14.          <h:form>  15.             <h:panelGrid columns="2" style  16.                    columnClasses="menuColumn, chapterColumn">  17.                <f:facet name="header">  18.                   <h:panelGrid columns="1" style>  19.                      <h:graphicImage value="#{book.image}"/>  20.                      <h:outputText value="#{msgs[book.titleKey]}"  21.                               styleClass='bookTitle'/>  22.                      <hr/>  23.                   </h:panelGrid>  24.                </f:facet>  25.  26.                <h:dataTable value="#{book.chapterKeys}" var="chapterKey"  27.                          style columnClasses="linksColumn">  28.                   <h:column>  29.                      <h:commandLink>  30.                         <h:outputText value="#{msgs[chapterKey]}"/>  31.                         <f:param name="chapter" value="#{chapterKey}"/>  32.                      </h:commandLink>  33.                   </h:column>  34.                </h:dataTable>  35.  36.                <c:import url="${param.chapter}.html"/>  37.             </h:panelGrid>  38.          </h:form>  39.       </body>  40.    </f:view>  41. </html>     

Listing 8-2. book-viewer/web/WEB-INF/faces-config.xml

  1. <?xml version="1.0"?>   2. <faces-config xmlns="http://java.sun.com/xml/ns/javaee"   3.    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   4.    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   5.         http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"   6.    version="1.2">   7.    <managed-bean>   8.       <managed-bean-name>book</managed-bean-name>   9.       <managed-bean-class>com.corejsf.Book</managed-bean-class>  10.       <managed-bean-scope>request</managed-bean-scope>  11.  12.       <managed-property>  13.          <property-name>titleKey</property-name>  14.          <value>aliceInWonderland</value>  15.       </managed-property>  16.  17.       <managed-property>  18.          <property-name>image</property-name>  19.          <value>cheshire.jpg</value>  20.       </managed-property>  21.  22.       <managed-property>  23.          <property-name>numChapters</property-name>  24.          <property-class>java.lang.Integer</property-class>  25.          <value>12</value>  26.       </managed-property>  27.    </managed-bean>  28. </faces-config>     

Listing 8-3. book-viewer/src/java/com/corejsf/Book.java

  1. package com.corejsf;   2.   3. import java.util.LinkedList;   4. import java.util.List;   5.   6. public class Book {   7.    private String titleKey;   8.    private String image;   9.    private int numChapters;  10.    private List<String> chapterKeys = null;  11.  12.    // PROPERTY: titleKey  13.    public void setTitleKey(String titleKey) { this.titleKey = titleKey; }  14.    public String getTitleKey() { return titleKey; }  15.  16.    // PROPERTY: image  17.    public void setImage(String image) { this.image = image; }  18.    public String getImage() { return image; }  19.  20.    // PROPERTY: numChapters  21.    public void setNumChapters(int numChapters) { this.numChapters = numChapters;}  22.    public int getNumChapters() { return numChapters; }  23.  24.    // PROPERTY: chapterKeys  25.    public List<String> getChapterKeys() {  26.       if(chapterKeys == null) {  27.          chapterKeys = new LinkedList<String>();  28.          for(int i=1; i <= numChapters; ++i)  29.             chapterKeys.add("chapter" + i);  30.       }  31.       return chapterKeys;  32.    }  33. }     

Listing 8-4. book-viewer/src/java/com/corejsf/messages.properties

  1. bookWindowTitle=Welcome to Alice in Wonderland   2. aliceInWonderland=Alice in Wonderland   3.   4. chapter1=Chapter 1   5. chapter2=Chapter 2   6. chapter3=Chapter 3   7. chapter4=Chapter 4   8. chapter5=Chapter 5   9. chapter6=Chapter 6  10. chapter7=Chapter 7  11. chapter8=Chapter 8  12. chapter9=Chapter 9  13. chapter10=Chapter 10  14. chapter11=Chapter 11  15. chapter12=Chapter 12  16. chapter13=Chapter 13  17. chapter14=Chapter 14  18. chapter15=Chapter 15

Listing 8-5. book-viewer/web/styles.css

  1. .bookHeader {   2.    width: 100%;   3.    text-align: center;   4.    background-color: #eee;   5.    padding: 0 px;   6.    border: thin solid CornflowerBlue;   7. }   8. .bookTitle {   9.    text-align: center;  10.    font-style: italic;  11.    font-size: 1.3em;  12.    font-family: Helvetica;  13. }  14. .book {  15.    vertical-align: top;  16.    width: 100%;  17.    height: 100%;  18. }  19. .menuColumn {  20.    vertical-align: top;  21.    background-color: #eee;  22.    width: 100px;  23.    border: thin solid #777;  24. }  25. .chapterColumn {  26.    vertical-align: top;  27.    text-align: left;  28.    width: *;  29. }     

Common Content Inclusion

A monolithic JSF page is a poor choice for the book viewer because the JSF page is difficult to modify. Also, realize that our monolithic JSF page represents two things: layout and content.

Layout is implemented with an h:panelGrid tag, and content is represented by various JSF tags, such as h:graphicImage, h:outputText, h:commandLink, and the book chapters. Realize that with a monolithic JSF page, we cannot reuse content or layout.

In the next section, we concentrate on including content. In "Looking at Tiles" on page 331, we discuss including layout.

Content Inclusion in JSP-Based Applications

Instead of cramming a bunch of code into a monolithic JSF page, as we did in Listing 8-1 on page 322, it is better to include common content so you can reuse that content in other JSF pages. With JSP, you have three choices for including content:

  • <%@ include file="header.jsp"% >

  • <jsp:include page="header.jsp"/>

  • <c:import url="header.jsp"/>

The first choice listed above the JSP include directive includes the specified file before the enclosing JSF page is compiled to a servlet. However, the include directive suffers from an important limitation: If the included file's content changes after the enclosing page was first processed, those changes are not reflected in the enclosing page. That means you must manually update the enclosing pages whether the including pages changed or not whenever included content changes.

The last two choices listed above include the content of a page at runtime and merge the included content with the including JSF page. Because the inclusion happens at runtime, changes to included pages are always reflected when the enclosing page is redisplayed. For that reason, jsp:include and c:import are usually preferred to the include directive.

The c:import tag works just like jsp:include, but it has more features for example, c:import can import resources from another web application, whereas jsp:include cannot. Also, prior to JSP 2.0, you cannot use JSP expressions for jsp:include attributes, whereas you can with c:import. Remember that you must import the JSTL core tag library to use c:import.

Throughout this chapter, we use c:import for consistency. You can use either jsp:include or c:import to dynamically include content. If you do not need c:import's extra features, then it is ever-so-slightly easier to use jsp:include because you do not need to import the JSTL core tag library.

JSF-Specific Considerations

Regardless of whether you include content with the include directive, jsp:include, or c:import, you must take into account two special considerations when you include content in a JavaServer Faces application:

  1. You must wrap included JSF tags in an f:subview tag.

  2. Included JSF tags cannot contain f:view tags.

The first rule applies to included content that contains JSF tags. For example, the book viewer should encapsulate header content in its own JSF page so that we can reuse that content:

  <%-- this is header.jsp --%>   <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>   <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>   <h:panelGrid columns="1" style>      <h:graphicImage value="books/book/cheshire.jpg"/>      <h:outputText value="#{msgs.bookTitle}" style/>      ...   </h:panelGrid>

Now we can include that content from the original JSF page:

  <%-- This is from the original JSF page --%>   <f:view>      ...      <f:subview >         <c:import url="header.jsp"/>      </f:subview>      ...   </f:view>

You must assign an ID to each subview. The standard convention for including content is to name the subview after the imported JSF page.

JSF views, which are normally web pages, can contain an unlimited number of subviews. But there can be only one view. Because of that restriction, included JSF tags which must be wrapped in a subview cannot contain f:view tags.

Caution

The book-viewer-include application maps the Faces servlet to *.faces. That means you can start the application with this URL: http://www.localhost:8080/book-viewer-include/book.faces. The Faces servlet maps books.faces to books.jsp. However, you cannot use the faces suffix when you use c:import. If you use c:import, you must use the jsp suffix.




Core JavaServerT Faces
Core JavaServer(TM) Faces (2nd Edition)
ISBN: 0131738860
EAN: 2147483647
Year: 2004
Pages: 84

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