今回の記事では、Jersey 2.11でのmultipart/form-dataを受け取るやり方を調べてみました。
JAX-RS 2.0の仕様自体には、特別なmultipartリクエストの対応は盛り込まれていません。
もともと基本的にServletの仕様に乗っかっていて、フィルタやMessageReaderなどリクエストを間で見張って独自に変更できる仕組みを備えています。
そのため、multipartのような複雑なリクエストについては開発者の方でパース処理を実装する考え方のようです。
JerseyやRESTeasyなどメジャーな実装ライブラリでは、開発者が自力で実装しなくても、便利なアノテーションやフィルタ、Providerなどを既に用意してくれていますので、それを利用するのをまず検討しましょう。
ただし、それらはあくまでも実装ライブラリに依存したクラス名やアノテーション名になりますので、他の実装に切り替えた際はそこの修正が必要になると思われます。
Jersey本家ドキュメントをまず参照:
基本的な流れ:
サンプル:
以下、https://github.com/msakamoto-sf/jaxrs2-exercise-jersey-servlet を例に実施にmultipart受付機能を組み込む手順を、対応するコミットログと一緒に解説します。
解説:
Mavenプロジェクトなので、素直にdependencyに追加してます。
解説:本来の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
今回の例では、1個のアップロードしか想定しない方を "FormDataContentDisposition + InputStream" のセットで受け取り、複数ファイルの受け取りを想定する方を FormDataBodyPart 型で受け取り、ループで処理してます。
以上になりますが、"jersey-media-multipart"の依存関係を見てたら Commons のFileUploadではなく、java.net製のmultipart処理ライブラリである "mimepull" というのを使ってました。ライセンスの都合でAPL2のライブラリが使えないせいか、それとも他の技術的な理由かは分かりませんが、commons-fileupload以外のmime処理の選択肢があることは歓迎できますので、頭の片隅に覚えておきたいと思いました。