33

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

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

我只是返回 HTTP 400 Bad Request(“客户端发送的请求在语法上不正确。”)。

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

4

6 回答 6

52

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

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

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

public void doSomething(@RequestBody MyObject myobj) {

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

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

编辑: 鉴于您在评论中的要求,您可以简单地将 HttpServletRequest 注入您的方法并自己阅读正文。

public void doSomething(HttpServletRequest request) {
  String jsonBody = IOUtils.toString( request.getInputStream());
  // do stuff
}
于 2013-05-09T17:17:36.703 回答
6

我们有一种情况,我们需要一些控制器方法来将POST主体映射到beans,而其他方法我们只需要原始String@RequestBody 要使用annotation完成此操作,您需要配置多个消息转换器,例如...

<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>

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

于 2014-03-28T05:03:08.137 回答
2

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

于 2013-12-06T01:33:34.717 回答
1

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

{ entity: "OneEntity"} 

但这一个是的:

{ "entity": "OneEntity"}

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

于 2014-02-26T12:27:51.537 回答
0

对我来说,春季版本更新它只是一个“现在必须的”。“XXX”而不是 XXX,一切正常,因为你拥有它。内容类型应用程序/json

于 2017-09-06T16:13:08.390 回答
0

如果您的 Content-type 是“application/json”并且您的第一个 messageConvertor 不是 org.springframework.http.converter.StringHttpMessageConverter ,则 Spring 无法正常工作。就我而言,我这样做了:

<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>

于 2017-05-12T10:47:10.163 回答