angularjsからspringbootに画像を送信する3つのパターン

Monaca上で動いているangularjsからspringbootにファイルを送信するパターンを3つご紹介します。
まだまだあると思うけど、これで満足。

環境はこんな感じです。
Monaca : 2.0.4
onsen-ui :1.3.14
springboot : 1.3.1.RELEASE

formから送る場合

クライアント
<form id="form" enctype="multipart/form-data">
	<input type="file" id="file" name="file" />
</form>
$scope.imgFormSendServer = function() {
  var form = document.getElementById("form");
  var fd = new FormData(form);

  $http.post(
    "http://localhost/image/form",  // URL
    fd, // パラメータ
    {headers:{"Content-type":undefined} ,transformRequest:null} // オプション
  ).success(function() {
    console.log("success");
  }).error(function() {
    console.log("error");
  });
}

htmlにform情報を記載し、
jsでそのFormをFormDataの引数に渡して送信します。

その時angularjsでヘッダー情報に以下が必要とのことです。

{headers:{"Content-type":undefined} ,transformRequest:null}

こちら参考にさせていただきました。ありがとうございます。

AngularJSでFormDataをPOSTする(ファイルのアップロードする) - Qiita

サーバ
@RequestMapping(value = "image/form", method = RequestMethod.POST)
public @ResponseBody Object imageForm(
  @RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException {

  log.info("name={} , length={}", file.getName(), file.getBytes().length);
  return null;
}

型をMultipartFileに、
RequestParamのパラメータ名に"file"を指定してあげます。
(アノテーションの引数は変数名がfileになっていれば必要ありません)


input=fileから送る場合

「formから送る場合」をちょっと変えます

クライアント
<input type="file" id="file" name="file" />
var file = document.getElementById("file").files[0];
var fd = new FormData();
fd.append("file", file);
$http.post(..... // あとは同じです

html側でformがなくなり、代わりにjs側でファイルの指定をすればOKです。
サーバ側は同じです。


byte[] で送る場合

こちら参考にさせていただきました。ありがとうございます。

AngularJSでファイルをアップロードする - Qiita


new FileReader()を使ってreader.resultを取得するとbase64の値が取得できます。
その値を「fd.append("file", べーす64の変数);」として格納し、
サーバ側で「@RequestParam("file") byte[] b」の形で取得できます。

(データが消えたのでこのくらいの説明で。。。)


その他学んだこと

サーバ側でファイル以外の引数を取得する

FormDataのappendを使って送信する場合、サーバ側でファイル以外の引数を受け取ることが可能です。
クライアント側「fd.appendの第一引数」とサーバ側「RequestParamの引数」が同じであればOKです。

抜粋します。

クライアント

var fd = new FormData();
fd.append("file", file);
fd.append("arg", "custom parameter");

サーバ

@RequestParam("args") String args
input=typeを消す

UIがイケてないinput=typeを消して自作ボタンでファイル取得できます。

<input type="file" id="file" name="file" style="opacity:0;" />

opacityを0にすると消えます。(ヤッター)
あとはjs側でトリガーを設定してあげればOKですね。

jQueryの例

$('#file').trigger("click");


最初サーバ側でspringのExceptionをはきまくってなんでかなーと思いましたが、
クライアント側でMultipartFileに対応したフォーマットを作らないといけないんですね。

MultipartFileの場合、受信するキー名が分かりづらいので、
ChromeのdevtoolなどでNetworkの情報をみると理解しやすいと思います。




Monaca使ってるのでCordovaプラグインが使えますが、あえてHTML側の機能でやってみました。


たぶん業務で使う場合はUIをカスタマイズしたCordovaプラグインを使い、
使えない場合は今回のHTML側で対応、とかの分岐にするのがよいんではないかと思います。

または旧デバイス向けのangularjsの高性能なプラグインを使うとかですね。




おわり

※書いてて気づいたけど正確なangularjsではありませんでしたごめんなさい。