Mustache.java не предназначен для того, чтобы позволить ненадежным сторонам предоставлять шаблоны. Для обеспечения безопасности его можно заблокировать, но по умолчанию это НЕБЕЗОПАСНО. Используйте SafeMustacheFactory и внесите в белый список все шаблоны и частичные файлы.
Начиная с версии 0.9.0 mustache.java теперь поддерживает только Java 8. Для поддержки Java 6/7 используйте версию 0.8.x.
Внешних зависимостей нет, а библиотека компилятора составляет ~ 100 тысяч.
Mustache.java является производным от mustache.js.
Для поддержки и вопросов существует группа Google: http://groups.google.com/group/mustachejava.
Github CI: https://github.com/spullara/mustache.java/actions/workflows/maven.yml
Документация по API: http://spullara.github.io/mustache/apidocs/.
Крупнейшее промышленное развертывание Mustache.java:
Спасибо YourKit за множество улучшений производительности:
YourKit любезно поддерживает проект с открытым исходным кодом mustache.java своим полнофункциональным профилировщиком Java. YourKit, LLC — создатель инновационных и интеллектуальных инструментов для профилирования приложений Java и .NET. Взгляните на ведущие программные продукты YourKit:
Запрос на участие:
Документация:
mustache
по модулю разницы в пробелах.Iterable
может использоваться для поведения, подобного списку.Callable
объекта позволяет выполнять параллельную оценку, если настроен ExecutorService
{{<super}}{{$content}}...{{/content}}{{/super}}
).{{#func1}}...{{/func1}}
) реализованы с использованием Function
из Java 8 (после замены).TemplateFunction
, если вы хотите, чтобы mustache.java повторно анализировал результаты вашей функции/лямбды (предварительная замена)handlebar
будет отображать шаблоны + данные JSON для быстрого создания макетов шаблонов дизайнерами.CapturingMustacheVisitor
для макетов и тестов.invert
вызов может принимать текст и шаблон и решать данные.Производительность:
com.github.mustachejavabenchmarks
в модуле compiler
.indy
использует модуль codegen и ignoredynamic для компиляции шаблонов в байт-код.Предложения по сборке:
Информация о зависимостях Maven (т. е. в большинстве распространенных случаев вам просто понадобится модуль compiler
):
Ява 8+:
< dependency >
< groupId >com.github.spullara.mustache.java</ groupId >
< artifactId >compiler</ artifactId >
< version >0.9.10</ version >
</ dependency >
Ява 6/7:
< dependency >
< groupId >com.github.spullara.mustache.java</ groupId >
< artifactId >compiler</ artifactId >
< version >0.8.18</ version >
</ dependency >
Пример файла шаблона:
{{#items}}
Name: {{name}}
Price: {{price}}
{{#features}}
Feature: {{description}}
{{/features}}
{{/items}}
Может быть основано на каком-то вспомогательном коде:
public class Context {
List < Item > items () {
return Arrays . asList (
new Item ( "Item 1" , "$19.99" , Arrays . asList ( new Feature ( "New!" ), new Feature ( "Awesome!" ))),
new Item ( "Item 2" , "$29.99" , Arrays . asList ( new Feature ( "Old." ), new Feature ( "Ugly." )))
);
}
static class Item {
Item ( String name , String price , List < Feature > features ) {
this . name = name ;
this . price = price ;
this . features = features ;
}
String name , price ;
List < Feature > features ;
}
static class Feature {
Feature ( String description ) {
this . description = description ;
}
String description ;
}
}
И это приведет к:
Name: Item 1
Price: $19.99
Feature: New!
Feature: Awesome!
Name: Item 2
Price: $29.99
Feature: Old.
Feature: Ugly.
Оценка шаблона происходит последовательно. Например, если у вас есть блокирующий код в одном из ваших обратных вызовов, система приостановит их выполнение:
static class Feature {
Feature ( String description ) {
this . description = description ;
}
String description () throws InterruptedException {
Thread . sleep ( 1000 );
return description ;
}
}
Если вы измените описание, чтобы вместо этого оно возвращало Callable
, оно будет автоматически выполняться в отдельном потоке, если вы предоставили ExecutorService
при создании MustacheFactory
.
Callable < String > description () throws InterruptedException {
return new Callable < String >() {
@ Override
public String call () throws Exception {
Thread . sleep ( 1000 );
return description ;
}
};
}
Это обеспечивает запланированные задачи, потоковую передачу и асинхронный ввод-вывод. Ознакомьтесь с example
модуля, чтобы увидеть полный комплексный пример:
package mustachejava ;
import com . github . mustachejava . DefaultMustacheFactory ;
import com . github . mustachejava . Mustache ;
import com . github . mustachejava . MustacheFactory ;
import java . io . IOException ;
import java . io . PrintWriter ;
import java . io . Writer ;
import java . util . Arrays ;
import java . util . List ;
public class Example {
List < Item > items () {
return Arrays . asList (
new Item ( "Item 1" , "$19.99" , Arrays . asList ( new Feature ( "New!" ), new Feature ( "Awesome!" ))),
new Item ( "Item 2" , "$29.99" , Arrays . asList ( new Feature ( "Old." ), new Feature ( "Ugly." )))
);
}
static class Item {
Item ( String name , String price , List < Feature > features ) {
this . name = name ;
this . price = price ;
this . features = features ;
}
String name , price ;
List < Feature > features ;
}
static class Feature {
Feature ( String description ) {
this . description = description ;
}
String description ;
}
public static void main ( String [] args ) throws IOException {
MustacheFactory mf = new DefaultMustacheFactory ();
Mustache mustache = mf . compile ( "template.mustache" );
mustache . execute ( new PrintWriter ( System . out ), new Example ()). flush ();
}
}
Альтернативным подходом для предоставления переменных может быть использование объекта Map, например:
public static void main ( String [] args ) throws IOException {
HashMap < String , Object > scopes = new HashMap < String , Object >();
scopes . put ( "name" , "Mustache" );
scopes . put ( "feature" , new Feature ( "Perfect!" ));
Writer writer = new OutputStreamWriter ( System . out );
MustacheFactory mf = new DefaultMustacheFactory ();
Mustache mustache = mf . compile ( new StringReader ( "{{name}}, {{feature.description}}!" ), "example" );
mustache . execute ( writer , scopes );
writer . flush ();
}