Spring 4 官方文档学习View技术

Posted LarryZeal

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring 4 官方文档学习View技术相关的知识,希望对你有一定的参考价值。

关键词:view technology、template、template engine、markup。内容较多,按需查用即可。

  1. 介绍
  2. Thymeleaf
  3. Groovy Markup Templates
    1. 配置
    2. 例子
  4. Velocity & FreeMarker
    1. 依赖
    2. Context配置 -- 上下文配置
    3. 创建模板
    4. 高级配置
      1. velocity.properties
      2. FreeMarker
    5. 绑定支持和form处理
      1. bind marcos -- 绑定宏
      2. simple binding -- 简单绑定
      3. form input generation marcos -- 生成表单输入的宏
      4. Input Fields
      5. Selection Fields
      6. HTML escaping and XHTML compliance -- HTML转义和XHTML兼容
  5. JSP & JSTL
    1. View resolvers -- 视图解析器
    2. ’Plain-old’ JSPs vs JSTL
    3. 额外的标签促进开发
    4. 使用Spring的form标签库
      1. Configuration
      2. The form tag
      3. The input tag
      4. The checkbox tag
      5. The checkboxes tag
      6. The radiobutton tag
      7. The radiobuttons tag
      8. The password tag
      9. The select tag
      10. The option tag
      11. The options tag
      12. The textarea tag
      13. The hidden tag
      14. The errors tag
      15. HTTP Method Conversion
      16. HTML5 Tags -- H5 标签
  6. Script templates
    1. 依赖
    2. 如何集成基于脚本的模板
  7. XML Marshalling View(暂空)
  8. Tiles(暂空)
  9. XSLT(暂空)
  10. Document views (PDF/Excel)(暂空)
  11. JasperReports(暂空)
  12. Feed Views(暂空)
  13. JSON Mapping View(暂空)
  14. XML Mapping View (暂空)

1、介绍

Spring 有很多优越的地方,其中一个就是将view技术与MVC框架的其他部分相隔离。例如,在JSP存在的情况下使用Groovy Markup Templates 还是使用Thymeleaf,仅仅是一个配置问题。

本章覆盖了主要的view技术,嗯嗯,可以与Spring结合的那些,并简明的说明了如何增加新的view技术。

本章假定你已经熟悉了Spring 4 官方文档学习(十一)Web MVC 框架之resolving views 解析视图 -- 它覆盖了views如何耦合到MVC框架的基础。

 

2、Thymeleaf

Thymeleaf是一个非常好的例子:view技术完美的嵌入MVC框架中。该集成的支持不是由Spring团队提供的,而是由Thymeleaf团队提供的。

 

为Spring配置Thymeleaf,只需要定义几个beans,例如一个ServletContextTemplateResolver、一个SpringTemplateEngine、一个ThymeleafViewResolver。 详见Thymeleaf+Spring

 

3、Groovy Markup Templates

Groovy Markup Template Engine 是Spring支持的另一个view技术。该模板引擎的主要目标是生成 类XML (XML, Xhtml, HTML5,...)的标记,也可以被用于生成任意基于文本的内容。

嗯嗯,要求classpath中有 Groovy 2.3.1+。

 

3.1、配置

配置Groovy Markup Template Engine 非常简单:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

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

    @Bean
    public GroovyMarkupConfigurer groovyMarkupConfigurer() {
        GroovyMarkupConfigurer configurer = new GroovyMarkupConfigurer();
        configurer.setResourceLoaderPath("/WEB-INF/");
        return configurer;
    }
}

使用MVC namespace的XML 也类似:

<mvc:annotation-driven/>

<mvc:view-resolvers>
    <mvc:groovy/>
</mvc:view-resolvers>

<mvc:groovy-configurer resource-loader-path="/WEB-INF/"/>

 

3.2、例子

不像传统的模板引擎,这个引擎(Groovy)依赖于DSL -- DSL使用了builder syntax。 下面是一个HTML页面的简单模板:

yieldUnescaped \'<!DOCTYPE html>\'
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\')
    }
}

 

4、Velocity & FreeMarker

VelocityFreeMarker是模板语言,可被用作Spring MVC application中的view技术。它们是非常相似的,并且服务于相似的需要,因此本部分将二者放在一起。关于二者的语法和语义的区别,见FreeMarker站点。

自Spring Framework 4.3起,对Velocity的支持已经是deprecated的了,原因是Apache Velocity project已经有6年没有活动的维护了!我们推荐Spring的FreeMarker支持,或者Thymeleaf--其自身带有Spring支持。

 

4.1、依赖

如果想使用Velocity或FreeMarker,你的web应用应该包含velocity-1.x.x.jar or freemarker-2.x.jar,另外,Velocity还需要commons-collections.jar。通常它们会被放在 WEB-INF/lib 文件夹中 -- 该位置会由Java EE server自动发现并添加到应用的classpath中。当然,我们也假定你已经添加了spring-webmvc.jar。另外,如果想在Velocity views中使用Spring的dateToolAttribute 或 numberToolAttribute,还需要添加velocity-tools-generic-1.x.jar

 

4.2、Context配置 -- 上下文配置

一个合适的配置是这样来初始化的--通过在你的 *-servlet.xml 中添加相关的configurer bean definition,如下:

<!--
这个bean设置了Velocity环境--基于模板的一个root path。也可以在一个properties文件中指定更多的控制,但默认的已经很好了。
This bean sets up the Velocity environment for us based on a root path for templates.
Optionally, a properties file can be specified for more control over the Velocity
environment, but the defaults are pretty sane for file based template loading.
-->
<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
    <property name="resourceLoaderPath" value="/WEB-INF/velocity/"/>
</bean>

<!--
View resolvers can also be configured with ResourceBundles or XML files. If you need
different view resolving based on Locale, you have to use the resource bundle resolver.
-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
    <property name="cache" value="true"/>
    <property name="prefix" value=""/>
    <property name="suffix" value=".vm"/>
</bean>
<!-- freemarker config -->
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
    <property name="templateLoaderPath" value="/WEB-INF/freemarker/"/>
</bean>

<!--
View resolvers can also be configured with ResourceBundles or XML files. If you need
different view resolving based on Locale, you have to use the resource bundle resolver.
-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
    <property name="cache" value="true"/>
    <property name="prefix" value=""/>
    <property name="suffix" value=".ftl"/>
</bean>

提示:对于非web的应用,添加一个 VelocityConfigurationFactoryBeanFreeMarkerConfigurationFactoryBean 即可。-- Java-based config >> @Configuration classes。

 

4.3、创建模板

你的模板需要保存在一个目录中 -- 该目录由上面提到的 *Configurer bean指定!

本文档不涉及创建模板的细节 -- 有兴趣可以去看相关的站点。

如果你使用了上面提到的view resolvers,那么逻辑视图名会关联到模板文件名 -- 类似于InternalResourceViewResolver之于JSP。所以,当你的controller返回了一个包含welcome 视图名的ModelAndView对象时,该resolver会查找 /WEB-INF/freemarker/welcome.ftl/WEB-INF/velocity/welcome.vm 模板。

 

4.4、高级配置

上面提到的基本配置适用于大多数应用需求,除此之外,还有一些配置选项 -- 适用于不常见或者高级的需求。

 

velocity.properties

该文件完全是可选的,如果指定了,那其中的值会被传给Velocity runtime,从而配置velocity。只有高级配置时才需要,如果你需要,在VelocityConfigurer bean definition中指定其位置即可。如下:

<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
    <property name="configLocation" value="/WEB-INF/velocity.properties"/>
</bean>

或者,也可以这样指定:

<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
    <property name="velocityProperties">
        <props>
            <prop key="resource.loader">file</prop>
            <prop key="file.resource.loader.class">
                org.apache.velocity.runtime.resource.loader.FileResourceLoader
            </prop>
            <prop key="file.resource.loader.path">${webapp.root}/WEB-INF/velocity</prop>
            <prop key="file.resource.loader.cache">false</prop>
        </props>
    </property>
</bean>

详见API documentation

 

FreeMarker

通过设置FreeMarkerConfigurer bean的properties,即可将FreeMarker的 Settings 和 SharedVariables 可以被直接传给FreeMarker的Configuration对象(由Spring管理)。freemarkerSettings property需要一个java.util.Properties对象;freemarkerVariables则需要一个java.util.Map!如下:

<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
    <property name="templateLoaderPath" value="/WEB-INF/freemarker/"/>
    <property name="freemarkerVariables">
        <map>
            <entry key="xml_escape" value-ref="fmXmlEscape"/>
        </map>
    </property>
</bean>

<bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape"/>

详见FreeMarker文档。

 

4.5、绑定支持和form处理

Spring提供了在JSP中使用的一个标签库,其中有一个<spring:bind/>标签。该标签主要是让form显示来自form backing objects的值、显示Validator校验失败的结果。从版本1.1开始,Spring在Velocity和FreeMarker中支持同样的功能 -- 带有额外的便捷的宏,用于生成form input元素。 -- 几个意思?

 

bind marcos -- 绑定宏

spring-webmvc.jar中维持了宏的一个标准集合,可以用于二者(Velocity和FreeMarker)。

Spring库中定义的一些宏被认为是内部的(私有的),但在宏定义中不存在该scope,所以,所有的宏都是可见的。

下面的部分将专注于在模板内直接调用的那些宏。如果你想看一下这些宏代码,它们位于 org.springframework.web.servlet.view.velocityorg.springframework.web.servlet.view.freemarker 包中,名字是spring.vm / spring.ftl。

 

simple binding -- 简单绑定

在你的HTML forms (vm / ftl 模板)中,你可以使用类似下面的代码来为每一个input field绑定field values、显示错误信息 -- 类似于JSP。嗯嗯,此时这些HTML forms (vm / ftl 模板)是作为Spring MVC controller的一种form view。 -- 明明是模板形式的HTML表单!

下面的例子是配合上面提到的 personFormV/personFormF views :

<!-- velocity macros are automatically available -->
<html>
    ...
    <form action="" method="POST">
        Name:
        #springBind("myModelObject.name")
        <input type="text"
            name="${status.expression}"
            value="$!status.value"/><br>
        #foreach($error in $status.errorMessages) <b>$error</b> <br> #end
        <br>
        ...
        <input type="submit" value="submit"/>
    </form>
    ...
</html>
<!-- freemarker macros have to be imported into a namespace. We strongly
recommend sticking to \'spring\' -->
<#import "/spring.ftl" as spring/>
<html>
    ...
    <form action="" method="POST">
        Name:
        <@spring.bind "myModelObject.name"/>
        <input type="text"
            name="${spring.status.expression}"
            value="${spring.status.value?html}"/><br>
        <#list spring.status.errorMessages as error> <b>${error}</b> <br> </#list>
        <br>
        ...
        <input type="submit" value="submit"/>
    </form>
    ...
</html>

 

#springBind / <@spring.bind> 需要一个path argument,该argument由你的命令对象的名字(默认为command,可另行指定)、句点、还有你想绑定的field的名字组成。嵌套的field也可以使用,类似于"command.address.street"。bind 宏假定默认的HTML转义行为由web.xml中ServletContext的defaultHtmlEscape 参数指定。

 

该宏的可选form叫做#springBindEscaped / <@spring.bindEscaped>,会接收第二个参数,并显式的指定HTML转义是否用在status error messages 或 values中。如果设为true或false。额外的form处理宏简化了HTML转义的使用,所以,只要合适就用吧。下一部分会有解释。

 

form input generation marcos -- 生成表单输入的宏

其他便捷的宏简化了二者绑定和表单的生成(包括校验错误显示)。

只是,使用这些宏来生成表单输入字段永远不是必要,可以混合使用它们,或者直接调用spring bind marcos。

 

下面的表格是可用宏的表格,列出了VTL和FTL定义,以及其相应的参数列表。

Table 23.1. Table of macro definitions

macro VTL definition FTL definition

message (output a string from a resource bundle based on the code parameter)

#springMessage($code)

<@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)

#springMessageText($code $text)

<@spring.messageText code, text/>

url (prefix a relative URL with the application’s context root)

#springUrl($relativeUrl)

<@spring.url relativeUrl/>

formInput (standard input field for gathering user input)

#springFormInput($path $attributes)

<@spring.formInput path, attributes, fieldType/>

formHiddenInput * (hidden input field for submitting non-user input)

#springFormHiddenInput($path $attributes)

<@spring.formHiddenInput path, attributes/>

formPasswordInput * (standard input field for gathering passwords. Note that no value will ever be populated in fields of this type)

#springFormPasswordInput($path $attributes)

<@spring.formPasswordInput path, attributes/>

formTextarea (large text field for gathering long, freeform text input)

#springFormTextarea($path $attributes)

<@spring.formTextarea path, attributes/>

formSingleSelect (drop down box of options allowing a single required value to be selected)

#springFormSingleSelect( $path $options $attributes)

<@spring.formSingleSelect path, options, attributes/>

formMultiSelect (a list box of options allowing the user to select 0 or more values)

#springFormMultiSelect($path $options $attributes)

<@spring.formMultiSelect path, options, attributes/>

formRadioButtons (a set of radio buttons allowing a single selection to be made from the available choices)

#springFormRadioButtons($path $options $separator $attributes)

<@spring.formRadioButtons path, options separator, attributes/>

formCheckboxes (a set of checkboxes allowing 0 or more values to be selected)

#springFormCheckboxes($path $options $separator $attributes)

<@spring.formCheckboxes path, options, separator, attributes/>

formCheckbox (a single checkbox)

#springFormCheckbox($path $attributes)

<@spring.formCheckbox path, attributes/>

showErrors (simplify display of validation errors for the bound field)

#springShowErrors($separator $classOrStyle)

<@spring.showErrors separator, classOrStyle/>

  • 在FTL中,这两个宏实际上是不需要的,因为可以使用常规的formInput marco,指定 hidden或password作为fieldType parameter的值。

上面任意宏的parameters都有一致的含义:

  • path:要绑定到的字段的名字 ("command.name")
  • options:input field中可以选择的所有可用值组成的Map。--太长,懒得翻译。。。
  • separator:多个选项可用时(radio buttons或者checkboxes),字符序列(就是字符串,如<br>)用来将选项隔离。
  • attributes:一个额外的字符串 -- 任意标签或包含在HTML标签中的文本组成的字符串。该字符串由宏来显示。例如,在textarea 字段中,你可以提供attributes:rows=”5” cols=”60”,或者传递样式信息--诸如style=”border:1px solid silver”。
  • classOrStyle:对showErrors 宏来说,CSS class的名字封装了它要使用的每个error。如果没有提供(或者值是空空),那errors会被封装在<b></b>标签中。

 

宏的用例:

Input Fields

<!-- the Name field example from above using form macros in VTL -->
...
Name:
#springFormInput("command.name" "")<br>
#springShowErrors("<br>" "")<br>

宏formInput ,会接收path parameter (command.name)和一个额外的attributes parameter -- 上例中是空。该宏,配合其他所有生成表单的宏,共同实现了path parameter隐式地spring bind。该绑定一直持续到新的绑定发生,所以,showErrors宏不需要再次传递path parameter -- 它会直接操作上一次绑定的字段。

宏showErrors,会接收一个separator parameter,并会接收第二个参数,一个class name或style attribute。注意,FreeMarker能够为这些attributes parameter指定默认值,不像Velocity,这两个宏在FTL中这样表示:

<@spring.formInput "command.name"/>
<@spring.showErrors "<br>"/>

上述生成的表单的片断如下所示(会生成name字段、会显示校验错误):

Name:
<input type="text" name="name" value="">
<br>
    <b>required</b>
<br>
<br>

formTextarea宏,其工作方式与formInput宏一致,接收的parameter list也相同。共同地,第二个parameter (attributes) 会用来传递样式信息或该textarea的行列属性。

 

Selection Fields

4个选择字段宏,可用来生成通用UI value selection inputs。

  • formSingleSelect
  • formMultiSelect
  • formRadioButtons
  • formCheckboxes

每一个都接收一个options Map,包含了form 字段的值、以及该值相对应的label。value和label可以相同。

 

下面是一个FTL的radio buttons例子。form backing object指定了该字段的默认值为London,所以,不必需要校验了。当form被渲染时,cities的整个列表会作为名字为cityMap的model中的引用。

...
Town:
<@spring.formRadioButtons "command.address.town", cityMap, ""/><br><br>

这里会渲染一行radio buttons,cityMap中的每个value都对应一个 -- separator是""。没有提供更多attributes (该宏的最后一个参数缺失)。该map的keys都是form使用POST提交的请求参数,map的values都是用户看到的labels。上面的例子中,有一个由三个城市组成的列表和一个默认值,那HTML会是这样的:

Town:
<input type="radio" name="address.town" value="London">London</input>
<input type="radio" name="address.town" value="Paris" checked="checked">Paris</input>
<input type="radio" name="address.town" value="New York">New York</input>

如果你的应用想使用内部代码来处理cities,如下:

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 m = new HashMap();
    m.put("cityMap", cityMap);
    return m;
}

该code会produce output:

Town:
<input type="radio" name="address.town" value="LDN">London</input>
<input type="radio" name="address.town" value="PRS" checked="checked">Paris</input>
<input type="radio" name="address.town" value="NYC">New York</input>

 

HTML escaping and XHTML compliance -- HTML转义和XHTML兼容

上面提到的form macros的默认使用,其结果是HTML标签兼容HTML 4.01、使用默认值来HTML转义 -- 定义在web.xml中,被Spring的绑定支持所使用 (--什么鬼,狗屁不通)。

为了兼容XHTML或者想要覆盖默认的HTML转义值,可以在你的模板中(或model中)指定两个变量。在模板中指定它们的优点是它们能够被改成不同的值 -- 在模板处理过程中,从而为form中不同的字段提供不同的行为。

 

想要将你的标签切换至XHTML兼容的,指定名字为xhtmlCompliant的model/context变量的值为true即可:

# for Velocity..
#set($springXhtmlCompliant = true)

<-- for FreeMarker -->
<#assign xhtmlCompliant = true in spring>

现在,由Spring macros生成的标签都是XHTML兼容的了。

 

类似的,HTML转义:

<#-- until this point, default HTML escaping is used -->

<#assign htmlEscape = true in spring>
<#-- 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 -->

 

5、JSP & JSTL

Spring为JSP和JSTL views提供了一对开箱即用的解决方案。通过使用定义在WebApplicationContext中的一个普通的view resolver就可以使用JSP或JSTL。当然,你还需要写一些JSPs -- 会自动渲染其view。

设置你的应用来使用JSTL是error的一个常见原因,主要是由不同的servlet spec.、JSP和JSTL版本的混淆导致的。文章 How to Reference and Use JSTL in your Web Application 提供了一个很有用的指导,诸如常见陷阱、如何避免它们。注意,自Spring 3.0 起,最小支持的servlet版本是 2.4 (JSP 2.0, JSTL 1.1),这样会降低混淆的范围。

 

5.1、View resolvers -- 视图解析器

就像其他所有你集成到Spring的view技术一样,JSPs也需要一个view resolver。开发JSPs时,最常用的view resolver是InternalResourceViewResolver 和 ResourceBundleViewResolver。二者都声明在WebApplicationContext中:

<!-- the ResourceBundleViewResolver -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
    <property name="basename" value="views"/>
</bean>

# And a sample properties file is uses (views.properties in WEB-INF/classes):
welcome.(class)=org.springframework.web.servlet.view.JstlView
welcome.url=/WEB-INF/jsp/welcome.jsp

productList.(class)=org.springframework.web.servlet.view.JstlView
productList.url=/WEB-INF/jsp/productlist.jsp

如你所见,ResourceBundleViewResolver需要一个properties文件,该文件定义了映射到①一个class和②一个URL的视图名字。使用ResourceBundleViewResolver,你可以混合不同类型的视图 -- 只需要一个解析器

 

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    <Spring 4 官方文档学习 Spring与Java EE技术的集成

Spring 4 官方文档学习核心技术之SpEL

2017.4.10 spring-ldap官方文档学习

20191114 Spring Boot官方文档学习(4.7)

20191112 Spring Boot官方文档学习(4.5-4.6)

Spring 4 官方文档学习数据访问之JDBC