[파일업로드] 전송된 파일을 서버처리(APACHE COMMONS FILEUPLOAD 사용)

2020. 11. 12. 00:58프로젝트/파일업로드

728x90

파일업로드를 위해서 사용하는 라이브러리는 크게  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객체의 경로로 출력(저장)함

 

728x90

'프로젝트 > 파일업로드' 카테고리의 다른 글

[파일업로드] form enctype 속성(개념)  (0) 2020.11.11