[필독][기초] / 서블릿 / servlet [part 8]

2016.01.05 15:01language/jsp

파일 업로드


MultipartRequest
MultipartRequest 팩키지는 파일 업로드에 널리 이용되고 있는 팩키지이다.
http://www.servlets.com/cos/index.html 에서 가장 최신 버전인 cos-26Dec2008.zip 를 다운로드 하여 압축을 푼 후 서브 디렉토리 lib 에 있는 cos.jar 파일을 /WEB-INF/lib 디렉토리에 복사한다.


MultipartRequest 클래스의 생성자는 아래 링크에서 확인할 수 있듯이 8개가 있다.
http://www.servlets.com/cos/javadoc/com/oreilly/servlet/MultipartRequest.html
그 중 아래의 생성자는 한글 인코딩 문제를 해결할 수 있고 업로드하는 파일이 중복될 때 파일명을 변경해서 업로드한다. 예제에서는 이 생성자를 이용한다.


public MultipartRequest(
          HttpServletRequest request,
          String saveDirectory,
          int maxPostSize,
          String encoding,
          FileRenamePolicy policy) throws IOException


MultipartRequest 메소드
MultipartRequest 객체가 성공적으로 생성되었다면 이미 업로드는 성공한 것이다.
아래 메소드는 서버의 파일 시스템에 파일을 업로드 된 후 이용하는 MultipartRequest 멤버 메소드를 소개하고 있다.
 <input type="file" name="photo"/>를 이용해서 logo.gif 를 업로드했다고 가정하에 설명한다.


메소드와 설명

getContentType("photo");

          업로드된 파일의 MIME 타입 리턴, 예를 들어 확장자가 gif 이미지라면 "image/gif" 가 반환
getFile("photo");

          업로드되어 서버에 저장된 파일의 File 객체 리턴
getFileNames();

          폼 요소 중 input 태그 속성이 file 로 된 파라미터의 이름을 Enumeration 타입으로 리턴
getFilesystemName("photo");

          업로드되어 서버 파일시스템에 존재하는 실제 파일명을 리턴
getOriginalFileName("photo");

          원래의 파일명을 리턴


HttpServletRequest 구현체와 같은 인터페이스를 제공하기 위한 메소드
getParameter(String name);

          name 에 해당하는 파라미터의 값을 String 타입으로 리턴
getParameterNames();

          모든 파라미터의 이름을 String 으로 구성된 Enumeration 타입으로 리턴
getParameterValues(String name);

          name 에 해당하는 파라미터의 값들을 String[] 타입으로 리턴



MultipartRequest 예제
사용자로 부터 업로드 파일을 선택하도록 유도하는 페이지를 ROOT 애플리케이션의 최상위 디렉토리의 서브 디렉토리 example 에 작성한다.


/example/MultipartRequest.html


<!DOCTYPE html
     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
   <title>MultipartRequest 서블릿 예제</title>
   <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
</head>
<body>
<h2>MultipartRequest 를 이용한 파일 업로드 테스트</h2>
<form action="../servlet/UploadTest" method="post" enctype="multipart/form-data">
  <p>
    이름 : <input type="text" name="name" /><br />
    파일1 : <input type="file" name="file1" /><br />
    파일2 : <input type="file" name="file2" /><br />
  <input type="submit" value="전송" />
  </p> 
</form>
</body></html>


업로드를 실행할 서블릿을 아래와 같이 작성하고 컴파일한다.
컴파일 할 때에 자바 컴파일러는 cos.jar 파일에 대한 경로를 알아야 한다.


UploadTest.java


package example;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.oreilly.servlet.MultipartRequest;
import com.oreilly.servlet.multipart.DefaultFileRenamePolicy;

public class UploadTest extends HttpServlet {
         
          @Override         
          public void doPost(HttpServletRequest req, HttpServletResponse resp)
                              throws IOException, ServletException {
                             
                    resp.setContentType("text/html; charset=UTF-8");
                    PrintWriter out = resp.getWriter();
                   
                    ServletContext cxt = getServletContext();
                    String dir = cxt.getRealPath("/upload");
                   
                    try {
                              MultipartRequest multi =
                                        new MultipartRequest(
                                                  req,
                                                  dir,
                                                  5*1024*1024,
                                                  "UTF-8",
                                                  new DefaultFileRenamePolicy());
                                                 
                              out.println("<html>");
                              out.println("<body>");
                              out.println("<h1>사용자가 전달한 파라미터들</h1>");
                              out.println("<ol>");
                              Enumeration<?> params = multi.getParameterNames();
                             
                              while (params.hasMoreElements()) {
                                        String name = (String) params.nextElement();
                                        String value = multi.getParameter(name);
                                        out.println("<li>" + name + "=" + value + "</li>");
                              }
                             
                              out.println("</ol>");
                              out.println("<h1>업로드된 파일</h1>");
                             
                             
                              Enumeration<?> files = multi.getFileNames();
                             
                              while (files.hasMoreElements()) {
                                        out.println("<ul>");
                                        String name = (String) files.nextElement();
                                        String filename = multi.getFilesystemName(name);
                                        String orginalname =multi.getOriginalFileName(name);
                                        String type = multi.getContentType(name);
                                        File f = multi.getFile(name);
                                        out.println("<li>파라미터 이름 : "  + name + "</li>");
                                        out.println("<li>파일 이름 : " + filename + "</li>");
                                        out.println("<li>원래 파일 이름 : " + orginalname + "</li>");
                                        out.println("<li>파일 타입 : " + type + "</li>");
                                       
                                        if (f != null) {
                                                  out.println("<li>크기: " + f.length() + "</li>");
                                        }
                                        out.println("</ul>");
                              }
                    } catch(Exception e) {
                              out.println("<ul>");
                              e.printStackTrace(out);
                              out.println("</ul>");
                    }
                    out.println("</body></html>");
          }
}


다음으로 web.xml 파일을 열고 작성한 서블릿을 등록하고 매핑한다.


web.xml


<servlet>
    <servlet-name>UploadTest</servlet-name>
    <servlet-class>example.UploadTest</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>UploadTest</servlet-name>
    <url-pattern>/servlet/UploadTest</url-pattern>
</servlet-mapping>


예제를 실행하기 전에 ROOT 웹 애플리케이션의 최상위 디렉토리에 upload 라는 서브 디렉토리를 만든다.
톰캣을 재가동하고 http://localhost:8989/example/upload.html 를 방문하여 테스트한다.
중복된 파일을 업로드한 후 upload 폴더에서 파일명을 확인한다.
중복된 파일을 업로드하면 확장자를 제외한 파일이름의 끝에 숫자가 붙어서 업로드 되고 있음을 확인할 수 있다.
만약 테스트가 실패했다면 아래 리스트를 체크한다.

1.UploadTest 서블릿의 바이트 코드가 생성되어 있는지 확인한다.
2.ROOT 애플리케이션의 최상위 디렉토리에 upload 라는 서브 디렉토리가 있는지 확인한다.
3.톰캣 클래스로더가 찾을 수 있도록 cos.jar 파일이 /WEB-INF/lib 에 위치하는지 확인한다.
4.web.xml 파일에 UploadTest 서블릿이 제대로 등록되고 매핑되어 있는지 확인한다.
5.웹 애플리케이션이 로드되었는지 확인한다.


commons-fileupload
http://commons.apache.org/proper/commons-fileupload/download_fileupload.cgi
http://commons.apache.org/proper/commons-io/download_io.cgi
에서 최신 바이너리 파일을 다운로드 한 후
/WEB-INF/lib에 commons-fileupload-x.x.jar 와 commons-io-x.x.jar 를 위치시킨다.


/example/commons-fileupload.html


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
          "
http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>commons-fileupload 테스트</title>
</head>
<body>
<h1>파일 업로드 테스트</h1>
<form action="../CommonsUpload" method="post" enctype="multipart/form-data">
파일 : <input type="file" name="upload" /><br />
<input type="submit" value="전송" />
</form>
</body>
</html>

CommonsUpload.java 서블릿
package example;

import java.io.*;

import javax.servlet.*;
import javax.servlet.http.*;

import java.util.Iterator;
import java.io.File;
import java.util.List;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class CommonsUpload extends HttpServlet {

          @Override
          public void doPost(HttpServletRequest req, HttpServletResponse resp)
                              throws IOException, ServletException {
                             
                    resp.setContentType("text/html; charset=UTF-8");
                    PrintWriter out = resp.getWriter();
                    //Check that we have a file upload request
                    boolean isMultipart = ServletFileUpload.isMultipartContent(req);
                    //Create a factory for disk-based file items
                    DiskFileItemFactory factory = new DiskFileItemFactory();
                   
                    //Configure a repository (to ensure a secure temp location is used)
                    ServletContext servletContext = this.getServletConfig().getServletContext();
                    File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
                    factory.setRepository(repository);
                   
                    //Create a new file upload handler
                    ServletFileUpload upload = new ServletFileUpload(factory);
                    upload.setHeaderEncoding("UTF-8");//한글파일명 처리위해 추가
                    try {
                              //Parse the request
                              List<FileItem> items = upload.parseRequest(req);
                              //Process a file upload
                              Iterator<FileItem> iter = items.iterator();
                              while (iter.hasNext()) {
                                        FileItem item = iter.next();
                                        String fileName = null;
                                        if (!item.isFormField()) {
                                                  String fieldName = item.getFieldName();
                                                  out.println(fieldName);
                                                  fileName = item.getName();
                                                  out.println(fileName);
                                                  String contentType = item.getContentType();
                                                  out.println(contentType);
                                                  boolean isInMemory = item.isInMemory();
                                                  out.println(isInMemory);
                                                  long sizeInBytes = item.getSize();
                                                  out.println(sizeInBytes);
                                        }
                                        // Process a file upload
                                        ServletContext cxt = getServletContext();
                                        String dir = cxt.getRealPath("/upload");
                                        File uploadedFile = new File(dir + "/" + fileName);
                                        item.write(uploadedFile);
                              }
                    } catch (Exception e) {
                              out.println("<ul>");
                              e.printStackTrace(out);
                              out.println("</ul>");
                    }
                    out.println("<a href=\"example/commons-fileupload.html\">파일업로드폼으로</a>");
          }
}


web.xml 파일을 열고 작성한 서블릿을 등록하고 매핑한다.


web.xml


<servlet>
    <servlet-name>commonsUpload</servlet-name>
    <servlet-class>example.CommonsUpload</servlet-class>
</servlet>

<servlet-mapping>
          <servlet-name>commonsUpload</servlet-name>
          <url-pattern>/CommonsUpload</url-pattern>
</servlet-mapping>


톰캣을 재가동하고 http://localhost:8989/example/commons-fileupload.html를 방문하여 테스트한다.
중복된 파일을 업로드한 후 upload 폴더에서 파일명을 확인한다.
중복된 파일을 업로드하면 cos.jar와는 달리 기존 파일을 덮어쓴다는 것을 확인한다.
업로드된 파일을 확인하는 예제는 JSP에서 다룬다.

 

 

 

 

참고
http://docs.oracle.com/javaee/7/api/index.html?overview-summary.html
http://www.mkyong.com/servlet/a-simple-httpsessionlistener-example-active-sessions-counter/
http://commons.apache.org/proper/commons-fileupload/download_fileupload.cgi
http://commons.apache.org/proper/commons-io/download_io.cgi
http://commons.apache.org/proper/commons-fileupload/using.html
http://www.albumbang.com/board/board_view.jsp?board_name=free&no=292
http://www.docjar.com/docs/api/javax/servlet/GenericServlet.html
http://www.java-school.net/jsp/Servlet

 

 

도움이 되셨다면 공감을 부탁드립니다. ^^