Spring MVC:不反序列化JSON请求体

时间:2013-05-09 16:57:00

标签: java json spring-mvc

我正在开发一个Spring MVC项目,我需要完成的任务之一要求我在POST请求中通过用户发送一串JSON数据。我知道Spring会使用Jackson将JSON反序列化为对象,但如果我尝试以下内容:

@RequestMapping(value = "/test", method = RequestMethod.POST)
public void doSomething(@RequestBody String json) {
    // do something
}

我只是回复了HTTP 400错误请求(“客户端发送的请求在语法上不正确。”)。

如何将客户端发送的原始JSON作为字符串?

6 个答案:

答案 0 :(得分:50)

当Spring MVC找到与URL路径匹配的请求映射但参数(或标题或其他内容)与处理程序方法所期望的不匹配时,您通常会看到此类错误。

如果您使用@RequestBody注释,那么我相信Spring MVC期望将POST请求的整个主体映射到Object。我猜你的身体不仅仅是一个字符串,而是一些完整的JSON对象。

如果你有一个期望的JSON对象的java模型,那么你可以用你的doSomething声明中的String参数替换它,例如

public void doSomething(@RequestBody MyObject myobj) {

如果您没有与JSON匹配的Java对象,那么您可以尝试通过将String类型替换为Map<String, Object>来使其工作,看看是否让您更接近一个有效的解决方案。

您还可以打开Spring MVC中的调试日志记录,以获取有关它为什么是错误请求的更多信息。

修改 根据您在评论中的要求,您可以简单地将HttpServletRequest注入您的方法并自己阅读正文。

public void doSomething(HttpServletRequest request) {
  String jsonBody = IOUtils.toString( request.getInputStream());
  // do stuff
}

答案 1 :(得分:6)

我们有一种情况,我们想要一些控制器方法将 POST 正文映射到 beans ,以及我们只想要原始字符串的其他方法。要使用@RequestBody 注释完成此操作,您需要配置多个消息转换器,例如......

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
  <property name="useDefaultSuffixPattern" value="false"/>
</bean>

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <list>
            <ref bean="jsonConverter" />
            <ref bean="marshallingConverter" />
            <ref bean="stringHttpMessageConverter" />
        </list>
    </property>
</bean>

<bean id="jsonConverter"
      class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
    <property name="supportedMediaTypes" value="application/json" />
</bean>

<bean id="marshallingConverter"
      class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
    <constructor-arg ref="jaxb2Marshaller" />
    <property name="supportedMediaTypes" value="application/xml"/>
</bean>

<bean id="stringHttpMessageConverter"
      class="org.springframework.http.converter.StringHttpMessageConverter">
    <property name="supportedMediaTypes" value="text/plain"/>
</bean>

然后,对各种方法的请求必须指定&#34; 内容类型&#34;标头具有适当的值。对于请求主体映射到 JAXB bean 的那些方法,请指定&#34; application/xml&#34;。对于请求正文为 String 的用户,请使用&#34; text/plain&#34;。

答案 2 :(得分:2)

您可以尝试完全避免@RequestBody,而是直接通过InputStream / ReaderWebRequest / HttpServletRequest抓取请求正文。

答案 3 :(得分:1)

在我的情况下是因为json没有引用字段名称。 例如,这是不被接受的:

{ entity: "OneEntity"} 

但是这一个是:

{ "entity": "OneEntity"}

我还没有找到如何在spring上下文中配置对象映射。 我知道有一个JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES,但我不知道如何设置对象映射器。

答案 4 :(得分:0)

如果您的内容类型是&#34; application / json&#34;而你的第一个messageConvertor不是org.springframework.http.converter.StringHttpMessageConverter,Spring无法正常工作。就我而言,我这样做了:

&#13;
&#13;
<mvc:annotation-driven>
		<mvc:message-converters>
			<ref bean="stringHttpMessageConverter" /><!-- 放在前面,对@RequestBody String json 提供支持 -->
			<ref bean="mappingJacksonHttpMessageConverter" />
		</mvc:message-converters>
	</mvc:annotation-driven>


	<!-- 消息转换器 -->
	<bean id="stringHttpMessageConverter"
		class="org.springframework.http.converter.StringHttpMessageConverter">
		<property name="supportedMediaTypes">
			<list>
				<bean class="org.springframework.http.MediaType">
					<constructor-arg index="0" value="text" />
					<constructor-arg index="1" value="plain" />
					<constructor-arg index="2" value="UTF-8" />
				</bean>
				<bean class="org.springframework.http.MediaType">
					<constructor-arg index="0" value="application" />
					<constructor-arg index="1" value="json" />
					<constructor-arg index="2" value="UTF-8" />
				</bean>
			</list>
		</property>
	</bean>

	<bean id="mappingJacksonHttpMessageConverter"
		class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
		<property name="supportedMediaTypes">
			<list>
				<bean class="org.springframework.http.MediaType">
					<constructor-arg index="0" value="text" />
					<constructor-arg index="1" value="plain" />
					<constructor-arg index="2" value="UTF-8" />
				</bean>
				<bean class="org.springframework.http.MediaType">
					<constructor-arg index="0" value="application" />
					<constructor-arg index="1" value="json" />
					<constructor-arg index="2" value="UTF-8" />
				</bean>
			</list>
		</property>
		<!-- 设置时间格式, 有了这个就不用在pojo的属性上写了 -->
		<property name="objectMapper">
			<bean class="com.fasterxml.jackson.databind.ObjectMapper">
				<property name="dateFormat">
					<bean class="java.text.SimpleDateFormat">
						<constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss"></constructor-arg>
					</bean>
				</property>
			</bean>
		</property>
	</bean>
&#13;
&#13;
&#13;

答案 5 :(得分:0)

对于我的春季版更新,它只是一个“必要的现在。 “XXX”而不是XXX,一切正常,因为你拥有它。 Content-Type application / json