[Java]Tomcatのサーブレットを通じてファイルをダウンロードするサンプルです。

■目次


ファイルの配置

/CONTEXT_ROOT
┗ WEB-INF
 ┣ src
 ┃┗ DownloadServlet.java
 ┗ web.xml

ダウンロードサーブレット(DownloadServlet.java)

import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;
import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimeUtility;

public class DownloadServlet extends HttpServlet {
 @Override
 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
     IOException {
   // POSTメソッドでアクセスが来てもGETメソッドで全部処理します。
   doGet(req, resp);
 }

 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
     IOException {

   // ファイル名設定
   // リクエストパスからファイル名を取得
   String orgFileName = new String(req.getPathInfo().substring(1).getBytes("ISO-8859-1"), "UTF-8");
   String fileName;
   // リクエストヘッダからユーザーエージェント(ブラウザの名前)取得
   String ua = req.getHeader("user-agent");
   if (ua.contains("MSIE")) {
     // IE用ファイル名エンコード
     fileName = URLEncoder.encode(orgFileName, "UTF-8");
   } else {
     // IE以外(FireFox,Safari,Chrome)ファイル名エンコード
     fileName = MimeUtility.encodeWord(orgFileName, "ISO-2022-JP", "B");
   }

   // レスポンスヘッダー設定
   if (ua.contains("Safari")) {
     // サファリ用
     resp.setContentType("application/octet-stream;");
   } else {
     // サファリ以外用
     resp.setContentType("text/csv; charset=UTF-8;");
     resp.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
   }
   
   // ファイル名デコード
   String decFileName = URLDecoder.decode(orgFileName, "UTF-8");

   ServletOutputStream os = resp.getOutputStream();
   String dir = "/home/tomcat/dat/";
   File p = new File(dir);
   String path = dir + decFileName;
   File f = new File(path);
   if (!f.exists()) {
     // ファイルがない場合404
     resp.setStatus(404);
   } else if (!f.getParentFile().equals(p)) {
     // 許可したディレクトリ以外へのアクセスは403
     // 必要な場合、ログインユーザーごとにアクセスできるファイルの制御も行います。
     resp.setStatus(403);
   } else {
     // ファイルがあれば読み込んでレスポンスに突っ込む
     BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));
     byte[] buff = new byte[500];
     int len;
     while ((len = bis.read(buff)) > 0) {
       os.write(buff, 0, len);
     }
     bis.close();
     os.flush();
   }
   
 }
}

web.xmlの設定

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                     http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
 version="3.0">

 <!-- サーブレットの宣言 -->
 <servlet>
   <servlet-name>down</servlet-name>
   <servlet-class>DownloadServlet</servlet-class>
 </servlet>

 <!-- サーブレットとurlのマッピング -->
 <servlet>
   <servlet-name>down</servlet-name>
   <servlet-class>DownloadServlet</servlet-class>
 </servlet>
</web-app>

解説

 このサンプルは、サーブレットにアクセスしたファイル名と、「/home/tomcat/dat/」のディレクトリ名をがっちゃんこして、ファイルがあればレスポンスにファイルを詰め込んでダウンロード、ファイルがなければ404エラー、ファイルがあってもディレクトリ名が許可したディレクトリ名でなければ403エラーにするサンプルです。日本語のファイル名でもダウンロードできます。

ブラウザでアクセス

「/home/tomcat/dat/」にファイルを配置して、
http://localhost:8080/CONTEXT_ROOT/down/ファイル名」にアクセスすると、ブラウザのダウンロード処理が動きます。
http://localhost:8080/CONTEXT_ROOT/down/存在しないファイル名」にアクセスすると、404エラーになります。

「/home/tomcat/dat/hoge/」というディレクトリを作ってファイルを配置して、
http://localhost:8080/CONTEXT_ROOT/down/hoge/ファイル名」にアクセスすると、403のステータスコードを返しアクセスエラーになります。

その他のTomcatサンプル