Статьи

Trimou Templates Введение

Trimou — это простой в использовании и расширяемый движок шаблонов для любого приложения Java SE или Java EE. Это  реализация шаблона Усы, доступная под лицензией Apache 2.0. Эта статья — только краткое изложение, освещающее некоторые из самых полезных функций Trimou. Вы можете прочитать документацию и изучить пример кода, чтобы узнать больше.

Базовый набор функций каждой реализации усов определен в спецификации усов . Trimou проходит все тесты спецификаций (версия 1.1.2), за исключением «Раздел — альтернативные разделители» из дополнительного модуля лямбда-выражения. Но это не просто реализация усов …

Где шаблон?

Это задача для специального компонента, называемого локатором шаблона, который может автоматически найти содержимое шаблона для данного идентификатора шаблона. На самом деле вы можете иметь более одного локатора шаблона — те, которые имеют более высокий приоритет, вызываются первыми.

Trimou предоставляет несколько
встроенных реализаций (classpath, filesystem), которые хорошо работают в Java SE.
ServletContextTemplateLocator (часть расширения сервлета), с другой стороны, предназначен для контейнеров сервлетов и может найти шаблон в любом месте веб-приложения.


 

MustacheEngine engine = MustacheEngineBuilder
  .newBuilder()
  .addTemplateLocator(new ServletContextTemplateLocator(10, "/WEB-INF/templates"))
  .build();
// Pass the template contents as a String
Mustache m1 = engine.compileMustache("my-foo-template", "{{foo}}");
// And now use the locator
Mustache m2 = engine.getMustache("my-template.html");

поддержка i18n

Trimou имеет базовую поддержку i18n. Он предоставляет три необязательных преобразователя (NumberFormatResolver, DateTimeFormatResolver, ResourceBundleResolver) и один необязательный лямбда (ResourceBundleLambda).

// DateTimeFormatResolver example
MustacheEngine engine = MustacheEngineBuilder
                           .newBuilder()
                           .setProperty(DateTimeFormatResolver.CUSTOM_PATTERN_KEY, "DD-MM-YYYY HH:mm")
                           .addResolver(new DateTimeFormatResolver())
                           .build();
Mustache mustache = engine.compileMustache("{{now.formatCustom}}");
Assert.assertEquals("Now: 03-05-2013 22:05", mustache.render(ImmutableMap.<String, Object> of("now", new Date())));

Наследование шаблонов

Эта функция не поддерживается в спецификации. Однако это очень важно с точки зрения ремонтопригодности. Trimou в основном идет по пути mustache.java реализует  шаблон наследования. В расширенном шаблоне определены разделы для расширения — используйте $ для определения таких разделов. В расширяющихся шаблонах определяются расширяющиеся разделы — опять же, используйте $ для идентификации таких разделов. Разделы для расширения могут определять содержимое по умолчанию.

Этот шаблон для расширения:

{{$header}}
  The default header
{{/header}}
In between...
{{$content}}
  The default content
{{/content}}
© 2013

Может быть расширен таким образом:

Hello world!
{{<super}}
  {{$header}}
    My own header
  {{/header}}
{{/super}}
Lalala...

И результат:

Hello world!
This a template to extend
  My own header
In between...
  The default content
© 2013
Lalala...

CDI support

Contexts and Dependency Injection for the Java EE platform is a great programming model. Named CDI beans are automatically accessible via Unified EL and thus available on JSP/JSF pages. Trimou built-in CDI extension allows you to do the same. It automatically registers a special resolver which is able to lookup a named bean.

Suppose we have the following bean:

@Named("provider")
@RequestScoped
public class DataProvider {
    public String[] getData() {
        return new String[] {"foo","bar"};
    }
}

We can automatically use it in our template:

<ul>
{{#provider.data}}
    <li>{{this}}</li>
{{/provider.data}}
</ul>

to render something like:

<ul>
    <li>foo</li>
    <li>bar</li>
</ul>

CDI extension also implements a custom scope which is active during each rendering of a template (there is exactly one bean instance per template rendering). This could be useful in Java SE where usually only @ApplicationScoped and @Dependent built-in scopes are available. You can annotate your bean with org.trimou.cdi.context.RenderingScoped to declare the rendering scope.

PrettyTime — a nice way of displaying date and time

Most applications do have to display the date and time correctly. There’s a lot of stuff in Java to handle dates properly. But sometimes it’s useful to render nice relative timestamps like «right now» and «10 minutes from now». This is why Trimou integrates PrettyTime.

MustacheEngine engine = MustacheEngineBuilder.newBuilder().build();
// The PrettyTimeResolver is automatically loaded if you place the extension jar on the classpath
Mustache mustache = engine.compileMustache("prettyTime","{{now.prettyTime}}");
String output = mustache.render(ImmutableMap.<String, Object> of("now", new Date()));
// Renders something similar:
// moments from now

Minify your templates

It’s very common to minify JavaScript/CSS files so why not the template itself? You can save some bandwidth and also increase the performance of the rendering a little bit. Trimou integrates small and efficient HtmlCompressor library. There are two ways to minify the templates.

It’s possible to register a special listener to minify templates before parsing/compilation:

MustacheEngine engine = MustacheEngineBuilder.newBuilder().addMustacheListener(Minify.htmlListener()).build();
Mustache mustache = engine.compileMustache("minify_html","<html><body>     <!-- My comment -->{{foo}}  </body></html>");
String output = mustache.render(ImmutableMap.<String, Object> of("foo", "FOO"));
// Renders:
// <html><body> FOO </body></html>

Or use a special lambda to minify some parts of the template contents:

MustacheEngine engine = MustacheEngineBuilder.newBuilder().build();
Mustache mustache = engine.compileMustache("minify_html_lambda","<html><body><!-- Remains -->{{#mini}}<!-- Will be removed -->   FOO {{/mini}}</body></html>");
String output = mustache.render(ImmutableMap.<String, Object> of("mini", Minify.htmlLambda()));
// Renders:
// <html><body><!-- Remains --> FOO </body></html>

Eventually you can also implement your own minifier and leverage the existing infrastructure.