0

Ich benutze Angular ng-file-upload() auf dem Frontend, um den Datei-Upload-Prozess zu verwalten.Scala Play Framework Bild hochladen mit Angular ng-Datei-Upload

Leider enthält Formular ein komplexes Objekt mit mehreren Dateien. Mit der MultipartFormData (https://www.playframework.com/documentation/2.5.x/ScalaBodyParsers) auf der Serverseite habe ich den hochgeladenen Inhalt erfolgreich zerlegt und kann es aus der request.body lesen.

Nun zu meiner Überraschung, ich habe keine einfaches Json Objects sondern einen seltsam geformten Datentyp, auf der ng-file-upload Webseite wie folgt beschrieben:

(...) Server-Implementierungen verschachtelten Datenobjektschlüssel erwarten in .key oder [key] Format. Beispiel: Daten: {rec: {Name: 'N', Bild: Datei}} gesendet als: rec [Name] -> N, rec [Bild] -> Datei
Daten: {rec: {name: 'N 'pic: file}, objectKey:' .k '} als gesendet: rec.name -> N, rec.pic -> Datei

Bisher habe ich es geschafft, alle Daten auf einen gemeinsamen MultipartFormData.Part zu bringen Typ, mit dem DataPart und FilePart wie folgt aus:

val opts = body.dataParts.map { 
    case (key, values) => DataPart(key, values.head) 
} 

val parts = opts ++ body.files 

So bin ich jetzt links mit einem sehr bedauerlich Iterable[Part]:

0 = {[email protected]} "DataPart(arabic[active],false)" 
1 = {[email protected]} "DataPart(english[active],true)" 
2 = {[email protected]} "DataPart(english[url],2132132132)" 
... 
7 = {[email protected]} "FilePart(english[image],fb_icon_325x325.png,Some(image/png),TemporaryFile(/tmp/playtemp5909927824995768544/multipartBody8348573128070542611asTemporaryFile))" 

Jedes Objekt name enthält das key seiner Json-Struktur und seine entsprechende value. Anstatt nun key[level1][level2] würde Ich mag es, um Objekte zu analysieren, in meinem Fall:

case class PcBanner(english: PcBanners, arabic: PcBanners, kurdish: PcBanners) 
case class PcBanners(active: Boolean, url: Option[String], image: Option[String])` 

Ich hoffe, Sie auf die Idee kommen.

Die Frage

Ich weiß, ich könnte versuchen, die name Strings zu analysieren versucht, es zu Objekten passen, aber ich glaube, ich in der Mitte irgendwie einen Fehler gemacht. Gibt es eine Möglichkeit, diese Struktur in die Objekte zu analysieren, indem Sie Feldnamen als Referenz verwenden? Irgendwelche Build in Play Funktionen oder ähnliches?

Vielen Dank für Ihre Hilfe!

+0

Der Grund, warum die Daten so gesendet werden, ist, dass es sich um eine mehrteilige/Formulardatenanforderung handelt. Stellen Sie es sich als ein HTML-Formular mit einigen Eingabe-Schlüssel/Wert-Paaren vor, deren Wert eine Zeichenfolge ist. Eine Alternative wäre, Ihre Daten mit 'JSON.stringify()' in json string zu konvertieren und dann auf dem Server diese Zeichenfolge zu lesen und Server-Bibliotheken zu verwenden, um die json-Zeichenfolge in Modellobjekte zu konvertieren. – danial

+0

@danial Ich habe zwar von 'JSON.stringify()' vorher, aber ich bin mir nicht sicher, wie man das Bild in die 'JSON' passt. Soll ich die Bytes nur als String senden? – Atais

+0

Nein, die Datei muss separat wie folgt gesendet werden '{Datei: file, otherData: JSON.stringify (myData)}' – danial

Antwort

0

Wie ich im Titel sagte, war mein Fall zu senden Bilder. Wie nicht anders zu erwarten, präsentiere ich auch eine Vorschau und die aktuell in der Datenbank gespeicherten Dateien.

In Anbetracht aller Vor-und Nachteile habe ich beschlossen, alle Daten im JSON-Format, beide Wege zu senden. Das bedeutet, dass die Bilder in der JSON-Struktur codiert und gesendet werden.

Trotz der Tatsache, dass obige Lösung sehr praktisch aussieht, entstehen bei der Implementierung tatsächlich neue Probleme.

  1. Sie werden die Größe der POST-Anfrage des Servers schnell überschreiten. Für Play Server können die Standard 100kB erweitert werden, aber ...
  2. Ich habe bald in einigen Daten Missbildungen gelandet, da das Bild gespeichert als riesige Zeichenfolge von Bytes hatte wahrscheinlich einige Sende-/Parsing-Fehler.

nicht tiefer in diese fehlerhafte Lösung, die ich die @danial Beratung verwendet haben:

Nein haben die Datei separat wie diese
{file: file, otherData: JSON.stringify(myData)}

Meine Lösung

gesendet

Wenn jemand ähnliche Ansatz zu meinen verwenden möchte, pres ent meine Antwort. Auf der Vorderseite habe ich beschlossen, ng-file-upload Bibliothek verwendet. Die Bindung es zu HTML-Komponente mit ngf-select mit ngf-drop, die die Komponente ermöglicht:

<div ngf-drop ngf-select 
    ng-model="image" 
    ngf-accept="'image/*'" 
    ngf-resize="{width: {{width}}, height: {{height}}, quality: 1.0, restoreExif: false}"> 

    <img ng-show="!!image && !!image.$ngfName" ngf-src="image"> 

    <img ng-show="(!image || !image.$ngfName)" ng-src="{{ imageUrl }}"> 
</div> 

Innerhalb des Upload-Tag habe ich die Bildvorschau. Das funktioniert einwandfrei. Wenn das Bild nicht ausgewählt ist, verwende ich das in der Datenbank gespeicherte Bild.

Die Daten und Bilder teilen das Modell nicht mehr. Die Upload-Funktion sieht wie folgt:

return Upload.upload({ 
    url: url, 
    data: {file: images, data: angular.toJson(data)} 
}).then(function (resp) { 
    console.log(resp); 
}, function (error) { 
    console.log(error); 
}); 

Der Zusammenstellung aller oben gab mir das Ausgangsdatenobjekt:

{ 
    "english":{ 
     "active":true, 
     "url":"http://google.com" 
    }, 
    "arabic":{ 
     "active":true, 
     "url":"http://google.com" 
    }, 
    "kurdish":{ 
     "active":true, 
     "url":"http://google.com" 
    } 
} 

Auf der Serverseite der JSON entsprechen die vorbereitete Fallklasse und ist mit Build- analysiert in Jackson Parser, so dass Objektmanipulation leicht möglich ist. Das Bild hat manuell ausgewählt werden:

val key = s"file[${lang.name}][${imageType.name}]" 
body.file(key).map(mp => (mp.ref.file, imageType)) 

Enjoy:

val json = r.body.dataParts("data") 
val jsValue = Json.parse(json.head) 
val result = jsValue.validate(LocalizedBanner.dataModelFormat) // parse JSON 

Extrahieren von Dateien aus Körper kann mit eingebauter Funktion .file durchgeführt werden!

Verwandte Themen