--- title: Spring MVC 之视图技术 date: 2023-02-17 11:21:25 order: 06 categories: - Java - 框架 - Spring - SpringWeb tags: - Java - 框架 - Spring - Web - View permalink: /pages/264d3a22/ --- # Spring MVC 之视图技术 Spring MVC 中视图技术的使用是可插拔的。无论决定使用 Thymeleaf、Groovy 等模板引擎、JSP 还是其他技术,都可以通过配置来更改。 Spring MVC 的视图位于该应用程序的内部信任边界内。 视图可以访问应用程序上下文的所有 bean。 因此,不建议在模板可由外部源编辑的应用程序中使用 Spring MVC 的模板支持,因为这可能会产生安全隐患。 ## Thymeleaf [Thymeleaf](https://www.thymeleaf.org/) 是一个现代服务器端 Java 模板引擎,它强调自然的 HTML 模板,可以通过双击在浏览器中预览,而无需运行服务器,这对于 UI 模板的独立工作(例如,由设计师)非常有帮助。 Thymeleaf 与 Spring MVC 的集成由 Thymeleaf 项目管理。 配置涉及一些 bean 声明,例如 `ServletContextTemplateResolver`、`SpringTemplateEngine` 和 `ThymeleafViewResolver`。 有关详细信息,请参阅 [Thymeleaf+Spring](https://www.thymeleaf.org/documentation.html)。 ## FreeMarker [Apache FreeMarker](https://freemarker.apache.org/) 是一个模板引擎,用于生成从 HTML 到电子邮件等任何类型的文本内容。 Spring 框架内置了 Spring MVC 与 FreeMarker 模板结合使用的集成。 ### 视图配置 以下示例显示了如何将 FreeMarker 配置为视图技术: ```java @Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { @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; } } ``` 以下示例显示了如何在 XML 中配置相同的内容: ```xml ``` 或者,您也可以声明 `FreeMarkerConfigurer` 以完全控制所有属性,如以下示例所示: ```xml ``` 您的模板需要存储在前面示例中所示的 `FreeMarkerConfigurer` 指定的目录中。鉴于前面的配置,如果您的控制器返回视图名称 `welcome`,解析器将查找 `/WEB-INF/freemarker/welcome.ftl` 模板。 ### FreeMarker 配置 可以通过在 `FreeMarkerConfigurer` 上设置适当的 bean 属性,将 FreeMarker 'Settings' 和 'SharedVariables' 直接传递给 FreeMarker `Configuration` 对象(由 Spring 管理)。 `freemarkerSettings` 属性需要一个 `java.util.Properties` 对象,`freemarkerVariables` 属性需要一个 `java.util.Map`。 以下示例显示了如何使用 `FreeMarkerConfigurer`: ```xml ``` 有关应用于 `Configuration` 对象的设置和变量的详细信息,请参阅 FreeMarker 文档。 ### 表单处理 Spring 提供了一个用于 JSP 的标记库,其中包含一个 `` 元素。 此元素主要让表单显示来自表单支持对象的值,并显示来自 Web 或业务层中的“验证器”的验证失败的结果。 Spring 还支持 FreeMarker 中的相同功能,以及用于生成表单输入元素的额外便利宏。 #### 绑定宏 在 FreeMarker 的 `spring-webmvc.jar` 文件中维护了一组标准宏,因此它们始终可用于适当配置的应用程序。 Spring 模板库中定义的一些宏被认为是内部的(私有的),但宏定义中不存在这样的范围,这使得所有宏对调用代码和用户模板都是可见的。以下部分仅关注您需要从模板中直接调用的宏。如果您想直接查看宏代码,该文件名为 `spring.ftl` ,位于 `org.springframework.web.servlet.view.freemarker` 包中。 #### 简单绑定 在基于充当 Spring MVC 控制器表单视图的 FreeMarker 模板的 HTML 表单中,您可以使用类似于下一个示例的代码来绑定到字段值,并以类似于 JSP 等价物的方式为每个输入字段显示错误消息。以下示例显示了一个 personForm 视图: ```xml <#import "/spring.ftl" as spring/> ...
Name: <@spring.bind "personForm.name"/>
<#list spring.status.errorMessages as error> ${error}

...
... ``` `<@spring.bind>` 需要一个 'path' 参数,它由命令对象的名称(它是 'command',除非您在控制器配置中更改它)组成,在您希望绑定的命令对象后跟一个句点和字段名称。 您还可以使用嵌套字段,例如 `command.address.street`。 `bind` 宏采用 `web.xml` 中的 `ServletContext` 参数 `defaultHtmlEscape` 指定的默认 HTML 转义行为。 称为 `<@spring.bindEscaped>` 的宏的另一种形式采用第二个参数,该参数明确指定是否应在状态错误消息或值中使用 HTML 转义。 您可以根据需要将其设置为 `true` 或 `false` 。 附加的表单处理宏简化了 HTML 转义的使用,您应该尽可能使用这些宏。 #### 输入宏 FreeMarker 的附加便利宏简化了绑定和表单生成(包括验证错误显示)。 永远不需要使用这些宏来生成表单输入字段,您可以将它们与简单的 HTML 混合搭配,或者直接调用我们之前强调的 Spring 绑定宏。 下表中的可用宏显示了 FreeMarker 模板 (FTL) 定义和每个采用的参数列表: | macro | FTL definition | | :------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------- | | `message` (output a string from a resource bundle based on the code parameter) | <@spring.message code/> | | `messageText` (output a string from a resource bundle based on the code parameter, falling back to the value of the default parameter) | <@spring.messageText code, text/> | | `url` (prefix a relative URL with the application’s context root) | <@spring.url relativeUrl/> | | `formInput` (standard input field for gathering user input) | <@spring.formInput path, attributes, fieldType/> | | `formHiddenInput` (hidden input field for submitting non-user input) | <@spring.formHiddenInput path, attributes/> | | `formPasswordInput` (standard input field for gathering passwords. Note that no value is ever populated in fields of this type.) | <@spring.formPasswordInput path, attributes/> | | `formTextarea` (large text field for gathering long, freeform text input) | <@spring.formTextarea path, attributes/> | | `formSingleSelect` (drop down box of options that let a single required value be selected) | <@spring.formSingleSelect path, options, attributes/> | | `formMultiSelect` (a list box of options that let the user select 0 or more values) | <@spring.formMultiSelect path, options, attributes/> | | `formRadioButtons` (a set of radio buttons that let a single selection be made from the available choices) | <@spring.formRadioButtons path, options separator, attributes/> | | `formCheckboxes` (a set of checkboxes that let 0 or more values be selected) | <@spring.formCheckboxes path, options, separator, attributes/> | | `formCheckbox` (a single checkbox) | <@spring.formCheckbox path, attributes/> | | `showErrors` (simplify display of validation errors for the bound field) | <@spring.showErrors separator, classOrStyle/> | 上述任何宏的参数具有一致的含义: - `path`: 要绑定到的字段的名称(例如,“command.name”) - `options`: 可在输入字段中选择的所有可用值的 `Map`。映射的键表示从表单回传并绑定到命令对象的值。针对键存储的 map 对象是在表单上显示给用户的标签,可能与表单回传的相应值不同。通常,这样的地图由控制器提供作为参考数据。您可以使用任何 `Map` 实现,具体取决于所需的行为。对于严格排序的映射,您可以使用带有合适的“比较器”的 `SortedMap`(例如 `TreeMap`),对于应按插入顺序返回值的任意映射,使用“LinkedHashMap”或“LinkedMap” `公共收藏`。 - `separator`: 在多个选项可用作离散元素(单选按钮或复选框)的情况下,用于分隔列表中每个选项的字符序列(例如 `
`)。 - `attributes`: 要包含在 HTML 标记本身中的任意标记或文本的附加字符串。该字符串按字面意思由宏回显。例如,在 `textarea` 字段中,您可以提供属性(例如“rows="5" cols="60"'),或者您可以传递样式信息,例如 'style="border:1px solid silver"'。 - `classOrStyle`: 对于 `showErrors` 宏,包装每个错误的 `span` 元素使用的 CSS 类的名称。如果未提供任何信息(或值为空),错误将包含在 `` 标签中。 以下部分概述了宏的示例。 输入字段 `formInput` 宏采用 `path` 参数 (`command.name`) 和一个额外的 `attributes` 参数(在接下来的示例中为空)。该宏与所有其他表单生成宏一起对路径参数执行隐式 Spring 绑定。绑定在新绑定发生之前一直有效,因此 `showErrors` 宏不需要再次传递路径参数——它对上次创建绑定的字段进行操作。 `showErrors` 宏接受一个分隔符参数(用于分隔给定字段上的多个错误的字符),还接受第二个参数——这次是类名或样式属性。请注意,FreeMarker 可以为 attributes 参数指定默认值。以下示例显示了如何使用 `formInput` 和 `showErrors` 宏: ```xml <@spring.formInput "command.name"/> <@spring.showErrors "
"/> ``` 下一个示例显示表单片段的输出,生成名称字段并在表单提交后显示验证错误,该字段中没有任何值。验证通过 Spring 的验证框架进行。 生成的 HTML 类似于以下示例: ```html Name:
required

``` `formTextarea` 宏的工作方式与 `formInput` 宏相同,并且接受相同的参数列表。通常,第二个参数 (`attributes`) 用于传递样式信息或 `textarea` 的 `rows` 和 `cols` 属性。 选中字段 您可以使用四个选择字段宏在 HTML 表单中生成常见的 UI 值选择输入: - `formSingleSelect` - `formMultiSelect` - `formRadioButtons` - `formCheckboxes` 四个宏中的每一个都接受一个“Map”选项,其中包含表单字段的值和与该值对应的标签。值和标签可以相同。 下一个例子是 FTL 中的单选按钮。表单支持对象为此字段指定默认值“伦敦”,因此无需验证。渲染表单时,整个可供选择的城市列表作为参考数据提供在模型中,名称为 `cityMap`。以下清单显示了示例: ```html ... Town: <@spring.formRadioButtons "command.address.town", cityMap, ""/>

``` 前面的清单呈现一行单选按钮,一个用于 `cityMap` 中的每个值,并使用分隔符 `""`。没有提供额外的属性(缺少宏的最后一个参数)。 `cityMap` 对地图中的每个键值对使用相同的 `String`。地图的键是表单实际作为 POST 请求参数提交的内容。地图值是用户看到的标签。在前面的示例中,给定三个知名城市的列表和表单支持对象中的默认值,HTML 类似于以下内容: ```html Town: London Paris New York ``` 如果您的应用程序希望通过内部代码处理城市(例如),您可以使用合适的键创建代码映射,如以下示例所示: ```java protected Map referenceData(HttpServletRequest request) throws Exception { Map cityMap = new LinkedHashMap<>(); cityMap.put("LDN", "London"); cityMap.put("PRS", "Paris"); cityMap.put("NYC", "New York"); Map model = new HashMap<>(); model.put("cityMap", cityMap); return model; } ``` 代码现在生成输出,其中无线电值是相关代码,但用户仍然看到更用户友好的城市名称,如下所示: ```html Town: London Paris New York ``` #### HTML 转义 前面描述的表单宏的默认使用导致 HTML 元素符合 HTML 4.01,并且使用 `web.xml` 文件中定义的 HTML 转义的默认值,如 Spring 的绑定支持所使用的那样。 要使元素符合 XHTML 或覆盖默认的 HTML 转义值,您可以在模板中指定两个变量(或在模型中,它们对模板可见)。 在模板中指定它们的好处是它们可以在稍后的模板处理中更改为不同的值,以便为表单中的不同字段提供不同的行为。 要为您的标签切换到 XHTML 合规性,请为名为 `xhtmlCompliant` 的模型或上下文变量指定 `true` 值,如以下示例所示: ```html <#-- for FreeMarker --> <#assign xhtmlCompliant = true> ``` 处理此指令后,Spring 宏生成的任何元素现在都符合 XHTML。 以类似的方式,您可以为每个字段指定 HTML 转义,如以下示例所示: ```html <#-- until this point, default HTML escaping is used --> <#assign htmlEscape = true> <#-- next field will use HTML escaping --> <@spring.formInput "command.name"/> <#assign htmlEscape = false in spring> <#-- all future fields will be bound with HTML escaping off --> ``` ## Groovy [Groovy 标记模板引擎](https://groovy-lang.org/templating.html#_the_markuptemplateengine) 主要用于生成类似 XML 的标记(XML、XHTML、HTML5 等),但可以使用它来生成任何基于文本的内容。 Spring Framework 具有将 Spring MVC 与 Groovy 标记结合使用的内置集成。 ### 配置 以下示例显示如何配置 Groovy 标记模板引擎: ```java @Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { @Override public void configureViewResolvers(ViewResolverRegistry registry) { registry.groovy(); } // Configure the Groovy Markup Template Engine... @Bean public GroovyMarkupConfigurer groovyMarkupConfigurer() { GroovyMarkupConfigurer configurer = new GroovyMarkupConfigurer(); configurer.setResourceLoaderPath("/WEB-INF/"); return configurer; } } ``` 以下示例显示了如何在 XML 中配置相同的内容: ```xml ``` ### 示例 与传统的模板引擎不同,Groovy 标记依赖于使用构建器语法的 DSL。以下示例显示了 HTML 页面的示例模板: ```groovy yieldUnescaped '' html(lang:'en') { head { meta('http-equiv':'"Content-Type" content="text/html; charset=utf-8"') title('My page') } body { p('This is an example of HTML contents') } } ``` ## 脚本视图 Spring 有一个内置的集成,可以将 Spring MVC 与任何可以在 [JSR-223](https://www.jcp.org/en/jsr/detail?id=223) 之上运行的模板库一起使用 Java 脚本引擎。 我们在不同的脚本引擎上测试了以下模板库: | 脚本库 | 脚本引擎 | | :--------------------------------------------------------------------------------- | :---------------------------------------------------- | | [Handlebars](https://handlebarsjs.com/) | [Nashorn](https://openjdk.java.net/projects/nashorn/) | | [Mustache](https://mustache.github.io/) | [Nashorn](https://openjdk.java.net/projects/nashorn/) | | [React](https://facebook.github.io/react/) | [Nashorn](https://openjdk.java.net/projects/nashorn/) | | [EJS](https://www.embeddedjs.com/) | [Nashorn](https://openjdk.java.net/projects/nashorn/) | | [ERB](https://www.stuartellis.name/articles/erb/) | [JRuby](https://www.jruby.org/) | | [String templates](https://docs.python.org/2/library/string.html#template-strings) | [Jython](https://www.jython.org/) | | [Kotlin Script templating](https://github.com/sdeleuze/kotlin-script-templating) | [Kotlin](https://kotlinlang.org/) | ### 要求 需要在类路径中包含脚本引擎,具体细节因脚本引擎而异: - The [Nashorn](https://openjdk.java.net/projects/nashorn/) Java 8+ 提供了 JavaScript 引擎。强烈建议使用可用的最新更新版本。 - [JRuby](https://www.jruby.org/) 应该作为 Ruby 支持的依赖项添加。 - [Jython](https://www.jython.org/) 应该作为 Python 支持的依赖项添加。 - `org.jetbrains.kotlin:kotlin-script-util` 依赖项和包含 `org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory` 行的 `META-INF/services/javax.script.ScriptEngineFactory` 文件应该被添加 Kotlin 脚本支持。 有关详细信息,请参阅[此示例](https://github.com/sdeleuze/kotlin-script-templating)。 您需要有脚本模板库。 为 JavaScript 做到这一点的一种方法是通过 [WebJars](https://www.webjars.org/)。 ### 脚本模板 可以声明一个 `ScriptTemplateConfigurer` 来指定要使用的脚本引擎、要加载的脚本文件、调用什么函数来渲染模板等等。 以下示例使用 Mustache 模板和 Nashorn JavaScript 引擎: ```java @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; } } ``` 以下示例显示了 XML 中的相同配置: ```xml ``` 对于 Java 和 XML 配置,controller 看起来没有什么不同,如以下示例所示: ```java @Controller public class SampleController { @GetMapping("/sample") public String test(Model model) { model.addAttribute("title", "Sample title"); model.addAttribute("body", "Sample body"); return "template"; } } ``` 以下示例显示了 Mustache 模板: ```html {{title}}

{{body}}

``` 使用以下参数调用渲染函数: - `String template`: 模板内容 - `地图模型`:视图模型 - `RenderingContext renderingContext`: [`RenderingContext`](https://docs.spring.io/spring-framework/docs/6.0.5/javadoc-api/org/springframework/web/servlet/view/script/RenderingContext.html) 允许访问应用上下文、语言环境、模板加载器和 URL(自 5.0 起) 如果您的模板技术需要一些自定义,您可以提供一个实现自定义渲染功能的脚本。 例如,[Handlerbars](https://handlebarsjs.com/) 需要在使用之前编译模板,并且需要一个 [polyfill](https://en.wikipedia.org/wiki/Polyfill) 来模拟一些浏览器工具,但在服务器端脚本引擎中不可用。 以下示例显示了如何执行此操作: ```java @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; } } ``` `polyfill.js` 只定义了 Handlebars 正常运行所需的 `window` 对象,如下: ```javascript var window = {} ``` 这个基本的 `render.js` 实现在使用之前编译模板。 生产就绪的实现还应该存储任何重复使用的缓存模板或预编译模板。 您可以在脚本端这样做(并处理您需要的任何定制——管理模板引擎配置,例如)。 以下示例显示了如何执行此操作: ```javascript function render(template, model) { var compiledTemplate = Handlebars.compile(template) return compiledTemplate(model) } ``` 查看 Spring Framework 单元测试,[Java](https://github.com/spring-projects/spring-framework/tree/main/spring-webmvc/src/test/java/org/springframework/web/servlet/view/script) 和[资源](https://github.com/spring-projects/spring-framework/tree/main/spring-webmvc/src/test/resources/org/springframework/web/servlet/view/script),以获取更多配置示例。 ## JSP 和 JSTL Spring Framework 具有将 Spring MVC 与 JSP 和 JSTL 结合使用的内置集成。 > 更多内容详见:[Spring 官方文档之 JSP and JSTL](https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-view-jsp) ## RSS and Atom `AbstractAtomFeedView` 和 `AbstractRssFeedView` 都继承自 `AbstractFeedView` 基类,分别用于提供 Atom 和 RSS Feed 视图。 它们基于 [ROME](https://rometools.github.io/rome/) 项目,位于 org.springframework.web.servlet.view.feed 包中。 `AbstractAtomFeedView` 要求您实现 `buildFeedEntries()` 方法并可选择覆盖 `buildFeedMetadata()` 方法(默认实现为空)。 以下示例显示了如何执行此操作: ```java public class SampleContentAtomView extends AbstractAtomFeedView { @Override protected void buildFeedMetadata(Map model, Feed feed, HttpServletRequest request) { // implementation omitted } @Override protected List buildFeedEntries(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { // implementation omitted } } ``` 类似的要求适用于实现 `AbstractRssFeedView`,如以下示例所示: ```java public class SampleContentRssView extends AbstractRssFeedView { @Override protected void buildFeedMetadata(Map model, Channel feed, HttpServletRequest request) { // implementation omitted } @Override protected List buildFeedItems(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { // implementation omitted } } ``` `buildFeedItems()` 和 `buildFeedEntries()` 方法传入 HTTP 请求,以防您需要访问 Locale。 传入 HTTP 响应仅用于设置 cookie 或其他 HTTP 标头。 方法返回后,提要会自动写入响应对象。 有关创建 Atom 视图的示例,请参阅 Alef Arendsen 的 Spring Team 博客 [entry](https://spring.io/blog/2009/03/16/adding-an-atom-view-to-an-application-using-spring-s-rest-support)。 ## PDF and Excel Spring 提供了返回 HTML 以外的输出的方法,包括 PDF 和 Excel 电子表格。 ### 文档视图简介 HTML 页面并不总是用户查看模型输出的最佳方式,Spring 使从模型数据动态生成 PDF 文档或 Excel 电子表格变得简单。 该文档是视图,从服务器流出正确的内容类型,(希望)使客户端 PC 能够运行他们的电子表格或 PDF 查看器应用程序作为响应。 为了使用 Excel 视图,您需要将 Apache POI 库添加到类路径中。 对于 PDF 生成,您需要添加(最好)OpenPDF 库。 ### PDF 视图 单词列表的简单 PDF 视图可以扩展 `org.springframework.web.servlet.view.document.AbstractPdfView` 并实现 `buildPdfDocument()` 方法,如以下示例所示: ```java public class PdfWordList extends AbstractPdfView { protected void buildPdfDocument(Map model, Document doc, PdfWriter writer, HttpServletRequest request, HttpServletResponse response) throws Exception { List words = (List) model.get("wordList"); for (String word : words) { doc.add(new Paragraph(word)); } } } ``` 控制器可以从外部视图定义(按名称引用它)或作为处理程序方法的 `View` 实例返回此类视图。 ### Excel 视图 从 Spring Framework 4.2 开始,`org.springframework.web.servlet.view.document.AbstractXlsView` 作为 Excel 视图的基类提供。 它基于 Apache POI,具有专门的子类(`AbstractXlsxView` 和 `AbstractXlsxStreamingView`),取代了过时的 `AbstractExcelView` 类。 编程模型类似于 `AbstractPdfView`,以 `buildExcelDocument()` 作为核心模板方法,控制器能够从外部定义(按名称)或作为处理程序方法的 `View` 实例返回此类视图。 ## Jackson Spring 提供对 Jackson JSON 库的支持。 ### 基于 Jackson 的 JSON MVC 视图 `MappingJackson2JsonView` 使用 Jackson 库的 `ObjectMapper` 将响应内容渲染为 JSON。 默认情况下,模型映射的全部内容(特定于框架的类除外)都编码为 JSON。 对于需要过滤 map 内容的情况,您可以使用 `modelKeys` 属性指定一组特定的模型属性进行编码。 您还可以使用 `extractValueFromSingleKeyModel` 属性直接提取和序列化单键模型中的值,而不是作为模型属性的映射。 您可以根据需要使用 Jackson 提供的注释自定义 JSON 映射。 当您需要进一步控制时,您可以通过 `ObjectMapper` 属性注入自定义 `ObjectMapper`,适用于需要为特定类型提供自定义 JSON 序列化器和反序列化器的情况。 ### 基于 Jackson 的 XML 视图 `MappingJackson2XmlView` 使用 [Jackson XML 扩展](https://github.com/FasterXML/jackson-dataformat-xml) `XmlMapper` 将响应内容渲染为 XML。 如果模型包含多个条目,您应该使用 `modelKey` bean 属性显式设置要序列化的对象。 如果模型包含单个条目,它会自动序列化。 您可以根据需要使用 JAXB 或 Jackson 提供的注释自定义 XML 映射。当您需要进一步控制时,您可以通过 `ObjectMapper` 属性注入自定义 `XmlMapper`,对于需要为特定类型提供序列化器和反序列化器的自定义 XML 的情况 ## XML `MarshallingView` 使用 XML `Marshaller`(在 `org.springframework.oxm` 包中定义)将响应内容渲染为 XML。 您可以使用 `MarshallingView` 实例的 `modelKey` 属性显式设置要编组的对象。 或者,视图遍历所有模型属性并编组 `Marshaller` 支持的第一个类型。 有关 `org.springframework.oxm` 包中功能的更多信息,请参阅 [Marshalling XML using O/X Mappers](https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#oxm)。 ## XSLT XSLT 是 XML 的一种转换语言,作为 Web 应用程序中的一种视图技术很受欢迎。 如果您的应用程序自然地处理 XML,或者如果您的模型可以很容易地转换为 XML,那么 XSLT 作为一种视图技术是一个不错的选择。 以下部分展示了如何生成 XML 文档作为模型数据,并在 Spring Web MVC 应用程序中使用 XSLT 对其进行转换。 此示例是一个简单的 Spring 应用程序,它在 `Controller` 中创建关键字列表并将它们添加到模型映射中。 返回映射以及我们的 XSLT 视图的视图名称。 有关 Spring Web MVC 的 `Controller` 接口的详细信息,请参阅 [Annotated Controllers](https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-controller)。 XSLT 控制器将单词列表转换为准备转换的简单 XML 文档。 ### Beans 配置是一个简单的 Spring Web 应用程序的标准配置:MVC 配置必须定义一个 `XsltViewResolver` 和常规 MVC 注释配置。以下示例显示了如何执行此操作: ```java @EnableWebMvc @ComponentScan @Configuration public class WebConfig implements WebMvcConfigurer { @Bean public XsltViewResolver xsltViewResolver() { XsltViewResolver viewResolver = new XsltViewResolver(); viewResolver.setPrefix("/WEB-INF/xsl/"); viewResolver.setSuffix(".xslt"); return viewResolver; } } ``` ### Controller 我们还需要一个控制器来封装我们的单词生成逻辑。 控制器逻辑封装在一个 `@Controller` 类中,处理方法定义如下: ```java @Controller public class XsltController { @RequestMapping("/") public String home(Model model) throws Exception { Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); Element root = document.createElement("wordList"); List words = Arrays.asList("Hello", "Spring", "Framework"); for (String word : words) { Element wordNode = document.createElement("word"); Text textNode = document.createTextNode(word); wordNode.appendChild(textNode); root.appendChild(wordNode); } model.addAttribute("wordList", root); return "home"; } } ``` 到目前为止,我们只创建了一个 DOM 文档并将其添加到模型映射中。请注意,您还可以将 XML 文件作为 `Resource` 加载并使用它来代替自定义 DOM 文档。 有可用的软件包可以自动 'domify' 一个对象图,但是在 Spring 中,您可以完全灵活地以您选择的任何方式从您的模型创建 DOM。这可以防止 XML 的转换在模型数据的结构中发挥太大作用,这在使用工具管理 DOMification 过程时是一种危险。 ### Transformation 最后,`XsltViewResolver` 解析 “home” XSLT 模板文件并将 DOM 文档合并到其中以生成我们的视图。如 `XsltViewResolver` 配置所示,XSLT 模板位于 `WEB-INF/xsl` 目录下的 `war` 文件中,并以 `xslt` 文件扩展名结尾。 以下示例显示了 XSLT 转换: ```xml Hello!

My First Words

  • ``` 前面的转换渲染为以下 HTML: ```html Hello!

    My First Words

    • Hello
    • Spring
    • Framework
    ``` ## 参考资料 - [Spring Framework 官方文档](https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/index.html) - [Spring Framework 官方文档之 Web](https://docs.spring.io/spring-framework/docs/current/reference/html/web.html)