2020. 11. 12. 00:58ㆍ프로젝트/파일업로드
파일업로드를 위해서 사용하는 라이브러리는 크게 COS.jar 를 사용하거나 Apache Commons FileUpload , Servlet 3.0이후 부터는 Part라는 API를 제공하여 Part를 사용할 수 있음.
* Part 사용법 참고출처 : dololak.tistory.com/726?category=636501
프레임워크 사용없이 Servlet으로 파일업로드를 구현해볼 예정(dynamic web project)
Apache Commons FileUpload 를 이용한 파일 업로드 구현
파일 업로드를 위한 라이브러리 세팅
http://jakarta.apache.org/ 접속
'commons-fileupload bin.zip' 파일을 다운로드
'commons-io bin.zip' 파일을 다운로드
다운로드한 두 개의 jar파일을 'WEB-INF/lib/' 하위에 붙여넣기
파일업로드 코드작성
import java.io.File;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import com.preview.controller.CommandAction;
public class UploadAction implements CommandAction {
private static final String CHARSET = "UTF-8";
private static final String ATTACHES_DIR = "C:\\temp";
private static final int LIMIT_SIZE_BYTES = 1024 * 1024;
@Override
public String requestPro(HttpServletRequest request, HttpServletResponse response) throws Throwable {
System.out.println("UploadAction Start");
response.setContentType("text/html; charset=UTF-8");
request.setCharacterEncoding(CHARSET);
PrintWriter out = response.getWriter();
File attachesDir = new File(ATTACHES_DIR);
DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
fileItemFactory.setRepository(attachesDir);
fileItemFactory.setSizeThreshold(LIMIT_SIZE_BYTES);
ServletFileUpload fileUpload = new ServletFileUpload(fileItemFactory);
try {
//import org.apache.commons.fileupload.FileItem;
List<FileItem> items = fileUpload.parseRequest(request);
for(FileItem item : items) {
if(item.isFormField()) {
System.out.printf("[파일형식이 아닌 파라미터] 파라미터명: %s, 파일 명: %s, 파일크기: %s bytes \n", item.getFieldName(), item.getName(), item.getSize());
} else {
System.out.printf("[파일형식 파라미터] 파라미터명: %s, 파일 명: %s, 파일 크기: %s bytes \n", item.getFieldName(), item.getName(), item.getSize());
if(item.getSize() > 0) {
String separator = File.separator;
int index = item.getName().lastIndexOf(separator);
String fileName = item.getName().substring(index + 1);
File uploadFile = new File(ATTACHES_DIR + separator + fileName);
item.write(uploadFile);
}
}
}
} catch(Exception e) {
e.printStackTrace();
System.out.println("파일업로드 중 오류가 발생하였습니다.");
}
return null;
}
}
DiskFileItemFactory
: ' DiskFileItemFactory '는 업로드 된 파일을 저장할 저장소와 관련된 클래스
File attachesDir = new File(ATTACHES_DIR);
DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
fileItemFactory.setRepository(attachesDir);
fileItemFactory.setSizeThreshold(LIMIT_SIZE_BYTES);
' setRepository() '메서드는 업로드된 파일을 저장할 위치를 'File'객체로 지정
' setSizeThreshold() '메서드는 저장소에 임시파일을 생성할 한계 크기를 byte단위로 지정
예를 들어 이 값을 '1024'로 지정한 경우 '1024byte'이상의 파일을 업로드 했을 때 메모리에 있던 파일의 바이너리 데이터를 저장소에 임시파일로 잠시 저장됨.
이렇게 임시파일로 저장하는 이유는 대용량 파일을 업로드 했을 때 그만한 크기의 데이터를 웹어플리케이션이 동작하는 JVM메모리상에 모두 로드하는 것은 부담이 되기 때문. 임시파일로 저장되었던파일은 이후에 ' FileItem write() '메서드를 통해 실제 파일로 변경되거나 'FilwItem delete() '메서드를 통해 제거됨
ServletFileUpload
: ' ServletFileUpload '클래스는 HTTP요청에 대한 'HttpServletRequest '객체로부터 ' multipart/form-data '형식으로 넘어온 HTTP Body부분을 다루기 쉽게 변환해주는 역할을 수행.
ServletFileUpload fileUpload = new ServletFileUpload(fileItemFactory);
List<FileItem> items = fileUpload.parseRequest(request);
' parseRequest() '메서드를 수행하면 ' FileItem '이라는 형식으로 반환해줌
FileItem
: 사용자가 업로드한 ' File '데이터나 사용자가 ' input text '에 입력한 일반 요청 데이터에 대한 객체.
' FileItem isFormField() '메서드의 리턴값이 'true'이면 'text'같은 일반 입력 데이터이며, 'false'이면 파일데이터임을 알 수 있음. 즉, 리턴값이 'false'인 경우에만 업로드된 파일인 것으로 인지하여 처리하면 됨.
String separator = File.separator;
int index = item.getName().lastIndexOf(separator);
String fileName = item.getName().substring(index + 1);
File uploadFile = new File(ATTACHES_DIR + separator + fileName);
item.write(uploadFile);
' File.separator '는 운영체제별로 다른 파일경로 구분자를 담고있음. 예를 들어 ' Windows ' 환경에서는 각 디렉터리를 구분할 때 '\'를 사용하며 ' linux '계열은 ' / '를 사용하는데 , 따라서 업로드한 파일 경로의 마지막 separator 뒤에 오는 값이 실제 파일명이라 할 수 있음. (예를 들어, C\app\text.txt 의 경우 마지막 \ 뒤인 text.txt가 실제 파일명이됨.)
크롬의 경우 POST로 파일전송시 실제파일명만을 넘겨주는 반면 인터넷익스플로러의 경우 사용자의 드라이버경로부터 절대경로 전부를 리턴해주기 때문에 파일명을 추출할 때 이를 고려하여 주어야 함
마지막으로 ' FileItem write() ' 메서드를 통해 업로드 된 파일을 저장소 디렉터리에 저장. 임시파일로 저장된 경우 임시파일을 실제 파일명으로 변경함.
public String getFieldName() | 데이터의 name을 리턴. input태그에 설정된 name값 |
public boolean isFormRield() | input태그에 입력된 데이터가 단순히 text나 checkbox등을 통해 입력된 값인지의 여부를 리턴. 첨부파일 같은 바이너리 데이터이면 false를 리턴 |
public String getString(final String charset) | 첨부파일이 아닌 단순한 form데이터인 경우 입력된 값을 charset에 따라 인코딩하여 리턴 |
public String getName() | 데이터가 첨부파일인 경우 파일명 또는 파일 경로를 리턴 |
public long getSize() | 데이터의 크기(파일의 크기)를 byte단위로 리턴 |
public void write(File file) throws Exception | 현재 데이터가 첨부파일 일 때 매개변수로 넘겨준 File객체의 경로로 출력(저장)함 |
'프로젝트 > 파일업로드' 카테고리의 다른 글
[파일업로드] form enctype 속성(개념) (0) | 2020.11.11 |
---|