Загрузка изображений в Scala Play Framework с угловой загрузкой файлов

0

Я использую 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 или аналогичная?

Спасибо за помощь!

  • 0
    Причина, по которой данные отправляются таким образом, заключается в том, что это запрос multipart / form-data. Думайте об этом как HTML-форму с некоторыми парами ввода / значения, значение которых является строкой. Альтернативой может быть преобразование ваших данных в строку json с помощью JSON.stringify() а затем на сервере прочитать эту строку и использовать серверные библиотеки для преобразования строки json в объекты модели.
  • 0
    @danial Я уже думал о JSON.stringify() раньше, но я не уверен, как вписать изображение в JSON . Должен ли я просто отправить байты в виде строки?
Показать ещё 1 комментарий
Теги:
multipartform-data
ng-file-upload
playframework-2.0

1 ответ

0
Лучший ответ

Как я сказал в названии, мое дело было отправить изображения. Как и следовало ожидать, я также представляю предварительный просмотр и файлы, сохраненные в настоящее время в базе данных.

Учитывая все плюсы и минусы, я решил отправить все данные в формате JSON в обоих направлениях. Это означает, что изображения кодируются и отправляются в структуре JSON.

Несмотря на то, что вышеупомянутое решение выглядит очень удобно, оно фактически создает новые проблемы во время реализации.

  1. Вы быстро превысите ограничение на размер запроса POST-сервера. Для Игрового сервера значение 100 КБ по умолчанию можно расширить, но...
  2. Я скоро столкнулся с некоторыми искажениями данных, поскольку изображение, сохраненное как огромная строка байтов, вероятно, имело некоторые ошибки отправки/разбора.

Не углубляясь в это ошибочное решение, я использовал @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))

Наслаждайтесь!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню