Previous Section  < Day Day Up >  Next Section

12.2 Combining JSF Views with Other Content

In the previous section, I described how to build a JSF view from multiple JSP pages, but sometimes you need to combine the content generated by a JSF view with content generated by other technologies, such as regular JSP pages and static HTML files.

Most web sites use a common layout for all pages, typically with a header at the top, a menu to the left, and footer at the bottom. To simplify maintenance and make it easy to change the site's look, large sites often use tools that pull together each page based on a layout template at runtime. For JSP-based sites, a tool called Tiles is commonly used. Tiles is distributed as part of Apache Struts,[1] but it can also be used independently. Tiles has a lot of features, but the main principle is pretty simple: each page directly requested by the user calls on a layout template to generate the response from the data the page tells the template to use. Example 12-7 shows a simple Tiles layout template.

[1] Struts is available at http://jakarta.apache.org/struts/.

Example 12-7. Tiles layout template (tilesLayout.jsp)
<%@ taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles" %>

<html>

  <body bgcolor="white">

    <table width="100%">

      <tr>

        <td colspan="2" align="center">

          <tiles:insert attribute="header" />

        </td>

      </tr>

      <tr>

        <td width="20%">

          <tiles:insert attribute="menu" />

        </td>

        <td>

          <tiles:insert attribute="body" />

        </td>

        <td>

          <tiles:insert page="poll.jsp" />

        </td>

      </tr>

    </table>

  </body>

</html>

The template is a JSP page. At the top, there's a taglib declaration for the Tiles tag library bundled with Struts. The rest of the page consists of HTML table elements defining the layout and <tiles:insert> action elements inserting the content from named sources. The action supports many different kinds of content sources. In Example 12-7, I use the attribute attribute to pull the content from an attribute provided by each page and the page attribute to explicitly name a JSP page, but there are many other options.

The last <tiles:insert> element inserts a page named poll.jsp, which is a JSP page with JSF components. It's shown in Example 12-8.

Example 12-8. A JSF-based poll page (poll.jsp)
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>



<f:view>

  <h3>Quick Poll</h3>

  What do you think of JSF?

  <h:form>

    <h:panelGrid columns="1">

      <h:commandLink action="#{poll.vote1}">

        <h:outputText value="It rocks!" />

      </h:commandLink>

      <h:commandLink action="#{poll.vote2}">

        <h:outputText value="It seems okay" />

      </h:commandLink>

      <h:commandLink action="#{poll.vote3}">

        <h:outputText value="It sucks!" />

      </h:commandLink>

    </h:panelGrid>

  </h:form>

  <h:panelGrid columns="2" rendered="#{poll.showScore}">

    <h:outputText value="Total votes:" />

    <h:outputText value="#{poll.total}" />

    <h:outputText value="It rocks!" />

    <h:outputText value="#{poll.vote1Score}%" />

    <h:outputText value="It seems okay" />

    <h:outputText value="#{poll.vote2Score}%" />

    <h:outputText value="It sucks!" />

    <h:outputText value="#{poll.vote3Score}%" />

  </h:panelGrid>

</f:view>

The details aren't really the point of this example, but the poll.jsp page is a JSP page with JSF components for displaying three alternative answers as links—bound to action methods counting the votes—and other components for displaying the current score. What is important is that it's a page with JSF components.

Example 12-9 shows one of the pages applying the template.

Example 12-9. A page applying the template (page1.jsp)
<%@ page contentType="text/html" %>

<%@ taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles" %>



<tiles:insert page="tilesLayout.jsp">

  <tiles:put name="header" value="header.html" />

  <tiles:put name="menu" value="menu.html" />

  <tiles:put name="body" value="body1.html" />

</tiles:insert>

It's also a JSP page with the Tiles tag library declaration at the top. The rest of the page contains just Tiles action elements. The <tiles:insert> element tells Tiles to use the layout template in Example 12-7 with the attribute values defined by the <tiles:put> elements. These elements define the files to use as the header, menu, and body of the final, laid-out page. For this simple example, all files are simple HTML files, but they could just as well be JSP pages or even servlets or pages for some other presentation technology.

Two more files, named page2.jsp and page3.jsp (which are identical to the one in Example 12-9, except for the body filename), complete the example. Requesting page1.jsp and clicking on the poll answers a few times results in a response like the one shown in Figure 12-4.

Figure 12-4. Response combining JSF content with other content
figs/Jsf_1204.gif

The response contains the content from the shared header and menu HTML files, the page-specific HTML file, and the shared JSP page with the poll JSF components, as expected. The crucial piece of the puzzle, though, is the URL used to request the page1.jsp file. It must be a URL that matches the pattern used for JSF requests, i.e., ending in .faces when you use the standard extension mapping. Requesting the page as a regular JSP page, i.e., with a .jsp extension, doesn't work because it doesn't invoke JSF. Trying to work around this and invoke JSF through the include mechanism instead (for example, by using poll.faces as the URL in the Tiles action elements) also fails, because the JSF 1.0 servlet only works if it's invoked directly, not when it's included by another resource. It's possible that some of this may be improved in a future version of the JSF specification.

If the template refers to more than one page containing JSF components, you must also apply the techniques described in the previous section regarding dynamic includes. Specifically, the page that includes the others (e.g., the layout page) must have the <f:view> element and the included pages must be wrapped in <f:subview> elements and must only contain JSF actions—no template text or non-JSF action elements, unless they are wrapped within <f:verbatim> elements.

    Previous Section  < Day Day Up >  Next Section