오봉이와 함께하는 개발 블로그

스프링 MVC 2 - 서블릿과 파일 업로드 1 본문

BE/Spring

스프링 MVC 2 - 서블릿과 파일 업로드 1

오봉봉이 2022. 9. 1. 17:15
728x90

서블릿과 파일 업로드 1

먼저 서블릿을 통한 파일 업로드를 알아보자.

ServletUploadControllerV1

@Controller
@Slf4j
@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";
    }
}

request.getParts() : multipart/form-data 송 방식에서 각각 나누어진 부분을 받아서 확인할 수 있다.

resources/templates/upload-form.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
</head>
<body>

<div class="container">

    <div class="py-5 text-center">
        <h2>상품 등록 폼</h2>
    </div>

    <h4 class="mb-3">상품 입력</h4>

    <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>

</div> <!-- /container -->
</body>
</html>

테스트를 진행하기 전에 먼저 다음 옵션들을 추가.
application.properties

logging.level.org.apache.coyote.http11=debug

이 옵션을 사용하면 HTTP 요청 메시지를 확인할 수 있다.

결과 로그

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryt9lnh4nNQKGjLBmf

------WebKitFormBoundaryt9lnh4nNQKGjLBmf
Content-Disposition: form-data; name="itemName"

asdasdasd
------WebKitFormBoundaryt9lnh4nNQKGjLBmf
Content-Disposition: form-data; name="file"; filename="IMG_4587.JPG"
Content-Type: image/jpeg

ÿØÿàJFIFHViÿØÿÛÿÀÿÄ
1A456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖ×ØÙÚáâãäåæçèéêñòóôõö÷øùú
................(기타 내용)

(¢
(¢?ÿÙ
------WebKitFormBoundaryt9lnh4nNQKGjLBmf--

................(기타 내용)

request = org.springframework.web.multipart.support.StandardMultipartHttpServletRequest@3bf8dc54
ServletUploadControllerV1          : itemName = asdasdasd
ServletUploadControllerV1          : parts = [org.apache.catalina.core.ApplicationPart@353f255b, org.apache.catalina.core.ApplicationPart@3100b724]

boundary=----WebKitFormBoundaryt9lnh4nNQKGjLBmf로 구분하고 마지막에 ------WebKitFormBoundaryt9lnh4nNQKGjLBmf--를 통해서 --로 끝을 나타내는 것을 볼 수 있다.

멀티파트 사용 옵션

업로드 사이즈 제한

spring.servlet.multipart.max-file-size=1MB
spring.servlet.multipart.max-request-size=10MB

큰 파일을 무제한 업로드하게 둘 수는 없으므로 업로드 사이즈를 제한할 수 있다.
사이즈를 넘으면 예외(SizeLimitExceededException)가 발생한다.

max-file-size : 파일 하나의 최대 사이즈, 기본 1MB
max-request-size : 멀티파트 요청 하나에 여러 파일을 업로드 할 수 있는데, 그 전체 합. 기본 10MB

spring.servlet.multipart.enabled 끄기

spring.servlet.multipart.enabled=false

결과 로그

request=org.apache.catalina.connector.RequestFacade@xxx
itemName=null
parts=[]

멀티파트는 일반적인 폼 요청인 application/x-www-form-urlencoded보다 훨씬 복잡하다.
spring.servlet.multipart.enabled옵션을 끄면 서블릿 컨테이너는 멀티파트와 관련된 처리를 하지 않는다.
그래서 결과 로그를 보면 request.getParameter("itemName"), request.getParts()의 결과가 비어있다.

spring.servlet.multipart.enabled 켜기

spring.servlet.multipart.enabled=true (기본 true)

이 옵션을 켜면 스프링 부트는 서블릿 컨테이너에게 멀티파트 데이터를 처리하라고 설정한다. 기본 값은 true다.

결과 로그

request=org.springframework.web.multipart.support.StandardMultipartHttpServletRequest
itemName=Spring
parts=[ApplicationPart1, ApplicationPart2]

request.getParameter("itemName")의 결과도 잘 출력되고, request.getParts() 에도 요청한 두 가지 멀티파트의 부분 데이터가 포함된 것을 확인할 수 있다.
이 옵션을 켜면 복잡한 멀티파트 요청을 처리해서 사용할 수 있게 제공한다.

로그를 보면 HttpServletRequest 객체가 RequestFacade(false 했을 때) -> StandardMultipartHttpServletRequest(ture 했을 때)로 변한 것을 확인할 수 있다.

참고

spring.servlet.multipart.enabled옵션을 켜면(ture로 하거나 건들지 않았을 때) 스프링의 DispatcherServlet에서 멀티파트 리졸버(MultipartResolver)를 실행한다.
멀티파트 리졸버는 멀티파트 요청인 경우 서블릿 컨테이너가 전달하는 일반적인 HttpServletRequest(false 했을 때는 RequestFacade로 바뀐다.)를 MultipartHttpServletRequest로 변환해서 반환한다.
MultipartHttpServletRequestHttpServletRequest의 자식 인터페이스이고, 멀티파트와 관련된 추가 기능을 제공한다.

스프링이 제공하는 기본 멀티파트 리졸버는 MultipartHttpServletRequest인터페이스를 구현한 StandardMultipartHttpServletRequest를 반환한다.
이제 컨트롤러에서 HttpServletRequest대신에 MultipartHttpServletRequest를 주입받을 수 있는데, 이것을 사용하면 멀티파트와 관련된 여러가지 처리를 편리하게 할 수 있다.

그런데 MultipartFile이라는 것을 사용하는 것이 더 편하기 때문에 MultipartHttpServletRequest를 잘 사용하지는 않는다.
더 자세한 내용은 MultipartResolver를 검색해보자.

출처 : 인프런 김영한 지식공유자님 강의 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
728x90
Comments