Handlebars 是一个轻量级的模板引擎,适用于 Java 项目中的动态内容生成。本文将介绍 Handlebars.java 的基本使用方法,包括模板定义、上下文传值、内置助手、自定义助手以及模板复用等内容。


1. 引入 Maven 依赖

使用 Handlebars 之前,需要先引入其 Maven 依赖:

<dependency>
    <groupId>com.github.jknack</groupId>
    <artifactId>handlebars</artifactId>
    <version>4.3.1</version>
</dependency>

2. 简单模板使用

Handlebars 模板本质上是文本文件,通过 {{变量名}}{{#each 变量}} 等标签进行动态内容替换。

我们可以通过 Map、普通对象或字符串作为上下文传入模板。

2.1 使用 this 传递字符串

当上下文是一个字符串时,可以使用 {{this}} 替换:

@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!");
}

✅ 注意:compileInline 方法用于直接编译字符串模板。

2.2 使用 Map 作为上下文

使用 Map 传值时,模板中应使用对应的 key 名:

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

    String templateString = template.apply(parameterMap);

    assertThat(templateString).isEqualTo("Hi Baeldung!");
}

✅ 注意:模板中 {{name}} 对应 Map 中的 "name" 键。

2.3 使用自定义对象作为上下文

Handlebars 也支持使用 POJO 作为上下文对象:

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

    public static class Address {
        private String street;
    }

    // Getter/Setter 省略
}
@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.getName() 获取值。


3. 模板加载器(Template Loaders)

Handlebars 支持从外部文件加载模板,常见的加载方式有:

  • 类路径(classpath)
  • 文件系统
  • Servlet 上下文

3.1 默认模板加载器

默认情况下,Handlebars 会从类路径中加载模板:

@Test
public void whenNoLoaderIsGiven_ThenSearchesClasspath() throws IOException {
    Handlebars handlebars = new Handlebars();
    Template template = handlebars.compile("greeting");
    Person person = new Person();
    person.setName("Baeldung");

    String templateString = template.apply(person);

    assertThat(templateString).isEqualTo("Hi Baeldung!");
}

⚠️ 注意:compile("greeting") 会尝试加载类路径下的 greeting.hbs 文件。

3.2 自定义模板加载器

可以通过 ClassPathTemplateLoader 设置模板路径和后缀:

@Test
public void whenClasspathTemplateLoaderIsGiven_ThenSearchesClasspathWithPrefixSuffix() throws IOException {
    TemplateLoader loader = new ClassPathTemplateLoader("/handlebars", ".html");
    Handlebars handlebars = new Handlebars(loader);
    Template template = handlebars.compile("greeting");
    // ... 其他逻辑不变
}

✅ 此时会加载 /handlebars/greeting.html

3.3 多个加载器串联

可以设置多个加载器,按顺序查找模板:

@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);
    // ...
}

4. 内置助手(Built-in Helpers)

Handlebars 提供了一些内置助手来增强模板功能,常见的有:

4.1 with 助手

{{#with}} 用于改变当前上下文:

{{#with address}}
<h4>I live in {{street}}</h4>
{{/with}}

Java 示例:

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

    String templateString = template.apply(person);

    assertThat(templateString).contains("<h4>I live in World</h4>");
}

4.2 each 助手

{{#each}} 用于遍历集合:

{{#each friends}}
<span>{{name}} is my friend.</span>
{{/each}}

Java 示例:

@Test
public void whenUsedEach_ThenIterates() throws IOException {
    Handlebars handlebars = new Handlebars(templateLoader);
    Template template = handlebars.compile("each");
    Person person = new Person();
    person.setName("Baeldung");
    person.getFriends().add(new Person("Java"));
    person.getFriends().add(new Person("Spring"));

    String templateString = template.apply(person);

    assertThat(templateString)
      .contains("<span>Java is my friend.</span>", "<span>Spring is my friend.</span>");
}

4.3 if 助手

{{#if}} 用于条件判断:

{{#if busy}}
<h4>{{name}} is busy.</h4>
{{else}}
<h4>{{name}} is not busy.</h4>
{{/if}}

Java 示例:

@Test
public void whenUsedIf_ThenPutsCondition() throws IOException {
    Handlebars handlebars = new Handlebars(templateLoader);
    Template template = handlebars.compile("if");
    Person person = new Person();
    person.setName("Baeldung");
    person.setBusy(true);

    String templateString = template.apply(person);

    assertThat(templateString).contains("<h4>Baeldung is busy.</h4>");
}

5. 自定义助手(Custom Helpers)

除了内置助手,我们还可以自定义模板助手。

5.1 实现 Helper 接口

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

模板中使用:

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

5.2 使用 Helper Source 类

可以定义多个助手方法在一个类中,通过反射注册:

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

注册方法:

handlebars.registerHelpers(new HelperSource());

6. 模板复用

Handlebars 提供了两种模板复用机制:

6.1 模板包含(Inclusion)

通过 {{>模板名}} 包含其他模板:

<!-- header.html -->
<h4>Hi {{name}}!</h4>

<!-- page.html -->
{{>header}}
<p>This is the page {{name}}</p>

Java 示例:

@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("<h4>Hi Baeldung!</h4>", "<p>This is the page Baeldung</p>");
}

6.2 模板继承(Inheritance)

使用 {{#block}}{{#partial}} 实现模板继承:

<!-- messagebase.html -->
<html>
<body>
{{#block "intro"}}
  This is the intro
{{/block}}
{{#block "message"}}
{{/block}}
</body>
</html>

<!-- simplemessage.html -->
{{#partial "message" }}
  Hi there!
{{/partial}}
{{> messagebase}}

7. 小结

本文介绍了 Handlebars.java 的基本使用方式,包括:

  • 模板编写与上下文传值
  • 模板加载器的配置
  • 内置助手的使用
  • 自定义助手的实现
  • 模板复用技巧(包含与继承)

Handlebars 是一个轻量级但功能强大的模板引擎,非常适合用于 Java 项目中的动态内容生成,尤其适合前后端分离或需要模板渲染的场景。


原始标题:Templating with Handlebars | Baeldung