檢視技術

Spring WebFlux 中的檢視渲染是可插拔的。您決定使用 Thymeleaf、FreeMarker 還是其他檢視技術主要取決於配置更改。本章涵蓋了與 Spring WebFlux 整合的檢視技術。

有關檢視渲染的更多上下文,請參閱 檢視解析

Spring WebFlux 應用程式的檢視位於應用程式的內部信任邊界內。檢視可以訪問應用程式上下文中的 Bean,因此,我們不建議在模板可由外部源編輯的應用程式中使用 Spring WebFlux 模板支援,因為這可能會帶來安全隱患。

Thymeleaf

Thymeleaf 是一種現代的伺服器端 Java 模板引擎,它強調自然的 HTML 模板,可以透過雙擊在瀏覽器中預覽,這對於獨立處理 UI 模板(例如,由設計師)而無需執行伺服器非常有幫助。Thymeleaf 提供了一整套功能,並且正在積極開發和維護。有關更完整的介紹,請參閱 Thymeleaf 專案主頁。

Thymeleaf 與 Spring WebFlux 的整合由 Thymeleaf 專案管理。配置涉及一些 bean 宣告,例如 SpringResourceTemplateResolverSpringWebFluxTemplateEngineThymeleafReactiveViewResolver。有關更多詳細資訊,請參閱 Thymeleaf+Spring 和 WebFlux 整合 公告

FreeMarker

Apache FreeMarker 是一種模板引擎,用於生成從 HTML 到電子郵件等各種文字輸出。Spring Framework 內建了使用 Spring WebFlux 與 FreeMarker 模板的整合。

檢視配置

以下示例展示瞭如何將 FreeMarker 配置為檢視技術

  • Java

  • Kotlin

@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("classpath:/templates/freemarker");
		return configurer;
	}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

	override fun configureViewResolvers(registry: ViewResolverRegistry) {
		registry.freeMarker()
	}

	// Configure FreeMarker...

	@Bean
	fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
		setTemplateLoaderPath("classpath:/templates/freemarker")
	}
}

您的模板需要儲存在由 FreeMarkerConfigurer 指定的目錄中,如前面的示例所示。根據前面的配置,如果您的控制器返回檢視名稱 welcome,解析器將查詢 classpath:/templates/freemarker/welcome.ftl 模板。

FreeMarker 配置

您可以透過在 FreeMarkerConfigurer bean 上設定適當的 bean 屬性,將 FreeMarker 'Settings' 和 'SharedVariables' 直接傳遞給 FreeMarker Configuration 物件(由 Spring 管理)。freemarkerSettings 屬性需要一個 java.util.Properties 物件,而 freemarkerVariables 屬性需要一個 java.util.Map。以下示例展示瞭如何使用 FreeMarkerConfigurer

  • Java

  • Kotlin

@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
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

	// ...

	@Bean
	fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
		setTemplateLoaderPath("classpath:/templates")
		setFreemarkerVariables(mapOf("xml_escape" to XmlEscape()))
	}
}

有關設定和變數如何應用於 Configuration 物件的詳細資訊,請參閱 FreeMarker 文件。

表單處理

Spring 提供了一個用於 JSP 的標籤庫,其中包含 <spring:bind/> 元素。此元素主要允許表單顯示來自表單支援物件的值,並顯示來自 Web 或業務層的 Validator 失敗驗證的結果。Spring 還支援 FreeMarker 中的相同功能,並提供額外的便捷宏來生成表單輸入元素本身。

繫結宏

Spring-webflux.jar 檔案中為 FreeMarker 維護了一組標準宏,因此它們始終可用於適當配置的應用程式。

Spring 模板庫中定義的一些宏被認為是內部(私有)的,但在宏定義中不存在這樣的作用域,這使得所有宏對呼叫程式碼和使用者模板都可見。以下部分只關注您需要直接從模板中呼叫的宏。如果您希望直接檢視宏程式碼,該檔名為 spring.ftl,位於 org.springframework.web.reactive.result.view.freemarker 包中。

有關繫結支援的更多詳細資訊,請參閱 Spring MVC 的 簡單繫結

表單宏

有關 Spring 對 FreeMarker 模板的表單宏支援的詳細資訊,請查閱 Spring MVC 文件的以下部分。

指令碼檢視

Spring Framework 內建了與任何可在 JSR-223 Java 指令碼引擎上執行的模板庫一起使用 Spring WebFlux 的整合。下表顯示了我們在不同指令碼引擎上測試過的模板庫

指令碼庫 指令碼引擎

Handlebars

Nashorn

Mustache

Nashorn

React

Nashorn

EJS

Nashorn

ERB

JRuby

字串模板

Jython

Kotlin 指令碼模板

Kotlin

整合任何其他指令碼引擎的基本規則是它必須實現 ScriptEngineInvocable 介面。

要求

您需要在類路徑中包含指令碼引擎,具體細節因指令碼引擎而異

  • Nashorn JavaScript 引擎隨 Java 8+ 提供。強烈建議使用最新的可用更新版本。

  • JRuby 應作為 Ruby 支援的依賴項新增。

  • Jython 應作為 Python 支援的依賴項新增。

  • org.jetbrains.kotlin:kotlin-script-util 依賴項和包含 org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory 行的 META-INF/services/javax.script.ScriptEngineFactory 檔案應新增以支援 Kotlin 指令碼。有關更多詳細資訊,請參閱 此示例

您需要指令碼模板庫。對於 JavaScript,一種方法是透過 WebJars

指令碼模板

您可以宣告一個 ScriptTemplateConfigurer bean 來指定要使用的指令碼引擎、要載入的指令碼檔案、要呼叫以渲染模板的函式等。以下示例使用 Mustache 模板和 Nashorn JavaScript 引擎

  • Java

  • Kotlin

@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;
	}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

	override fun configureViewResolvers(registry: ViewResolverRegistry) {
		registry.scriptTemplate()
	}

	@Bean
	fun configurer() = ScriptTemplateConfigurer().apply {
		engineName = "nashorn"
		setScripts("mustache.js")
		renderObject = "Mustache"
		renderFunction = "render"
	}
}

render 函式使用以下引數呼叫

  • String template:模板內容

  • Map model:檢視模型

  • RenderingContext renderingContextRenderingContext,它提供對應用程式上下文、區域設定、模板載入器和 URL 的訪問(自 5.0 起)

Mustache.render() 原生相容此簽名,因此您可以直接呼叫它。

如果您的模板技術需要一些定製,您可以提供一個實現自定義渲染功能的指令碼。例如,Handlerbars 需要在使用模板之前對其進行編譯,並且需要一個 polyfill 來模擬伺服器端指令碼引擎中不可用的一些瀏覽器功能。以下示例顯示瞭如何設定自定義渲染函式

  • Java

  • Kotlin

@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;
	}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

	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 上執行的 Handlebars 或 React)時,需要將 sharedEngine 屬性設定為 false。在這種情況下,由於 此錯誤,需要 Java SE 8 update 60,但通常建議在任何情況下都使用最新的 Java SE 補丁版本。

polyfill.js 只定義 Handlebars 正常執行所需的 window 物件,如下面的程式碼片段所示

var window = {};

此基本的 render.js 實現在使用模板之前對其進行編譯。一個生產就緒的實現還應該儲存和重用快取的模板或預編譯的模板。這可以在指令碼端完成,也可以完成您需要的任何定製(例如管理模板引擎配置)。以下示例顯示瞭如何編譯模板

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

檢視 Spring Framework 單元測試,Java資源,以獲取更多配置示例。

HTML 片段

HTMXHotwire Turbo 強調 HTML-over-the-wire 方法,其中客戶端以 HTML 而非 JSON 接收伺服器更新。這允許獲得 SPA(單頁應用)的好處,而無需編寫太多甚至任何 JavaScript。要獲得良好的概述並瞭解更多資訊,請訪問其各自的網站。

在 Spring WebFlux 中,檢視渲染通常涉及指定一個檢視和一個模型。然而,在 HTML-over-the-wire 中,常見的功能是傳送多個 HTML 片段,瀏覽器可以使用這些片段更新頁面的不同部分。為此,控制器方法可以返回 Collection<Fragment>。例如

  • Java

  • Kotlin

@GetMapping
List<Fragment> handle() {
	return List.of(Fragment.create("posts"), Fragment.create("comments"));
}
@GetMapping
fun handle(): List<Fragment> {
	return listOf(Fragment.create("posts"), Fragment.create("comments"))
}

透過返回專用型別 FragmentsRendering 也可以實現相同的功能

  • Java

  • Kotlin

@GetMapping
FragmentsRendering handle() {
	return FragmentsRendering.fragment("posts").fragment("comments").build();
}
@GetMapping
fun handle(): FragmentsRendering {
	return FragmentsRendering.fragment("posts").fragment("comments").build()
}

每個片段可以有一個獨立模型,並且該模型繼承請求的共享模型中的屬性。

HTMX 和 Hotwire Turbo 支援透過 SSE(伺服器傳送事件)進行流式更新。控制器可以使用 Flux<Fragment> 建立 FragmentsRendering,或者透過 ReactiveAdapterRegistry 將任何其他反應式生產者適應於 Reactive Streams Publisher。也可以直接返回 Flux<Fragment> 而無需 FragmentsRendering 包裝器。

JSON 和 XML

出於 內容協商 目的,根據客戶端請求的內容型別,能夠交替使用 HTML 模板渲染模型或以其他格式(如 JSON 或 XML)渲染模型非常有用。為了支援這樣做,Spring WebFlux 提供了 HttpMessageWriterView,您可以使用它來插入 spring-web 中的任何可用 編解碼器,例如 Jackson2JsonEncoderJackson2SmileEncoderJaxb2XmlEncoder

與其他檢視技術不同,HttpMessageWriterView 不需要 ViewResolver,而是 配置 為預設檢視。您可以配置一個或多個這樣的預設檢視,包裝不同的 HttpMessageWriter 例項或 Encoder 例項。與請求的內容型別匹配的例項將在執行時使用。

在大多數情況下,模型包含多個屬性。為了確定要序列化哪個屬性,您可以使用用於渲染的模型屬性的名稱來配置 HttpMessageWriterView。如果模型只包含一個屬性,則使用該屬性。

© . This site is unofficial and not affiliated with VMware.