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

(1)canRead 是否可以读

(2)canWrite 是否可以写

(3)read() 读数据

(4)write() 写数据

接下来我们介绍一下读取数据的处理操作。

首先要去重温一下参数处理器需要做的操作springMVC源码分析--RequestParamMethodArgumentResolver参数解析器(三),AbstractNamedValueMethodArgumentResolver中的resolveArgument方法,解析参数值

public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
		.......
		Object arg = resolveName(namedValueInfo.name, parameter, webRequest);
		......
	}

简单的提交数据的示例:

 @RequestMapping(value="/save")
    public String saveProduct( String name,@RequestBody String description,@RequestBody float price, Model model)
   .......
}

我们可以在HandlerMethodArgumentResolver的子类RequestResponseBodyMethodProcessor的方法resolveArgument看到如下处理,这里就是对提交的参数的处理

public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

		Object arg = readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType());
		.........
	}

接下来在readWithMessageConverters中的处理如下:

@Override
	protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter methodParam,
			Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
		HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
		ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
		Object arg = readWithMessageConverters(inputMessage, methodParam, paramType);
		if (arg == null) {
			if (methodParam.getParameterAnnotation(RequestBody.class).required()) {
				throw new HttpMessageNotReadableException("Required request body is missing: " +
						methodParam.getMethod().toGenericString());
			}
		}
		return arg;
	}

在父类AbstractMessageConverterMethodArgumentResolver的方法readWithMessageConverters中的处理如下:简单来说就是根据提供的实现的HttpMessageConverter来对提交的RequestBody中的数据进行转换处理。

@SuppressWarnings("unchecked")
	protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter param,
			Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
		//获取数据类型
		MediaType contentType;
		boolean noContentType = false;
		try {
			contentType = inputMessage.getHeaders().getContentType();
		}
		catch (InvalidMediaTypeException ex) {
			throw new HttpMediaTypeNotSupportedException(ex.getMessage());
		}
		if (contentType == null) {
			noContentType = true;
			contentType = MediaType.APPLICATION_OCTET_STREAM;
		}

		Class<?> contextClass = (param != null ? param.getContainingClass() : null);
		Class<T> targetClass = (targetType instanceof Class<?> ? (Class<T>) targetType : null);
		if (targetClass == null) {
			ResolvableType resolvableType = (param != null ?
					ResolvableType.forMethodParameter(param) : ResolvableType.forType(targetType));
			targetClass = (Class<T>) resolvableType.resolve();
		}

		HttpMethod httpMethod = ((HttpRequest) inputMessage).getMethod();
		Object body = NO_VALUE;

		try {
			inputMessage = new EmptyBodyCheckingHttpInputMessage(inputMessage);
			//选择适合的消息处理器来处理参数
			for (HttpMessageConverter<?> converter : this.messageConverters) {
				Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
				//判断是否适合处理参数
				if (converter instanceof GenericHttpMessageConverter) {
					GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter;
					if (genericConverter.canRead(targetType, contextClass, contentType)) {
						if (logger.isDebugEnabled()) {
							logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
						}
						if (inputMessage.getBody() != null) {
							inputMessage = getAdvice().beforeBodyRead(inputMessage, param, targetType, converterType);
							//处理参数
							body = genericConverter.read(targetType, contextClass, inputMessage);
							body = getAdvice().afterBodyRead(body, inputMessage, param, targetType, converterType);
						}
						else {
							body = null;
							body = getAdvice().handleEmptyBody(body, inputMessage, param, targetType, converterType);
						}
						break;
					}
				}
				else if (targetClass != null) {
					if (converter.canRead(targetClass, contentType)) {
						if (logger.isDebugEnabled()) {
							logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
						}
						if (inputMessage.getBody() != null) {
							inputMessage = getAdvice().beforeBodyRead(inputMessage, param, targetType, converterType);
							//处理数据,对于简单的String数据使用StringHttpMessageConverter进行处理
							body = ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
							body = getAdvice().afterBodyRead(body, inputMessage, param, targetType, converterType);
						}
						else {
							body = null;
							body = getAdvice().handleEmptyBody(body, inputMessage, param, targetType, converterType);
						}
						break;
					}
				}
			}
		}
		catch (IOException ex) {
			throw new HttpMessageNotReadableException("Could not read document: " + ex.getMessage(), ex);
		}

		if (body == NO_VALUE) {
			if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
					(noContentType && inputMessage.getBody() == null)) {
				return null;
			}
			throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
		}
		//最终返回处理的结果值
		return body;
	}

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

(1)MappingJackson2HttpMessageConverter

(2)GsonHttpMessageConverter

(3)ByteArrayHttpMessageConverter

(4)ObjectToStringHttpMessageConverter

(5)ProtobufHttpMessageConverter

(6)ResourceHttpMessageConverter

(7)StringHttpMessageConverter

(8)AllEncompassingFormHttpMessageConverter

springMVC源码分析--HttpMessageConverter参数read操作(二)的更多相关文章

  1. springMVC源码分析--HttpMessageConverter写write操作(三)

    上一篇博客springMVC源码分析--HttpMessageConverter参数read操作中我们已经简单介绍了参数值转换的read操作,接下来我们介绍一下返回值的处理操作.同样返回值的操作操作也 ...

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

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

  3. springMVC源码分析--RequestParamMethodArgumentResolver参数解析器(三)

    之前两篇博客springMVC源码分析--HandlerMethodArgumentResolver参数解析器(一)和springMVC源码解析--HandlerMethodArgumentResol ...

  4. springMVC源码分析--动态样式ThemeResolver(二)

    在上一篇博客springMVC源码分析--动态样式ThemeResolver(一)中我们介绍了多样式ThemeResolver的使用方法,接下来我们对源码进行简单的分析一下. ThemeResolve ...

  5. springMVC源码分析--HandlerMethodArgumentResolver参数解析器(一)

    HandlerMethodArgumentResolver是用来为处理器解析参数的,主要用在HandlerMethod中,每个Resolver对应一种类型的参数,其实现类特别的多. HandlerMe ...

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

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

  7. springMVC源码解析--HandlerMethodArgumentResolverComposite参数解析器集合(二)

    上一篇博客springMVC源码分析--HandlerMethodArgumentResolver参数解析器(一)中我们已经介绍了参数解析相关的东西,并且也提到了HandlerMethodArgume ...

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

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

  9. springMVC源码分析--访问请求执行ServletInvocableHandlerMethod和InvocableHandlerMethod

    在之前一篇博客中springMVC源码分析--RequestMappingHandlerAdapter(五)我们已经简单的介绍到具体请求访问的执行某个Controller中的方法是在RequestMa ...

随机推荐

  1. Error: cannot allocate vector of size 88.1 Mb问题

    这几天训练模型运行代码的时候,老是提示我说:Error: cannot allocate vector of size 88.1 Mb,只知道分配空间不足. 下面是查资料看到的一些回答: 一.这个是R ...

  2. 执行composer install 报错的解决办法

    执行composer install后报以下错误: Loading composer repositories with package informationInstalling dependenc ...

  3. Python【异常处理】

    def f(): first = input('请输入除数:') second = input('请输入被除数:') try: first = int(first) second = int(seco ...

  4. NATS_04:NATS协议详解

    NATS的协议是一个简单的.基于文本的发布/订阅风格的协议.客户端连接到 gnatsd(NATS服务器),并与 gnatsd 进行通信,通信基于普通的 TCP/IP 套接字,并定义了很小的操作集,换行 ...

  5. Excel批量删除换行符_clean函数

    http://jingyan.baidu.com/article/e2284b2b489b96e2e6118d30.html CLEAN函数,用于删除文本中不能打印的字符.对从其他应用程序中输入的文本 ...

  6. 已经菜到不行了 PAT 1010. Radix (25)

    https://www.patest.cn/contests/pat-a-practise/1010 题目大意: 输入四个数字,a,b,c,d. a和b是两个数字,c=1表示是第一个数字,c=2表示是 ...

  7. HDU 1422 重温世界杯 DP题

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1422 解题报告:DP题,要使旅行的城市最多,关键是要选出一个城市作为开始,以这个城市作为开始的城市时, ...

  8. HDU 1718 Rank 排序

    解题报告:给一个班的学生的分数排序,然后判断Jack在他们班级的排名是多少,并且有如下规定,若多个人的分数相同,则他们的排名也 是相同的.说白了就是问这个班上分数比Jack高的人数有多少个,如果有n个 ...

  9. POJ 3255 Roadblocks (次短路 SPFA )

    题目链接 Description Bessie has moved to a small farm and sometimes enjoys returning to visit one of her ...

  10. flask跨域请求三行代码搞定

    flask跨域请求三行代码就可以搞定.但是请注意几点: 第一:只能返回json格式数据,比如list.ndarray等都不可以 第二:返回的对象必须是是字符串.元组.响应实例或WSGI可调用. pyt ...