视图通常就是 JSP、Velocity 、FreeMark等。Spring 默认提供了多种视图解析器,比如,我们可以使用最常用解析器 InternalResourceViewResolver 来查找 JSP 视图(与之相对应的视图类为 InternalResourceView)。通常,一个视图解析器只能查找一个或多个特定类型的视图,我们就可以通过扩展 Spring 来自定义自己所需的视图解析器。目前,视图解析器都需要实现接口 org.springframework.web.servlet.ViewResolver, 它包含方法 resolveViewName,该方法会通过视图名查找并返回 Spring 视图对象。
Spring 常用视图解析器:
1、XmlViewResolver 接口 ViewResolver 的实现,从 XML 配置文件中查找视图实现(默认 XML 配置文件为 /WEB-INF/views.xml).
2、ResourceBundleViewResolver 接口 ViewResolver 的实现,用于从 properties 文件中查找视图。
3、UrlBasedViewResolver 接口 ViewResolver 的实现,用于根据请求的 URL 路径返回相应的视图,该视图需为抽象类 AbstractUrlBasedView 的实现。
4、InternalResourceViewResolver UrlBasedViewResolver 的子类,通常用于查找 JSP(类 InternalResourceView)和 JSTL(类 JstlView,InternalResourceView 的子类)等视图。
6、ContentNegotiatingViewResolver 接口 ViewResolver 的实现,用于根据请求文件的后缀名或请求的 header 中的 accept 字段查找视图。
自定义视图:
public class GenericFileView extends AbstractUrlBasedView {
// 默认内容类型
private final static String CONTENT_TYPE = "text/plain";
//http response conent
private String responseContent;
public GenericFileView() {
super();
setContentType(CONTENT_TYPE);
}
@Override
public void setContentType(String contentType) {
super.setContentType(contentType);
}
@Override
protected void renderMergedOutputModel(Map<String, Object> model,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
// 设置 content type
response.setContentType(getContentType());
// 写入 response 内容
response.getWriter().write(this.responseContent);
response.getWriter().close();
}
/**
* 设置 http response content
* @param responseContent
*/
public void setResponseContent(String responseContent) {
this.responseContent = responseContent;
}
}
本例中的视图类继承了抽象类 AbstractUrlBasedView,因此,我们的自定义通用视图类并不需太多修改,就是设置文件内容类型和将响应的内容设置到请求响应对象中。
自定义的视图解析器:
所有的视图解析器都需要实现接口 org.springframework.web.servlet.ViewResolver,但同视图的实现一样,Spring 还提供了一个抽象类,我们同样可以通过实现抽象类来节省开发工作。其中,通常一个项目中会有多个视图解析器,那么就需要我们设定各个解析器被调用的优先级,尤其是和 InternalResourceViewResolver 混用的情况下,必须要定义正确的调用优先级,则实现接口 org.springframework.core.Ordered,该接口用于设置视图解析器的调用优先级
视图解析器的核心方法是 loadView:
@Override
protected View loadView(String viewName, Locale locale) throws Exception {
if (location == null) {
throw new Exception(
"No location specified for GenericFileViewResolver.");
}
String requestedFilePath = location + viewName;
Resource resource = null;
try {
logger.finest(requestedFilePath);
resource = getApplicationContext().getResource(requestedFilePath);
} catch (Exception e) {
// 返回 null, 以便被下一个 resolver 处理
logger.finest("No file found for file: " + requestedFilePath);
return null;
}
logger.fine("Requested file found: " + requestedFilePath + ",
viewName:" + viewName);
// 根据视图名,获取相应的 view 对象
GenericFileView view = this.getApplicationContext().getBean(this.viewName,
GenericFileView.class);
view.setUrl(requestedFilePath);
// 写入 view 内容
view.setResponseContent(inputStreamTOString(resource.getInputStream(),
"UTF-8"));
return view;
}
需要注意的是,在找不到请求文件的时候,需要返回 null,这样 Spring 容器中所注册的其他低优先级的视图解析器才能被调用。
视图解析:
public class JeeDevViewResolver implements ViewResolver {
private static Log logger = LogFactory.getLog(JeeDevViewResolver.class);
public View resolveViewName(String viewName, Locale locale) throws Exception {
for(Map.Entry<Set<String>, ViewResolver> map : viewResolverMap.entrySet()){
Set<String> suffixs = map.getKey();
for(String suffix : suffixs){
if (viewName.endsWith(suffix)){
ViewResolver viewResolver = map.getValue();
if(null != viewResolver){
if (logger.isDebugEnabled()) {
logger.debug("found viewResolver '" + viewResolver + "' for viewName '" + viewName+ "'");
}
return viewResolver.resolveViewName(viewName, locale);
}
}
}
}
if(defaultViewResolver != null){
return defaultViewResolver.resolveViewName(viewName, locale);
}
// to allow for ViewResolver chaining
return null;
}
private Map<Set<String>,ViewResolver> viewResolverMap = new HashMap<Set<String>,ViewResolver>();
private ViewResolver defaultViewResolver = null;
public Map<Set<String>, ViewResolver> getViewResolverMap() {
return viewResolverMap;
}
public void setViewResolverMap(Map<Set<String>, ViewResolver> viewResolverMap) {
this.viewResolverMap = viewResolverMap;
}
public ViewResolver getDefaultViewResolver() {
return defaultViewResolver;
}
public void setDefaultViewResolver(ViewResolver defaultViewResolver) {
this.defaultViewResolver = defaultViewResolver;
}
}
视图映射配置dispather-servlet.xml
假如自定义的视图解析器叫NameViewResolver
<bean id="viewResolver" class="com.jeedev.common.web.springmvc.view.JeeDevViewResolver">
<property name="defaultViewResolver" ref="beanNameViewResolver"/>
<property name="viewResolverMap">
<map>
<entry>
<key>
<set>
<value>.jsp</value>
</set>
</key>
<ref bean="jspViewResolver"/>
</entry>
<entry>
<key>
<set>
<value>.vm</value>
<value>.htm</value>
</set>
</key>
<ref bean="velocityViewResolver"/>
</entry>
<entry>
<key><value>.ftl</value></key>
<ref bean="freeMarkerViewResolver"/>
</entry>
<entry>
<key><value>.ziding</value></key>
<ref bean="NameViewResolver"/>
</entry>
</map>
</property>
</bean>
同时注册
<bean id="NameResolver" class="org.springframework.web.servlet.view.NameViewResolver">
<property name="prefix" value="/WEB-INF/ziding/"/>
<!--<property name="suffix" value=".ziding"/>-->
</bean>