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 Framework' 카테고리의 다른 글
Spring Redirect: 다른 URL로 리다이렉트 (0) | 2022.09.14 |
---|---|
Spring 비동기 처리 @Async, CompletableFuture, TaskDecorator (0) | 2022.09.09 |
Spring @SessionAttributes, @SessionStatus: Model과 연동을 통한 상태 유지 (0) | 2022.09.07 |
Spring REST API 개념과 흐름도 (0) | 2022.09.06 |
Spring Model 객체: 컨트롤러에서 뷰로 데이터 전달 (0) | 2022.09.06 |