파일 업로드 기능 구현을 위해 서블릿이 제공하는 Part 인터페이스의 사용법과 실제 파일 업로드 구현 방법에 대해 알아보겠습니다.
먼저 업로드된 파일이 저장될 경로를 설정해야 합니다.
# application.properties
file.dir=/Users/kimyounghan/study/file/
주의사항
1. 실제 파일이 저장될 폴더를 미리 생성해두어야 합니다.
2. 경로 설정 시 마지막에 슬래시(/)를 포함해야 합니다.
@Slf4j
@Controller
@RequestMapping("/servlet/v2")
public class ServletUploadControllerV2 {
@Value("${file.dir}")
private String fileDir;
@GetMapping("/upload")
public String newFile() {
return "upload-form";
}
@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));
}
// 편의 메서드
log.info("submittedFileName={}", part.getSubmittedFileName());
log.info("size={}", part.getSize());
// 파일 데이터 저장
if (StringUtils.hasText(part.getSubmittedFileName())) {
String fullPath = fileDir + part.getSubmittedFileName();
log.info("파일 저장 fullPath={}", fullPath);
part.write(fullPath);
}
}
return "upload-form";
}
}
Part 인터페이스는 멀티파트 형식의 데이터를 편리하게 다룰 수 있는 다양한 메서드를 제공합니다:
| 메서드 | 설명 |
|---|---|
getSubmittedFileName() | 클라이언트가 전송한 파일명 반환 |
getInputStream() | Part의 전송 데이터를 읽기 위한 InputStream 제공 |
write(String filename) | Part를 통해 전송된 데이터를 파일로 저장 |
getHeaderNames() | Part의 모든 헤더 이름을 컬렉션으로 반환 |
getHeader(String name) | 지정된 헤더의 값을 반환 |
getSize() | Part의 데이터 크기 반환 |
예를 들어, "상품A"라는 이름과 "스크린샷.png" 파일을 업로드하면 다음과 같은 로그가 출력됩니다:
==== PART ====
name=itemName
header content-disposition: form-data; name="itemName"
submittedFileName=null
size=7
body=상품A
==== PART ====
name=file
header content-disposition: form-data; name="file"; filename="스크린샷.png"
header content-type: image/png
submittedFileName=스크린샷.png
size=112384
파일 저장 fullPath=/Users/kimyounghan/study/file/스크린샷.png
대용량 파일 업로드 테스트 시에는 다음 설정들을 비활성화하는 것이 좋습니다:
# application.properties에서 제거
logging.level.org.apache.coyote.http11=trace
// 컨트롤러에서 제거
// log.info("body={}", body);
멀티파트 요청은 다음과 같은 구조로 전송됩니다:
폼 데이터 Part
content-disposition 헤더만 존재파일 Part
content-disposition 헤더에 filename 정보 포함content-type 헤더로 파일 타입 정보 포함write() 메서드를 통해 간단히 구현할 수 있습니다.