つりくさいタイトルのほうがいいらしいので。
実はJavaOne時に発表されたpreview版では未実装だったのだけれども、今最新版にしてみたらちゃんと動いたので報告。
JavaEE 6、つまりServlet 3.0ではServletの定義にweb.xmlが必要なくなるとかソースで動的にフィルタやサーブレットを設定可能になったりかなり便利になったと思う。
この辺参照 http://d.hatena.ne.jp/shin/20090616/p1
ほかにも大きいものとしてやっと標準でマルチパートに対応した。つまり、サーブレットAPIで簡単にファイルアップロードが出来るのである。
ソースを見てもらうのが手っ取り早いので先に乗せる。
index.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP Page</title> </head> <body> <h1>Hello World!</h1> <form action="upload" method="post" enctype="multipart/form-data"> <input type="text" name="text"><br> <input type="file" name="file"> <input type="submit" value="送信"> </form> </body> </html>
NewServlet.java
import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.Reader; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Part; @WebServlet("/upload") public class NewServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { out.println("<html>"); out.println("<head>"); out.println("<title>Servlet NewServlet</title>"); out.println("</head>"); out.println("<body>"); for(Part p :request.getParts()){ out.println("------------------------------------<br>"); for(String h:p.getHeaderNames()){ out.println(p.getHeader(h)+","); } out.println("<br>"); out.println(p.getContentType()+":"+p.getName() + "="+p.getSize()+"バイト"); out.println("<br>"); Reader r = new InputStreamReader( p.getInputStream() ,"UTF-8"); int ch; while((ch = r.read()) >= 0){ out.print((char)(ch & 0xffff)); } r.close(); out.println("<br>"); } out.println("</body>"); out.println("</html>"); } finally { out.close(); } } }
アノテーションでマッピングしているのでweb.xmlは例によってなくてよい。
ファイルサイズの制限等は?
MultipartConfigにてリクエストのサイズ制限とかファイルアップロードのサイズ制限とか、サイズがこれ以上になったらメモリで確保ではなく、ファイルに書き出すようにするとか設定が出来る。
@WebServlet("/upload") @MultipartConfig(maxFileSize=10) public class NewServlet extends HttpServlet { …
たとえば、上のようにして先ほどのファイル(25バイト)をアップロードすると
致命的: StandardWrapperValve[NewServlet]: PWC1406: Servlet.service() for servlet NewServlet threw exception java.lang.IllegalStateException: org.apache.catalina.fileupload.SizeException: The field text exceeds its maximum permitted size of 10 characters. at org.apache.catalina.fileupload.Multipart.initParts(Multipart.java:134) at org.apache.catalina.fileupload.Multipart.getParts(Multipart.java:143) at org.apache.catalina.connector.Request.getParts(Request.java:4042) at org.apache.catalina.connector.RequestFacade.getParts(RequestFacade.java:1166) at NewServlet.doPost(NewServlet.java:28) at javax.servlet.http.HttpServlet.service(HttpServlet.java:754) at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1506) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:293) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641) at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97) at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641) at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:351) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:250) at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:202) at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:746) at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:655) at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:905) at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:161) at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:136) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:103) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:89) at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76) at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53) at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57) at com.sun.grizzly.ContextTask.run(ContextTask.java:69) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:619) Caused by: org.apache.catalina.fileupload.SizeException: The field text exceeds its maximum permitted size of 10 characters. at org.apache.catalina.fileupload.RequestItemIterator$RequestItemImpl$1.raiseError(RequestItemIterator.java:144) at org.apache.catalina.fileupload.LimitedInputStream.checkLimit(LimitedInputStream.java:109) at org.apache.catalina.fileupload.LimitedInputStream.read(LimitedInputStream.java:166) at java.io.FilterInputStream.read(FilterInputStream.java:90) at org.apache.catalina.fileupload.Streams.copy(Streams.java:133) at org.apache.catalina.fileupload.Streams.copy(Streams.java:103) at org.apache.catalina.fileupload.Multipart.initParts(Multipart.java:129) ... 31 more
Partの取得でとまるようになっているようだ。らくちんだね。