개발/Spring Boot
Spring Boot 시리즈 12편 – 파일 업로드 처리 전략: 이미지, 문서 업로드부터 S3 연동까지
B컷개발자
2025. 4. 26. 00:01
728x90
SMALL
Spring Boot에서 파일 업로드를 처리하는 전략을 소개합니다. 로컬 저장, 멀티파트 파일 처리, AWS S3 연동까지 실전 예제와 보안 고려사항을 함께 제공합니다.
Spring Boot 시리즈 12편 – 파일 업로드 처리 전략: 이미지, 문서 업로드부터 S3 연동까지
사용자 프로필 이미지, 게시글 첨부 파일, 문서 스캔 등
웹 서비스에서 파일 업로드는 거의 모든 도메인에서 요구되는 기능입니다.
이번 글에서는 Spring Boot에서 파일을 안전하게 업로드하고 저장하는 방법을,
- 로컬 파일 시스템 기반
- AWS S3 같은 외부 저장소 기반
- 으로 나누어 설계 → 구현 → 보안 → 유지보수 전략까지 통합적으로 다루어보겠습니다.
📌 1. 파일 업로드 처리 방식
방식설명특징
로컬 저장 | 서버 디렉토리에 파일 저장 | 빠르고 설정 간단, 확장성 낮음 |
외부 저장소 (S3) | 클라우드 스토리지에 저장 | 확장성 ↑, 보안 ↑, 유지보수 유리 |
DB 저장 | DB에 BLOB로 저장 | 비추천, 속도↓, 트래픽↑ |
✅ 2. 멀티파트 파일 기본 처리
1️⃣ Controller 구성
@RestController
@RequestMapping("/api/files")
public class FileUploadController {
@PostMapping("/upload")
public ResponseEntity<ApiResponse<String>> upload(@RequestPart MultipartFile file) throws IOException {
String fileName = file.getOriginalFilename();
String path = "/upload-dir/" + UUID.randomUUID() + "_" + fileName;
file.transferTo(new File(path));
return ResponseEntity.ok(ApiResponse.success("파일 업로드 성공: " + path));
}
}
기본 설정만으로도 Spring Boot는 MultipartFile을 자동 처리합니다.
2️⃣ application.yml 설정
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 20MB
- 업로드 용량 제한 설정 필수
- 대용량 파일 처리 시 파일 스트리밍 방식 고려 필요
🔐 3. 파일 저장 시 보안 고려사항
항목권장 설계
저장 경로 제한 | 외부 접근이 불가능한 서버 디렉토리 활용 |
확장자 제한 | .exe, .sh 등 실행 파일 차단 |
파일명 변경 | UUID 등으로 랜덤화 → 충돌 방지 |
파일 MIME 검사 | file.getContentType()으로 서버단 확인 |
업로드 전 인증 | 반드시 로그인 사용자만 가능하도록 제한 |
☁️ 4. AWS S3 연동 파일 업로드
1️⃣ 의존성 추가 (Gradle)
implementation 'software.amazon.awssdk:s3:2.20.40'
2️⃣ S3Config 설정
@Configuration
public class S3Config {
@Value("${cloud.aws.s3.bucket}")
private String bucket;
@Bean
public S3Client s3Client() {
return S3Client.builder()
.region(Region.AP_NORTHEAST_2) // 서울 리전
.credentialsProvider(ProfileCredentialsProvider.create())
.build();
}
@Bean
public String bucketName() {
return bucket;
}
}
3️⃣ S3 업로드 서비스 구현
@Service
@RequiredArgsConstructor
public class S3FileService {
private final S3Client s3Client;
private final String bucketName;
public String upload(MultipartFile file) throws IOException {
String key = "uploads/" + UUID.randomUUID() + "_" + file.getOriginalFilename();
PutObjectRequest putRequest = PutObjectRequest.builder()
.bucket(bucketName)
.key(key)
.acl(ObjectCannedACL.PUBLIC_READ) // 공개 여부 설정
.build();
s3Client.putObject(putRequest, RequestBody.fromInputStream(file.getInputStream(), file.getSize()));
return s3Client.utilities().getUrl(builder -> builder.bucket(bucketName).key(key)).toExternalForm();
}
}
4️⃣ Controller에서 호출
@PostMapping("/upload-s3")
public ResponseEntity<ApiResponse<String>> uploadToS3(@RequestPart MultipartFile file) throws IOException {
String fileUrl = s3FileService.upload(file);
return ResponseEntity.ok(ApiResponse.success(fileUrl));
}
🧠 실무 설계 팁
항목전략
고속 업로드 | 클라이언트에서 S3 Pre-signed URL 방식 활용 (권장) |
삭제 처리 | API → key → S3 delete 호출 필요 |
썸네일 생성 | 이미지 업로드 시 썸네일 서비스 별도 구성 가능 |
DB 저장 | 실제 파일은 URL만 저장 (S3 key 또는 full URL) |
파일 그룹화 | 사용자별 prefix (user/123/avatar.png) 관리로 정리 |
✅ 마무리 요약
항목요약
기본 처리 | MultipartFile → file.transferTo() |
용량 제한 | application.yml로 설정 |
로컬 저장 vs S3 | 빠른 개발 vs 확장성, 보안, 유지보수성 |
보안 고려 | 확장자 제한, 인증 체크, 경로 보호 |
실무 연동 | AWS SDK 기반 파일 업로드, URL 생성 및 공개 처리 |
📌 다음 편 예고
Spring Boot 시리즈 13편: 스케줄러와 배치 처리 전략 – Spring Task와 Quartz로 구현하는 실무 배치 구조
728x90
LIST