自动绑定复杂(JSON)表单数据

时间:2013-05-09 06:47:29

标签: java json playframework-2.1

我的JSON数据来自request().body().asFormUrlEncoded().get("records")

[{"string":"foo","termId":"793340"},{"string":"bar","termId":"460288"}]

我的表单定义:

public static class MyForm {
    @Constraints.Required
    public List<Map<String,String>> records;
    public String someField;
}

它不会自动绑定records。然后我尝试使用POJO:

public static class Record {
    public String string;
    public String termId;
    public void setString(String string) {
        this.string = string;
    }
    public void setTermId(String termId) {
        this.termId = termId;
    }
}

并改编了表格:

public static class MyForm {
    @Constraints.Required
    public List<Record> records;
    public String someField;
}

它也不会自动绑定数据。对于这个简单的用例,我真的需要使用像jackson这样的低级API吗?任何指针?找不到复制/粘贴示例,而且我在类路径上有org.codehaus.jacksoncom.fasterxml.jackson来自jackson。

更新2013-05-10:添加了辅助字段someField,以澄清records只是一个字段,而不是整个数据结构。下面的答案(我在这个编辑屏幕上看不到答案,所以没关系,只有一个)有效,但只有记录。这是一个例子:

private List<Record> recordsFromRequest() {
    String[] jsonData = request().body().asFormUrlEncoded().get("records");
    Form<Record> recordDummyForm = Form.form(Record.class);
    Iterator<JsonNode> it = Json.parse(jsonData[0]).iterator();
    List<Record> records = new ArrayList<>();
    while (it.hasNext()) {
        records.add(recordDummyForm.bind(it.next()).get());
    }
    return records;
}

对于我做的其他表单字段,像往常一样:

Form<MyForm> form = play.data.Form.form(MyForm.class).bindFromRequest();

所以现在我得到所有发布的表单数据,我的问题就这样解决了(谢谢!)。但是,它有点难看。我还想知道的是如何将所有发布数据放在一个对象中。如果有人回复此问题,我将更新问题并删除此部分。否则我会在几天内接受单一答案。

2 个答案:

答案 0 :(得分:2)

在我看来,您应该使用官方文档here中所述的jackson API。

我假设您使用request().body().asFormUrlEncoded().get()获取JSON,因此它返回包含您的JSON字符串的String[]。你可以做这样的事情(可能有点复杂而且错过Exception处理):

String[] jsonData = request().body().asFormUrlEncoded().get("records")
MyForm myForm = new MyForm();
// Record should act as form, because each JSON string data contain this type
Form<Record> form = Form.form(Record.class);
// parse the JSON string and assign iterator 
Iterator<JsonNode> it = Json.parse(jsonData[0]).iterator(); 
// assign to the MyForm instance
while (it.hasNext()) {
    formData.records.add(form.bind(it.next()).get()); // bind the JSON and add
}

因此,在上面代码的末尾,((MyForm) formData).records应该包含来自JSON的List<Record>对象。

答案 1 :(得分:1)

我试图重现你的错误。所以我创建了一个模型如下:

public class EasyContact {

public String someField;

@Required
public List<Record> records;

public static class Record {
    public String string;
    public String termId;
    @Override
    public String toString() {
        return "Record [string=" + string + ", termId=" + termId + "]";
    }
}

@Override
public String toString() {
    return "EasyContact [someField=" + someField + ", records=" + records+ "]";
}
}

然后像这样一个简单的控制器:

    public static Result submit() {
    Form<EasyContact> filledForm = form(EasyContact.class).bindFromRequest();
    Logger.info("Posted binding: " + filledForm.get().toString());
    return ok();
}

现在是时候测试了:

curl -X POST -H 'Content-Type: application/json' -d '{"someField":"didac", "records": [{"string": "string1", "termId": "111"},{"string": "string2", "termId": "222"}]}' localhost:9000/contacts

在播放命令行中,我可以看到正确的输出:

[info] application - Posted binding: EasyContact [someField=didac, records=[Record [string=string1, termId=111], Record [string=string2, termId=222]]]

我发现的唯一错误是在请求中未设置Content-Type(-H ...)。在这种情况下,框架会抛出IllegalState异常。