본문 바로가기
프로그래밍/java

Commons-Fileupload

by Super User 2009. 6. 10.

Commons-Fileupload

 

 

I. Commons-fileupload 란?

 

커먼스의 파일 업로드 패키지는 사용법이 쉬우며 쓸만한 함수들을 많이 지원합니다.

SmartUpload, MultipartRequest, Commons fileupload등을 모두 사용해 보았지만 개인적으로 가장 애착이 가는 파일 업로드입니다.

아쉬운점은 Commons-fileupload는 지난 2003년 6월 1.0버젼으로 정식 릴리즈 되었지만 그 이후로 이렇다 할 패치나 보안이 전혀 안되었다는 것입니다. 이말은 파일 업로드 자체가 그리 복잡한 패키지가 아니며 첫 정식 버젼이 그만큼 완벽하다는 것을 반증하는 말이기도 하겠지요 ^^

 

 

II. 다운로드 및 설치

 

자 다운로드 받으러 갑시다.

http://jakarta.apache.org/site/downloads/downloads_commons-fileupload.cgi

설치는 역시나 /WEB-INF/lib/ 폴더에 복사합니다.

 

 

III. 파일 업로드 처리 단계

 

① 먼저 파일 업로드된 아이쳄을 처리하기 전에 유효한 Request인지 확인해야 합니다.

boolean isMultipart = FileUpload.isMultipartContent(request);

이 코드는 현재 request가 multipart/form-data로 데이터를 전송했는지 유무를 true/false로 반환합니다.

 

② 업로드된 아이템이 매우 작다면 메모리에서 처리합니다.

 

③ 큰 아이템이라면 임시 파일을 만들어 디스크에 저장하여 처리합니다.

 

④ 너무 큰 아이템이라면 당연히 거부해야 합니다.

 

⑤ 그렇지 않고 디폴트로 설정한 메모리, 최대값의 범위를 초과하지 않는다면 업로드를 시작합니다.

② ~ ⑤ 까지를 다음과 같이 간단히 할 수 있습니다.

// 파일 업로드 핸들러를 생성
DiskFileUpload upload = new DiskFileUpload();

// 한번에 메모리에 저장할 사이즈 설정

upload.setSizeThreshold(yourMaxMemorySize);

// 파일 업로드 최대 사이즈를 설정

upload.setSizeMax(yourMaxRequestSize);

// 파일 업로드 경로를 설정
upload.setRepositoryPath(yourTempDirectory);

 

⑥ 이제 전송된 request를 parsing하여 아이템들을 추출합니다.

List /* FileItem */ items = upload.parseRequest(request);

위에서 설정한 값들을 request parsing단위로 따로 설정 할 수 있습니다.

List /* FileItem */ items = upload.parseRequest(request,
yourMaxMemorySize, yourMaxRequestSize, yourTempDirectory);

 

⑦ 이렇게 추출된 items를 이제 폼필드 타입에 따라 적절히 처리 합니다.

Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();


// 파일 타입이 아닌 다른 폼필드라면
if (item.isFormField()) {
processFormField(item);

 

// 파일 타입 폼필드라면
} else {
processUploadedFile(item);
}
}

 

⑧ 폼필드에 따른 처리

만약 폼필드가 파일 이외의 파라미터라면 다음과 같이 처리하면 됩니다.

if (item.isFormField()) {
//파라미터 이름

String name = item.getFieldName();

//파라미터 값

String value = item.getString();
...
}

 

만약 폼필드가 파일 파라미터라면 다음과 같이 처리하면 됩니다.

if (!item.isFormField()) {

// 파라미터 이름
String fieldName = item.getFieldName();

// 파일 이름 (경로포함)
String fileName = item.getName();
String contentType = item.getContentType();

// 업로드한 파일이 메모리에 저장된 상태면 true, 거렇지 않고 임시 파일로 저장된 경우 false를 리턴
boolean isInMemory = item.isInMemory();

// 파일사이즈
long sizeInBytes = item.getSize();
...

 

// 파일 객체를 하나 만들어 업로드 완료!

File uploadedFile = new File(...);

item.write (uploadedFile);
}

 

⑨ 파일 업로드 방식

파일 업로드 방식에는 모두 3가지가 존재합니다.

-. FileItem.write (File file);

-. FileItem.getInputStream();

-. FileItem.get()

 

write 는 직접적으로 업로드한 파일을 저장하는 가장 일반적이고 간단한 방식입니다.

나머지 두 방식은 스트림을 사용하여 업로드한 파일이 어떤 특별한 처리를 할 때 사용합니다. 혹은 데이터베이스에 바로 저장 할 경우에도 사용될 수 있습니다. 특히 get()은 메모리에 모두 할당하여 작업을 하니 주의를 요합니다.

 

 

VI. 샘플코드

 

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileItem;

 

public class UploadServlet extends HttpServlet {

 

String upload = null;


public void init(ServletConfig config) throws ServletException {
super.init(config);
upload = config.getServletContext().getRealPath("/upload/")
}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

try {

if (FileUpload.isMultipartContent(request)) {

DiskFileUpload fileUload = new DiskFileUpload();
fileUpload.setRepositoryPath(upload);
fileUpload.setSizeMax(100*1024*1024);
fileUpload.setSizeThreshold(1024*50);

List items = fileUpload.parseRequest(request);

 

Iterator iterator = items.iterator();
while (iterator.hasNext()) {


FileItem item = (FileItem) iterator.next();

if (!item.isFormField()) {
if (fileItem.getSize() > 0) {
//파일 이름을 가져온다
String filename = fileItem.getName().substring(fileItem.getName().lastIndexOf("")+1);

try {
File file = new File(upload+filename);
fileItem.write (file);
} catch (IOException e) {
System.out.println(e);
}
}
}
}
}

} catch (org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException e) {

// 파일 사이즈 초과시 발생하는 익셉션
System.out.println("파일 사이즈가 100메가 보다 더 초과되었습니다");
} catch (Exception e) {
System.out.println("업로드시 예기치 못한 오류가 발생하였습니다");
}
}
}

 

==============================================================================================================
    /**
     * form tag의 input name들이 아래와 같이 있습니다.
     */
    String sMode = "";
    
    String sPageNo = "";
    String sKeyWord = "";
    String sSearchPart = "";
    String sSeqNum = "";
    
    String sAnsTitle = "";
    String sAnsContent = "";
    
    String sFileName = "";
    String sTmpFileName = "";

 

    try {

      //Multipart로 넘어왔는가?
      if (FileUpload.isMultipartContent(req)) {
        
        DiskFileUpload dfuUpload = new DiskFileUpload();
        
        /**
         * 이 부분 상당히 애를 먹었습니다.
         * Windows 환경에서는 문제가 없는데,
         * 개발 서버(Linux)로 올리게 되면 계속해서 한글이 깨지더군요.
         *
         * 그래서, 아래와 같이 DiskFileUpload의 HearderEncoding을 해주었습니다.
         */
        dfuUpload.setHeaderEncoding("EUC_KR");
        
        List lsItems = dfuUpload.parseRequest(req);
        Iterator iterator = lsItems.iterator();
        

        while (iterator.hasNext()) {

          FileItem fItem = (FileItem) iterator.next();
          
          /**
           * 넘어오는 form이 multipart일때도 있고 아닐 경우도 있어서
           * 처리한 부분입니다.
           *
           * HashMap을 사용해서 put한 다음에, 필요할때 꺼내 써도 무방할듯 합니다.
           */
          if ("mode".equals(fItem.getFieldName())) {
            sMode = fItem.getString();
          } else if ("pageNo".equals(fItem.getFieldName())) {
            sPageNo = fItem.getString();
          } else if ("keyWord".equals(fItem.getFieldName())) {
            //한글처리
            sKeyWord = fItem.getString("EUC_KR");
          } else if ("searchPart".equals(fItem.getFieldName())) {
            sSearchPart = fItem.getString();
          } else if ("seqNum".equals(fItem.getFieldName())) {
            sSeqNum = fItem.getString();
          } else if ("ansTitle".equals(fItem.getFieldName())) {
            //한글처리
            sAnsTitle = fItem.getString("EUC_KR");
          } else if ("ansContent".equals(fItem.getFieldName())) {
            //한글처리
            sAnsContent = fItem.getString("EUC_KR");
          }

          //파일 타입 폼필드라면
          if (!fItem.isFormField()) {

            if (fItem.getSize() > 0) {
              //파일 이름을 가져온다
              //- 위에서 dfuUpload.setHeaderEncoding("EUC_KR")를 안해 줬더니

              //  파일이름이 자꾸 깨지더군요.
              sFileName = fItem.getName().substring(fItem.getName().lastIndexOf("\") + 1);

              try {
                /**
                 * upload변수는 servlet에서 init 할때 아래와 같이 선언해 주었습니다.
                 * upload = config.getServletContext().getRealPath("/upload/suggest/");
                 */
                File file = new File(upload + sFileName);
                fItem.write(file);
              } catch (IOException e) {
                System.out.println(e);
              }
            }
          }

        }

      } else {
        //multipart가 아닐때 사용되는 parameter들을 가지고 옴

        //WebUtil은 null Check를 위한 util입니다. - 빼도 상관없습니다.
        sMode = WebUtil.nvl((String) req.getParameter("mode"), "");
        sPageNo = WebUtil.nvl((String) req.getParameter("pageNo"), "");
        sKeyWord = WebUtil.nvl((String) req.getParameter("keyWord"), "");
        sSearchPart = WebUtil.nvl((String) req.getParameter("searchPart"), "");
        sSeqNum = WebUtil.nvl((String) req.getParameter("seqNum"), "");
        sAnsTitle = WebUtil.nvl((String) req.getParameter("ansTitle"), "");
        sAnsContent = WebUtil.nvl((String) req.getParameter("ansContent"), "");

      }
    } catch (Exception e) {
      LogManager.getLogger("error").error(e.toString());
    }

'프로그래밍 > java' 카테고리의 다른 글

jxl 수정  (0) 2009.06.10
POI  (0) 2009.06.10
문자열 자르기 ( substring )  (0) 2009.06.10
자바로 날짜 조작  (0) 2009.06.10
세션값 받아오기  (0) 2009.06.10