Spring 파일 업로드

Spring Framework에서 파일 업로드를 처리하는 가장 일반적인 방식은 `Multipart 파일 업로드`를 지원하는 기능을 활용하는 것입니다. 사용하는 방식은 다음과 같습니다.

 

1. 의존성 추가

`MultipartResolver` 인터페이스를 구현하는 대표적인 구현체로는 `StandardServletMultipartResolver` `CommonsMultipartResolver`가 있습니다.  

  • `CommonsMultipartResolver
    Apacher Commons FileUpload 라이브러리를 사용하여 Multipart 요청을 처리합니다.
    이 구현체는 Spring MVC 이전 버전에서 주로 사용되었으며 의존성을 추가해주어야 합니다.
dependencies {
    implementation 'commons-fileupload:commons-fileupload:1.4'
}

 

  • `StandardServletMultipartResolver`
    서블릿 컨테이너가 제공하는 `javax.servlet.http.Part` 객체를 사용하여 Multipart 요청을 처리합니다.
    Servlet 3.0 이상의 컨테이너에서 사용이 가능하며, 해당 컨테이너의 멀티파트 처리 기능을 활용하여 업로드 요청을 처리합니다. 별도의 의존성 없이 기본적으로 Spring MVC에 포함되어 있기 때문에 `multipartResolver` 빈을 설정하지 않아도 Spring MVC는 `StandardServletMultipartResolver`를 사용합니다. 

 

 

2. `MultipartResolver` 빈을 설정합니다.

Spring MVC에서 `@EnableWebMvc` 어노테이션을 사용하면 자동적으로 `StandardServletMultipartResolver`가 자동으로 빈이 등록된다고 하였지만 아래 처럼 코드를 작성하는 이유는 혹시 모를 커스터마이징 때문입니다.

@Configuration
@EnableWebMvc
public class AppConfig implements WebMvcConfigurer {

    @Bean
    public MultipartResolver multipartResolver() {
        return new StandardServletMultipartResolver();
    }
}

 

 

3. 파일 업로드(`multipart/form-data`) 요청을 처리할 컨트롤러 메서드를 작성합니다.

@Controller
public class FileUploadController {

    @PostMapping("/upload")
    public String handleFileUpload(@RequestParam("file") MultipartFile file) {
        // 업로드된 파일 처리 로직 작성
        if (!file.isEmpty()) {
            try {
                // 파일 저장 코드 및 성공 시 로직 작성
                return "redirect:/success";
            } catch (IOException e) {
                e.printStackTrace();
                // 파일 저장에 실패한 경우 처리 로직 작성
                return "redirect:/error";
            }
        } else {
            // 업로드된 파일이 없는 경우 처리 로직 작성
            return "redirect:/empty";
        }
    }
}

 

handleFileUpload 메서드가 파일 업로드를 처리하는 컨트롤러 메서드입니다.

@RequestParam 어노테이션을 사용하여 file 파라미터로 `MultipartFile` 객체를 받아옵니다. 이 객체를 통해 업로드된 파일의 정보와 데이터를 가져올 수 있습니다. 메서드 내에서는 업로드된 파일을 저장하거나 다른 작업을 수행하는 로직을 구현할 수 있습니다.

이러한 방식을 통해 Spring Framework에서 파일 업로드를 처리할 수 있습니다. MultipartResolver를 설정하고, 컨트롤러 메서드에서 `MultipartFile`을 받아 업로드된 파일을 처리하면 됩니다.

※ SpringBoot에서는?
Spring Boot를 사용하면 `spring-boot-starter-web` 또는 `spring-boot-starter-webflux` 의존성을 추가하면 기본적으로 `MultipartResolver`가 설정되어 있습니다. 따라서 별도의 설정이 필요하지 않고, MultipartFile을 파라미터로 받아 파일 업로드를 처리할 수 있습니다.

 


파일 업로드 설정

web.xml

    <servlet>
    	<!-- DispatcherServlet 등록 -->
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        
        <!-- 파일 업로드 설정 -->
        <multipart-config>
            <!-- 파일 하나 최대 크기: 5MB. 기본값 -1 (제한없음)-->
      		<max-file-size>5242880</max-file-size>
            
            <!-- 최대 업로드 요청 크기: 5MB. 기본값 -1 (제한없음) -->
      		<max-request-size>5242880</max-request-size>
            
            <!-- 전송된 파일 크기가 이 크기를 넘어서면 
 			     메모리에 있던 파일 내용을 임시 파일로 만든다. 
                 기본값 0 (항상 파일에 출력) -->
      		<file-size-threshold>1048576</file-size-threshold>
      	</multipart-config>
    </servlet>
  • <multipart-config>
    <multipart-config>를 별다른 설정 없이 사용하면 업로드라 수 있는 파일 크기가 무제한이 된다.
    파일 크기를 제한하고 싶다면 위와 같이 세 가지 설정을 추가해주어야 한다.

 


MultipartFile 메서드

  • String getName()
    업로드된 파일의 파라미터 이름을 반환합니다. HTML form에서 input 요소의 name 속성 값과 일치합니다.
  • String getOriginalFilename()
    업로드된 파일의 원본 파일명을 반환합니다.
  • long getSize()
    업로드된 파일의 크기를 바이트 단위로 반환합니다.
  • boolean isEmpty()
    업로드된 파일이 비어있는지 여부를 확인합니다.
  • byte[] getBytes() throws IOException
    업로드된 파일의 내용을 바이트 배열로 반환합니다. 주의할 점은 메모리에 파일의 내용을 모두 로드하므로 큰 파일의 경우 사용을 지양해야 합니다.
  • InputStream getInputStream() throws IOException
    업로드된 파일의 내용을 읽어오는 InputStream 객체를 반환합니다.
  • void transferTo(Path destination) throws IOException
    업로드된 파일을 지정된 경로에 저장합니다. destination 매개변수에는 저장할 파일의 경로를 java.nio.file.Path 타입으로 전달해야 합니다.
  • void transferTo(File dest) throws IOException
    업로드된 파일을 지정된 파일에 저장합니다. dest 매개변수에는 저장할 파일의 java.io.File 객체를 전달해야 합니다.
  • Resource getResource()
    업로드된 파일을 Spring의 Resource 타입으로 반환합니다. Resource 객체를 사용하여 파일을 읽거나 다른 처리를 할 수 있습니다.
  • MediaType getContentType()
    업로드된 파일의 컨텐츠 타입을 MediaType 객체로 반환합니다. 파일의 MIME 타입을 확인할 때 유용하게 사용될 수 있습니다.
  • boolean isImage(): 업로드된 파일이 이미지 파일인지 여부를 확인합니다. 이미지 파일인 경우 true를 반환하고, 그렇지 않은 경우 false를 반환합니다.

 

※ Resource 객체에 대해서 따로 포스팅하도록 하겠습니다.


파일 업로드 예제

@Controller
@RequestMapping("/file")
public class FileController {

    @PostMapping("/upload")
    public String uploadFile(@RequestParam("file") MultipartFile file) {
        if (!file.isEmpty()) {
            try {
                // 파일명 중복 방지를 위해 UUID 생성
                String originalFilename = getFileName(file);
                String fileExtension = getFileExtension(originalFilename);
                String fileName = UUID.randomUUID().toString() + fileExtension;

                // 파일 저장 경로 설정
                String filePath = UPLOAD_PATH + fileName;
                File destFile = new File(filePath);

                // 파일 저장
                file.transferTo(destFile);

                return "uploadSuccess";
            } catch (IOException e) {
                e.printStackTrace();
                return "uploadFailure";
            }
        } else {
            return "uploadFailure";
        }
    }
    
    private String getFileName(MultipartFile file) {
    	String originalFileName = file.getOriginalFileName();
        
        //IE(Internet Explorer)에서는 파일 이름이 전체 파일 경로가 전송됩니다.
        originalFileName = originalFileName.subString(originalFileName.lastIndexOf("\\") + 1);
        
        return originalFileName;
    }

    private String getFileExtension(String fileName) {
        int dotIndex = fileName.lastIndexOf(".");
        if (dotIndex >= 0 && dotIndex < fileName.length() - 1) {
            return fileName.substring(dotIndex);
        }
        return "";
    }
}

`File` 객체

Java에서 파일 및 디렉터리를 나타내는 클래스입니다.

  • new File()를 통한 파일 생성
  • `getName()`: 파일 이름
  • `renameTo()`: 파일 이름 변경
  • `delete()`: 파일 및 디렉터리 삭제
  • `getPath()`: 파일 경로
  • `length()`: 파일 크기
  • `lastModified()`: 파일 수정 날짜
  • `mkdir()`: 디렉터리 생성
  • `list()` 또는 `listFiles()`: 디렉터리 내의 파일 및 디렉터리
  • `getParent()`: 부모 디렉터리 경로
  • `getAbsolutePath()`: 절대 경로

 

 

파일 다운로드 예제

@Controller
public class FileDownloadController {

    private static final String DOWNLOAD_PATH = "/path/to/download/folder/";

    @GetMapping("/download/{fileName:.+}")
    public ResponseEntity<FileSystemResource> downloadFile(@PathVariable String fileName) throws IOException {
        // 파일 다운로드 폴더 경로 설정
        String filePath = DOWNLOAD_PATH + fileName;
        File file = new File(filePath);

        // 파일이 존재하는지 확인 후 다운로드
        if (file.exists()) {
            FileSystemResource resource = new FileSystemResource(file);

            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"");

            return ResponseEntity.ok()
                    .headers(headers)
                    .contentLength(file.length())
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .body(resource);
        } else {
            return ResponseEntity.notFound().build();
        }
    }
}
`FileSystemRousrce`란?
Spring Framework에서 제공하는 `Resource` 인터페이스의 구현체 중 하나입니다.
`Resource`는 파일 시스템, 클래스 패스, URL 등의 다양한 리소스에 접근할 수 있는 추상화된 방법을 제공합니다. `FileSystemResource` `Resource` 인터페이스의 메서드들을 구현하고 있어서 파일 관련 작업을 수행할 수 있습니다.
예를 들어, `getFile()` 메서드를 사용하여 `File` 객체를 얻을 수 있고, `InputStream` 또는 `OutputStream`을 사용하여 파일의 내용을 읽거나 쓸 수 있습니다.파일 다운로드와 같은 경우, `FileSystemResource`를 사용하여 다운로드할 파일을 읽고 클라이언트에게 전달할 수 있습니다. `FileSystemResource` 객체는 파일의 경로와 이름을 가지고 있으며, 이를 통해 파일의 내용을 읽어서 클라이언트에게 전달할 수 있습니다.

`Resource` 인터페이스에 관한 설명은 따로 포스팅하도록 하겠습니다.

 


파일 업로드 관련 실습

https://yeo-computerclass.tistory.com/338

 

Spring + Ajax 파일 업로드

서버에서 첨부파일 처리 방식 cos.jar 2002년에 개발이 종료되어, 더 이상 잘 사용되지 않음 commons-fileupload 가장 많이 사용되는 방식 자체적인 파일 업로드 처리 서블릿 3.0 이상부터 자체적인 파일

yeo-computerclass.tistory.com