#navi_header|Groovy| GroovyServletでファイルアップロードを処理させようとしたところ、思いっきり落とし穴に嵌りましたのでメモ。 時間がない方向けの結論: + GroovyServletでは、内部でHttpServletRequestのパラメータを読みだして独自にBindingしている。 ++ → このため、HttpServletRequest.getInputStream()を(恐らくContainer側の実装にも依ると思うが)GroovyServletの内部処理で読みきってしまう。 ++ → GroovyServlet上で動作するスクリプトからは、(既に読みきってしまっているため)HttpServletRequest.getInputStream()からHTTPリクエストのBODYデータを読み込めない。 ++ (もしかしたらInputStream.reset()を呼べば良いかもしれないが、関連トピックで調べてみたところあまりreset()を使う解法が無かったっぽいので、駄目なのかもしれない。) + 解法:Servletを呼ぶ前に独自のFilterでgetInputStream()からbyte[]型に読み出し、それをHttpServletRequestWrapper派生の独自ラッパーで包み込んだのを本体Servletに渡す。 ++ これにより、独自ラッパー内のbyte[]型として何回でもByteArrayInputStream経由で読み出せるようになる。 ++ 多分GroovyServletとの副作用も無いっぽい。 ++ Apache Commons FileUpload も使えたので、多分これで行けるだろう。実際好きなタイミングでリクエストボディ取り出せるのは便利。 ++ この時用意するFilterとかラッパーについては以下の詳細説明を参照してください。 #more|| ---- 用意するFilterやラッパーについては、以下のBlogが詳しいです。 - HonestyWorks TechNote » slim3のcontrollerでServletInputStreamを使いたいとき -- http://blog.honestyworks.jp/blog/archives/162 - Slim3 GAE/J で request getInputStream の中身がない|あきらるのブログ -- http://ameblo.jp/vashpia77/entry-10826082231.html - ServletInputStreamを2回使う - Usa&pre(){*}Usa日記 -- http://d.hatena.ne.jp/machi_pon/20090120/1232420325 GroovyServletのサンプルにも組み込んでいます。 - https://github.com/msakamoto-sf/groovyservlet-sample-template -- src/main/groovy/gsst/ToolKit.groovy, src/main/webapp/WEB-INF/web.xml を参照。 ---- 以下、落とし穴に嵌ったのを認識する前段階からの足跡。 1.Apache Commons FileUploadを使おうと、練習にまずはHttpServletRequest.getInputStream()を使ってみる。 - @IT:Java TIPS -- ファイルアップロード処理を簡単にする(Commons活用) -- http://www.atmarkit.co.jp/fjava/javatips/106jakarta018.html ・・・が、getInputStream()しても正常に取れない・・・。 2.自分が嵌るくらいだから、既に誰か対処法見つけてるんじゃないの? - groovyあれこれ: groovletsでファイルアップロードする -- http://groovyarekore.blogspot.jp/2009/10/groovlets.html - Add File Upload Support to Groovlets in Google App Engine - Messages from mrhaki -- http://mrhaki.blogspot.jp/2009/11/add-file-upload-support-to-groovlets-in.html ・・・できてるようではあるが・・・記事も古く、バージョンも大分古いので内部動作も変わってしまってるのかも。 3.ようやく、ServletAPIを確認しようとひっくり返してみる。 - Servlet 2.4 API 仕様 -- http://mergedoc.sourceforge.jp/tomcat-servletapi-5-ja/ これでようやく、getParameter系とかgetReader/getInputStreamって併用すると副作用ある感じ?ということに気づく。 4.getParameter系呼んだ後にgetInputStream()呼び出してトラブった人いないかな? - getReaderとgetParamater系って一回のリクエストで同時に使えないの?について調べてみた - 生き急げるほど意志は強くない -- http://d.hatena.ne.jp/tomobou/20091010/1255196298 - [#GROOVY-895] Groovlets: File upload support - jira.codehaus.org -- http://jira.codehaus.org/browse/GROOVY-895 --- GroovyServletで、Commons FileUploadを依存ライブラリに追加してファイルアップロードも取れるようにしようというpatchが投稿された・・・が、これ以上追加ライブラリ加えたくね~みたいな感じでrejectされたっぽい。 - groovy - user - Re: GroovyServlet - Cannot Read ServletInputStream -- http://groovy.329449.n5.nabble.com/Re-GroovyServlet-Cannot-Read-ServletInputStream-td352662.html --- これも古いMLの投稿だが、やっぱりGroovyServletのスクリプト側でgetInputStream()しても手遅れ状態だという話。 どうもPOSTの場合にgetParameter系呼ぶと、リクエストボディのストリーム(?)を読みきってしまい、その後にgetInputStream()を読んでも、既に読みきってしまってるため手遅れ状態っぽい・・・。 →最終的にGroovyServletの中身(=Groovyのソースコード)をたどったところ、GroovyServletのBinding中でgetParamXXXX()してるためか、その影響でgetInputStream()に副作用が生じているものと思われます。 #navi_footer|Groovy|