【问题标题】:Problems sending multiple objects through POST and SPRING-MVC通过 POST 和 SPRING-MVC 发送多个对象的问题
【发布时间】:2013-11-08 08:47:00
【问题描述】:

我正在开发必须接收多个信息的 REST 服务。在这种情况下,两个对象和一个属性。

这是我正在测试 POST 请求的 javascript

    var user = {
        username: "admin",
        password: "admin"
    };
    var userToSubscribe = {
        username: "newuser",
        password: "newpassword",
        email: "user@1and1.es"
    };

    var openid = "myopenid";

    $.ajax({
        url: '/myportal/rest/subscribeUser.json',
        type: 'POST',
        dataType: 'json',
        contentType: 'application/json',
        mimeType: 'application/json',
        data: JSON.stringify({ user: user, userToSubscribe: userToSubscribe, openid: openid})    
    });

POST 请求:

    JSON


    openid
        "myopenid"

    user
        Object { username="admin", password="admin"}

    userToSubscribe
        Object { username="newuser", password="newpassword", email="user@1and1.es"}
    Source
    {"user":{"username":"admin","password":"admin"},"userToSubscribe":{"username":"newuser","password":"newpassword","email":"user@1and1.es"},"openid":"myopenid"}

以及处理 POST 的控制器:

    @RequestMapping(method=RequestMethod.POST, value="/subscribeUser.json")
public @ResponseBody Message subscribeUser(@RequestBody("user") User user, @RequestBody("userToSubscribe") User userToSubscribe, @RequestParam String openid){
    ...
}

错误是

POST subscribeUser.json 400 请求不正确 localhost:8080 990 B [::1]:8080

我做错了什么?

谢谢

【问题讨论】:

  • servlet 容器日志中是否存在异常?
  • 感谢@Jk1 回复我。日志中没有异常。似乎 POST 格式错误并且没有到达控制器:/ 但我不知道我做错了什么。
  • 即使请求在到达控制器之前被拒绝,通常也会记录异常。如果是 Tomcat(例如),它将默认进入 catalina.out。我建议寻找服务器端异常。它也可能是一些中间网络代理,例如代理,它在目标服务器之前很久就拒绝了请求。
  • 如果我简化方法只包括用户和帖子,而不是直接在数据中包含 Json.Stringfy:'{"user":{"username":"john","password" :"johnjohn"}}' 到达控制器但未填充对象用户。

标签: java json spring spring-mvc


【解决方案1】:

您不能在接受 JSON 的 RESTful 方法中使用 @ModelAttributes。我相信正确的方法是使用@RequestBody,就像here 所做的那样。您很可能需要将对象包装在某个包装类中,但我可能错了,因为我之前从未亲自尝试在一个请求中传递多个 JSON 对象。

也就是说,如果可能的话,如果您重新考虑您的 REST api,删除 JSON 参数并将它们作为 URI 路径的一部分传递,我认为这将是一个好主意。我建议阅读this blog post

【讨论】:

  • 是的,我意识到 ModelAttribute 不正确。我用 RequestBody 替换了 ModelAttribute,但它没有按预期工作。我意识到我不能像使用 getElements(RequestBody ObjectType1, RequestBody ObjectType2..) 那样使用 JSON 发送多个不同类的对象。可以发送相同对象的列表或发送不同的对象,但您必须将它们作为 Map 接收
  • 您可以将其作为字符串接收,然后自行解析 JSON。但是,我仍然认为您应该考虑简化 API 并将 URI 路径用作输入的一部分。
  • 您介意解释一下您在说什么的更多细节吗?谢谢
【解决方案2】:

请求正文将包含整个 JSON 内容。因此,当您想要映射 JSON 时,您只使用一个 RequestBody 注释参数。你将不得不做这样的事情:

public @ResponseBody Message subscribeUser(@RequestBody String str)
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(str);

然后使用映射器的convertValue方法从字符串中获取你不同的对象。

JsonNode node = mapper.readTree(str);
User theUser = mapper.convertValue(node.get("user"), User.class);

其他对象也是如此

【讨论】:

  • 非常感谢@chinmayzen
  • 我不明白为什么杰克逊在将 JSON 映射到控制器参数时不能这样做。当您只有一个模型时,它会在其他情况下执行此操作 - 是什么阻止它在这里执行此操作?为什么它可以处理其他@RequestParam,但如果有任何其他@RequestParam,它就不是模型?
  • 不需要每次都创建ObjectMapper,因为它是线程安全的。最好将ObjectReader 存储在static 变量中作为final 字段。
【解决方案3】:

您可以创建一个包含所有对象的 java bean(POJO),例如..

class JavaBean{
    private User user;
    private UserTOSubscribe  userToSubscribe;
    private Long openId;

    // getter and setter
}

并将这个bean 传递给Web 服务。所以网络服务看起来像..

@RequestMapping(method=RequestMethod.POST, value="/subscribeUser.json")
public @ResponseBody Message subscribeUser(@RequestBody JavaBean javaBean) {
    ...
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-20
    • 2019-12-20
    • 1970-01-01
    • 2016-06-22
    • 2018-11-09
    相关资源
    最近更新 更多