JAVA에서는 기본적으로 제공되는 FILE과 PATH 클래스를 통해 파일에 접근하고 관리할 수 있는 기능을 가지고 있다. 하지만 HTTP 통신 과정에서는 외장 라이브러리를 사용하며, cos.jar(http://www.servlets.com/cos/)를 통한 방법을 살펴보겠다.
해당 라이브러리를 사용함에 있어서 조심해야 할 부분은, form을 다루는 방식이 기존의 것과 다르다는 부분이다. 기존 form 객체를 다룰 때, input을 통해 생성된 값을 parameter로서 서버는 접근한다. 그러니까 ModelAttribute 혹은 <Jsp:useBean>을 통해 DTO로서 관리하긴 하지만, 필드 값과 동일한 값을 자동으로 주입할 뿐이다. 해당 값을 DTO가 독점할 수 없고, 필요에 따라 서버에서 해당 파라미터를 호출할 수 있다.
이와 달리 cos 라이브러리는 form의 값 전체를 MultipartRequest를 통해 통제한다. 그러니까 input으로 생성된 각각의 값을 parameter로 사용 불가능하며, 반드시 MultipartRequest 객체를 통해 접근해야 한다. 이것이 라이브러리의 문제인지, 데이타 통신 방법 중 하나인 multipart/form-data의 특성인지는 잘 모르겠다. 차후에 더 채워 나가고자 한다.
마지막으로 MultipartRequest의 객체는 form에 있는 file의 value값이 하나라도 배열로서 받는다. getElementsbyNames처럼 말이다. 그러므로 파일을 추출할 때 반드시 반복문을 사용해야 한다.
마지막으로 파일을 서버에 저장할 때는 절대경로(config.getServletContext())를 path로 사용하며, 파일을 클라이언트에 출력할 때는 상대경로(request.getContextPath())를 path로 사용한다.
<form method="post" action="Ex01_proc.jsp" enctype="multipart/form-data"> .........(1)
input_text : <input type="text" name="input_text" value="작성자 : infoqoch"> <br>
input_file : <input type="file" name="input_file" value="abc.jpg"> <br>
<input type="submit" value="업로드">
</form>
(1) 이미지를 다룰 때는 반드시 post 방식을 사용하며, 인코딩 타입을 multipart/form-data로 해야한다. 이를 통하여 http는 range를 사용하여 데이타를 분할 전송할 수 있다(대용량 파일을 송수신 할 수 있다).
<%
int maxSize = 1024*1024*5;
String configPath = config.getServletContext().getRealPath("img"); .................(2)
System.out.println("configPath : "+configPath); // C:\JSP\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\uploadtest\img
String contextPath = request.getContextPath()+"/img"; .................(8)
System.out.println("contextPath: "+contextPath); // /14_Upload/img
System.out.println("(param)text 객체 : "+request.getParameter("input_text") ); // null
System.out.println("(param)file 객체 : "+request.getParameter("input_file") ); // null
............(1)
MultipartRequest multi = new MultipartRequest(
request,
configPath, ...........(2)
maxSize,
"utf-8",.............(3)
new DefaultFileRenamePolicy()...............(4)
);
System.out.println("(multi)text 객체 : "+multi.getParameter("input_text")); // 작성자 : infoqoch
System.out.println("(multi)file 객체 : "+multi.getParameter("input_file")); // null
............(5)
String fullPath1 = null;
String fullPath2 = null;
Enumeration<String> files = multi.getFileNames();
while(files.hasMoreElements()){...................(6)
String file = files.nextElement();
String fileName = multi.getFilesystemName(file);...........(7)
System.out.println("(반복문)text 객체 : "+file); // input_file
System.out.println("(반복문)file 객체 : "+fileName); // abc.jpg
.................(7)
fullPath1 = configPath+"\\"+fileName;
fullPath2 = contextPath+"\\"+fileName;..................(8)
}
%>
<br>
<img src="<%=fullPath1 %>" width="300px"> // 오류 (절대경로)
<img src="<%=fullPath2 %>" width="300px"> // 사진이 출력됨
(1) request.getParameter로 접근하여도 어떤 값도 가질 수 없다.
(5) MultipartRequest 객체를 생성한 후 그 객체를 통해서만 form의 값에 접근할 수 있다.
(7) MultipartRequest 객체를 각 각의 요소(element)를 통해 접근하고 나서야 파일 이름을 얻을 수 있다.
(2) MultipartRequest에서 파일을 저장하는 위치는 서버 내부의 절대경로로 해야 한다. config 객체를 사용한다.
(3) 문자 인코딩 방식을 설정해야 한다.
(4) 파일 이름에 대한 규칙을 정의한다. 기본 값은 중복되는 이름에 대하여 숫자를 붙인다.
(6) 업로드한 파일을 확인하는 과정이다. 반복문은 form의 요소들(elements)를 하나씩 꺼내는 방식이다. 방식은 ResultSet과 Iterator와 같다.
(7) 해당 파일을 클라이언트에 제공하기 위해서는 반드시 저장된 파일의 이름을 가져와야 한다. 왜냐하면 (4)DefaultFileRenamePolicy()으로 인해 이름이 변경될 수 있기 때문이다.
(8) 클라이언트에 제공할 때는 상대경로(context)를 통한다.
파일을 삭제할 경우는 다음과 같은 방식으로 진행한다.
File deleteFile1 = new File(fullPath1); //config를 통한 절대경로를 매개변수로 한다.
deleteFile1.delete();
수정을 하기 위해서는, 해당 객체(혹은 레코드)가 파일에 대한 식별자를 가지고 있는지, 혹은 해당 식별자를 통해 실제 파일에 접근할 수 있는지를 확인해야 한다. 전자는 식별자는 해당 파일의 디렉토리와 파일명을 객체(혹은 레코드)가 가지고 있는지 여부를 통해 확인한다. 후자는 해당 path를 매개변수로 하여 File 객체로 생성하고, File 객체의 exists() 매서드를 통해 확인 가능하다.