GET/POST방식의 차이에 대해 자세히 알아보고, 파일업로드 방법에 대해 알아보자.
◆ form의 POST방식
▶ form의 method
request.getMethod()를 호출하게되면 form에서 보낸 메서드방식을 반환해준다.
form에서 method=”get” 또는 “post”의 형식으로 옵션을 설정할 수 있다.
- 메서드의 종류는 GET과 POST 가 있다.
▶ GET방식의 요청 파라미터
form의 메서드가 get방식인 데이터들의 전달은 주소창에서 쿼리스트링이라고 불리는 ?뒤에 붙은 값들을 인식해서 뽑아내는 방식이다.
( request.getQueryString()으로 뽑아낸 데이터들을 반환 )
▶ POST방식의 요청 파라미터
form의 메서드가 post방식인 데이터들은 서버 측과 연결된 OutputStream을 이용하여 뽑아내는 방식이다.
즉, post방식에서 주소창 ?뒤에 파라미터들은 의미가 없다.
( 따라서, request.getInputStream() 등을 통해 InputStream으로 데이터를 읽어 들이는 형식이다. )
위의 코드를 치게 되면 post방식으로 보낼 때는 출력이 되지만, get 방식으로 보낼 때는 확인할 수 없다.
( get방식은 getQueryString()으로 뽑아내기 때문에.. )
단, POST방식이라고 하여 굳이 위의 방식으로 데이터를 뽑아낼 필요는 없다. WAS에서 request.getParameter()메서드로도 POST방식의 데이터를 뽑아낼 수 있게 처리해 주기 때문이다.
▶ post 방식으로 getParameter()할 때, 한글을 보내게 되면 깨지게 된다.
post방식은 데이터를 뽑아내는 방식이 다르기 때문에 response가 아닌 reqeust의 문자인코딩 방식을 바꿔주어야 한다. POST방식의 디폴트 request캐릭터인코딩은 ISO-8859-1이기 때문에
request.setCharacterEncoding("utf-8"); 으로 해주면 된다.
( 단, getParameter() 하기 전에 해주어야 인식한다. )
◆ POST 방식을 쓰는 이유
GET 방식으로 보낼 수 있는 데이터는 한계가 있기 때문에 (1024byte정도? )
일정 수치 이상의 데이터를 보내게 되면 깨지게 된다. (게시물 작성 등..)
따라서 넘기는 데이터가 많을 경우 POST를 쓰거나, 또는 로그인 폼 등의 보안상의 문제가 있는 경우에는 POST를 쓰게 된다.
보통의 경우 DB에서 데이터를 불러오는 등의 작업을 하는 JSP페이지로 보낼 때는 GET방식으로 처리하고, 그 외의 경우엔 POST로 처리한다.
◆ Multipart
▶ POST 방식의 getParameter()
POST 방식에서 request.getParameter()메서드를 WAS에서 알아서 처리할 수 있도록 되어있는 이유는 form에서 method가 POST방식일 때는 디폴트값으로 enctype="application/x-www-form-urlencoded" 옵션이 설정 되어있기 때문에 이를 WAS에서 인식하고 알아서 in/output방식으로 데이터를 처리하기 때문이다.
-
따라서, POST방식에서는 enctype이 "application/x-www-form-urlencoded"방식이 아닌 경우, getParameter()로 데이터를 불러올 수 없다.
-
request.getHeader(“Content-Type”) 또는 request.getContentType() 를 통해서 enctype을 확인할 수 있다. 또한 이 값은 get방식의 경우는 null을 반환하게 된다. ( get방식에는 enctype이 없다. )
▶ 파일전송
form에서 파일 또는 이미지를 전송하기 위해서는 enctype이 “multipart/form-data”로 설정되어 있어야 한다. 따라서, request.getParameter()로 데이터를 불러올 수 없게 된다.
-
또한 enctype은 post방식에서만 존재하기 때문에 GET방식에서는 파일전송이 불가능하다.
-
- request.getContentType();
- enctype을 확인할 수 있다.
-
- request.getContentLength();
- 전송받은 모든 데이터의 길이를 byte크기(int형)로 반환한다
.
- 파일전송의 경우 getParameter()를 사용할 수 없기 때문에, request.getReader().readLine(); 등의 in/out풋 방식을 통해서 불러와야 한다.
또한, form에서 파일등 여러 가지 데이터를 가져올 때, getParameter()로 하나씩 뽑아오지 않기 때문에 데이터의 구분이 어렵다. 따라서 multipart요청을 처리 할 때는 보통 라이브러리로 처리한다.
◆ multipart 라이브러리 처리
multipart 파일처리를 하기 위해 사용되는 라이브러리는 크게 두 가지가 있다.
- apache에서 만든 commons file upload libary
- O’Reilly에서 만든 cos libary - www.servlets.com
◆ cos library
1. 라이브러리 추가
www.servlets.com 에서 다운로드 후 WEB-INF/lib 파일에 복사
2. MultipartRequest 객체를 생성
객체 생성 시 생성과 동시에 form을 통해 받아온 파일이 바로 세이브 디렉토리로 복사된다.(업로드)
▶ MultipartRequest객체의 생성자의 매개인자로는 2개짜리부터 5개짜리까지 있다.
- 1번째 인자로는 무조건 request객체를 받는다.
- 2번째 인자는 세이브디렉토리의 경로.
- 3번째 인자는 제한용량설정(int 형 (1024*1024*100 =>100mb )
- 4번째 인자는 문자인코딩 방식
-
5번째 인자는 리네임정책
- MultipartRequest객체의 기본 문자인코딩 방식으로는 한글파일명이 처리가 불가능하기 때문에 4번째 인코딩 방식을 “utf-8”로 설정해준다.
=> 5번째 인자인 리네임정책은 중복파일명을 어떻게 처리할 것인지에 대해 설정하는 것
◆ 업로드경로
파일의 업로드 경로를 지정해 줄 때 웹 경로가 아닌 실제 경로를 적어 주어야 한다.
실제 경로를 적는것이 번거롭기 때문에 request.getRealPath(“웹경로”)메서드를 이용하면 해당 웹 경로에 대한 실제 서버경로를 반환해 준다.
파일은 실제 경로로 저장되기 때문에 이클립스에서 생성한 업로드폴더에 업로드된 폴더가 생성되지 않고, 실제 경로에 들어가야 해당 파일을 확인할 수 있다.
단, 업르드된 파일을 <img>태그등으로 불러올 때는 웹 경로를 사용하여 적어도 WAS가 알아서 인식해준다.
◆ MultipartRequest객체 메서드
▶ 파일이 아닌 데이터 처리 메서드
enctype이 multipart일 때 request.getParameter()로 데이터를 뽑아낼 수 없지만,
MultipartRequest객체를 이용하면 똑같이 getParameter()메서드로 일반 데이터를 뽑아낼 수 있다.
따라서, mr.getParameter(“네임”) 을 하게 되면 똑같이 데이터를 뽑아낼 수 있다.
▶ 파일 관련 메서드
-
- mr.getContentType(“name”);
- 보낸 파일의 형태가 무엇인지를 반환 ( request.getcontentType과 다른 메서드 )
=> 이미지파일만 허용하는 등의 기능에서 사용 ex ) image/jpeg (jpg일 경우)
-
- mr.getOriginalFileName(“form에서 보낸 파일의 name”);
- form에서 선택한 원래 파일의 이름
-
- mr.getFilesystemName(“form에서 보낸 파일의 name”);
- 업로드된 파일의 이름( 리네임 되었을 시 리네임된 이름 )
-
- mr.getFile(“form에서 보낸 파일의 name”);
- 업로드한 파일의 객체를 반환 – File
-
- mr.getFileNames()
- 파일형태의 인풋데이터의 name속성을 Enumeration객체로 반환해준다.
따라서 for-each문으로 name을 뽑아낼 수 있다.
▶ 에러가 터지는 경우
- form의 enctype이 multipart/form-data가 아닐 때
- 세이브 디렉토리경로가 잘못되거나 없을 때
- 제한용량(10241024100byte - 1mb)보다 클 때
◆ Multipart의 리네임정책
리네임 정책은 같은 이름의 파일이 업로드 될 때 어떻게 처리할 지를 결정하는 MultipartRequest객체 생성자의 5번째 인자이다.
▶ 디폴트 리네임정책
디폴트 리네임정책은 파일이름에 증가하는 숫자를 계속 붙여나가는 형식으로,
“파일”이라는 이름의 똑같은 파일이 또 업로드 되었을경우 “파일2”로 업로드 시키는 형식이며
인자로 new DefaultFileRenamePolicy()를 적어주면 된다.
▶ 리네임정책 만들기
리네임 정책을 직접 만들기 위해서는 implements FileRenamePolicy를 구현하는 클래스를 만들어서 rename(File f)메서드를 오버라이드 하여 처리해야 한다.
=> rename(File f) 메서드에서 파일객체를 리턴하여 이 리턴된 파일객체로 실제 복사될 파일이 만들어진다.
이런 식으로 인터페이스를 구현하고,5번째 인자로 TestPolicy객체를 생성하여 보내면 된다.
ex ) new MultipartRequest(reuqest,saveDir, …… , new TestPolicy(“파일명”));
▶ 파일 DB처리
업로드된 파일을 DB에 저장할 때 실제 파일을 저장하는 것이 아닌, 파일이 저장된 경로와 파일의 이름을 저장한다. 따라서 파일을 DB에서 불러온다는 것은 경로와 파일명의 정보를 불러오는 것이다.
◆ 파일이 여러 개일 때, 멀티파트 처리
=> 파일이 여러 개 일 때는 MultipartRequest객체로 처리할 수 없고, MultipartParser객체를 이용하여 처리해야 한다.
- 객체생성 : MultipartParser parser = new MultiParser(request, size);
- 파일 인코딩 : parser.setEncoding(“utf-8”)
- 폼으로 넘겨받은 인자를 하나씩 반환 : Part객체 = parser.readNextPart();
- Part객체는 파일일 경우 FilePart객체로 캐스팅, 파일이 아닌 파라미터의 경우 ParamPart객체로 캐스팅
- (FilePart)part.writeTo(file);
◆ 파일 미리보기
스크립트에서 input file태그의 객체의 onchange함수를 호출하여 페이지전환없이 파일을 미리볼 수 있도록 지원한다.
FileReader()객체를 통해서 readAsDataURL(파일객체)를 통해 FileReader객체를 해당 파일객체로 물려두고
onload()시 읽어 들인 데이터의 result로 업로드 되기 전에 파일을 미리 읽어 들일 수 있다.
=> 여러개일 때는 반복문을 돌리면서 처리하면 된다.