Script Views

Spring 框架有内置集成,可以将 Spring MVC 与任何模板库一起使用,这些模板库可以在 JSR-223 Java 脚本引擎之上运行。我们在不同的脚本引擎上测试了以下模板库:

The Spring Framework has a built-in integration for using Spring MVC with any templating library that can run on top of the JSR-223 Java scripting engine. We have tested the following templating libraries on different script engines:

Scripting Library Scripting Engine

Handlebars

Nashorn

Mustache

Nashorn

React

Nashorn

EJS

Nashorn

ERB

JRuby

String templates

Jython

Kotlin Script templating

Kotlin

集成其他任何脚本引擎的基本规则是它必须实现 ScriptEngineInvocable 接口。

The basic rule for integrating any other script engine is that it must implement the ScriptEngine and Invocable interfaces.

Requirements

您需要在类路径中使用脚本引擎,其详细信息因脚本引擎的不同而有所不同:

You need to have the script engine on your classpath, the details of which vary by script engine:

  • The Nashorn JavaScript engine is provided with Java 8+. Using the latest update release available is highly recommended.

  • JRuby should be added as a dependency for Ruby support.

  • Jython should be added as a dependency for Python support.

  • org.jetbrains.kotlin:kotlin-script-util dependency and a META-INF/services/javax.script.ScriptEngineFactory file containing a org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory line should be added for Kotlin script support. See this example for more details.

你需要具有脚本模板化库。对于 JavaScript,执行此操作的一种方法是通过 WebJars

You need to have the script templating library. One way to do that for JavaScript is through WebJars.

Script Templates

您可以声明一个 ScriptTemplateConfigurer bean 来指定要使用的脚本引擎、要加载的脚本文件、调用以呈现模板的功能,等等。以下示例使用了 Mustache 模板和 Nashorn JavaScript 引擎:

You can declare a ScriptTemplateConfigurer bean to specify the script engine to use, the script files to load, what function to call to render templates, and so on. The following example uses Mustache templates and the Nashorn JavaScript engine:

  • Java

  • Kotlin

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		registry.scriptTemplate();
	}

	@Bean
	public ScriptTemplateConfigurer configurer() {
		ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer();
		configurer.setEngineName("nashorn");
		configurer.setScripts("mustache.js");
		configurer.setRenderObject("Mustache");
		configurer.setRenderFunction("render");
		return configurer;
	}
}
@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 中的相同安排:

The following example shows the same arrangement in 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 配置的控制器,没有区别,如同以下示例所示:

The controller would look no different for the Java and XML configurations, as the following example shows:

  • Java

  • Kotlin

@Controller
public class SampleController {

	@GetMapping("/sample")
	public String test(Model model) {
		model.addAttribute("title", "Sample title");
		model.addAttribute("body", "Sample body");
		return "template";
	}
}
@Controller
class SampleController {

	@GetMapping("/sample")
	fun test(model: Model): String {
		model["title"] = "Sample title"
		model["body"] = "Sample body"
		return "template"
	}
}

以下示例展示了 Mustache 模板:

The following example shows the Mustache template:

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

呈现功能使用以下参数进行调用:

The render function is called with the following parameters:

  • String template: The template content

  • Map model: The view model

  • RenderingContext renderingContext: The RenderingContext that gives access to the application context, the locale, the template loader, and the URL (since 5.0)

Mustache.render() 本身与其签名兼容,因此您可以直接调用它。

Mustache.render() is natively compatible with this signature, so you can call it directly.

如果你的模板化技术需要一些自定义,你可以提供一个实现了自定义渲染功能的脚本。例如,在使用模板之前, Handlerbars需要编译模板,并且需要 polyfill来模拟服务器端脚本引擎中不可用的某些浏览器功能。

If your templating technology requires some customization, you can provide a script that implements a custom render function. For example, Handlerbars needs to compile templates before using them and requires a polyfill to emulate some browser facilities that are not available in the server-side script engine.

以下示例演示了如何执行此操作:

The following example shows how to do so:

  • Java

  • Kotlin

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		registry.scriptTemplate();
	}

	@Bean
	public ScriptTemplateConfigurer configurer() {
		ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer();
		configurer.setEngineName("nashorn");
		configurer.setScripts("polyfill.js", "handlebars.js", "render.js");
		configurer.setRenderFunction("render");
		configurer.setSharedEngine(false);
		return configurer;
	}
}
@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
	}
}

当在 Nashorn 上运行 Handlebar 或 React 等不适用于并发且专为并发设计的模板化库中使用非线程安全脚本引擎时,设置 sharedEngine 属性为 false 是必需的。在这种情况下,由于 this bug,Java SE 8 更新 60 是必需的,但无论如何通常建议使用最近的 Java SE 修补程序版本。

Setting the sharedEngine property to false is required when using non-thread-safe script engines with templating libraries not designed for concurrency, such as Handlebars or React running on Nashorn. In that case, Java SE 8 update 60 is required, due to this bug, but it is generally recommended to use a recent Java SE patch release in any case.

polyfill.js 仅定义 Handlebars 正确运行所需的 window 对象,如下所示:

polyfill.js defines only the window object needed by Handlebars to run properly, as follows:

var window = {};

这个基本的 render.js 实现编译了模板,然后使用它。适于生产的实现还应该存储任何重新使用的缓存模板或预编译的模板。您可以在脚本端完成此操作(并处理您需要的任何自定义——管理模板引擎配置,例如)。以下示例展示了如何执行此操作:

This basic render.js implementation compiles the template before using it. A production-ready implementation should also store any reused cached templates or pre-compiled templates. You can do so on the script side (and handle any customization you need — managing template engine configuration, for example). The following example shows how to do so:

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

查看 Spring Framework 单元测试、https://github.com/spring-projects/spring-framework/tree/main/spring-webmvc/src/test/java/org/springframework/web/servlet/view/script[Java] 和 resources,以获取更多配置示例。

Check out the Spring Framework unit tests, Java, and resources, for more configuration examples.