File Download Servlet

아래 클래스는 MS IE, Mozilla, Opera 등을 위해 한글 파일명 다운로드 처리까지 된 다운로드 도우미 클래스이다.

서블릿에서 download() 메소드를 호출하여 사용하면 된다.

현재 Tomcat 5.0.28 에서 MS IE 6.0, FireFox 1.0.6, Opera 8.5, 한글 인코딩 EUC-KR 일때 한글 파일명이 제대로 다운로드 되는 것을 확인하였다.

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
/**
 * 웹상에서 다운로드 작업을 수행하는 유틸리티
 * 
 * @author 손권남
 * 
 */
public class DownloadUtil {
 
  /** 다운로드 버퍼 크기 */
  private static final int BUFFER_SIZE = 8192; // 8kb
 
  /** 문자 인코딩 */
  private static final String CHARSET = "euc-kr";
 
  /**
   * 생성자 - 객체 생성 불가
   */
  private DownloadUtil() {
    // do nothing;
  }
 
  /**
   * 지정된 파일을 다운로드 한다.
   * 
   * @param request
   * @param response
   * @param file
   *            다운로드할 파일
   * 
   * @throws ServletException
   * @throws IOException
   */
  public static void download(HttpServletRequest request, HttpServletResponse response, File file)
      throws ServletException, IOException {
 
    String mimetype = request.getSession().getServletContext().getMimeType(file.getName());
 
    if (file == null || !file.exists() || file.length() <= 0 || file.isDirectory()) {
      throw new IOException("파일 객체가 Null 혹은 존재하지 않거나 길이가 0, 혹은 파일이 아닌 디렉토리이다.");
    }
 
    InputStream is = null;
 
    try {
      is = new FileInputStream(file);
      download(request, response, is, file.getName(), file.length(), mimetype);
    } finally {
      try {
        is.close();
      } catch (Exception ex) {
      }
    }
  }
 
  /**
   * 해당 입력 스트림으로부터 오는 데이터를 다운로드 한다.
   * 
   * @param request
   * @param response
   * @param is
   *            입력 스트림
   * @param filename
   *            파일 이름
   * @param filesize
   *            파일 크기
   * @param mimetype
   *            MIME 타입 지정
   * @throws ServletException
   * @throws IOException
   */
  public static void download(HttpServletRequest request, HttpServletResponse response, InputStream is,
      String filename, long filesize, String mimetype) throws ServletException, IOException {
    String mime = mimetype;
 
    if (mimetype == null || mimetype.length() == 0) {
      mime = "application/octet-stream;";
    }
 
 
    byte[] buffer = new byte[BUFFER_SIZE];
 
    response.setContentType(mime + "; charset=" + CHARSET);
 
    // 아래 부분에서 euc-kr 을 utf-8 로 바꾸거나 URLEncoding을 안하거나 등의 테스트를
    // 해서 한글이 정상적으로 다운로드 되는 것으로 지정한다.
    String userAgent = request.getHeader("User-Agent");
 
    // attachment; 가 붙으면 IE의 경우 무조건 다운로드창이 뜬다. 상황에 따라 써야한다.
    if (userAgent != null && userAgent.indexOf("MSIE 5.5") > -1) { // MS IE 5.5 이하
      response.setHeader("Content-Disposition", "filename=" + URLEncoder.encode(filename, "UTF-8") + ";");
    } else if (userAgent != null && userAgent.indexOf("MSIE") > -1) { // MS IE (보통은 6.x 이상 가정)
      response.setHeader("Content-Disposition", "attachment; filename="
          + java.net.URLEncoder.encode(filename, "UTF-8") + ";");
    } else { // 모질라나 오페라
      response.setHeader("Content-Disposition", "attachment; filename="
          + new String(filename.getBytes(CHARSET), "latin1") + ";");
    }
 
    // 파일 사이즈가 정확하지 않을때는 아예 지정하지 않는다.
    if (filesize > 0) {
      response.setHeader("Content-Length", "" + filesize);
    }
 
    BufferedInputStream fin = null;
    BufferedOutputStream outs = null;
 
    try {
      fin = new BufferedInputStream(is);
      outs = new BufferedOutputStream(response.getOutputStream());
      int read = 0;
 
      while ((read = fin.read(buffer)) != -1) {
        outs.write(buffer, 0, read);
      }
    } catch (IOException ex) {
        // Tomcat ClientAbortException을 잡아서 무시하도록 처리해주는게 좋다.
    } finally {
      try {
        outs.close();
      } catch (Exception ex1) {
      }
 
      try {
        fin.close();
      } catch (Exception ex2) {
 
      }
    } // end of try/catch
  }
}
  1. 추가(2010/08/30) : response.setHeader(“Content-Transfer-Encoding”, “binary”); 도 함께 할 것.
  2. 추가(2011/11/09) : userAgent null 체크 추가. 가끔 웹 다운로더 플러그인들이 User-Agent 헤더를 안보내주는 현상이 있다.
  3. 추가(2012/07/23) : Content-Disposition 헤더 값의 문자열 중에 IE의 경우 “attachment;”가 있어야 다운로드 창이 뜬다. 아니면 MimeType이 application/octet-stream 일지라도 파일명의 MimeType에 따라 행동한다.