Document last updated 10 April 2001.
We are very interested in feedback that would make these materials
better. Feel free to write the author, Jonathan Revusky.
You will recall that in the "Hello, Niggle" example, our execDefault() method exposed two template variables which were simply strings -- or scalars in template-speak. While this might have seemed like a big step compared to completely static HTML pages, it is really only a very small feature of what we can do with the built-in template system, which allows us to dynamically expose complex data structures made up of lists and hashes-- as well as scalars.
This application contains 3 page templates.
The entries.nhtml
template
displays all the guestbook entries. The add.nhtml
template
contains a form which allows the user to add a guestbook entry. The
thanks.nhtml
simply thanks the user for her comments, after
processing the form. Take a look at entries.nhtml
. As
we pointed out in the first example, freemarker templates use the ${...} as an
escape syntax, meaning that the strings within that ${...} block are
interpreted in a special way -- as template variables.
The entries.nhtml
also introduces a directive that is specific
to Freemarker. Look at the line:
<list entries as entry>
This assumes the presence of a list type variable called entries
.
Now, a scalar variable, since it is simply a string, is typically used directly as page
content via the ${...} escape syntax. By contrast, what you do with a list variable,
such as entries
in this case, is that you iterate over its
elements. This is what that directive <list entries as entry>
is saying.
The template code within that list
block is repeated n times where n is the
number of elements in the list. The entry variable in the block represents
the current nested variable that we are iterating over.
What further adds interest to this example is that the elements of the
entries
list are themselves hashes, with
their own subvariables, which finally are scalars. So finally, the various
subvariables in the entry hash are used directly in the page via the ${...} syntax,
e.g. ${entry.name}
and so on.
Now that you have eyeballed the entries template, take a look at the corresponding java code in GuestbookServletInteraction.java. Look at the execEntries() method. It's incredibly brief.
public void execEntries() throws IOException { this.page = getPage("entries.nhtml"); page.expose("entries", entries); // expose the list of entries to the page. }
Actually, the code for this servlet is surprisingly terse. The most
involved method is execProcess() which processes the
CGI variables sent by the form in the add.nhtml
template.
If no name was specified, it exposes an error variable.
Otherwise, it creates a hashtable containing the subvariables
that make up the guestbook entry and adds it to the static entries list.
Note that the exposeDefaultVariables
method
provides a convenient hook to define variables that are always exposed
independently of which execXXX method was invoked.
Even though this guestbook is primitive, since it does not deal with persistence of data, it does a surprising amount with very little code. This is achieved mostly due to our ability to expose a complex data structure to the page template at one go. In this case, we were able to drop a list -- which in turn contained hashes -- onto the page and unroll all of the nested content for display. And this required very very little java code to be written. You will realize also that we can nest lists and hashes to an arbitrary level of complexity! We could have a list of lists that in turn contain hashes that contain further lists!
Since all of the code -- including both the java side and the freemarker templates -- is little over 100 lines, it should be feasible to study the example and fully understand all of its various elements.
I would encourage you to make small changes to the code and templates and observe the changes. This will reinforce what you have learned. When you are comfortable with this example, I would encourage you to move on to the next example, the mini-rolodex.