본문 바로가기

프로그래밍/JAVA, Servlet, JSP

[FileUpload] File 전송(jakarta FileUpload API)

[01] File 전송(jakarta FileUpload API, 파일 업로드)
   - http://archive.apache.org/dist/jakarta/commons/fileupload/binaries/
  
   - 'commons-fileupload-1.0.jar' 파일을 "tomcat-5.5/common/lib" 그리고
     "eclipse/lib"에  복사합니다.
   - Tomcat Application Folder
     . WebContent/fileupload        : jsp파일을 저장합니다.
     . WebContent/fileupload/temp   : 파일 upload시 임시로 사용할 폴더
     . WebContent/fileupload/storage: Upload된 파일이 저장될 공간
   - FileItem 클래스가 제공하는 메소드 내역
     . boolean isFormField(): 일반적인 입력 파라미터인 경우 true를 리턴 합니다.
     . String getFieldName(): 파라미터의 이름을 구합니다.
     . String getString()   : 기본 캐릭터셋을 이용하여 파라미터의 값을 구합니다.
     . String getString(String encoding): 지정한 인코딩을 이용하여 파라미터값을 구함
     . String getName()     : 업로한 파일의 전체 경로를 포함한 이름을 구합니다.
     . long getSize()       : 업로드한 파일의 크기를 구합니다.
     . void write(File file): 업로드한 파일을 file이 나타내는 파일로 저장합니다.
     . InputStream getInputStream(): 업로드한 파일을 읽어오는 입력 스트림을 리턴합니다.
     . byte[] get()         : 업로드한 파일을 byte 배열로 구합니다.
     . boolean isInMemory() : 업로드한 파일이 임시 디렉토리에 저장된 상태인 경우
                              true를 리턴하고, 임시 데렉토리에 저장된 경우 false를
                              리턴합니다.
     . void delete()        : 파일과 관련된 자원을 제거합니다.메모리가 사용되고
                              있을 경우 메모리를 반환하고, 임시 디렉토리에 있는
                              파일을 삭제합니다.
 
※ WTP 상에서 개발할시에 사용하는 UPLOAD 경로 
F:\200703_ojt\eclipse\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\webapps\www_oracle\pilot\dataroom\storage
 
1. request.getParameter()메소드의 지원 빈즈 작성
>>>>> FileUploadRequestWrapper.java
package www.utility;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import java.util.Map;
import java.util.HashMap;
import java.util.Enumeration;
import java.util.Iterator;
/**
 * FileUpload API를 사용하는 HttpServletRequestWrapper 클래스로서
 * HttpServletRequest에 기반한 API를 사용하기 위한 래퍼이다.
 */
public class FileUploadRequestWrapper extends HttpServletRequestWrapper {
   
    private boolean multipart = false;
   
    private HashMap parameterMap;
    private HashMap fileItemMap;
   
    /**
     * 기본 생성자
     * @param request
     * @throws FileUploadException
     */
    public FileUploadRequestWrapper(HttpServletRequest request)
    throws FileUploadException{
        this(request, -1, -1, null);
    }
   
    /**
     * 생성자
     * @param request HttpServletRequest 객체
     * @param threshold 메모리에 저장할 최대크기
     * @param max 업로드할 최대 파일크기
     * @param repositoryPath 업로드 경로
     * @throws FileUploadException
     */
    public FileUploadRequestWrapper(HttpServletRequest request,
        int threshold, int max, String repositoryPath) throws FileUploadException {
        super(request);
       
        parsing(request, threshold, max, repositoryPath);
    }
   
    /**
     * 일반 입력 필드와 파일 필드를 MAP에 저장
     * @param request HttpServletRequest 객체
     * @param threshold 메모리에 저장할 최대크기
     * @param max 업로드할 최대 파일크기
     * @param repositoryPath 업로드 경로
     * @throws FileUploadException
     */
    private void parsing(HttpServletRequest request,
        int threshold, int max, String repositoryPath) throws FileUploadException {
       
        if (FileUpload.isMultipartContent(request)) {
            multipart = true;
           
            parameterMap = new java.util.HashMap();
            fileItemMap = new java.util.HashMap();
           
            DiskFileUpload diskFileUpload = new DiskFileUpload();
            if (threshold != -1) {
                diskFileUpload.setSizeThreshold(threshold);
            }
            diskFileUpload.setSizeMax(max);
            if (repositoryPath != null) {
                diskFileUpload.setRepositoryPath(repositoryPath);
            }
           
            java.util.List list = diskFileUpload.parseRequest(request);
            for (int i = 0 ; i < list.size() ; i++) {
                FileItem fileItem = (FileItem) list.get(i);
                String name = fileItem.getFieldName();
               
                if (fileItem.isFormField()) {
                    String value = fileItem.getString();
                    String[] values = (String[]) parameterMap.get(name);
                    if (values == null) {
                        values = new String[] { value };
                    } else {
                        String[] tempValues = new String[values.length + 1];
                        System.arraycopy(values, 0, tempValues, 0, 1);
                        tempValues[tempValues.length - 1] = value;
                        values = tempValues;
                    }
                    parameterMap.put(name, values);
                } else {
                    fileItemMap.put(name, fileItem);
                }
            }
            addTo(); // request 속성으로 설정한다.
        }
    }
   
    /**
     * 파일을 전송하는 enctype="multipart/form-data"인경우 true리턴
     * @return enctype="multipart/form-data"인경우 true리턴
     */
    public boolean isMultipartContent() {
        return multipart;
    }
   
    /**
     * 주어진 파라미터에 대한 값을 리턴
     */
    public String getParameter(String name) {
        if (multipart) {
            String[] values = (String[])parameterMap.get(name);
            if (values == null) return null;
            return values[0];
        } else
            return super.getParameter(name);
    }
   
    /**
     * 파라미터의 값들을 리턴
     */
    public String[] getParameterValues(String name) {
        if (multipart)
            return (String[])parameterMap.get(name);
        else
            return super.getParameterValues(name);
    }
   
    /**
     * 전체 파라미터의 이름을 리턴
     */
    public Enumeration getParameterNames() {
        if (multipart) {
            return new Enumeration() {
                Iterator iter = parameterMap.keySet().iterator();
               
                public boolean hasMoreElements() {
                    return iter.hasNext();
                }
                public Object nextElement() {
                    return iter.next();
                }
            };
        } else {
            return super.getParameterNames();
        }
    }
   
    public Map getParameterMap() {
        if (multipart)
            return parameterMap;
        else
            return super.getParameterMap();
    }
   
    /**
     * 지정한 파라미터 이름과 관련된 FileItem을 리턴합니다.
     * @param name
     * @return
     */
    public FileItem getFileItem(String name) {
        if (multipart)
            return (FileItem) fileItemMap.get(name);
        else
            return null;
    }
   
    /**
     * 임시로 사용된 업로드 파일을 삭제합니다.
     */
    public void delete() {
        if (multipart) {
            Iterator fileItemIter = fileItemMap.values().iterator();
            while( fileItemIter.hasNext()) {
                FileItem fileItem = (FileItem)fileItemIter.next();
                fileItem.delete();
            }
        }
    }
   
    /**
     * 래퍼객체 자체를 request 객체에 저장합니다.
     */
    public void addTo() {
        super.setAttribute(FileUploadRequestWrapper.class.getName(), this);
    }
   
    /**
     * request 속성에 저장된 FileUploadRequestWrapper를 리턴합니다.
     * @param request
     * @return
     */
    public static FileUploadRequestWrapper
                  getFrom(HttpServletRequest request) {
        return (FileUploadRequestWrapper)
            request.getAttribute(FileUploadRequestWrapper.class.getName());
    }
   
    /**
     * 지정한 request가 래퍼를 속성으로 포함하고 있으면 true를 리턴합니다.
     * @param request
     * @return
     */
    public static boolean hasWrapper(HttpServletRequest request) {
        if (FileUploadRequestWrapper.getFrom(request) == null) {
            return false;
        } else {
            return true;
        }
    }
}
 

2. 파일 업로드 폼
   - WebContent/fileupload/upload_form.jsp,
>>>>> upload_form.jsp
<%@ page contentType = "text/html; charset=euc-kr" %>
<html>
<head><title>파일 업로드 폼</title></head>
<body>
<form action="./upload_proc.jsp" method="post"
      enctype="multipart/form-data">
이미지 파일: <input type="file" name="file1"><br>
파일 설명: <input type="text" name="param1"><br>
<input type="submit" value="전송">
</form>
</body>
</html>
 

3. 파일 업로드 처리
>>>>> upload_proc.jsp
<%@ page contentType = "text/html; charset=euc-kr" %>
<%@ page import = "org.apache.commons.fileupload.*" %>
<%@ page import = "java.io.File" %>
<%@ page import = "java.io.IOException" %>
<%@ page import = "www.utility.*" %>
<%
//---------------------------------------------------------------
// Fileupload 콤포넌트 관련 코드, 하나의 파일을 업로드 처리
//---------------------------------------------------------------
request.setCharacterEncoding("euc-kr");
String root = request.getContextPath();  // www_jsp2
//임시 저장 폴더
String temporaryDir = application.getRealPath("/fileupload/temp");
//저장 폴더
String upDir = application.getRealPath("/fileupload/storage");
//다운로드 폴더
String downDir = root + "/fileupload/storage";
String param1 = "";         //일반 폼 태그
FileItem fileItem = null;   //업로드 파일 객체 ★
String filename = "";       //업로드 파일명
String fileName_enc = "";   //인코딩된 파일명
String down_file_name = ""; //다운로드할 전체 파일명
// FileUpload 콤포넌트를 쓰기위한 Manager Class 생성
// request: HttpServletRequest 객체
// -1: 메모리에 저장할 최대크기 지정하지 않음
// -1: 업로드할 최대 파일크기 지정하지 않음
// temporaryDir: 임시 업로드 폴더
FileUploadRequestWrapper requestWrap = new FileUploadRequestWrapper(request, -1, -1, temporaryDir);
// Wrapping된 request객체를 할당
request = requestWrap;
//일반 폼 태그
param1 = request.getParameter("param1");
System.out.println("이미지 설명: " + param1);
//파일 태그
fileItem = requestWrap.getFileItem("file1");
System.out.println("전송된 파일명: " + fileItem.getName());
//전송하는 파일이 있다면
if (fileItem.getSize() > 0) {
  int idx = fileItem.getName().lastIndexOf("\\"); //윈도우 기반
  if (idx == -1) { //유닉스, 리눅스 기반
      idx = fileItem.getName().lastIndexOf("/");
  }
 
  //순수 파일명 추출
  filename = fileItem.getName().substring(idx + 1);
 
  try {
      //-----------------------------------------------
      //대상 폴더에 저장할 파일 객체 생성, 폴더 + 파일명
      //-----------------------------------------------
      File uploadedFile = new File(upDir, filename);
     
      //올릴려는 파일과 같은 이름이 존재하면 중복파일 처리
      if ( uploadedFile.exists()){
          for(int k=0; true; k++){
              //파일명 중복을 피하기 위한 일련 번호를 생성하여
              //파일명으로 조합
              uploadedFile = new File(upDir, "("+k+")"+filename);
              //조합된 파일명이 존재하지 않는다면, 일련번호가
              //붙은 파일명 다시 생성
              if(!uploadedFile.exists()){ //존재하지 않는 경우
                  filename = "("+k+")"+filename;
                  break;
              }
          }
      }
     
      //pilot/dataroom/storage 폴더에 파일명 저장
      fileItem.write(uploadedFile);
  } catch(IOException ex) {
      System.out.println(ex.toString());   
  }
}
fileName_enc = Utility.getEncoding(filename);
down_file_name = downDir + "/" + fileName_enc;
//---------------------------------------------------------------
//Fileupload 콤포넌트 관련 코드 끝
//---------------------------------------------------------------
%>

<html>
<head><title>파일 업로드 처리</title></head>
<body>
<h3>
<br><br>
전송된 파일 미리보기<br>
<img src=<%=down_file_name%>><br><br>
<a href="<%=down_file_name%>"><%=filename%></a><br><br>
전송된 파일 내 컴퓨터에 저장<br>
- 한글 손상안됨<br>
- JPG등 Plug-In 파일도 다운됩니다.<br>
<a href="./down.jsp?downDir=<%=downDir%>&filename=<%=filename%>">
<%=filename%>
</a>
</h3>
</body>
</html>
 

4. Plug-In 파일의 다운 로드 지원
>>>>> down.jsp
<%@ page contentType = "text/html; charset=euc-kr" %>
<%@ page import = "java.io.*" %>
<%
//---------------------------------------------------------------
// Fileupload 콤포넌트 관련 코드, 하나의 파일을 업로드 처리
//---------------------------------------------------------------
request.setCharacterEncoding("euc-kr");
//저장 폴더
String downDir = application.getRealPath(request.getParameter("downDir"));
String filename = request.getParameter("filename"); // 파일명 받기
String fileNameEnc = new String(filename.getBytes("euc-kr"),"8859_1");
File file = new File(downDir + "/" + filename);
byte buffer[] = new byte[4096];
response.setHeader("Content-Disposition", "attachment;filename=" + fileNameEnc + ";");
if (file.isFile()){
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
    BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
    int read = 0;
    // 파일의 끝이면 -1
    while ((read = bis.read(buffer)) != -1){
        bos.write(buffer,0,read);
    }//while
    bis.close();
    bos.close();
}
%>

출처 : http://blog.empas.com/seeun791/22596695