上一篇博客springMVC源码分析--HttpMessageConverter参数read操作中我们已经简单介绍了参数值转换的read操作,接下来我们介绍一下返回值的处理操作。同样返回值的操作操作也是在HandlerMethodReturnValueHandler中处理的,可以参考一下老田写的springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)

简单的返回值处理示例使用@ResponseBody进行注解:

@ResponseBody
	@RequestMapping("/get")
	public Object get(){
		Product product = new Product();
		product.setDescription("hello  springMVC  RestFul");
		product.setId(10);
		product.setName("springMVC");
		product.setPrice(10);
		return product; //在页面中返回json数据
	}

这里返回值是一个Product对象,但真正浏览器获取的数据是json数据,处理的过程就是在HttpMessageConverter中实现的 。

配置一下消息处理使用FastJSON处理的配置

<mvc:annotation-driven>
		<mvc:message-converters register-defaults="true">
			<bean
				class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
				<property name="supportedMediaTypes">
					<array>
						<value>text/html;charset=UTF-8</value>
					</array>
				</property>
				<property name="features">
					<array>
						<value>WriteMapNullValue</value>
						<value>WriteNullStringAsEmpty</value>
						<value>DisableCircularReferenceDetect</value>
					</array>
				</property>
			</bean>
		</mvc:message-converters>
	</mvc:annotation-driven>

这样返回值的处理操作就是使用FastJsonHttpMessageConverter来进行处理,将返回值转为json数据返回。

返回值的处理是在HandlerMethodReturnValueHandlerComposite中handleReturnValue中实现的。

@Override
	public void handleReturnValue(Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

		HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
		Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]");
		handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
	}

接下来是在子类RequestResponseBodyMethodProcessor的handleReturnValue中处理操作

@Override
	public void handleReturnValue(Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

		mavContainer.setRequestHandled(true);

		// Try even with null return value. ResponseBodyAdvice could get involved.
		writeWithMessageConverters(returnValue, returnType, webRequest);
	}

在RequestResponseBodyMethodProcessor的父类AbstractMessageConverterMethodProcessor的writeWithMessageConverters中处理操作

protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType, NativeWebRequest webRequest)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

		ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
		ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
		writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
	}

接下来就是通过职责链模式选择HttpMessageConverter的实现类来进行数据转换操作。

@SuppressWarnings("unchecked")
	protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType,
			ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

		Class<?> returnValueClass = getReturnValueType(returnValue, returnType);
		Type returnValueType = getGenericType(returnType);
		HttpServletRequest servletRequest = inputMessage.getServletRequest();
		List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(servletRequest);
		List<MediaType> producibleMediaTypes = getProducibleMediaTypes(servletRequest, returnValueClass, returnValueType);

		if (returnValue != null && producibleMediaTypes.isEmpty()) {
			throw new IllegalArgumentException("No converter found for return value of type: " + returnValueClass);
		}

		Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
		for (MediaType requestedType : requestedMediaTypes) {
			for (MediaType producibleType : producibleMediaTypes) {
				if (requestedType.isCompatibleWith(producibleType)) {
					compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));
				}
			}
		}
		if (compatibleMediaTypes.isEmpty()) {
			if (returnValue != null) {
				throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
			}
			return;
		}

		List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
		MediaType.sortBySpecificityAndQuality(mediaTypes);

		MediaType selectedMediaType = null;
		for (MediaType mediaType : mediaTypes) {
			if (mediaType.isConcrete()) {
				selectedMediaType = mediaType;
				break;
			}
			else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {
				selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
				break;
			}
		}

		if (selectedMediaType != null) {
			selectedMediaType = selectedMediaType.removeQualityValue();
			//匹配消息数据转换器
			for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
				if (messageConverter instanceof GenericHttpMessageConverter) {
					if (((GenericHttpMessageConverter<T>) messageConverter).canWrite(returnValueType,
							returnValueClass, selectedMediaType)) {
						returnValue = (T) getAdvice().beforeBodyWrite(returnValue, returnType, selectedMediaType,
								(Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
								inputMessage, outputMessage);
						if (returnValue != null) {
							addContentDispositionHeader(inputMessage, outputMessage);
							//进行消息转换成配置的格式
							((GenericHttpMessageConverter<T>) messageConverter).write(returnValue,
									returnValueType, selectedMediaType, outputMessage);
							if (logger.isDebugEnabled()) {
								logger.debug("Written [" + returnValue + "] as \"" +
										selectedMediaType + "\" using [" + messageConverter + "]");
							}
						}
						return;
					}
				}
				else if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {
					returnValue = (T) getAdvice().beforeBodyWrite(returnValue, returnType, selectedMediaType,
							(Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
							inputMessage, outputMessage);
					if (returnValue != null) {
						addContentDispositionHeader(inputMessage, outputMessage);
						//将数据转换为配置的数据格式
						((HttpMessageConverter<T>) messageConverter).write(returnValue,
								selectedMediaType, outputMessage);
						if (logger.isDebugEnabled()) {
							logger.debug("Written [" + returnValue + "] as \"" +
									selectedMediaType + "\" using [" + messageConverter + "]");
						}
					}
					return;
				}
			}
		}

		if (returnValue != null) {
			throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
		}
	}

最终会选择FastJsonHttpMessageConverter 的write方法中进行处理操作,就是将数据转换为json写到输出流中

@Override
	protected void writeInternal(Object obj, HttpOutputMessage outputMessage)
			throws IOException, HttpMessageNotWritableException {
        HttpHeaders headers = outputMessage.getHeaders();
        ByteArrayOutputStream outnew = new ByteArrayOutputStream();
        int len = JSON.writeJSONString(outnew, //
                                       fastJsonConfig.getCharset(), //
                                       obj, //
                                       fastJsonConfig.getSerializeConfig(), //
                                       fastJsonConfig.getSerializeFilters(), //
                                       fastJsonConfig.getDateFormat(), //
                                       JSON.DEFAULT_GENERATE_FEATURE, //
                                       fastJsonConfig.getSerializerFeatures());
        headers.setContentLength(len);
        OutputStream out = outputMessage.getBody();
        outnew.writeTo(out);
        outnew.close();
    }

springMVC默认提供了很多参数和结果值处理器,包括如下:

(1)MappingJackson2HttpMessageConverter

(2)GsonHttpMessageConverter

(3)ByteArrayHttpMessageConverter

(4)ObjectToStringHttpMessageConverter

(5)ProtobufHttpMessageConverter

(6)ResourceHttpMessageConverter

(7)StringHttpMessageConverter

(8)AllEncompassingFormHttpMessageConverter

springMVC源码分析--HttpMessageConverter写write操作(三)的更多相关文章

  1. springMVC源码分析--HttpMessageConverter参数read操作(二)

    上一篇博客springMVC源码分析--HttpMessageConverter数据转化(一)中我们简单介绍了一下HttpMessageConverter接口提供的几个方法,主要有以下几个方法: (1 ...

  2. springMVC源码分析--HttpMessageConverter数据转化(一)

    之前的博客我们已经介绍了很多springMVC相关的模块,接下来我们介绍一下springMVC在获取参数和返回结果值方面的处理.虽然在之前的博客老田已经分别介绍了参数处理器和返回值处理器: (1)sp ...

  3. springMVC源码分析--拦截器HandlerExecutionChain(三)

    上一篇博客springMVC源码分析--HandlerInterceptor拦截器调用过程(二)中我们介绍了HandlerInterceptor的执行调用地方,最终HandlerInterceptor ...

  4. springMVC源码分析--视图View(一)

    之前的博客springMVC源码分析--HttpMessageConverter数据转化(一)中我们已经介绍了数据返回值的处理,在博客springMVC源码分析--ViewResolver视图解析器( ...

  5. springMVC源码分析--HandlerMapping(一)

    HandlerMapping的工作就是为每个请求找到合适的请求找到一个处理器handler,其实现机制简单来说就是维持了一个url到Controller关系的Map结构,其提供的实际功能也是根据req ...

  6. [心得体会]SpringMVC源码分析

    1. SpringMVC (1) springmvc 是什么? 前端控制器, 主要控制前端请求分配请求任务到service层获取数据后反馈到springmvc的view层进行包装返回给tomcat, ...

  7. springMVC源码分析--国际化实现Session和Cookie(二)

    上一篇博客springMVC源码分析--国际化LocaleResolver(一)中我们介绍了springMVC提供的国际化的解决方案,接下来我们根据springMVC提供的解决方案来简单的实现一个多语 ...

  8. SpringMVC源码分析--容器初始化(五)DispatcherServlet

    上一篇博客SpringMVC源码分析--容器初始化(四)FrameworkServlet我们已经了解到了SpringMVC容器的初始化,SpringMVC对容器初始化后会进行一系列的其他属性的初始化操 ...

  9. springMVC源码分析--ViewNameMethodReturnValueHandler返回值处理器(三)

    之前两篇博客springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)和springMVC源码分析--HandlerMethodReturnValu ...

随机推荐

  1. 【最小割】【网络流24题】【P2762】 太空飞行计划问题

    Description W 教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合E={E1,E2,-,Em},和进行这些实验需要使 ...

  2. 为什么只有一个元素的tuple要加逗号?

    如果要定义一个空的tuple,可以写成(): >>> t = () >>> t () 但是,要定义一个只有1个元素的tuple,如果你这么定义: >>& ...

  3. Centos6.6下安装nginx1.6.3

    安装环境: [root@nginx ~]# cat /etc/redhat-release CentOS release 6.6 (Final) [root@nginx ~]# uname -r 2. ...

  4. OpenStack介绍(一)

    官方网站:http://www.openstack.org/ 介绍 OpenStack是一个由NASA(美国国家航空航天局)和Rackspace合作研发并发起的,以Apache许可证授权的自由软件和开 ...

  5. Django分别使用Memcached和Redis作为缓存的配置(Linux环境)

    1 使用memcached 1.1 安装memcached 安装(Linux) sudo apt install memcached 启动 #方式一: service memcached start ...

  6. 编写可维护的js代码

    在工作中,制定一套统一的编码风格,可以提高开发效率,维护起来的也要容易很多,也能避免一些不必要的错误出现. 项目中常用的检查编码风格的工具JSLint.JSHint.JSCS.ESLint,,在这呢, ...

  7. SQL语句(十八_补充)——存储过程

    一. 变量 1. 形式: @x (局部), @@x(全局) 2. 定义: declare @x 3. 赋值:Set @x = ? 4. 作用: 通用化 存储在服务器 5. 存储过程(预编译过的T-SQ ...

  8. Django 2.0.1 官方文档翻译: 高级教程:如何编写可重用的app (page 13)

    高级教程:如何编写可重用的app (page 13) 本节教程上接第七部分(Page 12).我们会把我们的 web-poll应用转换成一个独立的python包,你可以在新的项目中重用或者把它分享给其 ...

  9. IEnumerable 与 IQueryable

    无论是在ado.net EF或者是在其他的Linq使用中,我们经常会碰到两个重要的静态类Enumerable.Queryable,他们在System.Linq命名空间下.那么这两个类是如何定义的,又是 ...

  10. 苏宁OLAP架构设计

    一. 功能综述 OLAP引擎为存储和计算二合一的引擎,自身内部涵盖了对数据的管理以及提供查询能力.底层数据完全规划在引擎内部,外部系统不允许直接操作底层数据,而是需要通过暴露出来的接口来读写引擎内部数 ...