spring mvc视图与视图解析器
视图的作用是渲染模型数据,将模型数据以某种形式呈现给客户。视图对象可以是常见的JSP,还可以是Excel或PDF等形式不一的媒体形式。为了实现视图模型和具体实现技术的解耦。
spring 在org.springframework.web.servlet包中定义了一个高度抽象的View接口,该接口定义了两个方法
String getContextType():视图对应的MIME类型,如text/xml,text/html
void render(Map model,HttpServletRequestrequest,HttpServletResponse response):将视图模型以某种MIME类型渲染出来
视图对象是一个Bean,通常视图对象由视图解析器负责实例化。由于视图Bean是无状态的,所有它们不会有线程安全的问题。
不同类型的视图实现技术对应不同的View实现,这些视图实现类都位于org.springframework.web.servlet.view包中
大类 | 视图类型 | 说明 |
URL资源视图 | InternalResourceView | 将JSP或其他资源封装成一个视图,这个InternalResolver默认使用视图实现类 |
JstlView | 如果JSP文件中使用了JSTL国际化标签的功能,则需要使用该视图类,而非InternalResourceView | |
XSTL视图 | XstlView | XSTL驱动的视图 |
Tiles视图 | TilesView | 基于Tiles页面布局的视图 |
TilesJstlView | 如果Tiles模板的JSP组成文件使用了JSTL,需要使用该视图替换TilesView | |
文档视图 | AbstractExcelView | Excel文档视图的抽象类,开发者可以通过该抽象类实现自己的Excel文档视图,该视图实现类基于POI构造Excel文档 |
AbstractJExcelView | 与AbstractExcelView类似,基于JExcelAPI | |
AbstractPdfStamperView | PDF文档视图抽象类,通过AcroForm技术对PDF文档进行操作 | |
AbstractPdfView | PDF文档视图的对象抽象类,可以通过该抽象类实现自己的PDF文档视图,该视图实现类基于iText构造PDF文档 | |
报表视图 | ConfigurableJasperReportsView | 几个使用JasperReports报表技术的视图 |
JasperReportsCsvView | ||
JasperReportsHtmlView | ||
JasperReportsMultiFormatView | ||
JasperReportsPdfView | ||
JasperReportsXlsView | ||
模板视图 | FreeMarkerView | 使用FreeMarker模板引擎的视图 |
VelocityLayoutView | 使用Velocity模板引擎的视图 | |
VelocityToolboxView | ||
VelocityView | ||
XML视图 | MarshallingView | 将模型数据以XML方式输出 |
JSON视图 | MappingJacksonJsonView | 将模型数据通过Jackson的ObjectMapper以Json方式输出 |
其它视图 | RedirectView | 进行重定向视图,可以重定向到上下文的绝对路径或相对路径,也可以重定向到当前请求的相对路径下 |
视图解析器
spring mvc为逻辑视图名的解析提供了不同的策略,可以在spring 上下文中配合一种或多种解析策略,并指定它们之间的先后顺序。每种解析策略都对应一个具体的视图解析器实现类
视图解析器的工作比较单一,将逻辑视图名解析为一个具体的视图对象。所有的视图解析器都实现了ViewResoler接口。该接口仅有一个方法
View resolverViewName(String viewName,Locale locale):根据逻辑视图名与本地化对象得到一个视图对象。spring拥有众多的视图解析器实现类
大类 | 视图解析类型 | 说明 |
解析为Bean名称 | BeanNameViewResolver | 将逻辑视图名解析为一个Bean,Bean的Id等于逻辑视图名 |
国际化解析 | ResourceBundleViewResolver | 在国际化资源文件中定义视图实现类及相关信息。该视图解析器可以为不同的本地化类型提供不同的解析结果 |
解析为URL文件 | InternalResourceViewResolver | 将视图名解析为一个URL文件,一般使用该解析器将视图名映射为保存在/WEB-INF目录中的程序文件(如JSP) |
XsltViewResolver | 将视图名解析为一个指定的XSLT样式的URL文件 | |
JasperReportsViewResolver | 将视图名解析为报表文件对应的URL | |
模板文件视图 | FreeMarkerViewResolver | 解析为基于FreeMarker模板文件 |
| VelocityViewResolver | 解析为Velocity模板文件 |
| VelocityLayoutViewReslver | |
内容协商 |
|
|
用户可以选择一种视图解析器或混用多种视图解析器,每个视图解析器都实现了Ordered接口并开放了一个orderNo的属性,可以通过orderNo属性指定解析器的优先顺序,orderNo值越小优先级越高。
spring mvc会按照视图解析器的优先顺序对逻辑视图名进行解析,直到解析成功并返回视图对象,否则抛出servletException。
JSP与JSTL
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<propertyname="prefix" value="/WEB-INF/pages/"/>
<propertyname="suffix" value=".jsp"/>
</bean>
InternalResourceViewResolver默认使用InternalResourceView作为视图实现类,如果JSP文件使用了JSTL的国际化功能,用户需要使用JstlView替换默认的视图实现类。
<beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver">
<propertyname="prefix" value="/WEB-INF/pages/"/>
<propertyname="suffix" value=".jsp"/>
</bean>
spring mvc表单标签
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<form:form>
一般情况下,我们通过Get请求获取表单页面,而通过Post请求提交页面,因此获取表单页面与提交表单页面的URL地址是相同的。只要满足这条最佳实践的契约,
<form:form>标签就无须通过action属性指定表单提交的URL
可以通过modelAttribute指定绑定的模型属性,如果modelAttribute属性不指定,那么从模型尝试获取名称为”command”的表单对象,如果不存在此表单对象,将发生错误,通过action指定处理表单提交的URL地址。
spring mvc标签常见属性
path:用属性路径表示表单对象属性,如username
htmlEscape:绑定的表单对象属性值是否对HTML特殊字符进行转换,默认为true
cssClass、cssErrorClass、cssStyle
关于复选框、单选框及下拉列表和表单对象属性映射问题
对应以下复选框标签:
<form:form checkboxes path=”preferences.interests” items=”${interests}”/>
其生成的HTML如下:
<input id=”favorites1” name=”favorites” type=”checkbox” value=”1”checked=”checked”/>
<input id=”favorites2” name=”favorites” type=”checkbox” value=”2”checked=”checked”/>
<input id=”favorites3” name=”favorites” type=”checkbox” value=”3”checked=”checked”/>
<input id=”favorites4” name=”favorites” type=”checkbox” value=”4”checked=”checked”/>
<input name=”_favorites” type=”hidden” value=”1”/>
当html页面所有复选框都没有勾选时,表单提交所对应的http请求报文不会包含复选框的参数名,这就给spring的表单数据绑定机制带来了麻烦,因此无法触发setFavorites()方法调用(如果这个表单对象已经缓存在Session中,且该属性已经有值,这个属性值将不会设置为空)
解决方式是在每个复选框后添加隐藏组件。并且在对应的复选框名字前添加”_”作为隐藏组件的名字。这样一来,相当于告诉Spring mvc:这个表单中存在这样一个复选框,spring mvc可以根据此保存服务端的表单对象和页面表单组件数据一致性。
复选框、单选按钮及下拉框的组件标签都有类似的功能,如果手动编写HTML代码,在碰到单选框、复选框及下拉框时,也应该采用类似的方式以保证spring mvc数据绑定机制正常工作,当然,如果表单对象没有缓存在Session中,而是每次提交都重新创建,则不存在这个问题,也无需添加一个带有下划线的隐含组件。
模板视图
FreeMarker和Velocity是除了JSP外被使用最多的页面模板视图。Spring对FreeMarker和velocity都提供了支持,它们在使用时都大同小异。
在spring web上下文中装配FreeMarker
<!-- 通过FreeMarkerConfigurer配置FreeMarker环境 -->
<beanclass="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<!-- 指定模板存放位置-->
<propertyname="templateLoaderPath" value="/WEB-INF/ftl"/>
<!-- 指定模板编码方式-->
<propertyname="defaultEncoding" value="UTF-8"/>
<!-- 统一设置自定义属性-->
<propertyname="freemarkerSettings">
<props>
<!--freeMarker碰到值为null的对象属性时,抛出异常 -->
<!-- 设置为true后显示空白字符串-->
<propkey="classic_compatible">true</prop>
</props>
</property>
</bean>
搭建好FreeMarker的环境后,就可以通过FreeMarkerViewResolver视图解析器将”userListFlt”的逻辑视图名解析为一个对应的FreeMarkerView视图对象。
<beanclass="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<!-- 指定视图解析器优先级-->
<propertyname="order" value="5"/>
<!-- 指定后缀 -->
<propertyname="suffix" value=".ftl"/>
<!-- 由于FreeMarker最终产生的是HTML,设置以UTF-8编码格式输出 -->
<propertyname="contentType" value="text/html;charset=utf-8"/>
</bean>
使用Spring为FreeMarker提供的宏
<a href=”/user/showUser/${user.userName}.html”>${user.userName}</a>
这里,我们使用的URL地址没有考虑部署路径,如果部署路径不是”/”将发生URL错误。
在JSP中一般通过JSTL的<c:url>转换应用部署路径的绝对URL
<a href=”<c:url value=”/user/showUser/${user.userName}.html”>”>${topic.tilte}</a>
在spring中可以通过FreeMarker宏来实现
<!—引入spring的FreeMarker宏定义文件-->
<#import “spring.ftl” as spring>
<!—引入国际化资源-->
<@spring.message “website.title”/>
<@spring.message “user.userList.title”/>
<!—使用spring宏对URL进行格式化-->
<a href=”<@spring.url ”/user/showUser/${user.userName}.html”/>”>${user.userName}</a>
${user.birthday?string(“yyyy-MM-dd”)}
spring为FreeMarker提供的表单宏与其他宏
宏类型 | 说明 |
国际化信息,code代表国际资源代码 | <@spring.message code/> 示例:<@spring.message “user.userName”> |
国际化信息,如果没有相应代码,使用默认值(text)指定 | <@spring.messageText code,text/> 示例:<@spring.messageText “user.userName”,”用户名”/>
|
获取应用服务器绝对路径 | <@spring.url relativeUrl/> 示例:<@spring.url “/register.html”/> |
输入框组件 | <@spring.formInput path attributes fieldType/> 示例:<@spring.formInput “user.userName” class=”inputSty”/> |
隐藏组件 | <@spring.formHiddenInput path attributes /> 示例:<@spring. formHiddenInput “user.userName” /> |
密码组件 | <@spring.formPasswordInput path attributes /> 示例:<@spring. formPasswordInput “user.password” /> |
Excel
如果希望使用Excel展示用户列表,仅需要扩展spring的AbstractExcelView或AbstractJExcelView即可。实现buildExcelDocument方法,在方法中使用模型数据对象构建Excel文档就可以了。
public class UserListExcelView extends AbstractExcelView{
@RequestMapping(value="/showUserListByXls")
public StringshowUserListInExcel(ModelMap mm){
userList.add(user1);
userList.add(user2);
mm.addAttribute("userList",userList);
return"userListExcel"
}
@Override
protected voidbuildExcelDocument(Map<String, Object> model,
HSSFWorkbookworkbook, HttpServletRequest request,
HttpServletResponseresponse) throws Exception{
//显示对话框提示用户下载或打开
response.setHeader("Content-Disposition","attachment;filename="+
newString("用户列表".getBytes(),"ISO-8859-1"));
List<User>userList = (List<User>)model.get("userList");
HSSFSheetsheet = workbook.createSheet("users");
HSSFRowheader = sheet.createRow(0);
header.createCell(0).setCellValue("账号");
header.createCell(1).setCellValue("姓名");
int rowNum =1;
for(Useruser:userList){
HSSFRowrow = sheet.createRow(rowNum++);
row.createCell(0).setCellValue(user.getuserName());
row.createCell(1).setCellValue(user.getRealName());
}
}
}
<beanclass="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order"value="10"/>
</bean>
<bean id="userListExcel" class="xxx"/>
由于UserListExcelView代表Excel视图对象是一个Bean,因此我们使用.BeanNameViewResolver作为视图解析器,将其优先级设置为10
PDF视图与Excel类似,也使用一个Bean作为视图对象
输出XML
spring mvc还可以将模型中的数据以XML的形式输出,其对应的视图对象为MarshallingView