[英]Scala Play Framework image upload with Angular ng-file-upload
I am using Angular ng-file-upload
( https://github.com/danialfarid/ng-file-upload ) on the frontend to manage the file upload process. 我在前端使用Angular ng-file-upload
( https://github.com/danialfarid/ng-file-upload )管理文件上传过程。
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
. 使用服务器端的MultipartFormData
( https://www.playframework.com/documentation/2.5.x/ScalaBodyParsers ),我已经成功分解了上传的内容,并且可以从request.body
读取它。
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: 现在,令我惊讶的是,我没有一个简单的Json Objects
,而是一个奇怪地形成的数据类型,在ng-file-upload
网站上描述为:
(...) server implementations expecting nested data object keys in .key or [key] format. (...)服务器实现期望使用.key或[key]格式的嵌套数据对象键。 Example: data: {rec: {name: 'N', pic: file}} sent as: rec[name] -> N, rec[pic] -> file 示例:数据:{记录:{名称:'N',图片:文件}}发送为:记录[名称]-> N,记录[图片]->文件
data: {rec: {name: 'N', pic: file}, objectKey: '.k'} sent as: rec.name -> N, rec.pic -> file 数据:{记录:{名称:'N',图片:文件},对象关键字:'。k'}发送为:记录名称-> N,记录图片->文件
So far I have managed to bring all the data to a common MultipartFormData.Part
type, using the DataPart
and FilePart
like this: 到目前为止,我已经设法使用DataPart
和FilePart
将所有数据转换为通用的MultipartFormData.Part
类型:
val opts = body.dataParts.map {
case (key, values) => DataPart(key, values.head)
}
val parts = opts ++ body.files
So I am now left with a quite unfortunate Iterable[Part]
: 因此,我现在有一个非常不幸的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))"
Each object name
contains the key
of it's Json structure and its according value
. 每个对象name
包含其Json结构的key
及其相应的value
。 Now instead of key[level1][level2]
I would like to parse it to objects, in my case: 现在,我想将其解析为对象而不是key[level1][level2]
:
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. 我希望你有主意。
The question 问题
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. 我知道我可以尝试解析name
字符串以使其适合对象,但是我相信中间还是有一个错误。 Is there a way to parse this structure into the objects, using field names as a reference? 有没有一种方法可以使用字段名称作为参考来将此结构解析为对象? Any build in Play functions or alike? 播放功能有内置功能吗?
Thanks for help! 感谢帮助!
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. 如您所料,我还将展示一个预览以及当前保存在数据库中的文件。
Considering all pros and cons I have decided to send all the data in JSON format, both ways.
考虑到所有优点和缺点,我决定以两种方式均以JSON格式发送所有数据。
Meaning that the images are encoded and sent along in JSON structure.
这意味着图像将以JSON结构进行编码和发送。
Despite the fact that above solution looks very convenient it actually creates new problems during the implementation. 尽管上述解决方案看起来非常方便,但实际上在实施过程中会产生新的问题。
Not going deeper into this faulty solution I have used the @danial advice: 对于这个错误的解决方案,我不会使用更深的含义,而是使用@danial建议:
No have the file sent separately like this 没有像这样单独发送文件
{file: file, otherData: JSON.stringify(myData)}
My solution 我的解决方案
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. 在前端,我决定使用ng-file-upload库。 Binding it to HTML component with ngf-select
with ngf-drop
which enables the component: 它具有结合到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>
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"
}
}
On the server side the JSON matches the prepared case class and is parsed with build-in Jackson parser, allowing for easy object manipulation. 在服务器端,JSON与准备好的case类匹配,并使用内置的Jackson解析器进行解析,从而简化了对象操作。 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
Extracting the files from body can be done with build in function .file
: 可以使用内置函数.file
从主体中提取文件:
val key = s"file[${lang.name}][${imageType.name}]"
body.file(key).map(mp => (mp.ref.file, imageType))
Enjoy! 请享用!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.