81.参考: アップロード/ダウンロードの実装例
概要
Spring MVCにおけるアップロード/ダウンロードの実装例を見ていきます。
他にも方法はあるかと思いますので、一例として見ていただければと思います。
ここではアップロード/ダウンロードに関わる部分のみコードを記述します。
その他の設定等は以前のサンプル記事を参照ください。
【補足:multipartとは】
ファイルアップロードするときは、multipartという形式でブラウザからデータが送られてきます。
通常は、a=12&c=a という形式で送られてくるのですが、全く違う形式で送られてくるのです。
しかも、ファイルのデータだけでなく、通常のa=12のようなデータもすべて、multipartの形式で
送られてきます。
通常はリクエストオブジェクトはこの形式を解釈(パース)できず、パラメタがすべてNULLか空文字になります。
そこでこの形式からパラメタやファイルを抽出できるラッパークラスを作成し、
リクエストオブジェクトをラップしてやることで、パラメタやファイルを取得できるようにします。
ただ、tomcatのフィルタ処理などのようにラップする前の処理では、当然、パラメタを取得できないことには
注意です。
【注意!】
実は、tomcat7からservlet3.0が導入され、servlet3.0ではmultipartを扱う機能(パース)があるようです。
その機能を使用するか?、それとも以前のApacheCommonsのUpload機能を使用するか?、でやり方が少し違うようです。
ここでは、ApacheCommonsの機能を使用する方法を記述してみます。
servlet3.0を使用する方法で実装する場合も、使用するMultipartResolver(後述)の派生クラスを変更するくらいで、
あとは通常のservlet3.0を使用するときと同じ設定をするだけのようです。
(通常のservlet3.0の使用方法はまだ調べていませんので、すみませんが各自お願いします。)
アップロードの実装サンプル
<Controllerのメソッドのサンプル>
@RequestMapping(value="upload/finish")
public String upload(@RequestParam("file") MultipartFile file) throws Exception {
File saveFile = new File("c:/temp/upload.txt");
FileUtils.copyInputStreamToFile(file.getInputStream(), saveFile);
return "user-Edit-Finish";
}
ここでは、アップロードされたファイルを「c:/temp/upload.txt」というファイル名で保存しています。
【MaltipartFileクラスについて】
引数にMaltipartFileという見慣れないクラスがあるかと思います。
このクラスはブラウザからアップロードされたファイルの中身やファイル名を保持するクラスです。
このクラスを使用すればファイルの受け取りは、getInputStream()を呼び出すだけになります。
ただし、このクラスを使用できるようにするには、以下のようにSpringの設定ファイルにマルチパートの
設定をします。
【FileUtilsクラス】
このクラスのパッケージまで含めたクラス名は、org.apache.commons.io.FileUtilsです。Apacheのライブラリです。
ここで使用したメソッドはInputStreamをcloseしてくれるので、プログラマーがcloseする必要はありません。
海外のプログラマーはこういったライブラリをうまく使ってプログラミングしますが、日本の方は使用できるライブラリを探すより
自作するのが好きなようですね。
でも、このようなよく使う機能はライブラリをうまく利用した方がよいかなと個人的には思っています。
<Springの設定ファイル、および、web.xmlのフィルタの設定サンプル>
【SpringのapplicationContext.xmlの設定】
<!-- Multipartのクラスの設定。id(bean名)は以下の通りにすること -->
<bean id="filterMultipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- ファイルアップロードの最大サイズ(byte) -->
<property name="maxUploadSize" value="100000"/>
</bean>
MultipartResolverをSpringの設定ファイルに追記すればMaltipartFileクラスをControllerクラスのメソッドで受け取れます。
以下の記事も参照ください。
⇒ちなみに、servlet3.0を使用する場合は、org.springframework.web.multipart.support.StandardServletMultipartResolverを
使用するようです。
ただし、最大ファイルサイズなどはservlet3.0の機能の方で設定するようで、あまりpropertyは設定することはないようです。
そして、web.xmlにもtomcatのフィルタを設定します。
【tomcatのフィルタの設定(web.xmlファイル)】
<filter>
<filter-name>MultipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MultipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注意点: SpringSecurityのフィルタの前に記述してください。
このフィルタは実はSpringSecurityでCSRF対策を実施する場合に必要です。
そういう意味では上記のフィルタはCSRF対策が不要な場合は必須ではないのですが、いつでも設定しておいて良いと思います。
さて、MultipartResolverを設定しているのに、なぜこのようなフィルタが必要なのでしょうか?
ファイルのアップロード時はブラウザから送られてくるパラメタの記述形式が通常と違います。
SpringSecurityのCSRF対策では、ブラウザからトークンをパラメタとして受け取って正しいトークンかをチェックしますが
マルチパート(アップロード時)の場合は形式が違うのでパラメタを抽出できず、トークンを空として扱ってしまい、エラーになります。
上記のフィルタがSpringSecurityの処理の前に、MultipartResolverを使用してマルチパートを解釈(パース)して
トークンパラメタを抽出してSpringSecurityに渡すことができるのです。
<JSPのサンプル(User-Edit-Input.jsp)>
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<form:form action="finish.html" method="POST" enctype="multipart/form-data" >
<table class="data-col">
<tr>
<th>ファイル<br></th>
<td><input type="file" name="file"/></td>
</tr>
</table>
<br>
<input type="submit" value="送信" />
</form:form>
JSP記述上の留意点は、formタグで、enctypeを記述することと、type="file"のinputタグを作ることです。
<JSPのサンプル(User-Edit-Finish.jsp)>
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<html>
<body>
完了しました。
</body>
</html>
<動かし方>
eclipseなどでWEB起動後、JSPのサンプルのページで、ファイルを指定して送信してください。
c:/tempディレクトリにファイルができているかと思います。
別の場所に保存したい場合や、アップロードしたファイル名で保存したいときはContorllerのメソッドを書き換えてみてください。
ダウンロードの実装サンプル
<Controllerのメソッドのサンプル>
@RequestMapping(value="download/finish")
public void download(HttpServletResponse response) throws Exception {
Resource file = new FileSystemResource("c:/temp/test.txt");
response.setContentType("text/plain");
response.setContentLength((int)FileUtils.sizeOf(file.getFile()));
response.setHeader("Content-Disposition","attachment; filename=\"" + file.getFile().getName() +"\"");
FileCopyUtils.copy(file.getInputStream(), response.getOutputStream());
}
「c:/temp/test.txt」というファイルをダウンロードします。
【引数について】
ダウンロードするときは、引数にレスポンスオブジェクトを指定します。
そして、ダウンロードさせたいファイルのInputStreamを渡してしまうのが簡単です。
【返り値について】
通常のSpringMVCのサンプルではView名の文字列を返します。
それはSpring にView処理(つまりHTML作成処理)をさせるためでした。
しかしダウンロード処理でのView処理はファイルをブラウザに返すことですが、それは上記のControllerのメソッドが実施してしまっています。
ですので、View処理をSpring MVC にやらせる必要はありません。
返り値なし(void)にすれば良いのです。
【FileCopyUtilsクラス】
このクラスのパッケージ名まで含めた名前は、org.springframework.util.FileCopyUtilsです。
ここで使用したメソッドはcloseもしてくれるので、特にプログラマー側でclose処理する必要はありません。
Springが用意しているクラスです。
こういったクラスもうまく使っていきましょう。
<動かし方>
eclipseなどでWEB起動後、指定のURLにアクセスすればダウンロードが始まります。
例えば、「http://localhost:8080/spring_mvc_sample/user/download/finish.html」です。
Created Date: 2012/04/18