01.JAVA/Java2008. 7. 7. 17:21
반응형
★ MultipartRequest를 이용하여 업로드구현하기

Last Modified 2002/05/26
Written by hsboy
ReadCount 2250


* 강좌를 시작하기전에....

- 기존의 jspSmartUpload를 대체해 가고 있는 MultipartRequest에 대한 간단한 사용법에 대해 강의 합니다.
JSP만을 사용하는 강좌이며 Beans, Servlet은 다루지 않습니다.

- MultipartRequest는 COS 패키지에 포함되어 있는 파일 업로드 컴포넌트 입니다.

- COS 에서는 한글등(non-Latin-1)의 언어를 지원하지 않았었습니다. 그러한 이유로 이아스(이창신)님 께서 배포한 COSI(COS International) 를 주로 사용 하였으나, 이아스님의 노력에 힘입어 2002년 5월 9일 자 COS에서는 한글을 포함한 non-Latin-1 계열의 언어를 지원하게 되었습니다. 근 2년간의 국제화를 위한 투쟁이 비로서 결실을 맺는 순간이었습니다.
이에 따라 본 강좌의 내용도 COS 맞추어 약간의 수정을 했습니다.

COS 공식 사이트 : http://www.servlets.com/cos/index.html


* MultipartRequest는....

필자는 기존에 jspSmartUpload를 주로 사용하여 업로드를 구현했었다. 하지만 jspSmartUpload는 로직자체에 상당한 문제점(업로드된 파일을 메모리에 올리고 작업하여 그로인해 파생되는 문제점들)이 있음이 밝혀 졌고, 그로인해 jspSmartUpload의 사용은 급속히 줄어 들었다.

사실 jspSmartUpload에서는 편리한 많은 메소드를 지원해주고 있어 MultipartRequest를 사용하는것 보다 훨씬 쉽게 원하는 기능을 구현 할수 있는 것이 사실이다. 하지만 jspSmartUpload는 문제점이 발견 되었으므로 가능한사용을 자제하는 것이 좋겠다.

MultipartRequest는 아주 간단한 메소드를 몇개 지원한다. 하지만 이 메소드들 만으로도 왠만한 기능은 전부 구현이 가능하니 실망하지 말자. getFile() 메소드를 이용하면 java.io.File 객체를 얻어 낼수 있으니 이를 이용하면 될것이다.


* 설치하기

MultipartRequest는 oreilly에서 배포하며, http://www.servlets.com/cos/index.html에서 다운로드 받아도 되고, 필자의 홈페이지(http://aboutjsp.com)의 자료실에도 업로드를 해놓았으니 다운받아 사용해 보기 바란다.

설치 하는 방법은 다운로드 받아서 압축을 푼뒤, classes 디렉토리 아래를 톰캣의 classes 디렉토리에 통째로 복사한다. (예.ROOT/WEB-INF/classes) 혹은 cos.jar를 lib에 복사해도 된다.

COS 패키지기에는 MultipartRequest 말고도 유용한 많은 클래스들이 많이 존재하므로, 여기의 API문서를 참고하여 사용하기 바란다


* 업로드 구현

간단한 예제를 통해서 알아 보도록 하자.

wirte.htm
<html> <body> <form action="up.jsp" enctype="multipart/form-data" method="post"> 이름 : <input type="text" name="userName"> <br /> 파일 : <input type="file" name="upfile"> <input type="submit" value="Upload"> </form> <div style="margin:0; padding:0; border:none; background:none; float:none; clear:none; z-index:0"></div> <script type="text/javascript" src="https://tistory1.daumcdn.net/tistory_admin/userblog/userblog-9f215d513ac1c1fc530f1b625c346be762e46741/static/script/common.js"></script> <script type="text/javascript">window.roosevelt_params_queue = window.roosevelt_params_queue || [{channel_id: 'dk', channel_label: '{tistory}'}]</script> <script type="text/javascript" src="//t1.daumcdn.net/midas/rt/dk_bt/roosevelt_dk_bt.js" async="async"></script> <script>window.tiara = {"svcDomain":"user.tistory.com","section":"글뷰","trackPage":"글뷰_보기","page":"글뷰","key":"218144-24","customProps":{"userId":"0","blogId":"218144","entryId":"24","role":"guest","trackPage":"글뷰_보기","filterTarget":false},"entry":{"entryId":"24","entryTitle":"MultipartRequest를 이용하여 업로드구현하기","entryType":"POST","categoryName":"01.JAVA/Java","categoryId":"134516","serviceCategoryName":null,"serviceCategoryId":null,"author":"216141","authorNickname":"1010","blogNmae":"개발자(開發者) a developer","image":"","plink":"/24","tags":[]},"kakaoAppKey":"3e6ddd834b023f24221217e370daed18","appUserId":"null"}</script> <script type="module" src="https://t1.daumcdn.net/tistory_admin/frontend/tiara/v1.0.5/index.js"></script> <script src="https://t1.daumcdn.net/tistory_admin/frontend/tiara/v1.0.5/polyfills-legacy.js" nomodule="true" defer="true"></script> <script src="https://t1.daumcdn.net/tistory_admin/frontend/tiara/v1.0.5/index-legacy.js" nomodule="true" defer="true"></script> </body> </html>

up.jsp
<%@ page contentType="text/html;charset=euc-kr" 
%><%@ page import="com.oreilly.servlet.MultipartRequest,
                   com.oreilly.servlet.multipart.DefaultFileRenamePolicy,
                   java.util.*" 
%><%
 String savePath="/usr/local/tomcat/webapps/ROOT/test/upload"; // 저장할 디렉토리 (절대경로)

 int sizeLimit = 5 * 1024 * 1024 ; // 5메가까지 제한 넘어서면 예외발생

 try{

	MultipartRequest multi=new MultipartRequest(request, savePath, sizeLimit, new DefaultFileRenamePolicy());
 	Enumeration formNames=multi.getFileNames();  // 폼의 이름 반환
	String formName=(String)formNames.nextElement(); // 자료가 많을 경우엔 while 문을 사용
	String fileName=multi.getFilesystemName(formName); // 파일의 이름 얻기

	if(fileName == null) {   // 파일이 업로드 되지 않았을때
		out.print("파일 업로드 되지 않았음");
	} else {  // 파일이 업로드 되었을때
		fileName=new String(fileName.getBytes("8859_1"),"euc-kr"); // 한글인코딩 - 브라우져에 출력
		out.print("User Name : " + multi.getParameter("userName") + "<BR>");
		out.print("Form Name : " + formName + "<BR>");
		out.print("File Name  : " + fileName);
	} // end if

 } catch(Exception e) {
	out.print("예외 상황 발생..! ");
 } 
%>
				

위의 예제 소스를 보면 대부분이 이해가 잘 갈것이라 생각되지만.. 하나씩 살펴 보도록 하겠다. 우선 write.htm 에서는 폼에서 method="post" 형식으로 해야 하며 ecntype="multipart/form-data" 를 꼭 붙여 주어야 한다.

다음으로 up.jsp를 하나 하나 살펴 보자. MultipartRequest 클래스를 import 하고, java.util.* 는Enumeration 객체를 사용하기 위해서 import 한다..

savePath 는 저장될 실제 디렉토리(시스템상의 절대 경로)를 적으면 된다. sizeLimit 에서는 제한 용량을 셋팅하는데, 위와같은방법으로 메가바이트 단위로 지정할 수 있다.

그 다음줄에서는 MultipartRequest 객체가 생성됨과 동시에 업로드가 이루어져 지정한 디렉토리에 저장된다. 이때 MultipartRequest의 여러 생성자들중 하나를 이용하면 되는데, 기존에는 새성자로 한글 "euc-kr"을 줬어야 했는데, 어쩐일인지 이제는 주지 않아아 한글 이름의 파일이 잘 저장되느는 것을 볼수 있다. 또한 가장 오른쪽의 'new DefaultFileRenamePolicy' 는 는 파일 이름 중복처리에 관한 것으로 넣을수도 있고, 뺄수도 있다. 필요하지 않다고 생각된다면 빼버리도록 하자.

그아래에 if 문을 보면, 파일이 업로드 되었을때와 업로드 되지 않았을때의 처리를 나누어서 할수 있도록 하고 있다.

if 문 위의 3라인은 파일의 이름을 얻기위한 로직으로 Enumeration 객체로 받은 폼의 이름을 이용하고 있다. 만약 폼이 여러개가 있을 경우엔 적절한 자료형을 이용하여 폼의 이름을 통해서 파일의 이름들을 얻어 낼수 있을 것이다. 만약 파일 업로드를 Beans로 구현할 경우엔 반드시 이러한 로직을(Enumeration 객체를 이용한 loop구문)사용해야 할 것이다.

사실 위의 예제에서는 굳이 Enumerration 객체를 가지고 구현할 필요는 없지만, 해당 메소드의 사용법을 보여주기 위해서 사용하였다. 이러한 방법을 사용하지 않을 경우에는 if 위에 3라인을 삭제하고 아래의 내용을 추가 하면다.

String fileName=multi.getFilesystemName("upfile");


* FileRenamePolicy 에 관해서...

이번 버젼의 MultipartRequest 에서 부터는 파일 중복처리 인터페이스가 추가 되었고, 위의 예제 소스는 그러한 내용이 반영되어있다. DefaultFileRenamePolicy는 FileRenamePolicy Interface 를 구현한 것으로, 중복된 파일 이름뒤에 숫자를 붙여 주고 있다. ( abcd.zip , abcd1.zip, abcd2.zip, abcd3.zip ....... )

DefaultFileRenamePolicy Class를 바탕으로 새로운 RenamePolicy class 를 만들면 자신이 원하는 FileRenamePolicy 를 적용할수 있다.

또한 getFilesystemName()메소드를 이용하여 변경된 파일 이름을 얻을수 있고, getOriginalFileName()메소드는 변경되기 이전의 파일이름을 넘겨준다.


* multi.getParameter()

write.htm 에서 서정한바와 같이 enctype="multipart/form-data" 로 지정하면, request.getParameter()로는 아무러 값도 받아 올수가 없게된다. 그러한 이유로 대부분의 파일업로드 컴포넌트에서는 getParameter() 메소드를 지원하는데, MultipartRequest에서도 이러한 메소드를 지원한다. 지원하는 메소드는 아래와 같으며, 사용법은 request.getParameter() 등과 동일하다.

String getParameter(String name)
Enumeration getParameterNames()
String[] getParameterValues(String name)


* 한글관련 문제 처리법

MultipartRequest multi=new MultipartRequest(request, savePath, sizeLimit, new DefaultFileRenamePolicy());

위를 아래와 같이 수정한다.

MultipartRequest multi=new MultipartRequest(request, savePath, sizeLimit, "euc-kr", new DefaultFileRenamePolicy());

"euc-kr" 부분엔 "ksc5601", "ms949" 등 자신의 환경에 알맞는 캐릭터셋을 넣어 주면 된다.

각 메소드들에 대한 자세한 사용법은 아래의 API문서를 참고 하기 바란다.

http://aboutjsp.com/docs/cos/



* 관련사이트
http://www.servlets.com/cos/
   COS 공식 사이트

저자 : 이선재(hsboy)
http://www.aboutjsp.com
다른곳에 올리실 때는 반드시 출처를 명시해 주시기 바라며 되도록 이면 링크를 걸어 주시기 바랍니다.

Posted by 1010