Templates

How to use multiple controllers on a single page

Templates allow you to compose a page of multiple fragments that are each rendered by a separate controller.

A template is a regular view and therefore can be implemented with any view technology supported by Spring, like JSP, Velocity or FreeMarker. This documentation will only cover FreeMarker, which is the recommended templating language for Riot projects.

The model passed to a template-view contains URLs. These URLs are then included using a RequestDispatcher. Here's a very simple template:

<html>
  <body>
    <div id="navigation"><@common.include navigation /></div>
    <div id="content"><@common.include content /></div>
  </body>
</html>

The template contains two slots, navigation and content. To use a template, URLs must be assigned to the slots:

<template:definition name="/posts.html" view-name="default.ftl">
  <template:insert slot="navigation" url="/inc/navigation.html" />
  <template:insert slot="content" url="/inc/all-posts.ftl" />
</template:definition>

Instead of using the template-namespace, we could also use Spring's bean tag. The syntax is quite verbose and harder to read, but it might be useful to know what is actually happening under the hood:

<bean name="/posts.html" class="org.riotfamily.website.template.TemplateController">
  <property name="viewName" value="default.ftl" />
  <property name="configuration">
    <map>
      <entry key="navigation" value="/inc/navigation.html" />
      <entry key="content" value="/inc/all-posts.html" />
    </map>
  </property>
</bean>

Anonymous (inline) controllers

Instead of specifying URLs, you can also nest a handler bean directly into the insert-tag:

<template:insert slot="navigation">
  <bean class="org.riotfamily.blog.ArchiveController" />
</template:insert>

In this case a synthetic URL is generated for the include. Alternatively you can also use a <ref> tag:

<template:insert slot="navigation">
  <ref local="myController" />
</template:insert>

Inheritance

A templates definition may extend another one by specifying a parent attribute:

<!-- The common parent -->
<template:definition name="default" view-name="default.ftl">
  <template:insert slot="navigation" url="/inc/navigation.html" />
</template:definition>

<!-- Child one -->
<template:definition name="/posts.html" parent="default">
  <template:insert slot="content" url="/inc/all-posts.html" />
</template:definition>

<!-- Child two -->
<template:definition name="/archive.html" parent="default">
  <template:insert slot="content" url="/inc/archive.html" />
</template:definition>

This becomes even more useful when you are working with nested templates. Check out the following example to see how to replace the contents of a nested template:

<template:definition name="/foo.html" parent="default">
  <template:insert slot="content">
    <template:definition view-name="two-columns.ftl">
      <template:insert slot="left" url="/inc/left-content.html" />
      <template:insert slot="right" url="/inc/right-content.html" />
    </template:definition>
  </template:insert>
</template:definition>

<template:definition name="/bar.html" parent="/foo.html">
  <template:insert slot="content.left" url="/inc/alternative-right-content.html" />
</template:definition>

Multiple controllers in one slot

If you want to put multiple controllers into the same slot you can either use a nested template or, in case you don't need any surrounding markup, you can simply put several beans into the tag:

<template:insert slot="foo">
  <bean class="org.riotfamily.example.MyFirstController" />
  <bean class="org.riotfamily.example.MySecondController" />
</template:insert>

Filling slots with plain text

You can not only put URLs into slots but also plain text. A common use for this feature is to assign different CSS class names to your body tag, depending on the template being used.

<template:definition id="default" view-name="default.ftl">
  <template:insert slot="bodyClass" data="two-columns" />
  <template:insert slot="content">
    <template:definition view-name="two-columns.ftl">
      <!-- Omitted for brevity -->
    </template:definition>
  </template:insert>
</template:definition>

<template:definition id="wide" parent="default">
  <template:insert slot="bodyClass" data="wide" />
  <template:insert slot="content" url="/inc/wide-content.html" />
</template:definition>