1、了解视图的解析
前面的章节中我们知道了,Spring控制器会返回一个用于表示视图的字符串和Model对象给视图解析器。
下面详细了解一下:
ViewResolver接口和View接口
ViewResolver接口的大致内容为:
public interface ViewResolver{
//接收一个视图名和Locale对象,返回是一个视图
View resolveViewName(String viewName , Locale locale)throws Exception;
}
View接口:
public interface View{
String getContentType();
//接收Http的Request和Response中,然后将内容渲染后放到Response中。
void render(Map<String , ?> model ,
HttpServletRequest request ,
HttpServletResponse response) throws Exception;
}
Spring提供了很多ViewResolver的实现:
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 定义。类似于BeanName-ViewResolver
XsltViewResolver 将视图解析为 XSLT 转换后的结果
上面这些视图解析器都分别对应不同的技术,例如:
InternalResourceViewResolver 一般会用于 JSP
TilesViewResolver 用于Apache的Tiles视图
FreeMarkerViewResolver 对应 FreeMarker模板式图
VelocityViewResolver 对应 Velocity模板视图
2、创建JSP视图:
1:InternalResourceViewResolver会将视图名解析为jsp文件,并支持JSTLE。
这个视图解析器会遵循,前缀+逻辑视图名+后缀的形式指定物理路径。
使用java配置视图解析器:
@Bean
public ViewResolver viewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.serPrefix("/WEB-INF/views");
resolver.setSuffix(".jsp");
return resolver;
}
使用Xml配置视图解析器:
<bean id = "viewResolver"
class = "org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix = "/WEB-INF/views"
p:suffix = ".jsp"/>
如果在jsp页面使用了JSTL的话,为了恰当的格式化,需要将InternalResourceViewResolver转为JstlView。
分别在java配置和xml配置中添加:
resolver.setViewClass(org.springframework.web.servlet.view.JstlView.class);
p:viewClass = "org.springframework.web.servlet.view.JstlView"
2:Spring提供了两个JSP标签库,一个用于表单到模型的绑定,一个提供了通用的工具。
将表单绑定到模型上:
Spring提供了14个用于绑定的标签,这些他们会绑定模型中的一个对象,能够根据模型中对象的属性填充值。还有个一用于渲染错误信息的标签。借助这些标签我们能够将Model绑定到渲染后的HTML页面。
为了使用表单绑定库,需要在jsp中声明:<%@ taglib uri = "http://www.springframework.org/tags/form" prefix = "sf" %> 前缀也有人指定为form
JSP 标签 描 述
<sf:checkbox> 渲染成一个 HTML <input>标签,其中type属性设置为checkbox
<sf:checkboxes> 渲染成多个 HTML <input>标签,其中type属性设置为checkbox
<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属性设置为password
<sf:radiobutton> 渲染成一个 HTML <input>标签,其中type属性设置为radio
<sf:radiobuttons> 渲染成多个 HTML <input>标签,其中type属性设置为radio
<sf:select> 渲染为一个 HTML <select>标签
<sf:textarea> 渲染为一个 HTML <textarea>标签
例如:
<!--commandName会针对某个模型对象创建上下文,下面的标签将引用里面的属性-->
<!--下面的commandName指定了spitter。这需要Controller中的Model中要有key为spitter的对象,-->
<sf:form method = "post" commandName = "spitter">
First Name : <sf:input path = "firstName" />
Last Nmae : <sf:input path = "lastName" />
User Name : <sf:input path = "userName" />
Pass Word : <sf:password path = "password">
<input type = "submit" value = "Register" />
</sf:form>
修改Controller
@RequestMapping(value = "/register" , method = GET)
public String showRegistrationForm(Model model){
model.addAttribute(new Spitter()); //key的值是根据对象类型推断得到的
return "registerForm";
}
3、展现错误:
如果存在校验错误,错误信息存放在Model中。我们需要将其中信息取出来(使用<sf:errors)。
<sf:form method = "POST" commandName = "spotter">
...
First Name : <sf:input path = "firstName">
<sf:errors path = "firstName" /> <!--显示firstName属性的错误,如果有校验错误的话将在<span>中显示-->
<span id = "firstName.errors"> 文字不能太长或为空</span>
<!--另外的一种方式是,将所有错误都放到一个span中-->
<sf:errors path = "*" element = "div" cssClass = "errors">
//如果只显示一个错误的话使用span是比较合适的,但是如果有多个的话最好将element设置为div。CssClass是指定样式
...
</sf:form>
提示信息和国际化:
到目前为止我们可对错误信息输出了,也可以在@size中添加message属性
@NotNull
@Size(min = 5 , max = 6 , message = "{userName.size}")
private String userName;
@NotNull
@Size(min = 5 , max = 6 , message = "{firstName.size}")
private String firstName;
@NotNull
@Size(min = 5 , max = 6 , message = "{lastName.size}")
private String lastName;
@NotNull
@Size(min = 5 , max = 6 , message = "{passWord.size}")
private String passWord;
现在我们创建一个名为:ValidationMessage.properties文件,并将其放到根路径下。
userName.size = 用户名长度需要在{min}和{max}之间。
firstName.size = firstName长度需要在{min}和{max}之间。
...
4、Spring通用标签库:
除了表单绑定标签库之外,Spring还提供了更为通用的jsp标签库。
使用Spring通用标签库,需要引入:<% taglib uri="http://www.springframework.org/tags" prefix = "s" %> s可以使你喜欢的任何值
Spring 的 JSP 标签库中提供了多个便利的标签,还包括一些遗留的数据绑定标签:
JSP 标签 描 述
<s:bind> 将绑定属性的状态导出到一个名为status的页面作用域属性中,与<s:path>组合使用获取绑定属性的值
<s:escapeBody> 将标签体中的内容进行 HTML 和 / 或 JavaScript 转义
<s:hasBindErrors> 根据指定模型对象(在请求属性中)是否有绑定错误,有条件地渲染内容
<s:htmlEscape> 为当前页面设置默认的 HTML 转义值
<s:message> 根据给定的编码获取信息,然后要么进行渲染(默认行为),要么将其设置为页面作用域、请求作用域、会话作用域或应用作用域的变量(通过使用var和scope属性实现)
<s:nestedPath> 设置嵌入式的 path ,用于<s:bind>之中
<s:theme> 根据给定的编码获取主题信息,然后要么进行渲染(默认行为),要么将其设置为页面作用域、请求作用域、会话作用域或应用作用域的变量(通过使用var和scope属性实现)
<s:transform> 使用命令对象的属性编辑器转换命令对象中不包含的属性
<s:url> 创建相对于上下文的 URL ,支持 URI 模板变量以及 HTML/XML/JavaScript 转义。可以渲染 URL (默认行为),也可以将其设置为页面作用域、请求作用域、会话作用域或应用作用域的变量(通过使用var和scope属性实现)
<s:eval> 计算符合 Spring 表达式语言( Spring Expression Language , SpEL )语法的某个表达式的值,然后要么进行渲染(默认行为),要么将其设置为页面作用域、请求作用域、会话作用域或应用作用域的变量(通过使用var和scope属性实现)
有些标签已经被Spring淘汰。
5、展现国际化信息
将例如:<h1> hello World </h1>的硬编码改为:
<h1><s:message code = "spittr.welcome" /></h1>
上面的<s:message>会根据一个数据源获取keyspittr.welcome的value。
配置数据来源:
1:ResourceBundleMessageSource来实现
/**
下面代码关键是设置Basename。设置之后ResourceBundleMessageSource会试图在根路径的属性文件中解析信息。
*/
@Bean
public MessageSource messageSource(){
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("message"); //这里的message可以使任意值
return messageSource;
}
2:ReloadableResourceBundleMessageSource和上面的工作类似,但是它不用重新编译即可加载
/**
这里的basename是可以设置位置的。例如:file:、classpath:等。
*/
@Bean
public MessageSource messageSource(){
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("file:///etc/spittr/message");
messageSource.setCacheSeconds(10);
return messageSource;
}
创建数据来源文件:
在指定的位置(根路径、file:或者classpath指定的位置)创建message.properties文件
本例中内容为:
spittr.welcome = welcome to this page
6、创建URL:<s:url> ???????????
7、转义内容:<s:escapeBody> ???????????
8、Apache Tiles布局视图(具体可以看书)
9、使用Thymeleaf(具体可以看书)