# 1.9 View Technologies

Spring WebFlux中视图技术的使用是可插入的，无论您决定使用Thymeleaf，Groovy标记模板，JSP还是其他技术，主要取决于配置更改。 本章介绍与Spring WebFlux集成的视图技术。 我们假设您已经熟悉View Resolution。

## 1.9.1 Thymeleaf

Thymeleaf是一种现代的服务器端Java模板引擎，它强调可以通过双击在浏览器中预览的自然HTML模板，这对于独立处理UI模板（例如，由设计人员）而无需使用非常有用。 正在运行的服务器。 如果要替换JSP，Thymeleaf提供了最广泛的功能集之一，以使这种过渡更加容易。 Thymeleaf是积极开发和维护的。 有关更完整的介绍，请参见Thymeleaf项目主页。

Thymeleaf与Spring MVC的集成由Thymeleaf项目管理。 该配置涉及一些Bean声明，例如ServletContextTemplateResolver，SpringTemplateEngine和ThymeleafViewResolver。 有关更多详细信息，请参见Thymeleaf + Spring。

## 1.9.2 FreeMarker

Apache FreeMarker是一个模板引擎，用于生成从HTML到电子邮件等的任何类型的文本输出。 Spring框架具有内置的集成，可以将Spring MVC与FreeMarker模板一起使用。

**View配置**

以下示例显示如何将FreeMarker配置为一种视图技术：

```java
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

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

    // Configure FreeMarker...

    @Bean
    public FreeMarkerConfigurer freeMarkerConfigurer() {
        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
        configurer.setTemplateLoaderPath("/WEB-INF/freemarker");
        return configurer;
    }
}
```

您的模板需要存储在上例所示的FreeMarkerConfigurer指定的目录中。 给定上述配置，如果您的控制器返回欢迎的视图名称，则解析器将查找/WEB-INF/freemarker/welcome.ftl模板。

**FreeMarker Configuration**

您可以通过在FreeMarkerConfigurer bean上设置适当的bean属性，将FreeMarker的“设置”和“ SharedVariables”直接传递给FreeMarker配置对象（由Spring管理）。 freemarkerSettings属性需要一个java.util.Properties对象，而freemarkerVariables属性需要一个java.util.Map。 以下示例显示了如何使用FreeMarkerConfigurer：

```java
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    // ...

    @Bean
    public FreeMarkerConfigurer freeMarkerConfigurer() {
        Map<String, Object> variables = new HashMap<>();
        variables.put("xml_escape", new XmlEscape());

        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
        configurer.setTemplateLoaderPath("classpath:/templates");
        configurer.setFreemarkerVariables(variables);
        return configurer;
    }
}
```

有关设置和变量应用于Configuration对象的详细信息，请参见FreeMarker文档。

## 1.9.3 Script Views

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

| Scripting Library        | Scripting Engine |
| ------------------------ | ---------------- |
| Handlebars               | Nashorn          |
| Mustache                 | Nashorn          |
| React                    | Nashorn          |
| EJS                      | Nashorn          |
| ERB                      | JRuby            |
| String templates         | Jython           |
| Kotlin Script templating | Kotlin           |

> 集成任何其他脚本引擎的基本规则是，它必须实现ScriptEngine和Invocable接口。

**Requirements**

您需要在类路径上具有脚本引擎，其细节因脚本引擎而异：

* Java 8+随附了Nashorn JavaScript引擎。 强烈建议使用可用的最新更新版本。
* 应该将JRuby添加为对Ruby支持的依赖。
* 应该将Jython添加为对Python支持的依赖项。
* 应该添加org.jetbrains.kotlin：kotlin-script-util依赖项和包含org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory行的META-INF / services / javax.script.ScriptEngineFactory文件。 有关更多详细信息，请参见此示例。

您需要具有脚本模板库。 针对Javascript的一种方法是通过WebJars。

**Script Templates**

您可以声明一个ScriptTemplateConfigurer bean来指定要使用的脚本引擎，要加载的脚本文件，调用呈现模板的函数等等。 以下示例使用Mustache模板和Nashorn JavaScript引擎：

```java
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @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;
    }
}
```

使用以下参数调用render函数：

* String template：模板内容
* Map model：视图模型
* RenderingContext renderingContext：RenderingContext，用于访问应用程序上下文，语言环境，模板加载器和URL（自5.0起）

Mustache.render（）与该签名本地兼容，因此您可以直接调用它。

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

以下示例显示了如何执行此操作：

```java
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @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;
    }
}
```

当您将非线程安全脚本引擎与不是为并发设计的模板库一起使用时，例如，在Nashorn上运行的Handlebars或React，必须将sharedEngine属性设置为false。 在这种情况下，由于此错误，需要Java 8u60或更高版本。

polyfill.js仅定义Handlebars正常运行所需的window对象，如下所示：

```javascript
var window = {};
```

这个基本的render.js实现在使用模板之前先对其进行编译。 生产就绪的实现还应该存储任何重用的缓存模板或预编译的模板。 您可以在脚本方面进行操作（并处理所需的任何自定义，例如管理模板引擎配置）。 以下示例显示了如何执行此操作：

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

## 1.9.4 JSON and XML

出于内容协商的目的，根据客户端请求的内容类型，能够在使用HTML模板呈现模型或以其他格式（例如JSON或XML）呈现模型之间进行切换非常有用。为了支持此操作，Spring WebFlux提供了HttpMessageWriterView，您可以使用它插入spring-web中的任何可用编解码器，例如Jackson2JsonEncoder，Jackson2SmileEncoder或Jaxb2XmlEncoder。

与其他视图技术不同，HttpMessageWriterView不需要ViewResolver，而是配置为默认视图。您可以配置一个或多个此类默认视图，并包装不同的HttpMessageWriter实例或Encoder实例。在运行时使用与请求的内容类型匹配的内容。

在大多数情况下，模型包含多个属性。要确定要序列化的对象，可以使用模型属性的名称配置HttpMessageWriterView进行渲染。如果模型仅包含一个属性，则使用该属性。
