Spring实战(六)-渲染Web视图

本文基于《Spring实战(第4版)》所写。

理解视图解析

Spring MVC定义了一个名为ViewResolver的接口,它大致如下所示:

public interface ViewResolver {
    View resolveViewName(String viewName, Locale locale) throws Exception;
}

当给resolveViewName()方法传入一个视图名和Locale对象时,它会返回一个View实例。View是另外一个接口,如下所示:

public interface View {
    String getContentType();
    void render(Map model,
                       HttpServletRequest request,
                       HttpServletResponse response) throws Exception;
}

View接口的任务就是接受模型以及Servlet的request和response对象,并将输出结果渲染到response中。

尽管我们可以编写ViewResolver和View的实现,在有些特定的场景下,这样做也是有必要的,但一般来讲,我们并不需要关心这些接口。Spring提供了多个内置的实现。如下表所示,Spring自带了13个视图解析器,能够将逻辑视图名转换为物理实现。

视图解析器 描述
BeanNameViewResolver 将视图解析为Spring应用上下文的bean,其中bean的ID与视图的名字相同
ContentNegotiatingViewResolver 通过考虑客户端需要的内容类型来解析视图,委托给另外一个能够产生对应内容类型的视图解析器
FreeMarkerViewResolver 将视图解析为FreeMarker模版
InternalResourceViewResolver 将视图解析为Web应用的内部资源(一般为JSP)
JasperReportsViewResolver 将视图解析为JasperReports定义
ResourceBundleViewResolver 将视图解析为资源bundle(一般为属性文件)
TilesViewResolver 将视图解析为Apache Tile定义,其中tile ID与视图名称相同。注意有两个不同的TilesViewResolver实现,分别对应于Tiles 2.0和Tiles 3.0
UrlBasedViewResolver 直接根据视图的名称解析视图,视图的名称会匹配一个物理视图的定义
VelocityLayoutViewResolver 将视图解析为Velocity布局,从不同的Velocity模板中组合页面
VelocityViewResolver 将视图解析为Velocity模板
XmlViewResolver 将视图解析为特性XML文件中的bean定义。类似于BeanNameViewResolver
XsltViewResolver 将视图解析为XSLT转换后的结果

Spring 4和Spring 3.2支持表6的所有视图解析器。Spring 3.1支持除Tiles 3 TilesViewResolver之外的所有视图解析器。

创建JSP视图

Spring提供了两种支持JSP视图的方式:

  • InternalResourceViewResolver会将视图名解析为JSP文件。另外,如果在你的JSP页面中使用了JSP标准标签库(JavaServer Pages Standard Tag Library, JSTL)的话,InternalResourceViewResolver能够将视图名解析为JstlView形式的JSP文件,从而将JSTL本地化和资源bundle变量暴露给JSTL的格式化(formatting)和信息(message) 标签。
  • Spring提供了两个JSP标签库,一个用于表单到模型的绑定,另一个提供了通用的工具类特性。

不管使用JSTL,还是准备使用Spring的JSP标签库,配置解析JSP的视图解析器都是非常重要的。尽管Spring还有其他的几个视图解析器都能将视图名映射为JSP文件,但就这项任务来讲,InternalResourceViewResolver是最简单和最常用的视图解析器。

配置适用于JSP的视图解析器

InternalResourceViewResolver遵循一种约定,会在视图名上添加前缀和后缀,进而确定一个Web应用中视图资源的物理路径。

通用的实践是将JSP文件放到Web应用的WEB-INF目录下,防止对它的直接访问。假设逻辑视图名为home,那么可以确定物理视图的路径就是逻辑视图名home再加上“/WEB-INF/views/”前缀和“.jsp”后缀。

Spring实战(六)-渲染Web视图_第1张图片
InternalResourceViewResolver解析视图时,会在视图名上添加前缀和后缀

当使用@Bean注解的时候,我们可以按照如下的方法配置InternalResourceViewResolver,使其在解析视图时,遵循上述的约定。

    @Bean
    public ViewResolver viewResolver(){   // 配置jsp视图解析器
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

作为替代方案,如果更喜欢使用基于XML的Spring配置,那么可以按照如下的方式配置InternalResourceViewResolver


InternalResourceViewResolver配置就绪之后,它就会将逻辑视图名解析为JSP文件,如下所示:

  • home将会解析为“/WEB-INF/views/home.jsp”
  • productList将会解析为“/WEB-INF/views/productList.jsp”
  • books/detail将会解析为“/WEB-INF/views/books/detail.jsp”

重点看一下最后一个样例。当逻辑视图名中包含斜线时,这个斜线也会带到资源的路径名中。因此,它会对应到prefix属性所引用目录的子目录下的JSP文件。这样的话,我们就可以很方便地将视图模板组织为层级目录,而不是将它们都放到同一个目录之中。

解析JSTL视图

如果JSP使用JSTL标签来处理格式化和信息的话,那么我们会希望InternalResourceViewResolver将视图解析为JstlView。

JSTL的格式化标签需要一个Locale对象,以便于恰当地格式化地域相关的值,如日期和货币。信息标签可以借助Spring的信息资源和Locale,从而选择适当的信息渲染到HTML之中。通过解析JstlView,JSTL能够获得Locale对象以及Spring中配置的信息资源。

如果想让InternalResourceViewResolver将视图解析为JstlView,而不是InternalResourceView的话,那么我们只需设置它的viewClass属性即可:

    @Bean
    public ViewResolver viewResolver(){   // 配置jsp视图解析器
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        resolver.setViewClass(org.springframework.web.servlet.view.JstlView.class);
        return resolver;
    }

同样,我们也可以使用XML完成这一个任务:


不管使用Java配置还是使用XML,都能确保JSTL的格式化和信息标签能够获得Locale对象以及Spring中配置的信息资源。

使用Spring的JSP库

Spring提供了两个JSP标签库,用来帮助定义Spring MVC Web的视图。其中一个标签库会用来渲染HTML表单便签,这些标签可以绑定model中的某个属性。另外一个标签库包含了一些工具类标签,我们随时都可以非常便利地使用它们。

我们将会看到如何将Spittr应用的注册表单绑定到模型上,这样表单就可以预先填充值,并且在表单提交失败后,能够展现校验错误。

将表单绑定到模型上

Spring的表单绑定JSP标签库包含了14个标签,它们中的大多数都用来渲染HTML中的表单标签。但是,它们与原生HTML标签的区别在于它们会绑定模型中的一个对象,能够根据模型中对象的属性填充值。标签库中还包含了一个为用户展示错误的标签,它会将错误信息渲染到最终的HTML之中。

为了使用表单绑定库,需要在JSP页面中对其进行声明:

<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>

需要注意,我们将前缀指定为“sf”,但通常也可能使用“form”前缀,可以自定义前缀。

在声明完表单绑定标签库之后,你就可以使用14个相关的便签了。如下表

JSP标签 描述
渲染成一个HTML 标签,其中type属性设置为checkbox
渲染成多个HTML 标签,其中type属性设置为checkbox
在一个HTML 中渲染输入域的错误
渲染成一个HTML
标签,并为其内部标签暴露绑定路径,用于数据绑定
渲染成一个HTML 标签,其中type属性设置为hidden
渲染成一个HTML 标签,其中type属性设置为text
渲染成一个HTML
渲染成一个HTML
按照绑定的集合、数组或Map,渲染成一个HTML
渲染成一个标签,其中type属性设置为password
渲染成一个标签,其中type属性设置为radio
渲染为一个HTML
渲染为一个HTML