https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-servlet/multipart.html
1. 파일 업로드란?
파일 업로드는 클라이언트가 자신의 디바이스에서 서버로 파일 데이터를 전송하는 과정입니다.
Spring MVC는 파일 업로드를 처리하기 위해 Multipart 요청을 지원하며, 파일 데이터와 함께 일반 폼 데이터도 처리할 수 있습니다.
2. Multipart란?
2.1 Multipart 요청
- HTTP 요청의 Content-Type이 multipart/form-data로 지정된 요청.
- 파일, 텍스트 데이터, 기타 필드들을 여러 파트로 나누어 전송.
- 주로 HTML 폼에서 파일 업로드를 위해 사용.
요청 구조 예시
POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="username"
testuser
------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="example.txt"
Content-Type: text/plain
This is the content of the file.
------WebKitFormBoundary--
3. Spring에서 파일 업로드 처리
Spring은 Commons FileUpload 또는 Spring Web의 내장 MultipartResolver를 사용하여 Multipart 요청을 처리합니다.
Spring Boot에서는 기본적으로 StandardServletMultipartResolver가 사용됩니다.
4. Spring Boot 파일 업로드 설정
4.1 의존성 추가
Spring Boot는 기본적으로 파일 업로드를 지원하므로 추가 의존성이 필요하지 않습니다.
(단, 특별히 Apache Commons FileUpload를 사용할 경우 관련 의존성 추가 필요)
4.2 application.properties 설정
파일 업로드 크기 제한과 같은 설정을 정의합니다.
# 최대 파일 크기 설정
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=20MB
5. MultipartFile 인터페이스
Spring에서 파일 업로드 요청은 MultipartFile 객체로 처리됩니다.
주요 메서드
메서드 설명
getName() | 요청에서 필드 이름 반환 |
getOriginalFilename() | 업로드된 파일 이름 반환 |
getBytes() | 파일 데이터를 바이트 배열로 반환 |
getInputStream() | 파일 데이터를 읽기 위한 InputStream 반환 |
transferTo(File dest) | 파일 데이터를 지정된 경로에 저장 |
6. 파일 업로드 구현 예제
6.1 단일 파일 업로드
HTML 폼
<form action="/upload" method="post" enctype="multipart/form-data">
<label for="file">파일 업로드:</label>
<input type="file" name="file" id="file">
<button type="submit">업로드</button>
</form>
컨트롤러
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
@RestController
public class FileUploadController {
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return "파일을 선택하지 않았습니다.";
}
try {
// 저장 경로 설정
String uploadDir = "uploads/";
File dest = new File(uploadDir + file.getOriginalFilename());
file.transferTo(dest); // 파일 저장
return "업로드 성공: " + dest.getAbsolutePath();
} catch (IOException e) {
e.printStackTrace();
return "업로드 실패";
}
}
}
6.2 다중 파일 업로드
HTML 폼
<form action="/multi-upload" method="post" enctype="multipart/form-data">
<label for="files">파일 업로드:</label>
<input type="file" name="files" id="files" multiple>
<button type="submit">업로드</button>
</form>
컨트롤러
import java.util.List;
@PostMapping("/multi-upload")
public String uploadMultipleFiles(@RequestParam("files") List<MultipartFile> files) {
StringBuilder result = new StringBuilder();
for (MultipartFile file : files) {
if (!file.isEmpty()) {
try {
String uploadDir = "uploads/";
File dest = new File(uploadDir + file.getOriginalFilename());
file.transferTo(dest); // 파일 저장
result.append("업로드 성공: ").append(dest.getAbsolutePath()).append("<br>");
} catch (IOException e) {
e.printStackTrace();
result.append("업로드 실패: ").append(file.getOriginalFilename()).append("<br>");
}
}
}
return result.toString();
}
7. Spring 파일 업로드 주요 설정
7.1 파일 업로드 크기 제한
- 파일 크기 제한은 application.properties에서 설정:
- spring.servlet.multipart.max-file-size=5MB spring.servlet.multipart.max-request-size=10MB
- 업로드 크기 초과 시 발생하는 예외 처리:
- @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(MaxUploadSizeExceededException.class) public String handleMaxSizeException(MaxUploadSizeExceededException ex) { return "파일 크기가 제한을 초과했습니다."; } }
8. 파일 저장 위치 관리
8.1 로컬 디렉토리
- 서버 내 디렉토리에 파일 저장.
- 단점: 서버가 재배포되면 파일 데이터가 삭제될 수 있음.
8.2 외부 저장소
- Amazon S3, Google Cloud Storage, FTP 서버 등 사용.
- 장점: 서버와 독립적인 파일 관리 가능.
8.3 데이터베이스
- 파일을 Blob 형식으로 데이터베이스에 저장.
- 장점: 트랜잭션과 연계 가능.
- 단점: 데이터베이스 부하 증가.
Spring 파일 업로드 저장 위치 및 설정 전략
1. 파일 저장 위치 선택
파일 업로드 시 저장 위치를 선택하는 것은 애플리케이션의 성능, 데이터 관리, 확장성 등에 큰 영향을 미칩니다. 저장 위치를 선택할 때 아래와 같은 기준을 고려합니다.
1.1 로컬 파일 시스템
- 설명: 업로드된 파일을 애플리케이션이 실행되는 서버의 디스크에 저장.
- 장점:
- 간단하고 빠르며 설정이 쉬움.
- 초기 개발 환경이나 단일 서버 애플리케이션에 적합.
- 단점:
- 다중 서버 환경에서 파일 공유가 어려움.
- 서버 장애 또는 재배포 시 파일이 손실될 수 있음.
예시
spring.servlet.multipart.location=/var/www/uploads
1.2 외부 저장소(네트워크 스토리지, NAS)
- 설명: 업로드된 파일을 서버 외부의 네트워크 스토리지에 저장.
- 장점:
- 다중 서버에서 파일 공유 가능.
- 데이터 관리 및 백업이 용이.
- 단점:
- 네트워크 지연으로 인해 성능 저하 가능.
- 설정 및 관리가 복잡.
예시
spring.servlet.multipart.location=//network-storage/shared/uploads
1.3 클라우드 스토리지 (예: AWS S3, Google Cloud Storage)
- 설명: 업로드된 파일을 클라우드 스토리지에 저장.
- 장점:
- 무제한 용량 제공 및 확장성.
- 다중 서버 환경에서 파일 공유가 매우 쉬움.
- 내장된 데이터 백업 및 복구 기능.
- 단점:
- 네트워크 종속성.
- 사용량에 따른 추가 비용 발생.
AWS S3 연동 예시
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.PutObjectRequest;
@RestController
public class FileUploadController {
private final AmazonS3 amazonS3;
public FileUploadController(AmazonS3 amazonS3) {
this.amazonS3 = amazonS3;
}
@PostMapping("/upload")
public String uploadToS3(@RequestParam("file") MultipartFile file) throws IOException {
String bucketName = "your-bucket-name";
amazonS3.putObject(new PutObjectRequest(bucketName, file.getOriginalFilename(), file.getInputStream(), null));
return "파일이 S3에 업로드되었습니다.";
}
}
1.4 데이터베이스
- 설명: 파일을 데이터베이스 테이블의 BLOB 또는 CLOB 필드에 저장.
- 장점:
- 데이터와 메타데이터를 함께 관리 가능.
- 트랜잭션 지원으로 데이터 일관성 보장.
- 단점:
- 대용량 파일 저장 시 데이터베이스 성능 저하.
- 백업 및 복구가 복잡.
데이터베이스 저장 예시
@Repository
public interface FileRepository extends JpaRepository<FileEntity, Long> {}
@Entity
public class FileEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String fileName;
@Lob
private byte[] data;
// Getters and Setters
}
@PostMapping("/upload")
public String uploadToDb(@RequestParam("file") MultipartFile file) throws IOException {
FileEntity fileEntity = new FileEntity();
fileEntity.setFileName(file.getOriginalFilename());
fileEntity.setData(file.getBytes());
fileRepository.save(fileEntity);
return "파일이 데이터베이스에 저장되었습니다.";
}
2. Spring Boot 파일 업로드 설정 전략
2.1 application.properties로 기본 설정
spring.servlet.multipart.enabled=true
spring.servlet.multipart.location=/var/uploads
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=50MB
설정 항목
- enabled: Multipart 요청 처리 활성화.
- location: 파일 임시 저장 경로.
- max-file-size: 업로드 파일 하나의 최대 크기.
- max-request-size: 요청 전체 크기(파일 + 폼 데이터 포함).
2.2 동적 저장 경로 설정
저장 경로를 동적으로 변경하려면 MultipartConfigElement를 사용합니다.
@Bean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
factory.setLocation("/dynamic/uploads");
factory.setMaxFileSize(DataSize.ofMegabytes(10)); // 10MB
factory.setMaxRequestSize(DataSize.ofMegabytes(50)); // 50MB
return factory.createMultipartConfig();
}
2.3 파일 저장 시 경로 생성
파일 업로드 시 저장 경로가 존재하지 않으면 동적으로 생성해야 합니다.
@PostConstruct
public void createUploadDir() {
File uploadDir = new File("/var/uploads");
if (!uploadDir.exists()) {
uploadDir.mkdirs(); // 디렉토리 생성
}
}
2.4 파일 이름 충돌 방지
같은 이름의 파일이 업로드되면 덮어씌워지는 문제가 발생할 수 있습니다. 이를 방지하기 위해 파일 이름을 고유하게 변경합니다.
UUID를 사용한 파일 이름 변경
String uniqueFileName = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
File dest = new File("/var/uploads/" + uniqueFileName);
file.transferTo(dest);
3. 파일 업로드 과정에서의 보안 고려 사항
3.1 허용된 파일 타입 검증
특정 파일 형식만 업로드 가능하도록 설정하여 악성 파일 업로드를 방지.
String contentType = file.getContentType();
if (!contentType.equals("image/png") && !contentType.equals("image/jpeg")) {
throw new IllegalArgumentException("허용되지 않은 파일 형식입니다.");
}
3.2 업로드 디렉토리 격리
업로드된 파일이 실행되지 않도록 별도의 디렉토리에 저장하고, 실행 권한을 제거.
chmod -R 700 /var/uploads
3.3 파일 크기 제한
application.properties에서 크기 제한 설정 외에도 추가 검증을 수행.
if (file.getSize() > 10 * 1024 * 1024) { // 10MB 제한
throw new IllegalArgumentException("파일 크기가 너무 큽니다.");
}
4. 파일 업로드 흐름 및 처리
4.1 파일 업로드 기본 흐름
- 클라이언트: HTML 폼 또는 API 요청으로 파일 업로드.
- Spring:
- MultipartResolver가 요청을 분석하고 MultipartFile 객체로 변환.
- 파일 저장: 컨트롤러에서 파일 저장 처리.
- 응답 반환: 업로드 성공 또는 실패 메시지 전달.
4.2 컨트롤러 구현 예제
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@RestController
@RequestMapping("/file")
public class FileController {
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return "파일이 선택되지 않았습니다.";
}
try {
String uploadDir = "/var/uploads/";
String uniqueFileName = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
File dest = new File(uploadDir + uniqueFileName);
file.transferTo(dest);
return "파일 업로드 성공: " + dest.getAbsolutePath();
} catch (IOException e) {
e.printStackTrace();
return "파일 업로드 실패";
}
}
}
업로드 전략 선택 기준
저장 위치 적합한 환경 예시 사용 사례
저장 위치 | 적합한 환경 | 예시 사용 사례 |
로컬 파일 시스템 | 단일 서버, 초기 개발 환경 | 간단한 이미지 업로드, 로그 파일 저장 |
외부 저장소 | 다중 서버, 고가용성 환경 | 대규모 웹 애플리케이션, 공유 문서 저장 시스템 |
클라우드 스토리지 | 글로벌 확장성, 무제한 저장소 필요 | 전자상거래, 사용자 생성 콘텐츠 플랫폼 |
데이터베이스 | 데이터 일관성, 파일 메타데이터와 함께 저장 필요 | 프로필 이미지, 보안 데이터 관리 |
'Spring' 카테고리의 다른 글
HttpServletRequest 객체에서 Parameter와 Attribute의 차이 (0) | 2024.12.23 |
---|---|
Spring Web MVC - WebMvcConfigurer (0) | 2024.12.23 |
Spring Web MVC - HandlerInterceptor (0) | 2024.12.23 |
리다이렉트(Redirect)와 포워드(Forward) (0) | 2024.12.23 |
Spring Web MVC - 모델(Model) 폼 데이터 처리 (0) | 2024.12.20 |