home ホーム search 検索 -  login ログイン  | reload edit datainfo version cmd icon diff delete  | help ヘルプ

Java/JAX-RS/Jerseyでmultipartのリクエストを受け取るには

Java/JAX-RS/Jerseyでmultipartのリクエストを受け取るには

Java / JAX-RS / Jerseyでmultipartのリクエストを受け取るには
id: 1308 所有者: msakamoto-sf    作成日: 2014-08-10 20:34:50
カテゴリ: JAX-RS Java Jersey 

今回の記事では、Jersey 2.11でのmultipart/form-dataを受け取るやり方を調べてみました。

そもそもJAX-RS 2.0の仕様では・・・

JAX-RS 2.0の仕様自体には、特別なmultipartリクエストの対応は盛り込まれていません。
もともと基本的にServletの仕様に乗っかっていて、フィルタやMessageReaderなどリクエストを間で見張って独自に変更できる仕組みを備えています。
そのため、multipartのような複雑なリクエストについては開発者の方でパース処理を実装する考え方のようです。
JerseyやRESTeasyなどメジャーな実装ライブラリでは、開発者が自力で実装しなくても、便利なアノテーションやフィルタ、Providerなどを既に用意してくれていますので、それを利用するのをまず検討しましょう。
ただし、それらはあくまでも実装ライブラリに依存したクラス名やアノテーション名になりますので、他の実装に切り替えた際はそこの修正が必要になると思われます。

Jerseyでのmultipartリクエストを受け取るイロハ

Jersey本家ドキュメントをまず参照:

基本的な流れ:

  1. org.glassfish.jersey.media:jersey-media-multipart ライブラリを組み込む。
  2. Jerseyの"Application"クラスに org.glassfish.jersey.media.multipart.MultiPartFeature をProviderとして登録する。
  3. リソースクラスで "@Consumes(MediaType.MULTIPART_FORM_DATA)" 付けた上で、POSTパラメータを"@FormDataParam"アノテーションで受け取る。(この時、"FormDataContentDisposition + InputStream" のセットにするか、FormDataBodyPart 型でまとめて受け取るか選べる。)

サンプル:

msakamoto-sf/jaxrs2-exercise-jersey-servlet を例に解説

以下、https://github.com/msakamoto-sf/jaxrs2-exercise-jersey-servlet を例に実施にmultipart受付機能を組み込む手順を、対応するコミットログと一緒に解説します。

1. org.glassfish.jersey.media:jersey-media-multipart ライブラリを組み込む。

https://github.com/msakamoto-sf/jaxrs2-exercise-jersey-servlet/commit/1f23cd0b577e2db6f8597d33b10403442be85cb2

解説:
Mavenプロジェクトなので、素直にdependencyに追加してます。

2. Jerseyの"Application"クラスに org.glassfish.jersey.media.multipart.MultiPartFeature をProviderとして登録する。

https://github.com/msakamoto-sf/jaxrs2-exercise-jersey-servlet/commit/8f405630131204aa1dee88d557944046b105f406

解説:本来のJAX-RSでは"Application"というクラスに、ResourceクラスやフィルタなどのProviderクラスを登録します。
Jerseyなど実装によっては、Javaコードで記述せずにweb.xmlで設定できたりします。
今回はJerseyでの解説になり、↑のcommit例では web.xml の org.glassfish.jersey.servlet.ServletContainer の初期パラメータとして、プロバイダのクラス名を与えられる "jersey.config.server.provider.classnames" に直接MultiPartFeatureを設定して登録させています。

公式ドキュメントだけでは以下のようにそっけないコード例しか無いので、慣れてないとどこを直せばよいのか戸惑いそうです。

Example 8.43. Creating JAX-RS application with MultiPart feature enabled.

// Create JAX-RS application.
final Application application = new ResourceConfig()
    .packages("org.glassfish.jersey.examples.multipart")
    .register(MultiPartFeature.class)

Jersey公式のmultipartのサンプルでは、ResourceConfigを継承した "MyApplication" クラスのコンストラクタで、super()で直接登録してしまってます。
https://github.com/jersey/jersey/blob/2.11/examples/multipart-webapp/src/main/java/org/glassfish/jersey/examples/multipart/webapp/MyApplication.java

@ApplicationPath("/")
public class MyApplication extends ResourceConfig {

    public MyApplication() {
        super(MultiPartResource.class, MultiPartFieldInjectedResource.class, MultiPartFeature.class);
    }
}

→このクラス名が、web.xml中で org.glassfish.jersey.servlet.ServletContainer の初期パラメータ "javax.ws.rs.Application" の値に設定されています。
https://github.com/jersey/jersey/blob/2.11/examples/multipart-webapp/src/main/webapp/WEB-INF/web.xml

3. リソースクラスで "@Consumes(MediaType.MULTIPART_FORM_DATA)" 付けた上で、POSTパラメータを"@FormDataParam"アノテーションで受け取る。

https://github.com/msakamoto-sf/jaxrs2-exercise-jersey-servlet/commit/474f18d4f8415b683f29313644b47309b24993ce

今回の例では、1個のアップロードしか想定しない方を "FormDataContentDisposition + InputStream" のセットで受け取り、複数ファイルの受け取りを想定する方を FormDataBodyPart 型で受け取り、ループで処理してます。


以上になりますが、"jersey-media-multipart"の依存関係を見てたら Commons のFileUploadではなく、java.net製のmultipart処理ライブラリである "mimepull" というのを使ってました。ライセンスの都合でAPL2のライブラリが使えないせいか、それとも他の技術的な理由かは分かりませんが、commons-fileupload以外のmime処理の選択肢があることは歓迎できますので、頭の片隅に覚えておきたいと思いました。



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2014-08-10 20:38:44
md5:872273ff5a4b23a62b99a832567b5582
sha1:f12d1e6773f1f06b1cb3f020e8c6bafc804f8610
コメント
コメントを投稿するにはログインして下さい。