스프링의
CommonsMultipartResolver클래스를 이용하면 여러 개의 파일을
한꺼번에 업로드할 수 있다.

<!-- 다중 파일 다운로드 관련 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.4</version>
</dependency>
<beans:bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<beans:property name="maxUploadSize" value="52428800" />
<beans:property name="maxInMemorySize" value="1000000" />
<beans:property name="defaultEncoding" value="utf-8" />
</beans:bean>
방법 1)

방법 2)
마우스 우클릭 → Properties

Properties → Location 복사

🌟 private static String IMAGE_REPO = "C:\\복사한 Location";🌟
만약 방법 1) 처럼 경로가 C:\ 일경우 private static String IMAGE_REPO = "C:\\image"; 작성한다.
"\" → "\\" (무조건 2개씩 적어주기 )"C:\\ccv.\\ecew\\~~" or " D:\\nsknj.nck\\~~"Spring MVC를 사용하여 서버에 저장된 이미지 파일을 다운로드할 수 있도록 하는 기능을 담당한다.
파일을 response 의 출력 스트림 (OutputStream) 을 사용하여 클라이언트로 전송한다.
Controller 의 이름은 물론 지정 가능하다.
package com.test.pro10.ex03;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller // Spring의 컨트롤러로 동작하도록 설정
public class FileDownloadController {
// 이미지 파일이 저장된 기본 디렉토리 경로 (로컬 PC의 "C:\\image" 폴더)
private static String IMAGE_REPO = "C:\\image";
// 파일 다운로드 요청을 처리하는 핸들러 메서드
@RequestMapping("/test03/download.do")
public void download(
@RequestParam("imageFileName") String imageFileName, // 요청에서 파일명을 받아옴
HttpServletRequest request, HttpServletResponse response // 요청 및 응답 객체
) throws IOException {
// 응답 객체에서 출력 스트림(OutputStream) 가져오기 (클라이언트에게 데이터를 전송하는 스트림)
OutputStream out = response.getOutputStream();
// 실제 다운로드할 파일의 전체 경로 생성 (예: "C:\image\example.jpg")
String downFile = IMAGE_REPO + "\\" + imageFileName;
// 해당 경로에 있는 파일 객체 생성
File file = new File(downFile);
// 응답 헤더 설정 (클라이언트에게 캐시를 사용하지 않도록 지시)
response.setHeader("Cache-Control", "no-cache");
// 응답 헤더 설정 (브라우저가 파일을 다운로드하도록 함)
response.setHeader("Content-disposition", "attachment;fileName=" + imageFileName);
// 파일을 읽어오기 위한 입력 스트림 (FileInputStream)
FileInputStream in = new FileInputStream(file);
// 8KB 크기의 바이트 배열 버퍼 생성 (한 번에 8KB씩 읽어들임)
byte[] buffer = new byte[1024 * 8];
// 파일을 끝까지 읽어서 클라이언트에게 전송
while (true) {
int cnt = in.read(buffer); // buffer 크기만큼 파일 읽기
if (cnt == -1) { // 더 이상 읽을 데이터가 없으면 반복 종료
break;
}
out.write(buffer, 0, cnt); // 읽은 만큼 클라이언트에게 전송
}
// 스트림 닫기 (리소스 해제)
in.close();
out.close();
}
}
📌 기능
클라이언트가 test03/download.do?imageFileName= 파일이름으로 요청을 보낸다.
@RequestParam ("imageFileName") 을 통해 요청에서 파일명을 받아온다.
C:\image 디렉토리에서 해당 파일을 찾는다.
response 의 헤더를 설정하여 캐시 방지 및 다운로드 가능하도록 설정한다.
파일을 FileInputStream 을 통해 읽고, OutputStream 을 사용하여 클라이언트에게 전송한다.
전송이 끝나면 스트림을 닫고 응답을 종료한다.
IMAGE_REPO는 파일이 저장된 디렉토리(폴더) 경로를 나타내는 변수이다.
package com.test.pro10.ex03; // 패키지 선언: 해당 클래스가 속한 패키지명
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
@Controller // Spring MVC의 컨트롤러로 지정
public class FIleUploadController {
private static final String IMAGE_REPO = "C:\\image"; // 업로드된 파일을 저장할 디렉터리 경로 지정
@RequestMapping("/test03/form.do") // 클라이언트가 "/test03/form.do" 요청을 보내면 실행
public String form() {
return "/test03/uploadForm"; // 업로드 폼 페이지(view)를 반환
}
@RequestMapping("/test03/upload.do") // "/test03/upload.do" 요청을 처리
public ModelAndView upload(MultipartHttpServletRequest mRequest, HttpServletResponse response) throws IOException {
mRequest.setCharacterEncoding("utf-8"); // 요청의 인코딩을 UTF-8로 설정하여 한글 깨짐 방지
Map<String, String> map = new HashMap<>(); // 요청에서 받은 파라미터를 저장할 Map 객체 생성
Enumeration<String> enu = mRequest.getParameterNames(); // 요청에서 전달된 모든 파라미터의 이름을 가져옴
// 요청에서 전달된 모든 파라미터 값을 map에 저장
while (enu.hasMoreElements()) { // 파라미터가 남아있으면 반복
String name = enu.nextElement(); // 파라미터 이름
String value = mRequest.getParameter(name); // 파라미터 값
map.put(name, value); // map에 저장
}
List<String> fileList = fileProcess(mRequest); // 파일 업로드 처리 및 파일명 리스트 반환
map.put("fileList", fileList.toString()); // 업로드된 파일명을 map에 추가
ModelAndView mav = new ModelAndView(); // ModelAndView 객체 생성 (뷰와 데이터를 함께 전달하기 위함)
mav.addObject("map", map); // map 데이터를 모델에 추가
mav.setViewName("/test03/result"); // 결과 페이지 지정
return mav; // ModelAndView 반환
}
private List<String> fileProcess(MultipartHttpServletRequest mRequest) throws IOException {
List<String> fileList = new ArrayList<>(); // 업로드된 파일명을 저장할 리스트
Iterator<String> fileNames = mRequest.getFileNames(); // 업로드된 파일들의 이름을 가져옴
while (fileNames.hasNext()) { // 업로드된 파일이 있으면 반복
String fileName = fileNames.next(); // 업로드된 파일의 이름
MultipartFile mFile = mRequest.getFile(fileName); // 해당 파일의 정보를 가져옴
String originalFileName = mFile.getOriginalFilename(); // 원본 파일명 가져오기
fileList.add(originalFileName); // 파일명을 리스트에 추가
// 저장할 파일 객체 생성 (경로 + 파일명)
File file = new File(IMAGE_REPO + "\\" + fileName);
// 파일 크기가 0이 아닌 경우에만 저장 진행
if (mFile.getSize() != 0) {
// 파일이 존재하지 않는 경우
if (!file.exists()) {
// 부모 디렉토리가 존재하지 않으면 생성
if (file.getParentFile().mkdirs()) {
file.createNewFile(); // 빈 파일 생성
}
}
// 업로드된 파일을 지정된 위치로 저장
mFile.transferTo(new File(IMAGE_REPO + "\\" + originalFileName));
}
}
return fileList; // 업로드된 파일명 리스트 반환
}
}
1. 파일 업로드 폼 제공 (form.do )
uploadForm.jsp 같은 업로드 폼을 반환한다.2. 파일 업로드 처리 (upload.do)
MultipartHttpServletRequest 를 통해 파일과 일반 파라미터를 받는다.
일반 파라미터는 map 에 저장한다.
파일은 fileProcess() 메서드에서 처리한 후 파일명 리스트를 반환한다.
업로드 결과를 ModelAndView 를 통해 result 페이지로 전달한다.
3. 파일 저장 (fileProcess)
mRequest.getFileNames()를 통해 업로드된 파일 목록을 가져온다.
mFile.getOriginalFilename() 을 이용해 원본 파일명을 저장한다.
파일이 존재하지 않으면 디렉터리를 만들고 저장한다.
mFile.transferTo() 로 실제 저장하고 수행한다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>파일업로드</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
var cnt = 1;
function fn_addFile(){
$("#d_file").append("<br><input type='file' name='file"+cnt+"' />");
cnt++;
}
</script>
</head>
<body>
<h3>파일 업로드 하기</h3>
<form method="post" action="/pro10/test03/upload.do" enctype="multipart/form-data">
<label>아이디 : </label>
<input type="text" name="id"><br>
<label>이름 : </label>
<input type="text" name="name"><br>
<input type="button" value="파일추가" onclick="fn_addFile()"><br>
<div id="d_file"></div>
<input type="submit" value="업로드">
</form>
</body>
</html>


스프링에서 파일 업로드 처리 객체를 말한다.
MultipartFile 은 Spring 에서 파일 업로드를 처리하는 인터페이스로, CommonsMultipartFile 을 기반으로 구현된다.주요 메서드
getOriginalFilename() → 원본 파일명 반환.
getSize() → 파일 크기 반환.
isEmpty() → 파일이 비어 있는지 확인.
transferTo(File dest) → 업로드된 파일을 지정한 위치로 저장.
MultipartFile mFile = mRequest.getFile(fileName); // 업로드된 파일 가져오기
if (mFile.getSize() != 0) { // 파일 크기가 0이 아닌 경우 저장
mFile.transferTo(new File(IMAGE_REPO + "\\" + originalFileName)); // 파일 저장
}
MultipartFile 은 파일의 크기, 이름, 내용 등의 실제 정보를 제공함.바이트 기반 스트림(Byte Stream)으로, 파일, 네트워크, 메모리 등에서 데이터를 읽고 쓰는 역할이다.

read() 로 데이터 읽기write() 로 데이터 쓰기@RequestParam 은 HTTP 요청 파라미터(Query Parameter, Form Data)를 컨트롤러의 메서드에서 받아올 때 사용하는 어노테이션이다.
주로 GET , POST 요청에서 사용되며, URL의 쿼리스트링 또는 form-data 값을 매핑할 때 사용된다.
required = false (필수 여부)@RequestParam 은 반드시 존재해야 하는 값이다.@GetMapping("/greet")
public String greet(@RequestParam(value = "name", required = false) String name) {
return name != null ? "Hello, " + name + "!" : "Hello, Guest!";
}
✔ 요청: http://localhost:8080/greet?name=Alice
✅ 출력: "Hello, Alice!"
✔ 요청: http://localhost:8080/greet (파라미터 없음)
✅ 출력: "Hello, Guest!" (값이 없으면 기본 메시지 출력)
defaultValue (기본값 설정)@GetMapping("/welcome")
public String welcome(@RequestParam(value = "name", defaultValue = "Guest") String name) {
return "Welcome, " + name + "!";
}
✔ 요청: http://localhost:8080/welcome?name=David
✅ 출력: "Welcome, David!"
✔ 요청: http://localhost:8080/welcome
✅ 출력: "Welcome, Guest!" (기본값 적용)
@RequestParam vs @PathVariable 차이
✔ @RequestParam → ? 뒤의 쿼리 파라미터 값 받을 때 사용한다.
✔ @PathVariable → /{변수} 형태의 경로 변수 값 받을 때 사용한다.
@RequestParam 을 사용 시 주의required=true 이므로, 요청 시 값이 없으면 400 에러 발생required=false 또는 defaultValue 사용int 로 선언하면 요청 값이 없을 경우 에러 발생Integer(객체 타입)로 선언하거나 defaultValue 설정