2013-05-09 9 views
6

Mein Kommen JSON-Daten in request().body().asFormUrlEncoded().get("records")Bind-Komplex (JSON) Formulardaten automatisch

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

Meine Form Definition:

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

Es ist nicht die records automatisch bindet. Dann habe ich versucht, mit einem POJO statt:

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

und geeignet ist, die Form:

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

Es werden die Daten nicht binden entweder automatisch. Muss ich wirklich Low-Level-APIs wie Jackson für diesen einfachen Anwendungsfall verwenden? Irgendein Zeiger? Konnte kein Beispiel zum Kopieren/Einfügen finden, und von jackson habe ich org.codehaus.jackson und com.fasterxml.jackson auf meinem Klassenpfad.

UPDATE 2013-05-10: hinzugefügt ein sekundäres Feld someField um zu verdeutlichen, dass die records ist nur ein Feld, nicht die gesamte Datenstruktur. Die Antwort unten von (Ich kann die Antworten auf diesen Bearbeitungsbildschirmen nicht sehen, also egal, es gibt nur eine) funktioniert, aber nur mit den Aufzeichnungen. Hier ein Beispiel:

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

Für die anderen Formularfelder ich, wie üblich:

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

So jetzt komme ich auf alle Formulareingaben, und mein Problem gelöst wird auf diese Weise (dank !). Es ist jedoch ein bisschen hässlich. Was ich noch nicht herausfinden kann ist, wie man alle Daten in einem Objekt posten kann. Wenn jemand darauf antwortet, werde ich die Frage aktualisieren und diesen Teil entfernen. Ansonsten werde ich die einzelne Antwort in ein paar Tagen akzeptieren.

Antwort

2

Meiner Meinung nach sollten Sie jackson APIs verwenden, wie in der offiziellen Dokumentation here beschrieben.

Ich nehme an, dass Sie die JSON mit request().body().asFormUrlEncoded().get() erhalten, so dass es String[] zurückgibt, die Ihre JSON-Zeichenfolge enthalten. Sie können etwas tun (vielleicht ein wenig kompliziert und Exception Handhabung verpassen):

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 
} 

Also, am Ende des Codes oben ((MyForm) formData).records sollte enthalten List<Record> Objekt aus Ihrem JSON.

+1

Wie in der Frage geschrieben: das funktioniert. Es lässt mich meine "Aufzeichnungen" nicht mit anderen Formwerten kombinieren. Und ich hoffe immer noch, dass das Spiel in Zukunft eine viel einfachere Lösung hat oder haben wird. –

1

Ich habe versucht, Ihren Fehler zu reproduzieren. Also habe ich ein Modell wie folgt:

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+ "]"; 
} 
} 

dann eine einfache Steuerung wie folgt aus:

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

Jetzt ist die Zeit zum Test:

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

In der Zeile Spiel Befehl, den ich sehen kann der korrekte Ausgang:

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

Der einzige Fehler, den ich gefunden habe, ist, wenn der Inhaltstyp in der Anfrage nicht gesetzt ist (-H ...).In diesem Fall löst das Framework eine IllegalState-Ausnahme aus.

+0

Funktioniert das '@ Required' für Sie? Ich habe diese Art von Architektur gemacht, aber es wird '@ Requiered' im Child-Objekt nicht überprüft (in unserem Fall Record) –

+1

Fügen Sie auch die @Valid-Anotation hinzu. Es sollte funktionieren –

+0

Ho mein Gott Du hast mich gerettet! Wenn Sie meine Frage hier beantworten möchten: http://stackoverflow.com/questions/31165273/form-validation-in-play-framework Ich werde es als gelöst markieren. –