使用Angular ng-file-upload上传Scala Play Framework图像 [英] Scala Play Framework image upload with Angular ng-file-upload
问题描述
我正在使用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
到目前为止,我已经设法使用DataPart
和FilePart
将所有数据转换为通用的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.
- 您将很快超过服务器的POST请求大小限制.对于Play服务器,可以扩展默认的100kB,但是...
- 我很快遇到了一些数据格式错误,因为保存为巨大字节字符串的图像可能存在一些发送/解析错误.
不深入探讨这个错误的解决方案,我使用了@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-select
和ngf-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屋!