Spring Framework має вбудовану інтеграцію для використання Spring MVC із будь-якою бібліотекою шаблонізації, що може виконуватися на основі механізму виконання скриптів за специфікацією JSR-223 у Java. Ми протестували такі бібліотеки шаблонізації на різних механізмах виконання скриптів:

Бібліотека скриптів Механізм виконання скриптів

Handlebars

Nashorn

Mustache

Nashorn

React

Nashorn

EJS

Nashorn

ERB

JRuby

String templates

Jython

Kotlin Script templating

Kotlin

Основне правило для інтеграції будь-якого іншого механізму виконання скриптів полягає в тому, що він повинен реалізувати інтерфейси ScriptEngine та Invocable.

Вимоги

Необхідно забезпечити наявність механізму виконання скриптів у своєму classpath, деталі якого залежать від механізму виконання скриптів:

  • Механізм обробки JavaScript під назвою Nashorn поставляється разом з Java 8+. Рекомендовано використовувати останній доступний випуск оновлення.

  • JRuby необхідно додати як залежність для забезпечення підтримки мови Ruby.

  • Jython необхідно додати як залежність для забезпечення підтримки мови Python.

  • Для забезпечення підтримки скриптів Kotlin слід додати залежність org.jetbrains.kotlin:kotlin-script-util та файл META-INF/services/javax.script.ScriptEngineFactory, що містить рядок org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory. Детальнішу інформацію дивися в цьому прикладі.

Тобі необхідно мати бібліотеку шаблонізації скриптів. Один зі способів зробити це для JavaScript — WebJars.

Шаблони скриптів

Ти можеш оголосити бін ScriptTemplateConfigurer, щоб зазначити, який механізм виконання скриптів використовувати, які файли скриптів завантажувати, яку функцію викликати для візуалізації шаблонів тощо. У цьому прикладі використовуються шаблони Mustache та механізм обробки скриптів JavaScript під назвою Nashorn:

Java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.scriptTemplate();
    }
    @Bean
    public ScriptTemplateConfigurer configurer() {
        ScriptTemplateConfigurer configurer = новий ScriptTemplateConfigurer();
        configurer.setEngineName("nashorn");
        configurer.setScripts("mustache.js");
        configurer.setRenderObject("Mustache");
        configurer.setRenderFunction("render");
        return configurer;
    }
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        registry.scriptTemplate()
    }
    @Bean
    fun configurer() = ScriptTemplateConfigurer().apply {
        engineName = "nashorn"
        setScripts("mustache.js")
        renderObject = "Mustache"
        renderFunction = "render"
    }
}

У наступному прикладі показаний такий самий спосіб організації в XML:

<mvc:annotation-driven/>
<mvc:view-resolvers>
    <mvc:script-template/>
</mvc:view-resolvers>
<mvc:script-template-configurer engine-name="nashorn" render-object="Mustache" render-function="render">
    <mvc:script location="mustache.js"/>
</mvc:script-template-configurer>

Контролер не буде відрізнятися для конфігурацій на Java та XML, як показано в наступному прикладі:

Java
@Controller
public class SampleController {
    @GetMapping("/sample")
    public String test(Model model) {
        model.addAttribute("title", "Sample title");
        model.addAttribute("body", "Sample body");
        return "template";
    }
}
Kotlin
@Controller
class SampleController {
    @GetMapping("/sample")
    fun test(model: Model): String {
        model["title"] = "Sample title"
        model["body"] = "Sample body"
        return "template"
    }
}

У цьому прикладі показано шаблон Mustache:

<html>
    <head>
        <title>{{title}}</title>
    </head>
    <body>
        <p>{{body}}</p>
    </body>
</html>

Функція візуалізації викликається з наступними параметрами:

  • String template: Зміст шаблону

  • Map model: Модель подання

  • RenderingContext renderingContext: RenderingContext, який надає доступ до контексту програми, регіональних налаштувань, завантажувача шаблонів та URL-адреси (починаючи з версії 5.0).

Mustache.render() від початку сумісний з цією сигнатурою, тому можна викликати його безпосередньо.

Якщо твоя технологія шаблонізації потребує певного налаштування, можна передати скрипт, який реалізує кастомну функцію візуалізації. Наприклад, Handlerbars вимагає компіляції шаблонів перед використанням і вимагає полізаповнення для емуляції деяких можливостей браузера, які недоступні в механізмі виконання скриптів на стороні сервера.

У цьому прикладі показано, як це зробити:

Java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.scriptTemplate();
    }
    @Bean
    public ScriptTemplateConfigurer configurer() {
        ScriptTemplateConfigurer configurer = новий ScriptTemplateConfigurer();
        configurer.setEngineName("nashorn");
        configurer.setScripts("polyfill.js", "handlebars.js", "render.js");
        configurer.setRenderFunction("render");
        configurer.setSharedEngine(false);
        return configurer;
    }
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        registry.scriptTemplate()
    }
    @Bean
    fun configurer() = ScriptTemplateConfigurer().apply {
        engineName = "nashorn"
        setScripts("polyfill.js", "handlebars.js", "render.js")
        renderFunction = "render"
        isSharedEngine = false
    }
}
Встановлення властивості sharedEngine у false необхідне при використанні небезпечних для потоків механізмів виконання скриптів з бібліотеками шаблонів, не розрахованими на паралелізм. Наприклад, Handlebars або React, що працюють на Nashorn. У цьому випадку потрібне оновлення Java SE 8 update 60 через цей баг, але зазвичай у будь-якому випадку рекомендується використовувати останній випуск патча Java SE.

polyfill.js визначає лише об'єкт window, необхідний Handlebars для правильної роботи, таким чином:

var window = {};

Ця базова реалізація render.js компілює шаблон перед його використанням. Реалізація, придатна до виробничого використання, повинна зберігати будь-які повторно використовувані кешовані шаблони або попередньо скомпільовані шаблони. Це можна зробити на стороні скрипта (і обробити будь-яке необхідне тобі налаштування — наприклад, керування конфігурацією шаблонізатора). У цьому прикладі показано, як це зробити:

function render(template, model) {
    var compiledTemplate = Handlebars.compile(template);
    return compiledTemplate(model);
}

Ознайомся з модульними тестами Spring Framework, Java та ресурсами, щоб переглянути більше прикладів конфігурації.