외부 라이브러리 없이 구현하는 효율적인 파일 업로드: request.getParts() 활용법
페이지 정보
- 조회 11
- 작성일 2026.03.04 13:33
웹 애플리케이션을 개발하다 보면 프로필 사진 업로드나 문서 첨부 같은 파일 업로드 기능은
필수적으로 들어가게 마련입니다.
예전에는 Apache Commons FileUpload 같은 외부 라이브러리를 사용하는 것이 당연시되었지만,
서블릿 3.0 표준이 등장하면서 상황이 완전히 바뀌었습니다.
이제는 복잡한 설정 없이도 자바 표준 API인 HttpServletRequest.getParts()를 통해
아주 우아하게 파일을 주고받을 수 있게 되었죠.
오늘은 실무에서 바로 적용할 수 있는 getParts() 사용법과 주의사항을 깊이 있게 다뤄보겠습니다.
1. 왜 request.getParts()를 사용해야 할까?
가장 큰 이유는 표준성과 간결함입니다.
라이브러리 의존성을 줄이는 것은 프로젝트의 가벼움을 유지하고 보안 취약점 관리 측면에서도 매우 유리합니다.
-
의존성 제거 :
pom.xml이나build.gradle에 별도의 라이브러리를 추가할 필요가 없습니다. -
직관적인 API :
Part인터페이스를 통해 파일명, 크기, Content-Type 등을 쉽게 가져올 수 있습니다. - 성능 최적화 : 서블릿 컨테이너(Tomcat 등) 레벨에서 직접 처리하므로 데이터 처리 효율이 높습니다.
- 기본 API : 톰캣에 가장 최적화된 로직으로 동작합니다.
2. 기본 설정: @MultipartConfig
request.getParts()를 사용하기 위해서는 서블릿에 멀티파트 데이터를 처리할 준비가 되었다고 알려줘야 합니다.
이때 사용하는 것이 @MultipartConfig 어노테이션입니다.
@WebServlet("/upload")
@MultipartConfig(
fileSizeThreshold = 1024 * 1024 * 1, // 1MB (메모리에서 처리할 임계치)
maxFileSize = 1024 * 1024 * 10, // 10MB (파일 하나당 최대 크기)
maxRequestSize = 1024 * 1024 * 15 // 15MB (전체 요청 최대 크기)
)
public class FileUploadServlet extends HttpServlet {
// ... 구현부
}
이 설정이 없으면 getParts()를 호출했을 때 멀티파트 요청이 아니라는 예외가 발생할 수 있으니 반드시 체크해야 합니다.
3. 실무형 구현 코드: request.getParts()
이제 실제 컨트롤러(서블릿) 단계에서 파일을 어떻게 처리하는지 코드로 살펴보겠습니다.
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 저장 경로 설정 (실제 서버 경로 혹은 외부 저장소)
String uploadPath = "C:/uploads";
File uploadDir = new File(uploadPath);
if (!uploadDir.exists()) uploadDir.mkdir();
// 1. 모든 Part 가져오기 (파일뿐만 아니라 일반 텍스트 데이터도 Part로 전달됨)
Collection<Part> parts = request.getParts();
for (Part part : parts) {
// 2. 파일인 경우만 필터링 (파일명이 존재하는 경우)
String fileName = getFileName(part);
if (fileName != null && !fileName.isEmpty()) {
// 3. 파일 저장
part.write(uploadPath + File.separator + fileName);
System.out.println(fileName + " 저장 완료!");
}
}
}
// 헤더에서 파일명을 추출하는 헬퍼 메서드
private String getFileName(Part part) {
String contentDisp = part.getHeader("content-disposition");
for (String content : contentDisp.split(";")) {
if (content.trim().startsWith("filename")) {
return content.substring(content.indexOf("=") + 2, content.length() - 1);
}
}
return null;
}
실제 사례 Tip: 실제 상용 서비스에서는 위 코드처럼 파일명을 그대로 저장하면 보안 위험(Path Traversal)이 있거나
파일명 중복 문제가 발생할 수 있습니다. 저 같은 경우 실무에서UUID.randomUUID()를 활용해 파일명을 치환하고,
DB에는 원본 파일명과 저장 파일명을 따로 관리하는 방식을 선호합니다.
4. 핵심 체크포인트
파일 업로드는 보안과 직결되는 문제입니다. 구글이 강조하는 신뢰성(Trustworthiness)을 높이기 위해 다음 사항을 꼭 고려하세요.
-
확장자 검증: 클라이언트 측 검증은 필수지만, 서버 측에서도 허용된 확장자(jpg, png, pdf 등)인지 반드시 재검증해야 합니다.
-
파일 크기 제한: 무분별하게 큰 파일이 업로드되면 서버 리소스가 고갈됩니다.
@MultipartConfig의 설정을 통해 원천 봉쇄하세요. -
저장 위치 분리: 업로드된 파일이 실행 권한을 가지지 않도록 WAS의 웹 루트(Web Root) 외부 경로에 저장하는 것이 보안의 정석입니다.
결론
request.getParts()는 현대적인 자바 웹 개발에서 가장 깔끔한 파일 업로드 해결책입니다.
라이브러리에 의존하지 않고 표준 API를 깊이 있게 이해하고 사용하는 것만으로도
여러분의 코드는 한층 더 견고해질 것입니다.
오늘 다룬 내용을 바탕으로 더 안전하고 효율적인 파일 업로드 로직을 구축해 보시기 바랍니다.
출처 및 참고:
-
Oracle Java EE 7 Documentation - Interface Part
댓글목록
등록된 댓글이 없습니다.