-
Spring MVC - Servlet의 파일 업로드Spring/Spring MVC 2022. 2. 17. 21:34728x90반응형
Servlet의 파일 업로드
HttpServletRequest를 이용하여 HTTP Form 멀티파트 전송 방식으로 넘어온 데이터를 어떻게 이용하는지 살펴보자.
HTML Form 전송 방식
- Form의 Content-Type은 다음과 같이 2가지 방식이 있다.
- application/x-www-form-urlencoded
- 일반적인 form 전송 방식
- form 태그 내의 입력된 일반 데이터들을 쿼리 파라미터 형식으로 메시지 바디에 담아 전송 - multipart/form-data
- 첨부파일을 포함한 전송 방식
- form 태그 내의 입력된 일반 데이터 문자들과 바이너리(첨부파일)를 함께 전송
- 메시지 바디에는 Content-Disposition이라는 항목별 헤더가 추가된다
- 메시지 바디에 각 항목별로 Part로 나누어져 전송
multipart/form-data 전송 방식의 HTTP 요청 메시지
multipart/form-data 방식으로 요청한 HTTP 요청 메시지 로그 확인
HTTP Form 전송 방식 중 하나인 multipart/form-data 방식으로 전송될 때 어떻게 HTTP 요청 메시지가 어떻게 전달되는지 간단한 html을 작성하여 로그를 확인해보자.
<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>
@Slf4j @Controller @RequestMapping("/servlet/v1") public class ServletUploadControllerV1 { @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); return "upload-form"; } }
위에서 작성한 form을 입력하여 요청하면 다음과 같은 HTTP 요청 메시지 로그를 확인할 수 있다
위처럼 form의 입력된 데이터만큼 Part로 나누어져 요청 메시지 바디에 전달되는 것을 볼 수 있다. Servlet은 Part로 나누어진 데이터들을 사용할 수 있도록 가공 처리해주기 때문에 request.getParameter, request.getParts을 이용하여 데이터들을 사용할 수 있다.
multipart/form-data 옵션
- application.properties에 해당 옵션을 설정할 수 있다.
- spring.servlet.multipart.max-file-size
- 파일 하나의 최대 사이즈 설정
- 기본 1MB - spring.servlet.multipart.max-request-size
- 여러 파일을 업로드할 때 합친 최대 사이즈 설정
- 기본 10MB - spirng.servlet.multipart.enabled
- 스프링 부트가 멀티파트 데이터를 처리하도록 설정
- 기본 true
- false로 설정하면 멀티파트 데이터를 처리하지 못한다.
Servlet을 이용한 파일 업로드
위에서 멀티파트 데이터가 어떻게 넘어오는지 로그를 통해 확인해 보았다. 이제 실제 파일을 서버에 업로드하는 방법을 알아보자.
파일이 저장되는 경로 설정
- apllication.properties에 파일이 저장되는 경로를 설정
- file.dir=파일 업로드 경로
ex) file.dir=C:/tools/spring/Spring_Lab/file/ - 경로 마지막에 슬래시(/)가 포함되어야 한다
file.dir=C:/tools/spring/Spring_Lab/file/
지정된 경로에 파일 저장
- 서블릿이 제공하는 Part는 멀티파트 형식의 데이터를 편리하게 읽을 수 있는
다양한 메서드를 제공한다. (각 part의 헤더와 바디를 읽어올 수 있다) - 제공 메서드
- part.getSubmittedFileName() : 클라이언트가 전달한 파일명
- part.getInputStream() : Part의 전송 데이터를 읽을 수 있다.
- part.write(...) : Part를 통해 전송된 데이터를 저장할 수 있다.
@Value("${file.dir}") private String fileDir; ... @PostMapping("/upload") ublic 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("headr {} : {}", headerName, part.getHeader(headerName)); } //편의 메서드 log.info("submittedFiledName={}", part.getSubmittedFileName()); log.info("size={}", part.getSize()); //데이터 읽기 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로 나누어 전송한다. Part로 나누어진 데이터들은
getParts메서드를 각각의 Part에 담긴 헤더 정보와 바디 정보를 읽어 올 수 있다. 또한 Part의 바디에 있는 데이터들은 옛날에는 part.getInputStream() 를 통해 읽어와야 했지만 요즘에는 서블릿이 내부적으로 처리해줘서 getParameter로 읽어올 수 있다.
728x90반응형'Spring > Spring MVC' 카테고리의 다른 글