Tutorial web development (with JSF) VI: Templates

This post is also available in Deutsch.

Templates

In the last part of this series, we created a second page, which looked similar to the first one. Now, we will put the common parts into a central place. To do this, we’ll create a template, which acts as kind of container for the shared part, which contains some individual information.

As a reminder, here is the souce of tese two pages:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">
  <h:head >
    <title>Tiny calculator</title>
    <h:outputStylesheet library="css" name="CalculatorStyle.css"/>
  </h:head>
  <h:body>
    <h1>Tiny calculator</h1>
    <h:graphicImage alt="BasicArithmetics"
                    library="images"
                    name="BasicArithmetics.png"/>
    <h:form id="calculator">
      <h:outputLabel styleClass="label" for="param1" value="Param 1:"/>
      <h:inputText id="param1" value="#{calculatorBean.param1}"/>
      <br/>
      <h:outputLabel styleClass="label" for="param2" value="Param 2:"/>
      <h:inputText id="param2" value="#{calculatorBean.param2}"/>
      <br/>
      <h:commandButton styleClass="button"
                       action="#{calculatorBean.add}"
                       value="add"/>
      <h:commandButton styleClass="button"
                       action="#{calculatorBean.substract}"
                       value="substract"/>
      <h:commandButton styleClass="button"
                       action="#{calculatorBean.multiply}"
                       value="multiply"/>
      <h:commandButton styleClass="button"
                       action="#{calculatorBean.divide}"
                       value="divide"/>
      <br/>
      <h:outputLabel styleClass="label" for="result" value="Result:"/>
      <h:outputText id="result" value="#{calculatorBean.result}"/>
    </h:form>
  </h:body>
</html>

(index.xhtml)

     
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">
  <h:head >
    <title>Tiny calculator</title>
    <h:outputStylesheet library="css" name="CalculatorStyle.css"/>
  </h:head>
  <h:body>
    <h:graphicImage alt="BasicArithmetics"
                    library="images"
                    name="BasicArithmetics.png"/>
    <h1>Tiny calculator</h1>
    <h:form id="calculator">
      <h:outputLabel styleClass="label" for="result" value="Result"/>
      <h:outputText id="result"
         value="#{calculatorBean.param1} +
                #{calculatorBean.param2} =
                #{calculatorBean.result}"/>
      <br/>
      <br/>
      <h:commandButton value="Back" action="index"/>
    </h:form>
  </h:body>
</html>

(result.xhtml)

If you take a pedantic look onto these pages, you’ll find they’ll differ only within the tag <h:form…>. The main part equals. Thus, we may use one of these pages as a starting point for templating. A template is nothing more than a JSF page where some content is replaced by specific requests.

Create a new JSF page (by using the wizzard for example) and name it CalculatorTemplate.xhtml. Replace the generated sourcecode by one of the two shown above. Or you simply copy one of these pages from the project tree (copy and past) and provide the new name.

To transform this page into a template, the individual parts have to be removed and replaced by a placeholder. To do so, replace everything within the form tags by

     
 <ui:insert name="content">Content</ui:insert>

The namespace ui isn’t known yet. Thus, it has to be declared in the header.

xmlns:ui="http://java.sun.com/jsf/facelets"

The complete code of CalculatorTemplate.xhtml now should look like this:

 <?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets">
  <h:head >
    <title>Tiny calculator</title>
    <h:outputStylesheet library="css" name="CalculatorStyle.css"/>
  </h:head>
  <h:body>
    <h:graphicImage alt="BasicArithmetics"
                    library="images"
                    name="BasicArithmetics.png"/>
    <h1>Tiny calculator</h1>
    <h:form id="calculator">
      <ui:insert name="content">Content</ui:insert>
    </h:form>
  </h:body>
</html>

Next, we have to adopt both pages to use this template. The AppServer has to know

  • Which template will be used?
  • Which elements will be inserted at the insertion points?

For both situations, JSF offers a appropriate tag.

<ui:composition template="./CalculatorTemplate.xhtml">
<ui:define name="content">

<ui:composition…> and, of course it’s endtag, it the container for the individual part.  You have to declare the namespace ui too. <ui:define…> defines the part of the page which should be inserted at the insertion point. You may have seen the name “content” which is the same as in the template. But why will we need two tags? Wouldn’t it have been possible to insert the individual part with just one tag? Imagine having a page with more than on variable part. To distinguish between more than one, you need different names. And all of them will be included in one template client. Thus, you need two different tags: One is the container for the client, the other declares a specific insertion part, and might be used multiple.

After these changes, result.xhtml looks like this:

 <?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets">
  <h:head >
    <title>Tiny calculator</title>
    <h:outputStylesheet library="css" name="CalculatorStyle.css"/>
  </h:head>
  <h:body>
    <h:graphicImage alt="BasicArithmetics"
                    library="images"
                    name="BasicArithmetics.png"/>
    <h1>Tiny calculator</h1>
    <h:form id="calculator">
      <ui:composition template="./CalculatorTemplate.xhtml">
        <ui:define name="content">
          <h:outputLabel styleClass="label" for="result" value="Result"/>
          <h:outputText id="result"
                        value="#{calculatorBean.param1} +
                        #{calculatorBean.param2} =
                        #{calculatorBean.result}"/>
         <br/>
         <br/>
         <h:commandButton value="Back" action="index"/>
       </ui:define>
     </ui:composition>
    </h:form>
  </h:body>
</html>

Run your project. It should behave like before.

If it doen’t run, e.g. alerting something like “Page not found”, please perform a “Clean” for your project (in context menu of your project tree).

Ok, after this change the site looks bigger than before. why all this effort, whether it will blow up our sources? Now, this is simply the result of our change. We may ommit a lot of this code if we only code the individual parts. And indeed, the server only uses the individual parts just now. Almost everything outside composition tag will be ignored. Thus, we are able to reduce our document to minimal HTML file without changing functionality.

 <?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets">
  <h:body>
    <ui:composition template="./CalculatorTemplate.xhtml">
      <ui:define name="content">
        <h:outputLabel styleClass="label" for="result" value="Result"/>
        <h:outputText id="result"
                      value="#{calculatorBean.param1} +
                      #{calculatorBean.param2} =
                      #{calculatorBean.result}"/>
        <br/>
        <br/>
        <h:commandButton value="Back" action="index"/>
      </ui:define>
    </ui:composition>
  </h:body>
</html>

Even more shorter, it would be as pure XML document with the composition tag as the root. To do this, you have to move the namespace declaration into this element.

 <?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns:h="http://java.sun.com/jsf/html"
                xmlns:ui="http://java.sun.com/jsf/facelets"
                template="./CalculatorTemplate.xhtml">
    <ui:define name="content">
        <h:outputLabel styleClass="label" for="result" value="Result"/>
        <h:outputText id="result"
                      value="#{calculatorBean.param1} +
                      #{calculatorBean.param2} =
                      #{calculatorBean.result}"/>
        <br/>
        <br/>
        <h:commandButton value="Back" action="index"/>
    </ui:define>
</ui:composition>

Even though his fragment will be inserted into the template and the whole page results into correct HTML, the server generates warnings for the first time alerting there would be no taglib for the namespace “br”. But the breaks (</br>) will be displayed correctly. For a running server next call to this page will be displayed without this warning. If you use the minimal HTML syntax GlassFish wouldn’t alert such warnings.Now it should be no problem for you to reduce the page index.xhtml. To get some practice you may perform these before continuing. It should be look similar to the following:

 <?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets">
  <body>
    <ui:composition template="./CalculatorTemplate.xhtml">
      <ui:define name="content">
        <h:outputLabel styleClass="label" for="param1" value="Param 1:"/>
        <h:inputText id="param1" value="#{calculatorBean.param1}"/>
        <br/>
        <h:outputLabel styleClass="label" for="param2" value="Param 2:"/>
        <h:inputText id="param2" value="#{calculatorBean.param2}"/>
        <br/>
        <h:commandButton styleClass="button"
                         action="#{calculatorBean.add}"
                         value="add"/>
        <h:commandButton styleClass="button"
                         action="#{calculatorBean.substract}"
                         value="substract"/>
        <h:commandButton styleClass="button"
                         action="#{calculatorBean.multiply}"
                         value="multiply"/>
        <h:commandButton styleClass="button"
                         action="#{calculatorBean.divide}"
                         value="divide"/>
        <br/>
        <h:outputLabel styleClass="label" for="result" value="Result:"/>
          <h:outputText id="result" value="#{calculatorBean.result}"/>
        </ui:define>
    </ui:composition>
  </body>
</html>

[translation in progress]

Naja, der Name index.xhtml passt nicht so ganz zu unserer Applikation. Wo kommt der Name eigentlich her? Nun, wenn Sie im Web eine Homepage ansteuern, geben Sie dann den vollen Dateinamen an? Oder nicht häufig einfach die URL der entsprechenden Domäne?. So erreichen Sie beispielsweise meine Homepage unter http://mueller.bruehl.de. Dies verweist auf meinen WebServer in ein bestimmtes Verzeichnis. Da aber nicht der Verzeichnisinhalt gelistet, sondern der Inhalt der Site angezeigt werden soll, sucht der HTTP-Server nach einer Datei wie index.html oder home.html oder ähnlich. Entsprechend hat NetBeans bei Erstellung unseres Projekts auch eine Startseite festgelegt, die bei Anwahl unserer Applikation angezeigt wird – ohne dass Sie den vollen Dateinamen angeben müssen. Um welche Datei es sich dabei handelt wird in der Konfiguration festgelegt.

Lassen Sie uns dies kurz durchspielen.

Benennen Sie im ersten Schritt die Seite index.xhtml um in calculator.xhtml. Falls Sie nun das Projekt starten sollten, so teilt Ihnen der Server mit, dass er die Seite nicht gefunden habe. Wie auch? GlassFish sucht noch immer nach index.xhtml, aber das gibt es nicht mehr…

Öffnen Sie nun im Inhaltsbaum den Ordner Configuration Files und doppelklicken dann web.xml. Im Editor wählen Sie dann den Bereich Pages. Nun können Sie im Feld Welcome Files den neuen Namen angeben – oder mittels [Browse...] sich auf die Suche begeben (und ggf. Index.xhtml anschließend entfernen).

Nachdem Sie dies angepasst haben, sollte Ihre Applikation wieder einwandfrei funktionieren. Der Editor ist nur ein nettes Frontend für die Konfigurationsdatei web.xml. Ein Klick auf den Bereich XML zeigt Ihnen die Datei im Original.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
  xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>client</param-value>
    </context-param>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>calculator.xhtml</welcome-file>
    </welcome-file-list>
</web-app>

Im Abschnitt <welcome-file-list> finden Sie die eingestellte Startseite. Und wenn Sie genau hinschauen, finden Sie auch die bereits früher über den Assistenten eingestellte Endung *.xhtml als Endung unserer Facelets. Auf die Konfiguration werde ich später noch genauer eingehen.

Zurück zu den Templates. In diesem Abschnitt haben wir das Template und die individuellen Dateien (Template Clients) manuell vorhandenen Seiten erstellt. Mit dem Wissen um Schablonen werden Sie künftige Projekte wohl eher anders angehen: Sie erstellen zuerst den Rahmen (das Template) und dann die einzelnen Seiten, die dieses Template nutzen. Genau eine solche Vorgehensweise unterstützt NetBeans von Haus aus. Diese IDE bietet Ihnen zwei Assistenten, zum Erstellen eines Templates, sowie zum Erstellen eines Template-Clients.

Die Generierung des Templates bietet dabei noch einie nette Ergänzung: Sie können im Assistenten das gewünschte Layout wählen, z. B. Um eine Kopfzeile abzusetzen oder für eine seitliche Navigationsleiste etc. Dazu wählen Sie das gewünschte Layout einfach durch Anklicken im Assitenten.

NetBeans erstellt die Struktur und im Falle des CSS-Layouts auch gleich passende Style Sheets. Mit den abgebildeten Angaben generiert NetBeans den folgenden Code:

 <?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html">

    <h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <link href="./resources/css/default.css" rel="stylesheet" type="text/css" />
        <link href="./resources/css/cssLayout.css" rel="stylesheet" type="text/css" />
        <title>Facelets Template</title>
    </h:head>

    <h:body>

        <div id="top">
            <ui:insert name="top">Top</ui:insert>
        </div>

        <div id="content">
            <ui:insert name="content">Content</ui:insert>
        </div>

        <div id="bottom">
            <ui:insert name="bottom">Bottom</ui:insert>
        </div>

    </h:body>

</html>

Hier können Sie schön die drei Bereiche erkennen, die Sie nun mit Ihren Clients füllen können. Wählen Sie das Layout immer entsprechend Ihren Anforderungen an die Seite, nicht entsprechend den Anforderungen an austauschbare Inhalte! Wenn also beispielsweise Kopf- und Fußbereich für alle Seiten gleich sein sollen, wählen Sie dieses Layout und Sie erhalten ein passendes Grundgerüst für Ihre Entwicklung. Die jeweiligen Insert-Tags ersetzen Sie dann durch Ihre festen Inhalte.

Der zweite der genannten Assitenten verlangt von Ihnen die Angabe des zu nutzenden Templates. Der generierte Client enthält dann Definitionen für jedes Insert-Tag, dass zu diesem Zeitpunkt im Template vorhanden ist.

Ein Template darf selbst Client eines anderen Templates sein. Auf diese Art und Weise können Sie Templates beliebig schachteln. Bei der Arbeit mit Schablonen nutzt ein Client also immer eine “vordefinierte” Umgebung. Der Client für ein Insert-Tag besteht aus den Komponenten innerhalb des Define-Tags. Sie können sich dies auch als eine zusammengesetze Komponente vorstellen. Was, wenn Sie eine solche Komponente an mehreren Stellen nutzen möchten? Wäre es nicht schön, in verschiedenen Seiten auf zusammengesetzte (“vordefinierte”) Komponenten zugreifen zu können? Auch dies ist mit JSF möglich. Hierfür gibt es die Tags composition und component. Es ist sogar möglich, eine eigene Komponente so zu erstellen, dass sie parametrisierbar wird. Dies in einem späteren Teil des Tutorials.

Zunächst aber etwas anders. Der kurze Blick in die Konfiguration sollte zeigen: Es gibt noch einiges neben der Seitendefinition und dem Java-Code in den Beans. Was passiert eigentlich, wenn der Browser eine Seite anfordert? Werfen wir im nächsten Teil also zunächst einmal einen Blick hinter die Kulissen.

 

To web development content.

This entry was posted in NetBeans, Programming, Tutorial, Web development and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>