스프링 부트 3.2.1 버전을 기준으로 작성됨
파일 업로드에서 HTML Form으로 데이터 전송할 때
단순히 문자만 전송하는 것이 아닌 파일 즉 바이너리 데이터를, 심지어 문자와 같이 전송하게 된다면 어떻게 처리해야할까?
-> Http의multipart/form-data
라는 전송 방식 제공
데이터의 각 항목을 구분에서 한 번에 전송
Form 태크에 enctype="multipart/form-data"를 지정해야함
multipart/form-data
는 매우 복잡하고 각각의 부분(Part)로 나누어져 있다.
이러한 HTTP 메시지를 서버에서 어떻게 사용할 수 있을까?
@PostMapping("/upload")
public String saveFileV1(HttpServletRequest request) throws ServletException, IOException {
//getParts() : multipart/form-data 전송 방식에서
// 각각 나누어진 부분을 반환
Collection<Part> parts = request.getParts();
//...
}
<form th:action method="post" enctype="multipart/form-data">
<ul>
<li>상품명 <input type="text" name="itemName"></li>
<li>파일<input type="file" name="file" ></li>
</ul>
<input type="submit"/>
</form>
//application.properties
spring.servlet.multipart.max-file-size=1MB
spring.servlet.multipart.max-request-size=10MB
//application.properties
// 멀티파트 처리 작동하지 않는다.
spring.servlet.multipart.enabled=false // default = true
// 폼 데이터에 맞게 입력 및 파일 전송시
request=org.springframework.web.multipart.support.StandardMultipartHttpServletRequest
itemName=Spring
parts=[ApplicationPart1, ApplicationPart2]
HttpServletRequest
객체가
RequestFacade
-> StandardMultipartHttpServletRequest
로 변환
spring.servlet.multipart.enabled
true시DispatcherServlet
에서 멀티파트 리졸버를 실행
해당 리졸버는 멀티파트 요청인 경우 HttpServletRequest -> MultipartHttpServletRequest로 변환하여 반환
// application.properties
file.dir=파일 업로드 경로 설정 (예): /Users/user/mvc/file/
* 1. 꼭 해당 경로에 실제 폴더 존재해야함
* 2. 마지막에 / 포함해야 함
// application.properties에서 설정 값 주입
@Value("${file.dir}")
private String fileDir;
@PostMapping("/upload")
public String saveFileV1(HttpServletRequest request) throws ServletException, IOException {
log.info("request={}", request);
String itemName = request.getParameter("itemName");
log.info("itemName={}", itemName);
Collection<Part> parts = request.getParts();
log.info("parts={}", parts);
for (Part part : parts) {
log.info("==== PART ====");
log.info("name={}", part.getName());
Collection<String> headerNames = part.getHeaderNames();
for (String headerName : headerNames) {
log.info("header {}: {}", headerName, part.getHeader(headerName));
}
//편의 메서드
// content=disposition; filename
log.info("submittedFilename={}", part.getSubmittedFileName());
log.info("size={}", part.getSize()); // part Body size
// 데이터 읽기
InputStream inputStream = part.getInputStream();
String body = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
log.info("body={}", body);
// 파일 저장하기
if (StringUtils.hasText(part.getSubmittedFileName())) {
String fullPath = fileDir + part.getSubmittedFileName();
log.info("파일 저장 fullPath={}", fullPath);
part.write(fullPath);
}
}
return "upload-form";
}
}
결과
part.getSubmittedFileName()
: 클라이언트가 전달한 파일명
part.getInputStream()
: Part의 전송 데이터를 읽을 수 있다.
part.write(...)
: Part를 통해 전송된 데이터를 저장할 수 있다.
@Value("${file.dir}")
private String fileDir;
@PostMapping("/upload")
public String saveFile(@RequestParam String itemName,
@RequestParam MultipartFile file, HttpServletRequest request) throws IOException {
if (!file.isEmpty()) {
String fullPath = fileDir + file.getOriginalFilename();
log.info("파일 저장 fullPath={}", fullPath);
file.transferTo(new File(fullPath));
}
}
@RequestParam MultipartFile file
업로드하는 HTML Form의 name에 맞추어 @RequestParam 을 적용
file.getOriginalFilename()
: 업로드 파일 명
file.transferTo(...)
: 파일 저장
🔖 학습내용 출처