SpringMVCでファイルダウンロード/zip圧縮ダウンロード
SpringMVCでファイルダウンロード、zip圧縮ファイルダウンロードのサンプル。
サンプルの内容
「http://[FQDN]:8080/spring3-mvc-down/download」
クライアントからのアクセスに対して、サーバローカルのファイル(C:\tmp\hoge1.csv)をInputStreamで読み込み、Streamのままレスポンスを返す。
「http://[FQDN]:8080/spring3-mvc-down/download/zip」
クライアントからのアクセスに対して、サーバローカルのファイル(C:\tmp\hoge2.csv)をInputStreamで読み込み、zip圧縮したStreamに変換し、Streamのままレスポンスを返す。
サンプルの作成
Eclipseで「spring3-mvc-down」というプロジェクトで作る。
Maven2を利用。(なんで3じゃないねんって突っ込みは無しで。)
次に以下を作成する。
- POMファイル(pom.xml)
- コントローラクラス(jp.sample.app.download.controller.DownloadController)
- HTTPリクエストに対する処理を実行するクラス。
- @Controllerや@RequestMappingアノテーションを使用する。
- Bean定義ファイル(/WEB-INF/mvc-dispatcher-servlet.xml)
- web.xml
- Springが提供するサーブレットを登録する。
■POMファイル(pom.xml)
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jp.sample.app</groupId> <artifactId>spring3-mvc-down</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>war</packaging> <name>${project.artifactId}</name> <description>SpringMVC3でファイルダウンロードのサンプル</description> <build> <plugins> <!-- コンパイラの設定 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.7</source> <target>1.7</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> <dependencies> <!-- javax.servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- Validation --> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.CR3</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.0.0.Final</version> </dependency> <!-- Spring Framework --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>3.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>3.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>3.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>3.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>3.2.2.RELEASE</version> </dependency> <!-- junit --> <dependency> <groupId>junit</groupId> <artifactId>junit-dep</artifactId> <version>4.4</version> <scope>test</scope> </dependency> </dependencies> </project>
■コントローラクラス(jp.sample.app.download.controller.DownloadController)
package jp.sample.app.download.controller; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/download") public class DownloadController { static final String dir = "C:\\tmp\\"; static final String[] targetFiles = {"hoge1.csv", "hoge2.csv", "hoge3.csv"}; static String fileName; static String zipFileName; static { try { fileName = new String("サンプル.csv".getBytes("MS932"), "ISO-8859-1"); zipFileName = new String("サンプル.zip".getBytes("MS932"), "ISO-8859-1"); } catch (UnsupportedEncodingException e) { } } @RequestMapping public void download(HttpServletResponse res) throws Exception { res.setContentType("text/csv;charset=MS932"); res.setHeader("Content-Disposition", "attachment; filename=" + fileName); OutputStream os = res.getOutputStream(); InputStream in = new FileInputStream(dir + targetFiles[0]); byte[] b = new byte[1024]; int len; while((len = in.read(b)) != -1) { os.write(b, 0, len); } in.close(); os.close(); } @RequestMapping("zip") public void downloadZip(HttpServletResponse res) throws Exception { res.setContentType("application/octet-stream;charset=MS932"); res.setHeader("Content-Disposition", "attachment; filename=" + zipFileName); res.setHeader("Content-Transfer-Encoding", "binary"); OutputStream os = res.getOutputStream(); ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(os)); ZipEntry ze = new ZipEntry(targetFiles[1]); zos.putNextEntry(ze); InputStream in = new BufferedInputStream(new FileInputStream(dir + targetFiles[1])); byte[] b = new byte[1024]; int len; while((len = in.read(b)) != -1) { zos.write(b, 0, len); } in.close(); zos.closeEntry(); zos.close(); } @RequestMapping("zip/all") public void downloadZipAll(HttpServletResponse res) throws Exception { res.setContentType("application/octet-stream;charset=MS932"); res.setHeader("Content-Disposition", "attachment; filename=" + zipFileName); res.setHeader("Content-Transfer-Encoding", "binary"); OutputStream os = res.getOutputStream(); ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(os)); for(int i=0; i<targetFiles.length; i++){ ZipEntry ze = new ZipEntry(targetFiles[i]); zos.putNextEntry(ze); InputStream in = new BufferedInputStream(new FileInputStream(dir + targetFiles[i])); byte[] b = new byte[1024]; int len; while((len = in.read(b)) != -1) { zos.write(b, 0, len); } in.close(); zos.closeEntry(); } zos.close(); } }
■Bean定義ファイル(/WEB-INF/mvc-dispatcher-servlet.xml)
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="jp.sample" /> <annotation-driven /> <resources mapping="/resources/**" location="/resources/" /> </beans:beans>
■web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:jsp="http://java.sun.com/xml/ns/javaee/jsp" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>SpringMVC-Application-sample</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> <servlet> <servlet-name>mvc-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc-dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> </web-app>
サンプルの応答電文
「http://[FQDN]:8080/spring3-mvc-down/download」
HTTPヘッダ | 値 |
---|---|
Status Code | 200 OK |
Content-Disposition | attachment; filename=サンプル.csv |
Content-Length | [数字] |
Content-Type | text/csv;charset=MS932 |
Date | [日付] |
Server | Apache-Coyote/1.1 |
サンプルの処理速度測定
右寄せにならなくて見辛い。。。
ファイル数 | ファイルサイズ(MByte) | 合計ファイルサイズ(MByte) | 処理時間(ミリ秒) |
---|---|---|---|
1 | 1 | 1 | 16.3 |
10 | 1 | 10 | 192.3 |
100 | 1 | 100 | 2610.3 |
1000 | 1 | 1000 | 20727.3 |
ファイル数 | ファイルサイズ(MByte) | 合計ファイルサイズ(MByte) | 処理時間(ミリ秒) |
1 | 10 | 10 | 192.3 |
10 | 10 | 100 | 1768.0 |
100 | 10 | 1000 | 18896.7 |
ファイル数 | ファイルサイズ(MByte) | 合計ファイルサイズ(MByte) | 処理時間(ミリ秒) |
1 | 100 | 100 | 1773.3 |
10 | 100 | 1000 | 18813.7 |
ファイル数 | ファイルサイズ(MByte) | 合計ファイルサイズ(MByte) | 処理時間(ミリ秒) |
1 | 1000 | 1000 | 17290.0 |
※処理時間は3回とった値の平均(少数大第2位を四捨五入)。サーバ側でzip化してStreamで流し切るまでの時間なのでネットワーク遅延は入ってない。