🌿 스프링/스프링 MVC 2편

파일 업로드

le2donguk 2026. 2. 15. 16:06

개요

 

HTML 폼 전송 방식

  • application/x-www-form-urlencoded
  • multipart/form-data

일판 폼 방식으로 data를 전송하면 Content-Type 헤더에 application/x-www-form-urlencoded 간다

해당 헤더는 문자를 통해 폼 데이터를 전송한다

 

그런데 파일은 문자가 아니라 바이너리 데이터를 전송해야 한다.

그리고 한 가지 문제가 또 있는데 보통 폼을 전송할 때 파일만 전송하는 게 아니라 문자도 같이 전송한다

즉 이름, 나이는 문자로 전송하고 첨부파일은 바이너리로 전송해야 한다

 

 


 

multipart/form-data

 

 

multipart/form-data 방식은 다른 종류의 여러 파일과 폼의 내용 함께 전송할 수 있다

폼의 입력 결과로 생성된 HTTP Message를 보면 각각의 항목이 구분되어 있다

 

 

특히 Content-Disposition이라는 항목별 헤더가 추가되어 있고  부가 정보가 담겨 있다

username, age, file1 이 각각 파트라는 이름으로  분리되어 있고

각 파트는 HTTP Message처럼 헤더와 바디로 또 나뉜다

 

폼의 일반 데이터는 각 항목별로 문자가 전송되고 파일의 경우 파일 이름과 Content-Type 이 추가되고 바이너리 데이터가 전송된다

 

 


멀티파트 사용 옵션 (Servlet)

이전까지 블로그를 썼던 것처럼 스프링이 제공하는 기술을 바로 가는 것보단 Servlet 이 어떻게 동작하는지부터 찾아가 보자 

서블릿은 이러한 멀티파트 특히 파일업로드 다운로드에 관하여 다양한 기술을 이미 제공하고 있었다 

 

1. 업로드 사이즈 제한

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

 

 

2. spring.servlet.multipart.enabled

멀티파티 관련 예외를 해라 말아라 하는 옵션

 

끄게 되면

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

 

spring.servlet.multipart.enabled 옵션을 끄면 서블릿 컨테이너는 멀티파트와 관련된 처리를 하지 않는다

그래서 결과 로그를 보면 request.getParameter("itemName") , request.getParts()의 결과가 비어있다

 

 

옵션 켜기

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

 

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

 

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

 


파일 저장하기

파일을 업로드하려면 해당 파일이 실제 저장되는 경로가 필요하다

저장되는 경로를 설정하고 싶으면 아래와 같이 application.properties에서 지정해 주면 된다 

 

 

application.properties

file.dir=파일 업로드 경로 설정

(예): /Users/kimyounghan/study/file/

 

 

 

예시

 @Value("${file.dir}")
    private String fileDir;

 @PostMapping("/upload")
    public String saveFileV1(HttpServletRequest request) throws ServletException, IOException 
       
       Collection<Part> parts = request.getParts();
				
        for (Part part : parts) {
            //편의 메서드
            //content-disposition ; filename ;
            log.info("sumittedFilename={}",part.getSubmittedFileName());
            log.info("size={}", part.getSize());

            //데이터 읽기
            InputStream inputStream = part.getInputStream();
            String body = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);


            //파일에 저장하기
            if(StringUtils.hasText(part.getSubmittedFileName())){
                String fullPath = fileDir + part.getSubmittedFileName();
                log.info("파일 저장 fullpath={}", fullPath);
                part.write(fullPath);
            }

        return "upload-form";
    }

 

 

서블릿으로 파일 업로드를 구현하려면 request.part를 통해서 Multipart에 있는 모든 part들을 꺼낸다

 

그 후 메서드를 통해 파일 업로드를 구현하면 된다 위에서 쓰인 메서드는 다음과 같다 

 

Part 주요 메서드

part.getSubmittedFileName() : 클라이언트가 전달한 파일명

part.getInputStream(): Part의 전송 데이터를 읽을 수 있다

part.write(…) : Part를 통해 전송된 데이터를 저장할 수 있다

 

 


스프링 파일 업로드

 

서블릿이 제공하는 Part가 편하긴 하다

근데 HtpServletRequest를 사용해야 하고 여러 파트 중에 파일 파트를 구분하려면 이런저런 코드를 넣어야 한다

이제는 스프링이 제공하는 파일업로드를 알아보자

 

    @PostMapping("/upload")
    public String saveFile(@RequestParam String itemName,
                           @RequestParam MultipartFile file) throws IOException {

        if (!file.isEmpty()) {
            String fullPath = fileDir + file.getOriginalFilename();
            log.info("파일 저장 fullPath ={}", fullPath);
            file.transferTo(new File(fullPath));
        }
        
  }

 

스프링은 MultipartFile이라는 Class를 제공해 사용자가 편하게 file을 가져올 수 있게 한다 

이를 @RequestParam과 같이 쓰고 스프링이 제공하는 편의 메서드를 사용하여 파일을 업로드하고 저장할 수 있다 

 

 

주요 메서드

  • file.getOriginalFilename() : 업로드 파일 명
  • file.transferTo(…) : 파일 저장

'🌿 스프링 > 스프링 MVC 2편' 카테고리의 다른 글

API 예외처리  (0) 2026.02.15
서블릿 예외 처리와 오류 페이지  (0) 2026.02.15
서블릿 필터와 스블릿 인터셉터  (0) 2026.02.15
로그인 처리- 쿠키,세션  (0) 2026.02.14
Validation  (0) 2026.02.14