`
zhangwei_david
  • 浏览: 475563 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

ContentNegotiatingViewResolver 学习

 
阅读更多

    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 视图找不到 这样的一个错误消息。

  为了解决命中率不高的问题,可以使用通过扩展名决定使用哪一个ViewResolver,根据ContentNegotiatingViewResolver的设计思路,设计一个ViewResolver ,它本身布解析视图,而是委派给指定的相应的视图解析器。

 

/**
 * 根据请求的扩展名决定使用什么ViewResolver
 * @author zhangwei_david
 * @version $Id: ExtensionViewResolver.java, v 0.1 2014年12月2日 上午10:37:02 zhangwei_david Exp $
 */
public class ExtensionViewResolver implements ViewResolver, Ordered {
    private static final Logger           logger        = LogManager
                                                            .getLogger(ExtensionViewResolver.class);

    private HashMap<String, ViewResolver> resolvers     = new HashMap<String, ViewResolver>();

    private ViewResolver                  defaultViewReslver;

    private UrlPathHelper                 urlPathHelper = new UrlPathHelper();
    /**
     * 默认使用最高优先级
     */
     private int                           order         = Ordered.HIGHEST_PRECEDENCE;

     /**
      * @see org.springframework.core.Ordered#getOrder()
      */
     public int getOrder() {
         return order;
     }

     /**
      * @see org.springframework.web.servlet.ViewResolver#resolveViewName(java.lang.String, java.util.Locale)
      */
     public View resolveViewName(String viewName, Locale locale) throws Exception {
         String extension = getExtension(viewName);
         if (logger.isDebugEnabled()) {
             logger.debug("当前的扩展参数是:" + extension);
         }
         ViewResolver resolver = getResolver(extension);
         if (logger.isInfoEnabled()) {
             logger.info("当前的视图解析器是:" + ToStringBuilder.reflectionToString(resolver));
         }
         return resolver.resolveViewName(viewName, locale);
     }

     /**
      *
      * @param viewName
      * @return
      */
     private String getExtension(String viewName) {
         RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
         Assert.isInstanceOf(ServletRequestAttributes.class, attrs);
         HttpServletRequest request = ((ServletRequestAttributes) attrs).getRequest();
         String uri = urlPathHelper.getRequestUri(request);
         return StringUtils.getFilenameExtension(uri);
     }

     /**
      *
      * @param extension
      * @return
      */
     private ViewResolver getResolver(String extension) {
         ViewResolver resolver = resolvers.get(extension);

         return resolver == null ? defaultViewReslver : resolver;
     }

     /**
      * Setter method for property <tt>resolvers</tt>.
      *
      * @param resolvers value to be assigned to property resolvers
      */
     public void setResolvers(HashMap<String, ViewResolver> resolvers) {
         this.resolvers = resolvers;
     }

     /**
      * Setter method for property <tt>order</tt>.
      *
      * @param order value to be assigned to property order
      */
     public void setOrder(int order) {
         this.order = order;
     }

     /**
      * Getter method for property <tt>defaultViewReslver</tt>.
      *
      * @return property value of defaultViewReslver
      */
     public ViewResolver getDefaultViewReslver() {
         return defaultViewReslver;
     }

     /**
      * Setter method for property <tt>defaultViewReslver</tt>.
      *
      * @param defaultViewReslver value to be assigned to property defaultViewReslver
      */
     public void setDefaultViewReslver(ViewResolver defaultViewReslver) {
         this.defaultViewReslver = defaultViewReslver;
     }

}

 

 定义一个JSON的视图解析器:

/**
 *
 * @author zhangwei_david
 * @version $Id: JsonViewResolver.java, v 0.1 2014年11月30日 上午12:09:44 zhangwei_david Exp $
 */
public class JsonViewResolver implements ViewResolver, Ordered {

    private static final Logger logger = LogManager.getLogger(JsonViewResolver.class);

    private int                 order  = Ordered.HIGHEST_PRECEDENCE;
    private UrlPathHelper       urlPathHelper;

    /**
     * @see org.springframework.web.servlet.ViewResolver#resolveViewName(java.lang.String, java.util.Locale)
     */
    public View resolveViewName(String viewName, Locale locale) throws Exception {

        RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
        Assert.isInstanceOf(ServletRequestAttributes.class, attrs);
        HttpServletRequest request = ((ServletRequestAttributes) attrs).getRequest();
        String uri = urlPathHelper.getRequestUri(request);
        if (uri.contains(".json")) {
            LogUtils.info(logger, "Handler the Uri {0} and Return A JSON View", uri);
            return new MappingJacksonJsonView();
        }
        //
        return null;
    }

    /**
     * Getter method for property <tt>urlPathHelper</tt>.
     *
     * @return property value of urlPathHelper
     */
    public UrlPathHelper getUrlPathHelper() {
        return urlPathHelper;
    }

    /**
     * Setter method for property <tt>urlPathHelper</tt>.
     *
     * @param urlPathHelper value to be assigned to property urlPathHelper
     */
    public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
        this.urlPathHelper = urlPathHelper;
    }

    /**
     * @see org.springframework.core.Ordered#getOrder()
     */
    public int getOrder() {
        return order;
    }

    /**
     * Setter method for property <tt>order</tt>.
     *
     * @param order value to be assigned to property order
     */
    public void setOrder(int order) {
        this.order = order;
    }

}

 

<bean id="urlPathHelper " class="org.springframework.web.util.UrlPathHelper" />

	<bean id="jsonViewResolver" class="com.david.web.view.JsonViewResolver">
		<property name="order" value="1" />
		<property name="urlPathHelper" ref="urlPathHelper" />
	</bean>
	<bean id="velocityViewResolver"
		class="org.springframework.web.servlet.view.velocity.VelocityLayoutViewResolver">
		<property name="order" value="3" />
		<property name="viewClass"
			value="org.springframework.web.servlet.view.velocity.VelocityLayoutView" />
		<property name="cache" value="false" />
		<property name="layoutUrl" value="layout.vm" />
		<property name="contentType">
			<value>text/html;charset=UTF-8</value>
		</property>
		<property name="exposeSpringMacroHelpers" value="true" />
	</bean>
	<bean class="com.david.web.view.ExtensionViewResolver">
		<property name="defaultViewReslver" ref="velocityViewResolver" />
		<property name="resolvers">
			<map>
				<entry key="htm" value-ref="velocityViewResolver" />
				<entry key="json" value-ref="jsonViewResolver" />
			</map>
		</property>
	</bean>

 

0
0
分享到:
评论

相关推荐

    SpringMVC PDF

    8. 内容协商解析器ContentNegotiatingViewResolver:这是Spring MVC提供的一个视图解析器,用于根据客户端的需求动态选择合适的视图。 9. 闪存属性FlashAttributes:用于在请求间传递参数,常用于重定向时传递数据...

    springmvc4.2.4中文版开发文档

    7. 内容协商解析器:介绍了ContentNegotiatingViewResolver的用法和配置。 8. 闪存属性:描述了FlashAttributes的使用场景和方法。 9. 文件上传支持:详细介绍了Spring对multipart文件上传的支持,以及Servlet 3.0...

    Spring Framework 4.1源代码

    在4.1版本中,Spring MVC增加了对ContentNegotiatingViewResolver的改进,使得内容协商更加智能,可以更好地处理多种格式的响应,如JSON、XML等。此外,模型视图名转换器(ModelAndViewNameTransformer)的引入允许...

    Spring MVC学习笔记之json格式的输入和输出

    配置了ContentNegotiatingViewResolver后,可以指定当客户端请求JSON格式的内容时,使用MappingJacksonJsonView来生成JSON响应。这种方式会将model对象序列化成JSON格式,但通常会包含model类名作为外层键值。 以上...

    使用-Spring-3-来创建-RESTful-Web-Services

    Spring 3 的 REST 支持包括注释、ContentNegotiatingViewResolver 等特性,支持资源标识和 URL 映射、多种 MIME 类型表示支持和 JAXB 支持等。 创建一个示例 RESTful Web Service 要创建这个示例应用,您需要: 1...

    Spring MVC 4.2.4.RELEASE 中文文档v

    Spring MVC 4.2.4.RELEASE 是 Spring Framework 中一个重要的 Web 框架版本,它提供了一套全面的解决方案来构建 Web 应用程序。...对于希望深入学习和掌握 Spring MVC 的开发者而言,这是一份宝贵的学习资料。

    spring3.1.0.RELEASE项目源码

    这个源码版本提供了一个深入理解Spring内部工作原理的机会,对学习和调试Spring应用非常有帮助。 首先,Spring 3.1.0.RELEASE对依赖注入(Dependency Injection,DI)进行了优化,使得配置更加简洁和灵活。这一版本...

    springmvc3.0

    另外,Spring MVC 3.0 引入了 ContentNegotiatingViewResolver 视图解析器,它可以自动根据请求的 Accept 头部选择最合适的视图,这对于支持多种格式的响应(如 JSON、XML)至关重要。 最后,Spring MVC 3.0 对于...

    springmvc_base1

    3. **ContentNegotiatingViewResolver**:根据请求的Accept头和URL扩展名选择合适的视图。 在"spring-base1"中,你可能配置了一个或多个ViewResolver,并指定了前缀和后缀,例如,逻辑视图名"home"会被解析为"/WEB-...

    Spring MVC 4.2.4.RELEASE 中文文档

    整个文档内容展现了 Spring MVC 的全面功能和使用方法,对于希望深入学习和使用 Spring MVC 框架的开发者来说,这个文档是宝贵的学习资源。翻译注记部分说明了翻译过程中的问题、取舍以及解决方案,反映了翻译者对...

    spring-3.1.0中文版api帮助文档

    3.1.0版本引入了ContentNegotiatingViewResolver,支持多格式响应内容,以及ModelAndView的改进,使得模型数据更容易管理。 6. **表达式语言(SpEL)**:Spring Expression Language允许在运行时查询和操纵对象图。...

    springMVC快速入门 深入分析

    本文中提到的“mvc:annotation-driven”是SpringMVC提供的一个便利标签,它自动注册了ConversionService和Formatter的实现类,同时启用了MessageConverter、ExceptionResolver、ContentNegotiatingViewResolver等...

    spring:Spring 4.0增强课程

    1. RESTful支持:Spring MVC 4.0提供了更完善的RESTful支持,如ContentNegotiatingViewResolver,可以根据请求头自动选择合适的视图。 2. JSON处理:Jackson 2.x被集成到Spring中,提供更高效、更强大的JSON序列化...

    springMVC整合DWR3.0 实例

    ### SpringMVC整合DWR3.0 实例详解 #### 一、前言 随着Web技术的不断发展,前后端分离的架构模式越来越受到开发者的青睐。...希望本文能为您的项目带来帮助,也欢迎各位提出宝贵意见,共同学习进步。

    spring-mvc-documentation-linesh-translation

    - **ContentNegotiatingViewResolver**: 该解析器可以根据客户端接受的内容类型来选择合适的视图渲染方式。 ### 闪存属性 - **使用 FlashAttributes**: 临时存储数据,在重定向后可以被下一个请求访问一次。 ### ...

    springmvc4.2中文文档

    这些知识点覆盖了Spring MVC的核心概念和常用功能,为开发者提供了深入学习Spring MVC的机会。由于文档内容非常丰富,以上总结尽量详尽地概括了文档的主要部分,以便于理解。在实际应用时,开发者应结合文档的具体...

    SSM框架整合案例

    &lt;bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"&gt; ``` 4. **配置MyBatis**:创建`mybatis-config.xml`,配置MyBatis的基本属性和...

    深入剖析Spring Web源码

    通过学习Spring Web MVC的架构设计,开发者不仅可以更好地理解和应用Spring框架,还可以借鉴其设计理念来改进自己的应用程序架构。对于想要深入了解Spring Web MVC的开发人员来说,这是一本非常有价值的参考资料。

    SSM框架常用核心接口和类.txt

    ### SSM框架常用核心接口和类 #### 一、概述 在Java EE开发领域中,SSM(Spring + Spring MVC + MyBatis)框架是非常流行的一种轻量级Web...希望本文能够为正在学习或使用SSM框架的开发者们提供一定的帮助和支持。

Global site tag (gtag.js) - Google Analytics