Layout templates
AcrossWebModule provides support for simple layout processing.
A controller method can be linked to a specific template which will determine some pre- and post-processing that might be done.
The base infrastructure is provided by WebTemplateProcessor
, WebTemplateInterceptor
and WebTemplateRegistry
.
Creating a template
The easiest way to create a new template is to create a bean extending LayoutTemplateProcessorAdapterBean
.
Your implementation should get a unique name and a path to the template view file.
This basic template implementation has adapter methods for registering of web resources and generating one or more menu structures.
@Component
public class MyTemplate extends LayoutTemplateProcessorAdapterBean {
public MyTemplate() {
super( "MyTemplate", "th/mysite/layout" );
}
@Override
protected void registerWebResources( WebResourceRegistry registry ) {
registry.add( WebResource.CSS, "/static/mysite/css/main.css", WebResource.VIEWS );
}
@Override
protected void buildMenus( MenuFactory menuFactory ) {
menuFactory.buildMenu( "topMenu" );
}
}
When the template is applied it will take the original view name and put it as a model attribute with the key childPage. The actual template view can then dispatch to the original view (or parts of it) when building the final layout.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>My Site</title>
<script th:each="javascript : ${webResourceRegistry.getResources('javascript')}" th:src="@{${javascript.data}}"
th:if="${javascript.location != 'inline'}"></script>
<link rel="stylesheet" type="text/css" th:each="css : ${webResourceRegistry.getResources('css')}"
th:href="@{${css.data}}"/>
</head>
<body>
<div th:replace="${childPage} :: content">
Insert original view
</div>
<script th:each="javascript : ${webResourceRegistry.getResources('javascript-page-end')}" th:src="@{${javascript.data}}"
th:if="${javascript.location != 'inline'}"></script>
</body>
</html>
After the initial registerWebResources(WebResourceRegistry)
has been executed by the template component, an BuildTemplateWebResourcesEvent
with the template name will be published.
This allows event listeners to add additional resources for a specific template.
Linking a template to a controller
Any controller method can specify the template to use by setting the @Template
annotation with the unique template name.
The @Template
annotation can be set on the @Controller
itself (in which case it will apply to all mapping methods) or on mapping method directly.
The latter will always take precedence.
You can always clear a template from being applied by setting a @ClearTemplate annotation on a method.
Special Spring MVC return options (like methods annotated with @ResponseBody ) will automatically suppress the template.
|
Methods in a @Controller do not take any @Template annotations of their @ControllerAdvice beans into account and vice versa.
|
Linking a template to an exception handler
Just like @Template
can be used on any @RequestMapping
method, it can also be used on a @ExceptionHandler
method.
Since an exception handler uses its own template, a template might be executed twice if an exception occurs.
Initially a template might have been executed for the controller method.
In case of an exception, that template will be cleared and a new WebResourceRegistry
will be created for the @ExceptionHandler
along with the optional template.
Registering the default template
If no explicit template is specified, the default template will be used it there is one.
The default template must be set on the WebTemplateRegistry
.
set on the WebTemplateRegistry
.
@Component
public class MyTemplate extends LayoutTemplateProcessorAdapterBean {
...
@Autowired
public void registerAsDefaultTemplate( WebTemplateRegistry webTemplateRegistry ) {
webTemplateRegistry.setDefaultTemplateName( getName() );
}
...
}