So geben Sie den Enumerator von JSON von ReactiveMongo in Play 2 zurück
-
21-12-2019 - |
Frage
In unserem Projekt verwenden wir ReactiveMongo
mit Play 2.2.1
.
Das Problem besteht darin, dass der Datenstrom in einer Form von Enumerator[A]
, zurückgegeben von ReactiveMongo
ist eigentlich ein Stream von Wertobjekten, die nicht durch Kommas getrennt sind und keine Stream-Anfangs- und Endanmerkungen haben, die als Array-Öffnungs- und Schließanweisungen behandelt werden können.
Dies schafft ein Problem für JSON
Verbraucher JS client
, da das erwartete Format ist[A1,A2, ...]
Also sprangen wir in Reifen und verwandelten unsere Enumeratee[A]
Zu Enumerator[String]
, mit Prüfung, ob es das erste Element ist oder nicht:
var first:Boolean = true
val aToStrs = (as.map(a => {
if(first) {
first = false;
Json.stringify(Json.toJson(a))
} else {
"," + Json.stringify(Json.toJson(a))
}
}))
Ok.chunked(
Enumerator.enumInput(Input.El("[")) andThen
aToStrs andThen
Enumerator.enumInput(Input.El("]")) andThen
Enumerator.enumInput(Input.EOF)
)
Das funktioniert, fühlt sich aber an, als würde man das Rad erfinden.
Gibt es eine bessere Lösung für dieses häufige Problem?
Lösung
Wenn Sie Comet oder EventSource verwenden, müssen Sie keine Möglichkeit zur Generierung der Ausgabe manuell erstellen und können die Antwort tatsächlich Element für Element im Client analysieren.Wenn Sie mit einem Array antworten, müssen Sie entweder Ihren eigenen Parsing-Code schreiben oder warten, bis alles auf der Client-Seite angekommen ist, bevor Sie den Build-Int-JSON-Parser in Ihrem JavaScript verwenden können.
Das Streamen mit dem EventSource-Protokoll ist mit Play ziemlich einfach. Sie sollten in der Lage sein, Folgendes zu tun:
implicit val cometEncoder = new Comet.CometMessage[JsValue](_.toString)
Ok.chunked(yourEnumerator &> EventSource()).as(EVENT_STREAM)
Und dann im Client-HTML:
<script type="text/javascript">
var es = new EventSource(jsRouter.controllers.Application.streamIt().url)
es.addEventListener("message", function (event) {
var item = JSON.parse(event.data)
// ... do something with the json value ...
})
</script>
Ein Beispiel hierfür finden Sie in den Play-Beispielprojekten, die Sie sich vielleicht auch ansehen möchten $YOUR_PLAY_DIR/samples/scala/eventsource-clock/