WebAPIとして動作しているPlayframeworkにmultipartでJsonとファイルデータを送信します。
Vue側の実装
template
axiosでPOSTするので、formにはmultipartをつけず、prevent指定でページロードしないように制御する。
<template> <form> <input type="text" v-model="shopMame"> <input @change="changeFile" type="file" name="upfile[]" multiple accept="image/*" /> <img v-for="(img, idx) in uploadedImageURL" :key="idx" :src="img.src" /> <button @click.prevent="postData">登録</button> </form> </template>
送信処理
例ではchangeFile
イベントで、ブラウザ上に画像プレビューするよう記述してある。
FormData
はappend単位でboundary区切りのデータを積むことができ、axios送信時に Content-Type': 'multipart/form-data
ヘッダーを送信すればよい。
<script> import axios from 'axios' export default { name: 'ShopForm', data: function () { return { shopMame: "", uploadedImageURL: [], uploadedImage: [] } }, methods: { changeFile (elem) { this.uploadedImage = [] const files = elem.target.files || elem.dataTransfer.files for (var i = 0; i < files.length; i++) { let file = files[i] let url = URL.createObjectURL(file) this.uploadedImageURL.push({ src: url }) this.uploadedImage.push( file ) } }, postData: function(){ let formData = new FormData(); let data = { shopName: this.shopMame } let jsonData = JSON.stringify(data); /* const blob = new Blob([jsonData], { type: 'application/json' }); */ formData.append("document", jsonData); this.uploadedImage.forEach(element => { formData.append("image", element) }); axios({ method: 'post', url: 'http://localhost:9000/shop/create', data: formData, header: { 'Accept': 'application/json', 'Content-Type': 'multipart/form-data', }, }) } } } </script>
尚、上記だと、Jsonのデータにmime指定されないので、mime(application/json)を指定したい場合、Jsonファイル
として送信する必要があるみたい。
let jsonData = JSON.stringify(data); const blob = new Blob([jsonData], { type: 'application/json' }); formData.append("document", blob);
但し、こうするとPlayframework側で添付ファイル
としてJsonコンテンツを解釈してしまうので、好きなほうで送信すれば良いのかな。と思う(^_^;)
Playframework側で各データの受け取り
Jsonデータの受信
jsonのmimeを指定せず、テキストデータとして送信したデータを解釈する。Action applyに(parse.multipartFormData)
を指定する。
def create() = Action(parse.multipartFormData){ implicit request => val document = request.body.dataParts.get("document").map( seq => Json.parse(seq.head) ) ...
document
にOption[JsValue]が入る。
添付ファイルデータの受信
def create() = Action(parse.multipartFormData){ implicit request => val document = request.body.dataParts.get("document").map( seq => Json.parse(seq.head) ) request.body.files.map { file => val filename = file.filename val contentType = file.contentType println(Paths.get(filename).getFileName) println(contentType) println(file.fileSize) //file.ref.moveTo(new File("/tmp", filename)) } ...
のような感じでfile.refと各プロパティを元に適宜処理すれば良い。
尚、Jsonもblobを使用し添付ファイルとして送信した場合は、こちらのfilesを経由してデータアクセスすることになる。
Jsonのバリデートやドメインオブジェクトのmappingに関しては、こちらの記事に記述しています。
Playframework 複雑なJsonデータをオブジェクトにmappingまたはForm bind、validateする - 追憶行