在 Spring MVC 控制器中反序列化单属性 JSON 负载
Deserializing single-attribute JSON payload in Spring MVC controller
我想创建语义上类似于以下内容的控制器方法
public HttpEntity<?> deleteUser(String userId){
...
}
客户端将作为 JSON 负载的一部分传递用户 ID。如果我尝试注释 @RequestBody
字符串参数并发出 {"userId":"foo"}
有效载荷,那么我会得到一个异常
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: java.io.PushbackInputStream@7311a203; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148) ~[jackson-databind-2.6.1.jar:2.6.1]
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:854) ~[jackson-databind-2.6.1.jar:2.6.1]
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:62) ~[jackson-databind-2.6.1.jar:2.6.1]
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:11) ~[jackson-databind-2.6.1.jar:2.6.1]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3702) ~[jackson-databind-2.6.1.jar:2.6.1]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2798) ~[jackson-databind-2.6.1.jar:2.6.1]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:221) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]
这是合理的,因为 JSON 想要将一个复杂对象(具有一个属性)反序列化为 String
.
我也知道 "foo"
无效 JSON。我知道我 可以 使用 Map<String,Object>
或更好的 ModelMap
,作为最后的手段,我可以使用查询字符串和 @RequestParam
, 但是今天我的老板明确要求我找到一种使用纯字符串而不是对象的方法,以使代码看起来更具可读性。
如何强制 Jackson/MVC 仅将 "username" 属性 反序列化为普通的旧 String
?
当 Spring MVC 找到与 URL 路径匹配但参数(或 headers 或其他东西)不匹配的请求映射时,您通常会看到此类错误匹配处理程序方法的预期。
如果您使用 @RequestBody 注释,那么 Spring MVC 期望将 POST 请求的整个 body 映射到 Object,它不适用于默认为字符串。
下面列出了不同的方法:
1) 将 deleteUser() 方法类型的方法类型更改为 GET 而不是 Post 并将 userId 用作 String.
2) 您可以简单地将 HttpServletRequest 注入您的方法并读取 body:
public void deleteUser(HttpServletRequest request) {
String userID = IOUtils.toString( request.getInputStream());
// do stuff
}
3) 使用包装器(JSON object 的java 模型)可以替换字符串参数,还有这个将与 json 中的 post 一起正常工作。
public class UserWrapper {
private String userId;
//getter setters
然后在你的控制器中使用:
public void deleteUser(@RequestBody UserWrapper user) {
//do your stuff
}
4) Spring提供了一种配置多个消息转换器的方法,如下所示:
注意: 然后,对各种方法的请求必须指定 "content-type" header 适当的值。对于将请求 body 映射到 JAXB bean 的那些方法,指定 "application/xml"。对于请求 body 是字符串的那些,请使用 "text/plain".
<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>
希望对您有所帮助!
我想创建语义上类似于以下内容的控制器方法
public HttpEntity<?> deleteUser(String userId){
...
}
客户端将作为 JSON 负载的一部分传递用户 ID。如果我尝试注释 @RequestBody
字符串参数并发出 {"userId":"foo"}
有效载荷,那么我会得到一个异常
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: java.io.PushbackInputStream@7311a203; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148) ~[jackson-databind-2.6.1.jar:2.6.1]
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:854) ~[jackson-databind-2.6.1.jar:2.6.1]
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:62) ~[jackson-databind-2.6.1.jar:2.6.1]
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:11) ~[jackson-databind-2.6.1.jar:2.6.1]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3702) ~[jackson-databind-2.6.1.jar:2.6.1]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2798) ~[jackson-databind-2.6.1.jar:2.6.1]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:221) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]
这是合理的,因为 JSON 想要将一个复杂对象(具有一个属性)反序列化为 String
.
我也知道 "foo"
无效 JSON。我知道我 可以 使用 Map<String,Object>
或更好的 ModelMap
,作为最后的手段,我可以使用查询字符串和 @RequestParam
, 但是今天我的老板明确要求我找到一种使用纯字符串而不是对象的方法,以使代码看起来更具可读性。
如何强制 Jackson/MVC 仅将 "username" 属性 反序列化为普通的旧 String
?
当 Spring MVC 找到与 URL 路径匹配但参数(或 headers 或其他东西)不匹配的请求映射时,您通常会看到此类错误匹配处理程序方法的预期。
如果您使用 @RequestBody 注释,那么 Spring MVC 期望将 POST 请求的整个 body 映射到 Object,它不适用于默认为字符串。
下面列出了不同的方法:
1) 将 deleteUser() 方法类型的方法类型更改为 GET 而不是 Post 并将 userId 用作 String.
2) 您可以简单地将 HttpServletRequest 注入您的方法并读取 body:
public void deleteUser(HttpServletRequest request) {
String userID = IOUtils.toString( request.getInputStream());
// do stuff
}
3) 使用包装器(JSON object 的java 模型)可以替换字符串参数,还有这个将与 json 中的 post 一起正常工作。
public class UserWrapper {
private String userId;
//getter setters
然后在你的控制器中使用:
public void deleteUser(@RequestBody UserWrapper user) {
//do your stuff
}
4) Spring提供了一种配置多个消息转换器的方法,如下所示: 注意: 然后,对各种方法的请求必须指定 "content-type" header 适当的值。对于将请求 body 映射到 JAXB bean 的那些方法,指定 "application/xml"。对于请求 body 是字符串的那些,请使用 "text/plain".
<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>
希望对您有所帮助!