Spring实战第六章(待完善)
渲染视图
1、视图解析器
在控制器方法都没有直接产生浏览器中渲染所需的HTML。这些方法只是将一些数据填充到模型中,然后将模型传递给一个用来渲染的视图。Spring MVC使得控制器中请求处理的逻辑和视图中的渲染实现解耦。
控制器方法和视图的实现会在模型内容上达成一致,这是两者的最大关联,除此之外,两者应该保持足够的距离。
视图解析器的基础:
Spring MVC定义了一个名为ViewResolver的接口,它大致如下所示:
当给resolveViewName()方法传入一个视图名和Locale对象时,它会返回一个View实例。View是另外一个接口,如下所示:
View接口的任务就是接受模型以及Servlet的request和response对象,并将输出结果渲染到response中。我们所需要做的就是编写ViewResolver和View的实现,将要渲染的内容放到response中,进而展现到用户的浏览器中。
但是:一般来讲,我们并不需要关心这些接口。Spring提供了多个内置的实现,如表6.1所示,它们能够适应大多数的场景。
Spring自带了12个视图解析器,能够将逻辑视图名转换为物理实现。
视图解析器 | 描 述 |
BeanNameViewResolver |
将视图解析为Spring应用上下文中的bean,其中 |
ContentNegotiatingViewResolver |
通过考虑客户端需要的内容类型来解析视图, |
FreeMarkerViewResolver | 将视图解析为FreeMarker模板 |
InternalResourceViewResolver |
将视图解析为Web应用的内部资源(一般为 |
JasperReportsViewResolver | 将视图解析为JasperReports定义 |
ResourceBundleViewResolver | 将视图解析为资源bundle(一般为属性文件) |
TilesViewResolver |
将视图解析为Apache Tile定义,其中tile ID与视 |
UrlBasedViewResolver |
直接根据视图的名称解析视图,视图的名称会 |
VelocityLayoutViewResolver |
将视图解析为Velocity布局,从不同的Velocity模 |
VelocityViewResolver | 将视图解析为Velocity模板 |
XmlViewResolver |
将视图解析为特定XML文件中的bean定义。类 |
XsltViewResolver | 将视图解析为XSLT转换后的结果 |
2、创建jsp视图
Spring提供了两种支持JSP视图的方式:
1、InternalResourceViewResolver会将视图名解析为JSP文件。另外,如果在你的JSP页面中使用了JSP标准标签库(JavaServer Pages Standard Tag Library,JSTL)的话,InternalResourceViewResolver能够将视图名解析为JstlView形式的JSP文件,从而将JSTL本地化和资源bundle变量暴露给JSTL的格式化(formatting)和信息(message)标签。
2、Spring提供了两个JSP标签库,一个用于表单到模型的绑定,另一个提供了通用的工具类特性。
不管你使用JSTL,还是准备使用Spring的JSP标签库,配置解析JSP的视图解析器都是非常重要的。尽管Spring还有其他的几个视图解析器都能将视图名映射为JSP文件,但就这项任务来讲,InternalResourceViewResolver是最简单和最常用的视图解析器
InternalResourceViewResolver遵循一种约定,会在视图名上添加前缀和后缀,进而确定一个Web应用中视图资源的物理路径。
例如:一个简单的场景,假设逻辑视图名为home。通用的实践是将JSP文件放到Web应用的WEB-INF目录下,防止对它的直接访问。如果将所有的JSP文件都放在“/WEB-INF/views/”目录下,并且home页的JSP名为home.jsp,那么我们可以确定物理视图的路径就是逻辑视图名home再加上“/WEB-INF/views/”前缀和“.jsp”后缀。
如何配置InternalResourceViewResolver视图解析器:
1、在Javaconfig中配置方式:
@Bean public ViewResolver viewResolver(){ //配置JSP视图解析器 InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); resolver.setExposeContextBeansAsAttributes(true); return resolver; }
2、或在xml中配置
InternalResourceViewResolver配置就绪之后,它就会将逻辑视图名解析为JSP文件
例子:books/detail将会解析为“/WEB-INF/views/books/detail.jsp”
注意:当逻辑视图名中包含斜线时,这个斜线也会带到资源的路径名中。因此,它会对应到prefix属性所引用目录的子目录下的JSP文件。
2.1解析JSTL视图
如果这些JSP使用JSTL标签来处理格式化和信息的话,那么应该InternalResourceViewResolver将视图解析为JstlView。
JSTL的格式化标签需要一个Locale对象,以便于恰当地格式化地域相关的值,如日期和货币。信息标签可以借助Spring的信息资源和Locale,从而选择适当的信息渲染到HTML之中。通过解析JstlView,JSTL能够获得Locale对象以及Spring中配置的信息资源。(Locale
对象表示了特定的地理、政治和文化地区。需要 Locale
来执行其任务的操作称为语言环境敏感的 操作,它使用 Locale
为用户量身定制信息。例如,显示一个数值就是语言环境敏感的操作,应该根据用户的国家、地区或文化的风俗/传统来格式化该数值。)
如果想让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); resolver.setExposeContextBeansAsAttributes(true); return resolver; }
(配置org.springframework.web.servlet.view.JstlView,是因为要解析成jstlview,但是当导入了JSTL的标签jar包,不配也可以解析)
或者在xml中:
2.2 JSP库
Spring提供了两个JSP标签库,用来帮助定义Spring MVC Web的视图。其中一个标签库会用来渲染HTML表单标签,这些标签可以绑定model中的某个属性。另外一个标签库包含了一些工具类标签,我们随时都可以非常便利地使用它们。
a、表单绑定到模型上
Spring的表单绑定JSP标签库包含了14个标签,它们中的大多数都用来渲染HTML中的表单标签。但是,它们与原生HTML标签的区别在于它们会绑定模型中的一个对象,能够根据模型中对象的属性填充值。标签库中还包含了一个为用户展现错误的标签,它会将错误信息渲染到最终的HTML之中。
使用表单绑定库,需要在JSP页面中对其进行声明:
<%@taglib uri="http://www.springframework.org/tags/form" prefix="sf" %>
或
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
十四个相关的标签
JSP标签 | 描 述 |
<sf:checkbox> |
渲染成一个HTML <input>标签,其中type属性设置 |
<sf:checkboxes> |
渲染成多个HTML <input>标签,其中type属性设置 |
<sf:errors> | 在一个HTML <span>中渲染输入域的错误 |
<sf:form> |
渲染成一个HTML <form>标签,并为其内部标签暴露绑定路 |
<sf:hidden> | 渲染成一个HTML <input>标签,其中type属性设置为hidden |
<sf:input> | 渲染成一个HTML <input>标签,其中type属性设置为text |
<sf:label> | 渲染成一个HTML <label>标签 |
<sf:option> |
渲染成一个HTML <option>标签,其selected属性根据所绑定 |
<sf:options> |
按照绑定的集合、数组或Map,渲染成一个HTML <option>标 |
<sf:password> |
渲染成一个HTML <input>标签,其中type属性设置 |
<sf:radiobutton> | 渲染成一个HTML <input>标签,其中type属性设置为radio |
<sf:radiobuttons> | 渲染成多个HTML <input>标签,其中type属性设置为radio |
<sf:select> | 渲染为一个HTML <select>标签 |
<sf:textarea> | 渲染为一个HTML <textarea>标签 |
介绍略
3、Tiles视图定义布局
Spring MVC以视图解析器的形式为Apache Tiles提供了支持,这个视图解析器能够将逻辑视图名解析为Tile定义。
3.1配置Tiles视图解析器
在Spring中使用Tiles,需要配置几个bean。
需要一个TilesConfigurer bean,它会负责定位和加载Tile定义并协调生成Tiles。除此之外,还需要TilesViewResolver bean将逻辑视图名称解析为Tile定义。
TilesConfigurer bean把其定义在了WebConfig中,
// Tiles @Bean public TilesConfigurer tilesConfigurer() { TilesConfigurer tiles = new TilesConfigurer(); tiles.setDefinitions(new String[] { "/WEB-INF/layout/tiles.xml", "/WEB-INF/views/**/tiles.xml" }); tiles.setCheckRefresh(true); return tiles; }
当配置TilesConfigurer的时候,所要设置的最重要的属性就是definitions。这个属性接受一个String类型的数组,其中每个条目都指定一个Tile定义的XML文件。对于Spittr应用来讲,我们让它在“/WEB-INF/layout/”目录下查找tiles.xml。 其实我们还可以指定多个Tile定义文件,甚至能够在路径位置上使用通配符(例如使用了Ant风格的通配符(**)),当然在上例中我们没有使用该功能。例如,我们要 求TilesConfigurer加载“/WEB-INF/”目录下的所有名字为tiles.xml 的文件,那么可以按照如下的方式设置definitions属性。
之后配置TilesViewResolver bean(在webConfig之中)
@Bean public ViewResolver viewResolverTile() { return new TilesViewResolver(); }
或者把上面的bean配置在xml之中
TilesConfigurer会加载Tile定义并与Apache Tiles协作,而TilesViewResolver会将逻辑视图名称解析为引用Tile定义的视图。
3.2定义Tiles
Apache Tiles提供了一个文档类型定义(document type definition,DTD),用来在XML文件中指定Tile的定义。每个定义中需要包含一个<definition>元素,这个元素会有一个或多个<put-attribute>元素。
<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN" "http://tiles.apache.org/dtds/tiles-config_3_0.dtd"> <tiles-definitions> <definition name="base" template="/WEB-INF/layout/page.jsp"> 定义bese Tiles <put-attribute name="header" value="/WEB-INF/layout/header.jsp"/> 扩展属性 <put-attribute name="footer" value="/WEB-INF/layout/footer.jsp"/> </definition> <definition name="home" extends="base"> 扩展base Tiles <put-attribute name="body" value="/WEB-INF/views/home.jsp" /> </definition> <definition name="registerForm" extends="base"> <put-attribute name="body" value="/WEB-INF/views/registerForm.jsp" /> </definition> <definition name="profile" extends="base"> <put-attribute name="body" value="/WEB-INF/views/profile.jsp" /> </definition> <definition name="spittles" extends="base"> <put-attribute name="body" value="/WEB-INF/views/spittles.jsp" /> </definition> <definition name="spittle" extends="base"> <put-attribute name="body" value="/WEB-INF/views/spittle.jsp" /> </definition> </tiles-definitions>
每个<definition>元素都定义了一个Tile,它最终引用的是一个JSP模板。在名为base的Tile中,模板引用的是“/WEB-INF/layout/page.jsp”。某个Tile可能还会引用其他的JSP模板,使这些JSP模板嵌入到主模板中。对于base Tile来讲,它引用的是一个头部JSP模板和一个底部JSP模板。
base Tile所引用的page.jsp模板如下面程序清单所示。主布局模板:引用其他模板来创建视图
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ taglib uri="http://www.springframework.org/tags" prefix="s" %> <%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="t" %> <%@ page session="false" %> <html> <head> <title>Spittr</title> <link rel="stylesheet" type="text/css" href="<s:url value="/resources/style.css" />" > </head> <body> <div id="header"> <t:insertAttribute name="header" /> </div> <div id="content"> <t:insertAttribute name="body" /> </div> <div id="footer"> <t:insertAttribute name="footer" /> </div> </body> </html>
(注意:在写<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="t" %>可能会报错,
需要在maven中写入:
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-jsp</artifactId>
<version>3.0.7</version>
</dependency>
)
使用Tile标签库中的<t:insert Attribute> JSP标签来插入其他的模板。在这里,用它来插入名为header、body和footer的模板。
在这里,base Tile不会期望单独使用。它会作为基础定义(这是其名字的来历),供其他的Tile定义扩展。在程序清单6.2的其余内容中,我们可以看到其他的Tile定义都是扩展自base Tile。它意味着它们会继承其header和footer属性的设置(当然,Tile定义中也可以覆盖掉这些属性),但是每一个都设置了body属性,用来指定每个Tile特有的JSP模板。
现在,我们关注一下home Tile,它扩展了base。因为它扩展了base,因此它会继承base中的模板和所有的属性。尽管home Tile定义相对来说很简单,但是它实际上包含了如下的定义: