10 KiB
물론이죠! 아래는 **스프링 부트(Spring Boot)**에서의 파일 업로드, 멀티 파일 업로드, 파일 다운로드를 다루는 실무 중심의 설명 글입니다.
✅ 스프링 부트에서 파일 업로드 및 다운로드 구현하기
현대 웹 애플리케이션에서는 사용자가 이미지를 업로드하거나 문서를 다운로드하는 기능이 필수입니다. 스프링 부트는 이러한 기능을 손쉽게 구현할 수 있도록 다양한 API를 제공합니다.
이 글에서는 다음을 다룹니다:
- 단일 파일 업로드
- 다중(멀티) 파일 업로드
- 파일 다운로드
- 실무에서 주의할 점
📁 1. 의존성 설정 (build.gradle 또는 pom.xml)
스프링 부트에서는 기본적으로 spring-boot-starter-web만으로도 파일 업로드/다운로드가 가능합니다.
Gradle 예시:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
}
📤 2. 단일 파일 업로드
✅ 컨트롤러 예시
@RestController
@RequestMapping("/files")
public class FileUploadController {
private final Path uploadDir = Paths.get("uploads");
public FileUploadController() throws IOException {
Files.createDirectories(uploadDir);
}
@PostMapping("/upload")
public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) throws IOException {
if (file.isEmpty()) return ResponseEntity.badRequest().body("파일이 비어 있습니다");
Path targetPath = uploadDir.resolve(file.getOriginalFilename());
Files.copy(file.getInputStream(), targetPath, StandardCopyOption.REPLACE_EXISTING);
return ResponseEntity.ok("업로드 성공: " + file.getOriginalFilename());
}
}
🔍 설명
@RequestParam("file"): HTML<input type="file">의 name과 일치해야 합니다.MultipartFile: 업로드된 파일을 표현하는 객체입니다.Files.copy(...): 서버의 특정 디렉토리에 저장.
📤 3. 멀티 파일 업로드
✅ 컨트롤러 예시
@PostMapping("/upload-multiple")
public ResponseEntity<String> uploadMultiple(@RequestParam("files") List<MultipartFile> files) throws IOException {
if (files.isEmpty()) return ResponseEntity.badRequest().body("업로드된 파일이 없습니다.");
for (MultipartFile file : files) {
if (!file.isEmpty()) {
Path targetPath = uploadDir.resolve(file.getOriginalFilename());
Files.copy(file.getInputStream(), targetPath, StandardCopyOption.REPLACE_EXISTING);
}
}
return ResponseEntity.ok("멀티 파일 업로드 성공");
}
🔍 HTML에서 보내는 방법
<form method="post" enctype="multipart/form-data" action="/files/upload-multiple">
<input type="file" name="files" multiple>
<button type="submit">업로드</button>
</form>
📥 4. 파일 다운로드
✅ 컨트롤러 예시
@GetMapping("/download/{filename}")
public ResponseEntity<Resource> downloadFile(@PathVariable String filename) throws IOException {
Path filePath = uploadDir.resolve(filename);
if (!Files.exists(filePath)) {
return ResponseEntity.notFound().build();
}
Resource resource = new UrlResource(filePath.toUri());
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"")
.body(resource);
}
🔍 주요 포인트
UrlResource: 파일을 다운로드 가능한 형태로 변환Content-Disposition: 파일이 브라우저에 표시되지 않고 다운로드되도록 설정
⚠️ 실무에서 주의할 점
1. 파일 이름 중복 처리
UUID를 붙이거나 시간 기반으로 처리해야 파일 덮어쓰기 방지 가능
String safeName = UUID.randomUUID() + "_" + file.getOriginalFilename();
2. 저장 경로 보안
- 사용자 입력을 통한 경로 조작 공격 방지 (
../등) - 반드시 경로를 정규화 (
normalize())하고 업로드 디렉토리 밖으로 벗어나지 않도록 체크
Path normalized = uploadDir.resolve(file.getOriginalFilename()).normalize();
if (!normalized.startsWith(uploadDir)) {
throw new SecurityException("잘못된 경로입니다");
}
3. 용량 제한 설정
application.properties
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=20MB
✅ 마무리
| 기능 | 구현 여부 |
|---|---|
| 단일 파일 업로드 | ✅ |
| 멀티 파일 업로드 | ✅ |
| 파일 다운로드 | ✅ |
스프링 부트에서는 MultipartFile, Resource, ResponseEntity 등의 기본 컴포넌트를 통해 파일 업로드/다운로드 기능을 쉽게 구현할 수 있습니다. 다만 실무에서는 보안, 파일 크기 제한, 파일명 중복 등의 다양한 상황을 고려해야 합니다.
필요하다면 AWS S3, FTP, 혹은 DB BLOB 저장 방식도 활용 가능하며, 이 글은 로컬 저장소 기반의 기본 구현을 중심으로 설명했습니다.
더 확장하고 싶은 부분이 있으면 언제든지 말해주세요!
좋습니다! 이번엔 파일을 데이터베이스에 BLOB(Binary Large Object) 형태로 저장하고, 다시 꺼내서 다운로드하는 방식을 다룬 글을 정리해드릴게요.
🗃️ 스프링 부트에서 파일을 DB(BLOB)로 업로드 및 다운로드하기
웹 애플리케이션에서 파일을 **데이터베이스(BLOB 컬럼)**에 직접 저장하는 방식은 파일 보안이나 백업, 이식성 측면에서 유리할 수 있습니다. 이 글에서는 다음을 다룹니다:
- DB에 파일 업로드 (BLOB 저장)
- DB에서 파일 다운로드
- 실제 구현 예시 (Spring Boot + JPA + H2/MySQL)
📦 1. 테이블 설계 (DDL 예시)
✅ MySQL 예시
CREATE TABLE file_data (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
file_name VARCHAR(255),
content_type VARCHAR(100),
data LONGBLOB
);
data컬럼이 실제 파일의 바이트 데이터를 저장하는 BLOB 필드입니다.
🧱 2. 엔터티 클래스 정의
import jakarta.persistence.*;
@Entity
@Table(name = "file_data")
public class FileData {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String fileName;
private String contentType;
@Lob
@Column(columnDefinition = "LONGBLOB")
private byte[] data;
// 생성자, Getter/Setter 생략
}
@Lob어노테이션은byte[]데이터를 BLOB으로 매핑합니다.contentType은 다운로드할 때 MIME 타입을 알려주기 위해 사용합니다.
📂 3. 리포지토리 인터페이스
import org.springframework.data.jpa.repository.JpaRepository;
public interface FileDataRepository extends JpaRepository<FileData, Long> {
}
📤 4. 파일 업로드 (DB 저장)
@RestController
@RequestMapping("/files")
public class FileDataController {
private final FileDataRepository fileDataRepository;
public FileDataController(FileDataRepository repo) {
this.fileDataRepository = repo;
}
@PostMapping("/upload")
public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) throws IOException {
if (file.isEmpty()) return ResponseEntity.badRequest().body("빈 파일입니다");
FileData fileData = new FileData();
fileData.setFileName(file.getOriginalFilename());
fileData.setContentType(file.getContentType());
fileData.setData(file.getBytes());
fileDataRepository.save(fileData);
return ResponseEntity.ok("파일 업로드 성공: ID = " + fileData.getId());
}
}
📥 5. 파일 다운로드 (DB에서 BLOB 조회)
@GetMapping("/download/{id}")
public ResponseEntity<byte[]> downloadFile(@PathVariable Long id) {
return fileDataRepository.findById(id)
.map(file -> ResponseEntity.ok()
.contentType(MediaType.parseMediaType(file.getContentType()))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFileName() + "\"")
.body(file.getData()))
.orElse(ResponseEntity.notFound().build());
}
🧪 6. Postman 또는 HTML 테스트 예시
✅ HTML 업로드 폼
<form method="post" enctype="multipart/form-data" action="/files/upload">
<input type="file" name="file">
<button type="submit">업로드</button>
</form>
✅ 다운로드 링크 예시
<a href="/files/download/1">파일 다운로드</a>
⚠️ 실무에서 주의할 점
1. 성능 문제
- BLOB 방식은 대용량 파일 처리 시 성능 저하가 발생할 수 있음
→ 작은 이미지나 문서 위주에 적합
2. DB 백업 크기 증가
- 파일이 많아지면 DB 백업/복원 시간이 길어질 수 있음
3. 파일 크기 제한 설정
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=20MB
4. 파일 다운로드 속도
- 서버가 파일을 전부 로드해야 하므로, 큰 파일은 스트리밍 방식 처리를 고려할 것
✅ 정리
| 기능 | 구현 방식 |
|---|---|
| 파일 업로드 | MultipartFile → BLOB 저장 |
| 파일 다운로드 | byte[] → HTTP 응답 |
| 확장성/보안 | 파일 시스템보다 안전하나 대용량엔 부적합 가능 |
🔚 마무리
파일을 데이터베이스 BLOB에 저장하는 방식은 외부 파일 시스템 없이 관리가 간편하고, 트랜잭션 처리와 보안이 뛰어납니다. 단, 대용량 파일이 많을 경우에는 성능과 저장소 이슈를 고려하여 S3, 파일 시스템 저장 방식과 함께 혼합하여 쓰는 것이 좋습니다.
필요하다면 썸네일 저장, 이미지 미리보기 API, 스트리밍 다운로드까지 확장도 가능합니다. 원하시면 다음 단계도 이어서 도와드릴게요!