본문 바로가기

Java

웹에서 파일 업로드 구현하기 -1

웹에서 파일 업로드 구현-1 (jsp)



1. 환경설정

http://www.servlets.com/cos 에 접속한다.



위 그림 위치로 가서 .zip 파일을 다운받고 압축을 풀자.

(혹시 몰라 파일첨부)
lib폴더에 가면 cos.jar 파일이 있다. 편한 위치로 옮겨도 되고 그대로 써도 무방하다.



이 jar파일을 카피한 후 

( 프로젝트 - WebContent - WEB-INF - lib ) 아래의 사진 위치에 붙여넣기한다.




그리고 데이터베이스 연동(오라클 사용)을 위한 ojdbc6.jar 와 
jstl문 사용을 위한 jstl.jar & standard.jar 총 3개를 추가로 넣어준다.

ojbc6.jar의 기본경로는 C:\oraclexe\app\oracle\product\11.2.0\server\jdbc\lib 이다.

(역시 귀찮은 분들을 위한 파일첨부)
jstl문을 위한 jar파일은 자바 JSTL 포스팅 업로드되어 있음.



2. 파일업로드 구축


파일업로드는 아래 사진과 같은 과정으로 이루어진다.


하나씩 단계별로 밟아갈 예정이다.




먼저 다음과 같은 간단한 폼을 위해 아래 html 코드를 추가한다.


Upload.html
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
<fieldset>
     <legend>파일 업로드</legend>
     <table>
     <form action="UploadService">
          <tr>
              <td>글쓴이 : </td>
              <td><input type="text" name="author"/></td>
          </tr>
          <tr>
              <td>제목 : </td>
              <td><input type="text" name="title"/></td>
          </tr>
          <tr>
              <td>글쓴이 : </td>
              <td><input type="file" value="파일 선택" name="file"/></td>
          </tr>
          <tr>
              <td colspan="2"><input type="submit" value="업로드"/></td>
          </tr>
          </form>
     </table>
</fieldset>

</body>
</html>



UploadService.java 서블릿을 만들어 값이 잘 들어오는지 확인한다.




UploadService.java
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/UploadService")
public class UploadService extends HttpServlet {
     protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          String fileName = request.getParameter("file");
          System.out.println(fileName);
     
     }
}


토대.hwp

벌써 전송이 되었다고 생각할 수 있겠지만 파일을 전송하기 위해서는 GET방식이 아닌 POST방식으로 보내야  한다. Form태그에 method를 지정하지 않으면 기본 GET방식으로 설정되기 때문에 현재는 사실 파일이 업로드된 것이 아니고 토대.hwp 라는 텍스트만 전달된 것이다.

또 method="post"라고 전송방식만 바꿔준다고 해서 파일을 받아낼 수 있는 것은 아니다. 서버에 내가 파일을 보낼 것이라고 알려주기 위해 enctype 옵션에 'multipart/form-data'라고 선언해준다.

Upload.html의 <Form>태그를 다음과 같이 수정:
<form action="UploadService" method="post" enctype="multipart/form-data">

수정한 후 다시 한번 파일을 업로드하고 전송해봤을때 


와 같이 null값이 뜨게 되면 잘 된 것이다.



그럼 실제로 서블릿에서 파일을 받아내기 위해서 아래 클래스의 메소드가 필요하다.

MultipartRequest 클래스의 메소드
메소드
설명
getParameterNames()
Form에서 전송된 Parameter 이름을 Enumeration 타입으로 반환
getParameterValues()
Form에서 전송된 Parameter들을 배열로 반환
getParameter()
From에서 전송된 Parameter 반환
getFileNames()
파일을 여러 개 업로드 할 경우 Enumeration 타입으로 반환
getFilesystemName()
서버에 실제 업로드 된 파일 이름
getOriginFileName()
클라이언트가 업로드한 파일 원본 이름
getContentType()
업로드 파일의 ContentType 반환
getFile()
서버에 업로드 된 파일의 정보를 객체로 반환





UploadService.java 서블릿에 아래 MultipartRequest 객체를 생성한다.
밑의 표는 파라미터에 관한 설명이다.

MultipartRequest multi = new MultipartRequest(request, saveDir, maxSize, encoding, new DefaultFileRenamePolicy());
매개변수
설명
request
MultipartRequest와 연결한 request 객체
saveDirectory
서버 측에 저장될 경로
maxPostSize
파일의 최대 크기 (Bytes단위) ex) 3MB = 3 * 1024 * 1024
encoding
파일의 인코딩 방식(파일명이 한글일 경우)
new DefaultFileRenamePolicy()
업로드 될 파일명이 중복될 경우 덮어쓰기를 방지하기 위한 객체


SerVletContext 인터페이스에 getServletContext() 메소드를 사용하면 현재 실행되는 어플리케이션에 대한 정보를 가져올 수 있다.
이 안에 들어있는 정보 중 우리가 필요한 경로를 구하기 위해 .getRealPath()를 이용하여 변수에 담아준다.

WebContent 안에 파일을 저장할 폴더를 만든 후 getRealPath()의 파라미터로 폴더이름을 주면 된다.

UploadService.java
ServletContext context = getServletContext(); //어플리케이션에 대한 정보를 ServletContext 객체가 갖게 됨. 
String saveDir = context.getRealPath("Upload"); //절대경로를 가져옴
System.out.println("절대경로 >> " + saveDir);

Upload.html 을 실행시켜 파일을 업로드해보면 
다음같은 경로가 나오게 된다.
절대경로 >> C:\Users\pc-20\Dropbox\JSP\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\FileUpload\Upload


위 경로를 탐색기로 실행하면 아래와 같이 메타데이터 안으로 들어가게 된다.




파일 max크기 설정. byte 단위로 설정되므로 계산을 통해 사용한다.
int maxsize = 3*1024*1024; // 3MB

인코딩 설정. 한글을 받기 위해 euc-kr로 설정한다.
String encoding = "euc-kr";



설정을 마치고 실제로 파일을 업로드해보면 아까 getRealPath()로 가져온 경로의 폴더에



파일이 업로드되어있음을 확인할 수 있고

같은 파일을 2번 업로드하면 숫자도 잘 붙음을 확인할 수 있다.



우리가 만든 Upload 폴더에는 실제로 파일이 들어있지 않아 헷갈리겠지만, 
이미지 파일을 올리고 img태그로 확인해보면

test.html
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
<img src="Upload/images.jpg">
</body>
</html>


실제 Upload 파일에 들어있지 않지만 출력이 잘 됨을 확인할 수 있다.


그럼 이제 DB에 실제로 사용자가 입력한 정보와 파일정보를 업로드하기 위해

(이 과정)



DB에서 실제로 테이블을 만들고
create table fileboard(
      num number,
      author varchar(30),
      title varchar(30),
      fileName varchar(50),
      day varchar(30)
);

순차적으로 증가하는 num을 위한 시퀀스 생성
//시퀀스 생성
create sequence file_num
start with 1
increment by 1;

테스트를 위해 SQL문으로 실제 삽입
insert into fileboard values(1, '도스토예프스키', '죄와 벌', 'file1', to_char(sysdate,'YYYY-MM-DD'));



(이클립스에서 SQL문 사용하는 Data Source Explorer는 포스팅(링크) 참고)


DB구축이 끝났으면 연동을 위한 DAO클래스를 만들고 실제로 DB와 연동한다.(코드생략)

FileDAO.java
package com.Model;
public class FileDAO {
      //DB연결
      public void getConnection() {}
    
      //DB연결 종료
      public void close() {}      

      //파일업로드
      public int uploadFile(String author, String title, String file) {
            return 0;
      }
}



ServletFileUploadisMultipartContent(request)를 사용하면 boolean 타입으로 넘어오는 Form태그의 전송방식을 확인할 수 있는데
boolean isMulti = ServletFileUpload.isMultipartContent(request);//boolean타입. ??????
            if(isMulti) {
                  System.out.println("파일전송 Form입니다");
            }else {
                  System.out.println("일반전송 Form입니다");
            }

파일전송 Form입니다


위의 if-else 안에 FileDAO에 만들었던 insert SQL문을 실행하는 uploadFile()메소드를 UploadService 서블릿에 추가한다.

UploadService.java
boolean isMulti = ServletFileUpload.isMultipartContent(request);// boolean타입. ??????
if (isMulti) {
    MultipartRequest multi = new MultipartRequest(request, saveDir, maxSize, encodingnew DefaultFileRenamePolicy());
    FileDAO dao = new FileDAO();
    String author = multi.getParameter("author");
    String title = multi.getParameter("title");
    String file = multi.getFilesystemName("file");
    try {
        int result = dao.uploadFile(author, title, file);
        if (result > 0) {
            System.out.println("저장완료");
        } else {
            System.out.println("저장실패");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
} else {
    System.out.println("일반 전송 Form입니다");
}


이제 Upload.html을 통해 파일을 업로드해보면 


console에 저장완료가 뜨고 DB에 저장이 된 것을 확인할 수 있다.

이제 성공적으로 저장된 경우 SelectService.java로 이동하여 리스트를 검색하도록 할 것이다.
UploadService 서블릿에 아래 코드를 추가한다.

UploadService.java
boolean isMulti = ServletFileUpload.isMultipartContent(request);// boolean타입. ??????
            if (isMulti) {
                  MultipartRequest multi = new MultipartRequest(request, saveDir, maxSize, encoding,
                              new DefaultFileRenamePolicy());
                  FileDAO dao = new FileDAO();
                  String author = multi.getParameter("author");
                  String title = multi.getParameter("title");
                  String file = multi.getFilesystemName("file");
                  try {
                        int result = dao.uploadFile(author, title, file);
                        String moveUrl = "";
                        if (result > 0) {
                              System.out.println("저장완료");
                              moveUrl = "selectService";
                        } else {
                              System.out.println("저장실패");
                              moveUrl = "Upload.html";
                        }
                        response.sendRedirect(moveUrl);
                  } catch (Exception e) {
                        e.printStackTrace();
                  }
            } else {
                  System.out.println("일반 전송 form 입니다.");
            }



업로드가 성공하면 SelectService.java 서블릿으로 이동하게 되게 설정하였는데 아직 존재하지 않는 서블릿이므로 실제로 서블릿파일을 만든다.
이 SelectService.java는 DB에 저장된 file정보를 모두 검색해서 jsp로 전송하는 역할을 맡게 될 것이다. 

SelectService.java
package com.Service;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.Model.FileDAO;
@WebServlet("/selectService")
public class selectService extends HttpServlet {
      protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //DB에 저장된 file정보를 모두 검색해서 jsp로 전송
            FileDAO dao = new FileDAO();
            
            //여러개니까 List로
            ArrayList<FileVO> list = dao.selectAll();      
      
      }
}


FileVO와 FileDAO에 없는 selectAll 메소드에서 에러가 날 것이다.
먼저 ArrayList 제네릭에 들어가는 File정보를 받아줄 객체를 만들기 위한 클래스 FileVO.java를 만든다.
필드는 DB의 컬럼과 같다. 생성자와 getter메소드도 만든다.

FileVO.java
package com.Model;
public class FileVO {
      private int num;
      private String author;
      private String title;
      private String file;
      private String day;
      
      public FileVO(int num, String author, String title, String file, String day) {
            this.num = num;
            this.author = author;
            this.title = title;
            this.file = file;
            this.day = day;
      }
      public int getNum() {
            return num;
      }
      public String getAuthor() {
            return author;
      }
      public String getTitle() {
            return title;
      }
      public String getFile() {
            return file;
      }
      public String getDay() {
            return day;
      }   
}


FileDAO 클래스에 DB에 접속해 모든 정보를 읽어오는 selectAll()메소드를 만든다.
public ArrayList<FileVO> selectAll() {
    //코드생략
    return new ArrayList<FileVO>();
}


DB를 읽어오는 메소드가 완성되었으면 SelectService.java 서블릿으로 돌아와 다음과 같이 코드를 추가한다.

SelectService.java
package com.Service;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.Model.FileDAO;
import com.Model.FileVO;
@WebServlet("/selectService")
public class selectService extends HttpServlet {
      protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //DB에 저장된 file정보를 모두 검색해서 jsp로 전송
            FileDAO dao = new FileDAO();
            
            try{
                  ArrayList<FileVO> list = dao.selectAll();
                  
                  if(list!=null) {
                        request.setAttribute("list", list);
                                             
                  }else {
                        System.out.println("비었습니다");
                  }
                  
                  RequestDispatcher dis = request.getRequestDispatcher("Board.jsp");
                  dis.forward(request, response);
                  
            }catch(Exception e) {
                  e.printStackTrace();
            }
      
      }
}


forward 방식으로 성공시 Board.jsp로 request, response 정보를 가지고 이동하게 되어 있다.
간단한 테스트를 위해 jsp페이지를 만들고 전송성공이라는 문구를 넣었다. 

Board.jsp
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!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=EUC-KR">
<title>Insert title here</title>
</head>
<body>
 전송성공
</body>
</html>


이제 Upload.html에서 다시 한번 파일을 업로드해본다.

DB에도 잘 올라가고



전송을 성공했으니 request, response 정보를 가지고 Board.jsp로 잘 넘어간 것을 확인할 수 있다.

(다음 포스팅에 계속)