Я использую Angular ng-file-upload
(https://github.com/danialfarid/ng-file-upload) в интерфейсе для управления процессом загрузки файлов.
К сожалению, форма содержит сложный объект с несколькими файлами. Используя MultipartFormData
(https://www.playframework.com/documentation/2.5.x/ScalaBodyParsers) на стороне сервера, я успешно разложил загруженный контент и прочитал его из request.body
.
Теперь, к моему удивлению, у меня нет простых Json Objects
а довольно странно сформированный тип данных, описанный на веб ng-file-upload
сайте ng-file-upload
:
(...), ожидающих вложенных ключей объектов объектов в формате.key или [key]. Пример: данные: {rec: {name: 'N', pic: file}} отправлены как: rec [имя] → N, rec [pic] → файл
data: {rec: {name: 'N', pic: file}, objectKey: '.k'} отправлено как: rec.name → N, rec.pic → file
До сих пор мне удалось передать все данные в общий тип MultipartFormData.Part
, используя DataPart
и FilePart
следующим образом:
val opts = body.dataParts.map {
case (key, values) => DataPart(key, values.head)
}
val parts = opts ++ body.files
Итак, теперь я остался с довольно неудачной Iterable[Part]
:
0 = {MultipartFormData$DataPart@86271} "DataPart(arabic[active],false)"
1 = {MultipartFormData$DataPart@86273} "DataPart(english[active],true)"
2 = {MultipartFormData$DataPart@86277} "DataPart(english[url],2132132132)"
...
7 = {MultipartFormData$FilePart@76473} "FilePart(english[image],fb_icon_325x325.png,Some(image/png),TemporaryFile(/tmp/playtemp5909927824995768544/multipartBody8348573128070542611asTemporaryFile))"
Каждое name
объекта содержит key
от его структуры Json и его value
. Теперь вместо key[level1][level2]
я хотел бы проанализировать его на объекты, в моем случае:
case class PcBanner(english: PcBanners, arabic: PcBanners, kurdish: PcBanners)
case class PcBanners(active: Boolean, url: Option[String], image: Option[String])'
Надеюсь, у вас есть идея.
Вопрос
Я знаю, что могу попытаться разобрать строки name
пытаясь поместить их в объекты, но я считаю, что я допустил ошибку в середине. Есть ли способ проанализировать эту структуру в объектах, используя имена полей в качестве ссылки? Любая встроенная функция Play или аналогичная?
Спасибо за помощь!
Как я сказал в названии, мое дело было отправить изображения. Как и следовало ожидать, я также представляю предварительный просмотр и файлы, сохраненные в настоящее время в базе данных.
Учитывая все плюсы и минусы, я решил отправить все данные в формате JSON в обоих направлениях. Это означает, что изображения кодируются и отправляются в структуре JSON.
Несмотря на то, что вышеупомянутое решение выглядит очень удобно, оно фактически создает новые проблемы во время реализации.
Не углубляясь в это ошибочное решение, я использовал @danial совет:
Нет, если файл отправлен отдельно
{file: file, otherData: JSON.stringify(myData)}
Мое решение
Если кто-то хотел бы использовать подобный подход к моему, я представляю свой ответ. На стороне входа я решил использовать библиотеку ng-file-upload. Связывание его с компонентом HTML с помощью ngf-select
с ngf-drop
который позволяет компоненту:
<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>
Внутри тега загрузки я помещаю предварительный просмотр изображения. Это работает безупречно. Если изображение не выбрано, я использую изображение, сохраненное в db.
Данные и изображения больше не разделяют модель. Функция загрузки выглядит следующим образом:
return Upload.upload({
url: url,
data: {file: images, data: angular.toJson(data)}
}).then(function (resp) {
console.log(resp);
}, function (error) {
console.log(error);
});
Соединяя все вышеизложенное, я дал выходной объект данных:
{
"english":{
"active":true,
"url":"http://google.com"
},
"arabic":{
"active":true,
"url":"http://google.com"
},
"kurdish":{
"active":true,
"url":"http://google.com"
}
}
На стороне сервера JSON соответствует подготовленному классу case и анализируется встроенным парсером Jackson, что позволяет легко манипулировать объектами. Изображение должно быть выбрано вручную:
val json = r.body.dataParts("data")
val jsValue = Json.parse(json.head)
val result = jsValue.validate(LocalizedBanner.dataModelFormat) // parse JSON
Извлечение файлов из тела может быть выполнено с помощью функции .file
:
val key = s"file[${lang.name}][${imageType.name}]"
body.file(key).map(mp => (mp.ref.file, imageType))
Наслаждайтесь!
JSON.stringify()
а затем на сервере прочитать эту строку и использовать серверные библиотеки для преобразования строки json в объекты модели.JSON.stringify()
раньше, но я не уверен, как вписать изображение вJSON
. Должен ли я просто отправить байты в виде строки?