Рубрики
Без рубрики

Шаблонирование с помощью руля

Узнайте, как создавать шаблоны и взаимодействовать с ними с помощью руля.

Автор оригинала: baeldung.

1. Обзор

В этом уроке мы рассмотрим Handlebars.java библиотека для удобного управления шаблонами.

2. Зависимости Maven

Давайте начнем с добавления зависимости handlebars :


    com.github.jknack
    handlebars
    4.1.2

3. Простой Шаблон

Шаблон руля может быть любым текстовым файлом. Он состоит из тегов типа {{name}} и {{#each people}}.

Затем мы заполняем эти теги, передавая контекстный объект, например Map или другой Объект.

3.1. Использование данного

Чтобы передать одно Строковое значение в наш шаблон, мы можем использовать любой Объект в качестве контекста. Мы также должны использовать {{ this}} t ag в нашем шаблоне.

Затем Handlebars вызывает метод toString для объекта context и заменяет тег результатом:

@Test
public void whenThereIsNoTemplateFile_ThenCompilesInline() throws IOException {
    Handlebars handlebars = new Handlebars();
    Template template = handlebars.compileInline("Hi {{this}}!");
    
    String templateString = template.apply("Baeldung");
    
    assertThat(templateString).isEqualTo("Hi Baeldung!");
}

В приведенном выше примере мы сначала создаем экземпляр Handlebars, нашей точки входа API.

Затем мы даем этому экземпляру наш шаблон. Здесь мы просто передаем шаблон в строку, но через мгновение мы увидим несколько более мощных способов.

Наконец, мы даем скомпилированному шаблону наш контекст. {{это}} просто в конечном итоге вызовет toString, вот почему мы видим “Привет, Баэлдунг!” .

3.2. Передача карты в качестве контекстного объекта

Мы только что видели, как отправить String для нашего контекста, теперь давайте попробуем Map :

@Test
public void whenParameterMapIsSupplied_thenDisplays() throws IOException {
    Handlebars handlebars = new Handlebars();
    Template template = handlebars.compileInline("Hi {{name}}!");
    Map parameterMap = new HashMap<>();
    parameterMap.put("name", "Baeldung");
    
    String templateString = template.apply(parameterMap);
    
    assertThat(templateString).isEqualTo("Hi Baeldung!");
}

Как и в предыдущем примере, мы компилируем наш шаблон и затем передаем объект context, но на этот раз в виде Map .

Кроме того, обратите внимание, что мы используем {{name}} вместо {{this}} . Это означает, что наша карта должна содержать ключ, имя .

3.3. Передача пользовательского объекта в качестве контекстного объекта

Мы также можем передать пользовательский объект в наш шаблон:

public class Person {
    private String name;
    private boolean busy;
    private Address address = new Address();
    private List friends = new ArrayList<>();
 
    public static class Address {
        private String street;       
    }
}

Используя класс Person , мы добьемся того же результата, что и в предыдущем примере:

@Test
public void whenParameterObjectIsSupplied_ThenDisplays() throws IOException {
    Handlebars handlebars = new Handlebars();
    Template template = handlebars.compileInline("Hi {{name}}!");
    Person person = new Person();
    person.setName("Baeldung");
    
    String templateString = template.apply(person);
    
    assertThat(templateString).isEqualTo("Hi Baeldung!");
}

{{name}} в нашем шаблоне будет детализирован наш Person объект и получено значение поля name .

4. Загрузчики шаблонов

До сих пор мы использовали шаблоны, определенные внутри кода. Однако это не единственный вариант. Мы также можем читать шаблоны из текстовых файлов.

Handlebars.java обеспечивает специальную поддержку для чтения шаблонов из пути к классу, файловой системы или servletcontext. По умолчанию Handlebars сканирует путь к классу, чтобы загрузить данный шаблон:

@Test
public void whenNoLoaderIsGiven_ThenSearchesClasspath() throws IOException {
    Handlebars handlebars = new Handlebars();
    Template template = handlebars.compile("greeting");
    Person person = getPerson("Baeldung");
    
    String templateString = template.apply(person);
    
    assertThat(templateString).isEqualTo("Hi Baeldung!");
}

Итак, поскольку мы вызвали compile вместо compile Inline, это подсказка рулю искать /greeting.hbs на пути к классу.

Однако мы также можем настроить эти свойства с помощью ClassPathTemplateLoader :

@Test
public void whenClasspathTemplateLoaderIsGiven_ThenSearchesClasspathWithPrefixSuffix() throws IOException {
    TemplateLoader loader = new ClassPathTemplateLoader("/handlebars", ".html");
    Handlebars handlebars = new Handlebars(loader);
    Template template = handlebars.compile("greeting");
    // ... same as before
}

В этом случае мы говорим Рулям искать /handlebars/greeting.html на пути к классу .

Наконец, мы можем связать несколько экземпляров Template Loader :

@Test
public void whenMultipleLoadersAreGiven_ThenSearchesSequentially() throws IOException {
    TemplateLoader firstLoader = new ClassPathTemplateLoader("/handlebars", ".html");
    TemplateLoader secondLoader = new ClassPathTemplateLoader("/templates", ".html");
    Handlebars handlebars = new Handlebars().with(firstLoader, secondLoader);
    // ... same as before
}

Итак, здесь у нас есть два загрузчика, и это означает, что Handlebars будет искать в двух каталогах шаблон приветствие .

5. Встроенные помощники

Встроенные помощники предоставляют нам дополнительную функциональность при написании наших шаблонов.

5.1. с помощником

Помощник with изменяет текущий контекст :

{{#with address}}

I live in {{street}}

{{/with}}

В нашем примере шаблона тег {{#with address}} начинает раздел, а тег {{/with}} заканчивает его .

По сути, мы сверлим текущий контекстный объект – скажем, p – и устанавливаем address в качестве локального контекста для раздела with . После этого каждая ссылка на поле в этом разделе будет предваряться person.address .

Таким образом, тег {{street}} будет содержать значение person.address.street :

@Test
public void whenUsedWith_ThenContextChanges() throws IOException {
    Handlebars handlebars = new Handlebars(templateLoader);
    Template template = handlebars.compile("with");
    Person person = getPerson("Baeldung");
    person.getAddress().setStreet("World");
    
    String templateString = template.apply(person);
    
    assertThat(templateString).contains("

I live in World

"); }

Мы компилируем наш шаблон и назначаем экземпляр Person в качестве объекта контекста. Обратите внимание, что класс Person имеет поле Address . Это поле, которое мы предоставляем помощнику with .

Хотя мы пошли на один уровень в наш контекстный объект, совершенно нормально идти глубже, если контекстный объект имеет несколько вложенных уровней.

5.2. каждый Помощник

каждый помощник перебирает коллекцию :

{{#each friends}}
{{name}} is my friend.
{{/each}}

В результате запуска и закрытия раздела итерации с тегами {{#each friends}} и {{/each}} Рули будут перебирать поле friends объекта контекста.

@Test
public void whenUsedEach_ThenIterates() throws IOException {
    Handlebars handlebars = new Handlebars(templateLoader);
    Template template = handlebars.compile("each");
    Person person = getPerson("Baeldung");
    Person friend1 = getPerson("Java");
    Person friend2 = getPerson("Spring");
    person.getFriends().add(friend1);
    person.getFriends().add(friend2);
    
    String templateString = template.apply(person);
    
    assertThat(templateString)
      .contains("Java is my friend.", "Spring is my friend.");
}

В этом примере мы назначаем два экземпляра Person полю friends объекта context. Таким образом, Handlebars повторяет HTML-часть два раза в окончательном выводе.

5.3. если Помощник

Наконец, помощник if обеспечивает условный рендеринг .

{{#if busy}}

{{name}} is busy.

{{else}}

{{name}} is not busy.

{{/if}}

В нашем шаблоне мы предоставляем различные сообщения в соответствии с полем занято .

@Test
public void whenUsedIf_ThenPutsCondition() throws IOException {
    Handlebars handlebars = new Handlebars(templateLoader);
    Template template = handlebars.compile("if");
    Person person = getPerson("Baeldung");
    person.setBusy(true);
    
    String templateString = template.apply(person);
    
    assertThat(templateString).contains("

Baeldung is busy.

"); }

После компиляции шаблона мы устанавливаем контекстный объект. Поскольку поле занято имеет значение true , конечный вывод становится Baeldung is busy. .

6. Пользовательские Помощники шаблонов

Мы также можем создать ваших собственных помощников.

6.1. Помощник

То Помощник интерфейс позволяет нам создать шаблон помощника.

В качестве первого шага мы должны обеспечить реализацию Helper :

new Helper() {
    @Override
    public Object apply(Person context, Options options) throws IOException {
        String busyString = context.isBusy() ? "busy" : "available";
        return context.getName() + " - " + busyString;
    }
}

Как мы видим, интерфейс Helper имеет только один метод, который принимает объекты context и options . Для наших целей мы выведем поля name и busy для Person .

После создания помощника мы также должны зарегистрировать наш пользовательский помощник с помощью руля :

@Test
public void whenHelperIsCreated_ThenCanRegister() throws IOException {
    Handlebars handlebars = new Handlebars(templateLoader);
    handlebars.registerHelper("isBusy", new Helper() {
        @Override
        public Object apply(Person context, Options options) throws IOException {
            String busyString = context.isBusy() ? "busy" : "available";
            return context.getName() + " - " + busyString;
        }
    });
    
    // implementation details
}

В нашем примере мы регистрируем нашего помощника под именем is Busy с помощью метода Handlebars.registerHelper () .

В качестве последнего шага мы должны определить тег в нашем шаблоне, используя имя помощника :

{{#isBusy this}}{{/isBusy}}

Обратите внимание, что у каждого помощника есть начальный и конечный тег.

6.2. Вспомогательные Методы

Когда мы используем интерфейс Helper , мы можем создать только один помощник . Напротив, вспомогательный исходный класс позволяет нам определить несколько помощников шаблонов.

Более того, нам не нужно реализовывать какой-либо конкретный интерфейс. Мы просто пишем наши вспомогательные методы в классе, а затем HandleBars извлекает вспомогательные определения с помощью отражения:

public class HelperSource {

    public String isBusy(Person context) {
        String busyString = context.isBusy() ? "busy" : "available";
        return context.getName() + " - " + busyString;
    }

    // Other helper methods
}

Поскольку вспомогательный источник может содержать несколько вспомогательных реализаций, регистрация отличается от регистрации одного помощника:

@Test
public void whenHelperSourceIsCreated_ThenCanRegister() throws IOException {
    Handlebars handlebars = new Handlebars(templateLoader);
    handlebars.registerHelpers(new HelperSource());
    
    // Implementation details
}

Мы регистрируем наших помощников с помощью метода Handlebars.registerhelper () . Более того, имя вспомогательного метода становится именем вспомогательного тега .

7. Повторное использование шаблона

Библиотека Handlebars предоставляет несколько способов повторного использования наших существующих шаблонов.

7.1. Включение шаблона

Включение шаблонов-это один из подходов к повторному использованию шаблонов. Это благоприятствует составу шаблонов .

Hi {{name}}!

Это содержимое шаблона headerheader.html.

Чтобы использовать его в другом шаблоне, мы должны обратиться к шаблону header .

{{>header}}

This is the page {{name}}

У нас есть страница шаблон – page.html – который включает в себя шаблон header с использованием {{>header}}.

Когда Handlebars.java обрабатывает шаблон, конечный вывод также будет содержать содержимое header :

@Test
public void whenOtherTemplateIsReferenced_ThenCanReuse() throws IOException {
    Handlebars handlebars = new Handlebars(templateLoader);
    Template template = handlebars.compile("page");
    Person person = new Person();
    person.setName("Baeldung");
    
    String templateString = template.apply(person);
    
    assertThat(templateString)
      .contains("

Hi Baeldung!

", "

This is the page Baeldung

"); }

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

В качестве альтернативы композиции, Handlebars предоставляет наследование шаблона .

Мы можем достичь отношений наследования с помощью тегов {{#block}} и {{#partial}} :



{{#block "intro"}}
  This is the intro
{{/block}}
{{#block "message"}}
{{/block}}

Таким образом, шаблон messagebase имеет два блока – intro и message .

Чтобы применить наследование, нам нужно переопределить эти блоки в других шаблонах с помощью {{#partial}} :

{{#partial "message" }}
  Hi there!
{{/partial}}
{{> messagebase}}

Это шаблон simple message . Обратите внимание, что мы включаем шаблон message base , а также переопределяем блок message .

8. Резюме

В этом уроке мы рассмотрели Handlebars.java для создания шаблонов и управления ими.

Мы начали с базового использования тегов, а затем рассмотрели различные варианты загрузки шаблонов рулей.

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

Наконец, проверьте исходный код для всех примеров на GitHub .