?? ?ContentNegotiatingViewResolver视图解析器是Spring MVC 中常用的一个视图解析器。 ??
????这个实现了ViewResolver接口,基于请求文件和Accept 头部信息。ContentNagotiatingViewResolver自己并不解析视图,而是委派给其他的视图处理器。 回过头来,哪些其他的视图解析器
是自动地从应用上下文中挑选出来的,虽然它可以通过viewResolvers属性配置。为了使这个解析器正常工作,序号需要设置成比其他的视图处理器高的优先级。这个视图处理器使用必要的媒体类型为一个请求去选择一个合适的视图。媒体类型通过如下的标准决定:
?如果请求路径中包含一个文件扩展名或者将favorPathExtension属性置为true, mediaTypes属性是否匹配媒体类型。
????看看这个类的属性:
?
// 是否使用请求文件扩展名作为媒体类型
private boolean favorPathExtension = true;
// 是否使用请求参数决定媒体类型
private boolean favorParameter = false;
// 媒体类型参数名
private String parameterName = "format";
private boolean useNotAcceptableStatusCode = false;
// 是否忽略Accept header
private boolean ignoreAcceptHeader = false;
private boolean useJaf = jafPresent;
// 媒体类型MAP
private ConcurrentMap<String, MediaType> mediaTypes = new ConcurrentHashMap<String, MediaType>();
// 默认的视图
private List<View> defaultViews;
//默认的媒体类型
private MediaType defaultContentType;
// 视图解析器
private List<ViewResolver> viewResolvers;
?????默认的优先级是最高的,也就是最小整数值!优先级和整数值是反比关系,数值越小优先级越高。
?
??????视图解析器的初始化,首先是从上下文中去查找,其次获取配置的解析器,最后通过解析器的优先级进行排序。
@Override
protected void initServletContext(ServletContext servletContext) {
Collection<ViewResolver> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(getApplicationContext(), ViewResolver.class).values();
if (this.viewResolvers == null) {
this.viewResolvers = new ArrayList<ViewResolver>(matchingBeans.size());
for (ViewResolver viewResolver : matchingBeans) {
if (this != viewResolver) {
this.viewResolvers.add(viewResolver);
}
}
}
else {
for (int i=0; i < viewResolvers.size(); i++) {
if (matchingBeans.contains(viewResolvers.get(i))) {
continue;
}
String name = viewResolvers.get(i).getClass().getName() + i;
getApplicationContext().getAutowireCapableBeanFactory().initializeBean(viewResolvers.get(i), name);
}
}
if (this.viewResolvers.isEmpty()) {
logger.warn("Did not find any ViewResolvers to delegate to; please configure them using the " +
"‘viewResolvers‘ property on the ContentNegotiatingViewResolver");
}
OrderComparator.sort(this.viewResolvers);
}
?
视图解析器的入口,首先通过请求路径获取媒体类型mediaType
?
public View resolveViewName(String viewName, Locale locale) throws Exception {
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
Assert.isInstanceOf(ServletRequestAttributes.class, attrs);
List<MediaType> requestedMediaTypes = getMediaTypes(((ServletRequestAttributes) attrs).getRequest());
if (requestedMediaTypes != null) {
List<View> candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes);
View bestView = getBestView(candidateViews, requestedMediaTypes);
if (bestView != null) {
return bestView;
}
}
if (this.useNotAcceptableStatusCode) {
if (logger.isDebugEnabled()) {
logger.debug("No acceptable view found; returning 406 (Not Acceptable) status code");
}
return NOT_ACCEPTABLE_VIEW;
}
else {
logger.debug("No acceptable view found; returning null");
return null;
}
}
?
?
通过所有视图解析器去解析视图,将解析的视图放入一个待选的集合中,然后在通过追加媒体类型的后缀再次去解析一次,将结果放入待选视图集合中,如果最后的集合还是空的则放入默认的视图集。
private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes)
throws Exception {
List<View> candidateViews = new ArrayList<View>();
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
candidateViews.add(view);
}
for (MediaType requestedMediaType : requestedMediaTypes) {
List<String> extensions = getExtensionsForMediaType(requestedMediaType);
for (String extension : extensions) {
String viewNameWithExtension = viewName + "." + extension;
view = viewResolver.resolveViewName(viewNameWithExtension, locale);
if (view != null) {
candidateViews.add(view);
}
}
}
}
if (!CollectionUtils.isEmpty(this.defaultViews)) {
candidateViews.addAll(this.defaultViews);
}
return candidateViews;
}
?最后从这些视图中返回一个最优的视图,?使用volecity?框架最常见的就是 xxx.htm.vm?或xxx.vm.htm?视图找不到
?
ContentNegotiatingViewResolver 学习
原文:http://zhangwei-david.iteye.com/blog/2162739