概要
Spring で multipart/form-data + MultipartFile を扱う場合は、通常は POST メソッドでなければなりません
どうやら MultipartFile は POST メソッドでないと操作できないようです
実装上そもそも不要なケースが多いですが、PUT メソッドで multipart/form-data を受け取る方法を紹介します
環境
- Mac OS X 10.10.4
- Eclipse Luna 4.4.1
- Spring Framework 4.1.6
- Spring Tool Suite 3.6.4
- Java 1.8.0_31
- Maven 3.2.1
サンプルプロジェクト作成
過去の記事を参考に作成してください
Spring Framework のバージョンが最新でない場合は pom.xml 「org.springframework-version」のバージョン記載部分を最新のバージョンに変更してください
コーディング
@RequestMapping に PUT で multipart/form-data を受け取る定義を記載する
@RequestMapping(value = "/**", method = {RequestMethod.PUT}, headers = "content-type=multipart/form-data")
@ResponseBody
public void receivePutMulti(@RequestParam(value = "file", required = true) MultipartFile file) {
...
}
受け取りたいURLマッピングに上記のようにメソッド名とヘッダーのタイプを指定します
今回はファイルのアップロードを想定しているため MultipartFile を受け取るように指定します
返り値は jsp を返却したい場合は String 型を返り値に指定し@ResponseBody
を削除してください
ちなみにこの状態で以下のように PUT メソッドでファイルのアップロードを実行しようとすると500エラーになります
curl -v -X PUT -H "Content-Type: multipart/form-data" http://localhost:8080/test/put/ -F "file=@pom.xml"
java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?
このエラーがでないように設定していきます
servlet-context.xml に独自 MultipartResolver を指定する
<beans:bean id="multipartResolver" class="com.sample.test.ExtendedMultipartResolver">
</beans:bean>
Multipart なデータは MultipartResolver というクラスでどう受け取るかのルール付けがされており、このクラスを拡張することで PUT メソッドでも MultipartFile が受信できるようにします
次に指定した独自の MultipartResolver クラスを作成していきます
独自 MultipartResolver クラスの作成
pom.xml に定義を追加する
<!-- FileUpload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
独自の MultipartResolver を作成するのに commons-fileupload が必要になるので pom.xml に追記します
既存の<dependencies>
タグ内に追記してください
ExtendedMultipartResolver クラスの作成
今回はcom.sampe.test.ExtendedMultipartResolver
として作成します
とりあえず以下がサンプルになります
package com.sample.test;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
public class ExtendedMultipartResolver extends CommonsMultipartResolver {
@Override
public boolean isMultipart(HttpServletRequest request) {
if (request != null) {
String httpMethod = request.getMethod().toLowerCase();
// test for allowed methods here...
String contentType = request.getContentType();
return (contentType != null && contentType.toLowerCase().startsWith("multipart"));
} else {
return false;
}
}
}
ポイントは@Override
しているisMultipart
メソッドでこの中でHttpServletRequest
からアクセスしているメソッド情報を取得して PUT メソッドでもtrue
を返却するように実装し直します
サンプルは全メソッドで multipart/form-data を許可する設定になっており特にメソッド名に応じてfalse
を返却するような if 分岐は入れていません
動作確認
ここまで実装できたらアプリを再起動してコードを反映しましょう
先ほどの PUT + multipart/form-data の curl のサンプルリクエストを投げてみましょう
すると先ほどのエラーにはならず定義したメソッド内の処理が実行されていることが確認できると思います
最後に
ちょっと調べてみたんですが Spring がデフォルトで実装していないのは RFC 的にそうなっているため(?) みたいな記事があったような気がします
詳細には調べていないので、わかりませんが PUT で multipart/form-data は基本は受け取らないんですかね
そもそもそれは実装が悪いってことになるのか
0 件のコメント:
コメントを投稿