spring MVC 获取request中的body体

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tianhongqiang/article/details/51636413

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"><span style="white-space:pre">	</span>在项目中,客户端向服务端传送一组json数据,这组数据随着时间的推移可能会越来越大,可能会受到服务器对参数大小的限制的影响,因此,想直接将数据塞进request的body体中,继而发送给服务端,服务端直接将request中body 以流的方式读出来,并持久化。</span>

HttpServletRequest类中有两个方法 getInputStream() 和request.getReader() ,本以为可以直接快速搞定,但是运行程序时报异常:getInputStream() has already been called for this request ,经过查证,原来项目采用springmvc框架,框架内部已经读过request中流,所以当再次读取时,就读不到了,所以直接获取走不通了。

在网上问了问度娘,springmvc 中有一个注解@RequestBody 可以获取request中数据,部分代码如下:

@RequestMapping("/save")

public ModelAndView save(HttpServletRequest request,@RequestBody String s){ 

//具体操作 省略

}

运行过程中,还是有问题,但至少有进了一步,上述的String对象依然无法获取数据,这就有些纠结了,又开始问度娘和下载找spring的源码,了解@RequestBody的实现细节,发现获取body spring用了一系列的HttpMessageConverter 来实现,如:ByteArrayHttpMessageConverter,stringHttpMessageConverter ,spring自个实现的转换器,com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter【国产的json转换器,该转换器需要在配置文件中配置】,默认的转换器的初始化工作在RequestMappingHandlerAdapter这个类中实现

	private List<HttpMessageConverter<?>> messageConverters;//转换器的集合
public RequestMappingHandlerAdapter() {

		StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
		stringHttpMessageConverter.setWriteAcceptCharset(false); // See SPR-7316

		this.messageConverters = new ArrayList<HttpMessageConverter<?>>();
		this.messageConverters.add(new ByteArrayHttpMessageConverter());
		this.messageConverters.add(stringHttpMessageConverter);
		this.messageConverters.add(new SourceHttpMessageConverter<Source>());
		this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
	}//初始化工作

找到这发现byte ,String的转换器已经初始化了,但是为啥还是拿不到String类型的数据呢,接着找关于converters相关的代码,有个setMessageConverters方法

	/**
	 * Provide the converters to use in argument resolvers and return value
	 * handlers that support reading and/or writing to the body of the
	 * request and response.
	 */
	public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
		this.messageConverters = messageConverters;
	}
spring在解析xml过程中会调用该方法 ,从而将用到的converters注入进去,因此明白项目在启动的过程中重新设置了HttpMessageConverter ,而我需要的converter并没有注入进去,因此在xml中配置如下

<mvc:annotation-driven >
		<mvc:message-converters> 
            <ref bean="fastJsonHttpMessageConverter" /> 
        </mvc:message-converters> 
	</mvc:annotation-driven>
	
	<bean id="stringHttpMessageConverter"  
        class="org.springframework.http.converter.StringHttpMessageConverter">  
        <constructor-arg value="UTF-8" index="0"></constructor-arg>
        <property name="supportedMediaTypes">  
            <list>  
                <value>text/plain;charset=UTF-8</value>  
            </list>  
        </property>  
    </bean>
    <bean id="byteHttpMessageConverter"  
        class="org.springframework.http.converter.ByteArrayHttpMessageConverter">  
    </bean>    
    <bean id="fastJsonHttpMessageConverter"  
        class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">  
  
        <property name="supportedMediaTypes">  
            <list>  
                <value>application/json;charset=UTF-8</value>  
                <value>text/html;charset=UTF-8</value> 
            </list>  
        </property>
         <property name="features">  
            <list>  
                <!-- <value>WriteMapNullValue</value> -->  
                <value>QuoteFieldNames</value>  
                <value>WriteDateUseDateFormat</value>  
            </list>  
        </property>    
    </bean>  

这时启动项目,可以拿到数据了。。。

因此,在遇到问题的时候,先按照自己的思路尝试着去解决,可能有时候有些问题确实不知道如何解决的时候,可以先查查网上有没有相关问题的解决方案,选择合适的方案,自然问题就迎刃而解了,但是个别的时候,会遇到相当棘手的问题,通过一系列方案都无法完美解决的时候,可以尝试去查阅源码,同过阅读源码,一会理解框架的开发者的设计思路,只要顺着他们的思路,我们的问题自然就不是问题了。

最后,多读读优秀的开源项目的源码。


附:遍历转换器的代码

AbstractMessageConverterMethodArgumentResolver 


/**
	 * Creates the method argument value of the expected parameter type by reading
	 * from the given HttpInputMessage.
	 *
	 * @param <T> the expected type of the argument value to be created
	 * @param inputMessage the HTTP input message representing the current request
	 * @param methodParam the method argument
	 * @param targetType the type of object to create, not necessarily the same as
	 * the method parameter type (e.g. for {@code HttpEntity<String>} method
	 * parameter the target type is String)
	 * @return the created method argument value
	 * @throws IOException if the reading from the request fails
	 * @throws HttpMediaTypeNotSupportedException if no suitable message converter is found
	 */
	@SuppressWarnings("unchecked")
	protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage,
			MethodParameter methodParam, Type targetType) throws IOException, HttpMediaTypeNotSupportedException {

				MediaType contentType = inputMessage.getHeaders().getContentType();
				if (contentType == null) {
					contentType = MediaType.APPLICATION_OCTET_STREAM;
				}

				Class<?> contextClass = methodParam.getDeclaringClass();
				Map<TypeVariable, Type> map = GenericTypeResolver.getTypeVariableMap(contextClass);
				Class<T> targetClass = (Class<T>) GenericTypeResolver.resolveType(targetType, map);

				for (HttpMessageConverter<?> converter : this.messageConverters) {
					if (converter instanceof GenericHttpMessageConverter) {
						GenericHttpMessageConverter genericConverter = (GenericHttpMessageConverter) converter;
						if (genericConverter.canRead(targetType, contextClass, contentType)) {
							if (logger.isDebugEnabled()) {
								logger.debug("Reading [" + targetType + "] as \"" +
										contentType + "\" using [" + converter + "]");
							}
							return genericConverter.read(targetType, contextClass, inputMessage);
						}
					}
					if (targetClass != null) {
						if (converter.canRead(targetClass, contentType)) {
							if (logger.isDebugEnabled()) {
								logger.debug("Reading [" + targetClass.getName() + "] as \"" +
										contentType + "\" using [" + converter + "]");
							}
							return ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
						}
					}
				}

				throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes);
			}












猜你喜欢

转载自blog.csdn.net/tianhongqiang/article/details/51636413