파일 업로드와 다운로드
파일 업로드와 다운로드 기능은 모든 웹 서비스에 반드시 필요한 핵심 기능입니다.
게시판, 회원 프로필, 보고서 제출, 이미지 관리 등 거의 모든 시스템이 이 기능을 사용합니다.
하지만 초보자에게 파일 업로드 기능은 난이도가 높습니다. 저장 경로, 용량 제한, 보안 정책, MIME 타입, 파일명 충돌 처리 등 신경 쓸 게 많기 때문입니다. 저 또한 엄청 고생했던 기억이 있습니다. 하나 해결하면 또 다른 하나가 문제가 되는 그런 상황들 말이죠.
이 글은 입문자도 바로 이해할 수 있도록 JSP·Servlet → Spring MVC → 실무 패턴 → 보안까지 전체 흐름을 한 번에 정리한 완성 가이드입니다. 많은 분들께 도움이 되길 기대합니다.
오늘은 파일 업로드 기능을 25개의 필수 체크리스트로 완전히 끝내 보겠습니다.

1. 단일 파일 업로드(기본)
핵심 개념: form 태그의 enctype="multipart/form-data" 필수
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file"/>
<button>업로드</button>
</form>
Tip) enctype 빠지면 절대 안 됩니다.(입문자 최다 실수 1위).
2. Servlet 기반 처리 (Commons FileUpload)
List<FileItem> items = new ServletFileUpload(factory).parseRequest(request);
for(FileItem item : items){
if(!item.isFormField()){
item.write(new File("C:/upload/" + item.getName()));
}
}
Tip) JSP 단독으로 하지 말고 반드시 Servlet으로 분리해 줍니다.
3. Spring MultipartFile (실무 표준)
@PostMapping("/upload")
public String upload(MultipartFile file) throws Exception {
file.transferTo(new File("C:/upload/" + file.getOriginalFilename()));
return "ok";
}
Tip) Spring은 MultipartResolver 자동 설정 덕분에 가장 사용률 높음.
4. 다중 파일 업로드 (List<MultipartFile>)
@PostMapping("/multi")
public void upload(List<MultipartFile> files) throws Exception {
for(MultipartFile f : files){
f.transferTo(new File("C:/upload/" + f.getOriginalFilename()));
}
}
Tip) 다중 업로드는 반드시 input 태그에 multiple 속성 필요.
5. 용량 제한 설정
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 30MB
Tip) max-request-size는 파일 여러 개 업로드 시 전체 용량 제한.
6. 경로 관리(절대경로 vs 상대경로)
| 방식 | 장점 | 단점 |
|---|---|---|
| 절대경로(C:/upload) | 설정 쉬움 | 서버 이동 시 수정 필요 |
| 상대경로(/resources/upload) | 이식성 좋음 | 초기 설정 필요 |
Tip) Docker·배포 고려하면 절대경로 사용 X.
7. 확장자 검사 (보안 필수)
String ext = FilenameUtils.getExtension(file.getOriginalFilename());
if(!List.of("png","jpg","pdf").contains(ext)) throw new RuntimeException("허용X");
Tip) .exe .bat .js .sh 반드시 차단.
8. MIME 타입 검사
if(!file.getContentType().startsWith("image")) throw new Exception("이미지만 가능");
Tip) contentType 위변조 가능 → 확장자 + MIME 두 개 모두 검사.
9. UUID 기반 저장명 생성(충돌 방지)
String saveName = UUID.randomUUID() + "." + ext;
Tip) 저장 파일명은 UUID, DB에는 원본명/저장명 둘 다 저장.
10. 날짜별 폴더 생성(대규모 시스템 표준)
String folder = LocalDate.now().toString().replace("-", "/"); // 2025/02/07
Files.createDirectories(Path.of(uploadPath, folder));
Tip) S3·NAS 쓰면 날짜 디렉토리 구조 필수.
11. 파일 메타데이터 DB 저장
DB에 저장하는 정보
| 컬럼 | 설명 |
|---|---|
| original_name | 원본 파일명 |
| save_name | UUID 저장명 |
| size | 파일 크기 |
| mime | 파일 타입 |
| path | 실제 저장 경로 |
| reg_date | 업로드일 |
Tip) 파일 다운로드는 DB save_name 기반으로 제공.
12. 게시판 파일 첨부 패턴
- 글 등록 → 파일 업로드
- DB에 게시글 ID + 파일 정보 연결
- 글 조회 시 files(1:N) 조회
- 다운로드 시 파일 단위 제공
Tip) 입문자가 가장 많이 하는 실수는 “글 수정 → 파일 덮어쓰기” 로직을 잘못 구성하는 부분입니다
13. 파일 다운로드(기본)
Path path = Paths.get(uploadPath + filename);
Resource res = new InputStreamResource(Files.newInputStream(path));
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + originalName)
.body(res);
Tip) 다운로드 파일명은 반드시 originalName 사용.
14. 파일명 한글 깨짐 문제 해결
String encoded = URLEncoder.encode(originalName, "UTF-8").replaceAll("\\+", "%20");
Tip) Window <-> Linux 간 이동할 때 자주 발생.
15. XSS 대비 파일명 필터링
공격 예시
image.png<script>alert(1)</script>
대응
originalName = originalName.replaceAll("[<>]", "");
16. 이미지 썸네일 자동 생성
Thumbnailator 사용 예시
Thumbnails.of(file).size(200, 200).toFile(thumbnailPath);
Tip) 관리자 페이지에 썸네일 리스트 빠르게 불러올 때 필수.
17. AWS S3 업로드
PutObjectRequest request = PutObjectRequest.builder()
.bucket("my-bucket")
.key("upload/" + saveName)
.build();
s3.putObject(request, RequestBody.fromBytes(file.getBytes()));
Tip) 실제 기업에서 가장 많이 쓰는 저장 방식.
18. NAS 연동
NAS(사내 파일 서버) 경로
/mnt/shared/upload/
Tip) 금융권·공공기관에서 가장 흔함.
19. 파일 삭제(단건)
Files.deleteIfExists(Path.of(path, saveName));
Tip) DB 레코드 삭제 + 실제 파일 삭제 둘 다 해야 함.
20. 파일 일괄 삭제
게시글 삭제 시 첨부파일 전체 삭제 필요
for(FileDTO f : files){
Files.deleteIfExists(Path.of(f.getPath(), f.getSaveName()));
}
21. 실패 시 롤백 처리
- 파일 저장
- DB 저장
- 중간 실패 시 저장된 파일 삭제
try {
file.transferTo(...)
dao.insert(...)
} catch(Exception e){
Files.delete(...)
}
22. Drag & Drop 업로드
프론트 예제
dropZone.addEventListener("drop", e=>{
e.preventDefault();
const files = e.dataTransfer.files;
});
Tip) 에디터 이미지 업로드에 가장 흔하게 사용.
23. AJAX 업로드 (FormData)
const fd = new FormData();
fd.append("file", file);
fetch("/upload", { method: "POST", body: fd });
Tip) 페이지 리로드 없이 업로드 가능 → 최근 UI 표준.
24. 다운로드 권한 체크
예) 로그인한 사용자만 다운로드
if(user == null) throw new UnauthorizedException();
Tip) 중요한 문서 다운로드에는 필수.
25. 실행가능 파일(.exe) 업로드 차단
웹쉘 공격 예방
String ext = ext.toLowerCase();
if(ext.equals("exe") || ext.equals("sh") || ext.equals("js")) throw new Exception();
Tip) 가장 중요한 보안 정책.
✔ 공식 문서(가장 신뢰도 높음)
- Servlet 3.0 File Upload 공식 스펙 (Oracle)
https://docs.oracle.com/javaee/6/tutorial/doc/glraq.html - Apache Commons FileUpload 공식 문서
https://commons.apache.org/proper/commons-fileupload/using.html - AWS S3 Upload 공식 개발자 가이드
https://docs.aws.amazon.com/AmazonS3/latest/userguide/upload-objects.html - Thumbnailator – GitHub 공식 문서
https://github.com/coobird/thumbnailator
✔ 실무·보안 자료(기업·기관 레퍼런스)
- OWASP File Upload Security Guide
업로드 취약점, MIME 위조, 파일 확장자 검사 등 업계 표준 보안 가이드
https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload - Naver D2 – 이미지 업로드/처리 기술 블로그
https://d2.naver.com/search?keyword=upload - Google Web Fundamentals – 사용자 파일 처리
https://developers.google.com/web/fundamentals/media/capturing-images
✔ 추가 참고 자료(확장 지식)
- MDN – FormData / 파일 업로드 & AJAX
https://developer.mozilla.org/en-US/docs/Web/API/FormData - StackOverflow – 파일 업로드 실무 패턴 Q&A
https://stackoverflow.com/questions/tagged/file-upload
마무리하며
이 25가지는 실제 회사에서 100% 사용되는 실무 구성입니다.
이걸 기반으로 게시판, 에디터, 관리자 도구 등 모든 시스템의 파일 업로드 기능을 만들 수 있습니다.
다음 편 예고
다음 글에서는 웹 개발에서 절대 피해갈 수 없는 인증(Authentication)과 보안(Security) 파트를 다룹니다. 입문자들이 가장 많이 막히는 구간이기도 하고, 실무에서는 한 줄의 설정 실수로도 보안 사고가 발생할 수 있어 반드시 정확히 이해해야 하는 주제입니다.
특히 다음 편은 단순 용어 설명을 넘어,
✔ 로그인 흐름이 어떻게 작동하는지
✔ 세션(Session)과 쿠키(Cookie)가 정확히 무엇을 하는지
✔ JWT 토큰이 왜 등장했고 어떻게 구성되는지
✔ CSRF, XSS 같은 보안 공격을 실제로 어떤 방식으로 막는지
등을 실제 업무 기준으로 하나씩 풀어낼 예정입니다.
[필수용어 실무] 이전 편을 보지 못했다면? 필수용어 실무 시리즈 바로가기
[필수용어 실무 1편] 비전공자가 실무에서 바로 활용 가능한 데이터 연동 & 서버 흐름 25선
[필수용어 실무 2편] 실무에서 마주치는 예외 처리 & 트러블슈팅 핵심 25선
[필수용어 실무 3편] JSP & MVC 패턴 실무 흐름 완전정복 25선
[필수용어 실무 4편] JSP 데이터 처리 & EL/JSTL 실무활용 25선
[필수용어 실무 5편] JSP + AJAX 비동기 데이터 통신 완전정복 25선
[필수용어 실무 6편] JSP + REST API 연동 실전 25선