#navi_header|Java| 今回の記事では、Jersey 2.11でのmultipart/form-dataを受け取るやり方を調べてみました。 * そもそもJAX-RS 2.0の仕様では・・・ JAX-RS 2.0の仕様自体には、特別なmultipartリクエストの対応は盛り込まれていません。 もともと基本的にServletの仕様に乗っかっていて、フィルタやMessageReaderなどリクエストを間で見張って独自に変更できる仕組みを備えています。 そのため、multipartのような複雑なリクエストについては開発者の方でパース処理を実装する考え方のようです。 JerseyやRESTeasyなどメジャーな実装ライブラリでは、開発者が自力で実装しなくても、便利なアノテーションやフィルタ、Providerなどを既に用意してくれていますので、それを利用するのをまず検討しましょう。 ただし、それらはあくまでも実装ライブラリに依存したクラス名やアノテーション名になりますので、他の実装に切り替えた際はそこの修正が必要になると思われます。 * Jerseyでのmultipartリクエストを受け取るイロハ Jersey本家ドキュメントをまず参照: - Chapter 8. Support for Common Media Type Representations -- https://jersey.java.net/documentation/latest/media.html#multipart - org.glassfish.jersey.media.multipart (Jersey 2.11 API) -- https://jersey.java.net/apidocs/2.11/jersey/org/glassfish/jersey/media/multipart/package-summary.html 基本的な流れ: + org.glassfish.jersey.media:jersey-media-multipart ライブラリを組み込む。 + Jerseyの"Application"クラスに org.glassfish.jersey.media.multipart.MultiPartFeature をProviderとして登録する。 + リソースクラスで "@Consumes(MediaType.MULTIPART_FORM_DATA)" 付けた上で、POSTパラメータを"@FormDataParam"アノテーションで受け取る。(この時、"FormDataContentDisposition + InputStream" のセットにするか、FormDataBodyPart 型でまとめて受け取るか選べる。) サンプル: - Jersey公式サンプル -- https://github.com/jersey/jersey/tree/2.11/examples/multipart-webapp - JAX-RSでファイルアップロード! - ゆみちの投げやりブログ -- http://yumix.hatenablog.jp/entry/2012/12/17/002515 --- "FormDataContentDisposition + InputStream" のセットで受け取っている例。 --- RESTeasyの例もあり。 - JAX-RSで複数ファイルをアップロードするには - Katsumi Kokuzawa's Blog -- http://kokuzawa.github.io/blog/2013/12/22/jaxrs-upload-multiple-files/ --- 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を設定して登録させています。 公式ドキュメントだけでは以下のようにそっけないコード例しか無いので、慣れてないとどこを直せばよいのか戸惑いそうです。 #pre||> 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 #pre||> @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処理の選択肢があることは歓迎できますので、頭の片隅に覚えておきたいと思いました。 - MIME pull - Efficient handling of MIME attachments — Project Kenai -- https://mimepull.java.net/ #navi_footer|Java|