在Spring MVC控制器中反序列化单属性JSON有效负载 [英] Deserializing single-attribute JSON payload in Spring MVC controller
问题描述
我想创建语义上类似于以下内容的控制器方法
I want to create controller methods that semantically look like the following
public HttpEntity<?> deleteUser(String userId){
...
}
客户端是将用户ID作为JSON有效内容的一部分传递。如果我尝试注释 @RequestBody
字符串参数并发出 {userId:foo}
有效负载,然后我得到一个异常
The client is going to pass the user ID as part of the JSON payload. If I try to annotate @RequestBody
the string parameter and issue a {"userId":"foo"}
payload, then I get an exception
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
。
And that is reasonable because JSON wants to deserialize a complex object (with namely one attribute) into a String
.
我也知道foo
是无效的JSON。我知道我可以使用 Map< String,Object>
,甚至更好的 ModelMap
,作为最后的手段,我可以使用查询字符串和 @RequestParam
,但今天我的老板明确要求我找到一个使用普通字符串而不是对象的方法,以使代码看起来更具可读性。
I also know that "foo"
is not valid JSON. And I know that I can use a Map<String,Object>
or even better a ModelMap
, and as a last resort I could use query string and @RequestParam
, but today I have been clearly asked by my boss to find a way to use a plain string instead of an object, in order for code to look more readable.
如何强制Jackson / MVC仅反序列化用户名属性到一个普通的旧字符串
?
How can I force Jackson/MVC to deserialize only the "username" property into a plain old String
?
推荐答案
你会看到这种类型当Spring MVC找到与URL路径匹配的请求映射但参数(或标题或某些内容)与处理程序方法所期望的不匹配时出现错误。
You will usually see this type of error when Spring MVC finds a request mapping that matches the URL path but the parameters (or headers or something) don't match what the handler method is expecting.
If你使用@RequestBody注释然后Spring MVC期望将POST请求的整个主体映射到一个Object,默认情况下它不能用于String。
If you use the @RequestBody annotation then Spring MVC is expecting to map the entire body of the POST request to an Object,it dont work with String by default.
1)将deleteUser()方法类型的方法类型更改为GET而不是Post,并将userId更改为String。
1) Change method type of deleteUser() method type to GET instead of Post and use userId as String.
2)你可以简单地将HttpServletRequest注入你的方法并读取正文:
2) You could simply inject the HttpServletRequest into your method and read the body:
public void deleteUser(HttpServletRequest request) {
String userID = IOUtils.toString( request.getInputStream());
// do stuff
}
3)使用可以替换String参数的包装器(JSON对象的java模型),这也适用于你帖子中的json。
3) Use a wrapper (java model of the JSON object) that could replace the String parameter,and also this will work fine with the json coming in your post.
public class UserWrapper {
private String userId;
//getter setters
然后在您的控制器中使用:
and then use in your controller as:
public void deleteUser(@RequestBody UserWrapper user) {
//do your stuff
}
4) Spring提供了一种配置多个消息转换器的方法,如下所示:
注意:然后,对各种方法的请求必须指定具有适当值的content-type标头。对于请求主体映射到JAXB bean的那些方法,请指定application / xml。对于请求体是String的那些,使用text / plain。
4) Spring provides a way to configure multiple message converters as shown below: Note: Then, requests to the various methods must specify the "content-type" header with an appropriate value. For those methods where the request body is mapped to a JAXB bean, specify "application/xml". And for those where the request body is a String, use "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>
希望这对你有帮助!
这篇关于在Spring MVC控制器中反序列化单属性JSON有效负载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!