使用Angular ng-file-upload上传Scala Play Framework图像 [英] Scala Play Framework image upload with Angular ng-file-upload

查看:126
本文介绍了使用Angular ng-file-upload上传Scala Play Framework图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Angular ng-file-upload( https://github.com/danialfarid/ng-file -up )来管理文件上传过程.

I am using Angular ng-file-upload (https://github.com/danialfarid/ng-file-upload) on the frontend to manage the file upload process.

不幸的是,表单包含具有多个文件的复杂对象.使用MultipartFormData( https://www.playframework.com/documentation/2.5.x /ScalaBodyParsers )在服务器端,我已经成功分解了上传的内容,并且可以从request.body读取它.

Unfortunately, form contains a complex object with multiple files. Using the MultipartFormData (https://www.playframework.com/documentation/2.5.x/ScalaBodyParsers) on the server side I have successfully decomposed the uploaded content and can read it from the request.body.

现在,令我惊讶的是,我没有一个简单的Json Objects,而是一个奇怪地形成的数据类型,在ng-file-upload网站上描述为:

Now, to my surprise, I do not have a simple Json Objects but rather a strangely formed datatype, described on the ng-file-upload website as:

(...)服务器实现期望使用.key或[key]格式的嵌套数据对象键. 示例:数据:{记录:{名称:'N',图片:文件}}发送为:记录[名称]-> N,记录[图片]->文件
数据:{记录:{名称:'N',图片:文件},对象关键字:'.k'}发送为:记录名称-> N,记录图片->文件

(...) server implementations expecting nested data object keys in .key or [key] format. Example: data: {rec: {name: 'N', pic: file}} sent as: rec[name] -> N, rec[pic] -> file
data: {rec: {name: 'N', pic: file}, objectKey: '.k'} sent as: rec.name -> N, rec.pic -> file

到目前为止,我已经设法使用DataPartFilePart将所有数据转换为通用的MultipartFormData.Part类型:

So far I have managed to bring all the data to a common MultipartFormData.Part type, using the DataPart and FilePart like this:

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

 val parts = opts ++ body.files

所以我现在很不幸地留下了Iterable[Part]:

So I am now left with a quite unfortunate 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都包含其Json结构的key及其相应的value.现在,我想将其解析为key[level1][level2]而不是对象:

Each object name contains the key of it's Json structure and its according value. Now instead of key[level1][level2] I would like to parse it to objects, in my case:

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

我希望你有这个主意.

I hope you got the idea.

问题

我知道我可以尝试解析name字符串以使其适合对象,但是我相信中间还是有一个错误. 有没有一种方法可以使用字段名称作为参考将这种结构解析为对象?内建Play功能或类似功能吗?

I know I could try to parse the name strings trying to fit it to objects, but I believe I made a mistake someway in the middle. Is there a way to parse this structure into the objects, using field names as a reference? Any build in Play functions or alike?

感谢帮助!

推荐答案

正如标题中所述,我的情况是发送图片.如您所料,我还将展示一个预览以及当前保存在数据库中的文件.

As I stated in the title my case was to send images. As you would expect, I am also presenting a preview and the files currently saved in the database.

考虑到所有优点和缺点,我决定以两种方式均以JSON格式发送所有数据.这意味着图像将以JSON结构进行编码和发送.

尽管上述解决方案看起来非常方便,但实际上在实施过程中会产生新的问题.

Despite the fact that above solution looks very convenient it actually creates new problems during the implementation.

  1. 您将很快超过服务器的POST请求大小限制.对于Play服务器,可以扩展默认的100kB,但是...
  2. 我很快遇到了一些数据格式错误,因为保存为巨大字节字符串的图像可能存在一些发送/解析错误.

不深入探讨这个错误的解决方案,我使用了@danial建议:

Not going deeper into this faulty solution I have used the @danial advice:

没有像这样单独发送文件
{file: file, otherData: JSON.stringify(myData)}

No have the file sent separately like this
{file: file, otherData: JSON.stringify(myData)}

我的解决方案

如果有人想使用类似的方法来挖掘我的答案,请提出我的答案. 在前端方面,我决定使用 ng-file-upload 库.将其与ngf-selectngf-drop绑定到HTML组件,以启用该组件:

If anyone would like to use similar approach to mine I present my answer. On the front-end side I have decided used ng-file-upload library. Binding it to HTML component with ngf-select with ngf-drop which enables the component:

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

在上传标签中,我放置了图像预览.这可以完美地工作.如果未选择该图像,则使用保存在数据库中的图像.

Inside the upload tag I put the image preview. This works flawlessly. If the image is not selected I use the image saved in the db.

数据和图像不再共享模型.上传功能如下:

The data and images do not share the model anymore. The upload function looks as follow:

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

将以上所有内容放在一起,便得到了输出数据对象:

Putting together all the above gave me the output data object:

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

在服务器端,JSON与准备好的case类匹配,并使用内置的Jackson解析器进行解析,从而可以轻松地进行对象操作.图片必须手动选择:

On the server side the JSON matches the prepared case class and is parsed with build-in Jackson parser, allowing for easy object manipulation. The image has to be manually selected:

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

可以使用内置函数.file从主体中提取文件:

Extracting the files from body can be done with build in function .file:

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

享受!

这篇关于使用Angular ng-file-upload上传Scala Play Framework图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆