πŸ“Œ Spring 파일 μ—…λ‘œλ“œ & λ‹€μš΄λ‘œλ“œ μ™„μ „ 정볡

My Pale Blue DotΒ·2025λ…„ 4μ›” 28일
0

SPRING

λͺ©λ‘ 보기
24/36
post-thumbnail

πŸ“… λ‚ μ§œ

2025-04-28


πŸ“ ν•™μŠ΅ λ‚΄μš©

1️⃣ 파일 μ—…λ‘œλ“œ & λ‹€μš΄λ‘œλ“œ κ°œμš”

  • μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ 파일 μ—…λ‘œλ“œλž€ μ‚¬μš©μžκ°€ μ„œλ²„λ‘œ νŒŒμΌμ„ μ „μ†‘ν•˜λŠ” κ³Όμ •.
  • 파일 λ‹€μš΄λ‘œλ“œλŠ” μ„œλ²„μ— μ €μž₯된 νŒŒμΌμ„ μ‚¬μš©μžμ—κ²Œ λ‹€μ‹œ μ „μ†‘ν•˜λŠ” κ³Όμ •.
  • 주둜 μ‚¬μš©ν•˜λŠ” ν˜•μ‹: multipart/form-data
  • HTTP λ©”μ„œλ“œ:
    • μ—…λ‘œλ“œ ➑️ POST
    • λ‹€μš΄λ‘œλ“œ ➑️ GET

2️⃣ μ—…λ‘œλ“œλ₯Ό μœ„ν•œ ν™˜κ²½ μ€€λΉ„

βœ… pom.xml μ˜μ‘΄μ„± μ„€μ •

파일 μ—…λ‘œλ“œλ₯Ό μœ„ν•΄ Apache Commons 라이브러리λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

<!-- 파일 μ—…λ‘œλ“œ 지원 (commons-fileupload, commons-io) -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.8.0</version>
</dependency>

3️⃣ Java Config μ„€μ • (WebMvcConfig)

βœ… servlet-context.xml을 λŒ€μ²΄ν•˜λŠ” μ„€μ • 클래슀

  • 파일 μ—…λ‘œλ“œλ₯Ό μœ„ν•œ MultipartResolver 빈 등둝
  • ViewResolver μ„€μ •
  • 정적 λ¦¬μ†ŒμŠ€ 경둜 λ§€ν•‘
@Bean
public MultipartResolver multipartResolver() {
    CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
    multipartResolver.setMaxUploadSize(20971520); 			// 20MB
    multipartResolver.setMaxUploadSizePerFile(20971520); 	// 20MB
    multipartResolver.setMaxInMemorySize(20971520); 		// 20MB
    return multipartResolver;
}

4️⃣ JSP 파일 μ—…λ‘œλ“œ 폼 κ΅¬ν˜„

βœ… multipart/form-data μ„€μ • ν•„μˆ˜

<form action="${pageContext.request.contextPath }/file/upload" method="post" enctype="multipart/form-data">
	<input type="file" name="files" multiple/>
	<button>전솑</button>
</form>

5️⃣ 파일 μ—…λ‘œλ“œ 컨트둀러 κ΅¬ν˜„

βœ… 곡톡 μ—…λ‘œλ“œ 둜직 (λ©”μ„œλ“œ 뢄리 μ˜ˆμ‹œ)

λ°˜λ³΅λ˜λŠ” 폴더 생성 및 μ €μž₯ λ‘œμ§μ€ λ©”μ„œλ“œλ‘œ λΆ„λ¦¬ν•˜λŠ” 것이 μœ μ§€λ³΄μˆ˜μ— μœ λ¦¬ν•©λ‹ˆλ‹€.

private String createUploadFolder() {
	LocalDateTime now = LocalDateTime.now();
	String folderName = now.format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
	String path = ROOT_PATH + File.separator + UPLOAD_PATH + File.separator + folderName + File.separator;
	File dir = new File(path);
	if (!dir.exists()) dir.mkdirs();
	return path;
}

private void saveFiles(MultipartFile[] files, String path) {
	for (MultipartFile file : files) {
		try {
			File fileObject = new File(path, file.getOriginalFilename());
			file.transferTo(fileObject);
		} catch (IOException e) {
			log.error("파일 μ €μž₯ μ‹€νŒ¨: " + file.getOriginalFilename(), e);
		}
	}
}

βœ… κΈ°λ³Έ μ—…λ‘œλ“œ 처리

@PostMapping("/upload")
public String upload(@RequestParam("files") MultipartFile[] files) {
	String path = createUploadFolder();
	saveFiles(files, path);
	return "file/upload";
}

βœ… DTO 기반 μ—…λ‘œλ“œ 처리

@PostMapping("/upload_dto")
public String upload_dto(FileDto dto) {
	String path = createUploadFolder();
	saveFiles(dto.getFiles(), path);
	return "file/upload";
}

πŸ”₯ 정리

  • 파일 μ—…λ‘œλ“œ μ‹œ λ°˜λ“œμ‹œ multipart/form-data와 MultipartResolver μ„€μ • ν•„μš”.
  • 동적 폴더 μƒμ„±μœΌλ‘œ 파일 관리 체계화.
  • μ»¨νŠΈλ‘€λŸ¬μ— μ§‘μ€‘λœ λ‘œμ§μ€ μ„œλΉ„μŠ€ κ³„μΈ΅μœΌλ‘œ λΆ„λ¦¬ν•˜μ—¬ μœ μ§€λ³΄μˆ˜μ„±μ„ λ†’μ΄μž.
  • μ—…λ‘œλ“œ 파일λͺ… 좩돌 λ°©μ§€λ₯Ό μœ„ν•΄ UUIDλ₯Ό ν™œμš©ν•˜λŠ” 것이 μ•ˆμ „.
  • 파일 ν™•μž₯자 및 크기 μ œν•œμ„ 톡해 λ³΄μ•ˆ 취약점 예방.
  • μ˜ˆμ™Έ μ²˜λ¦¬μ™€ μ—…λ‘œλ“œ ν›„ μ‚¬μš©μžμ—κ²Œ μ μ ˆν•œ 응닡 νŽ˜μ΄μ§€ 제곡 κ³ λ €.
  • DTO ν™œμš© μ‹œ 폼 데이터 관리가 더 κΉ”λ”ν•˜κ³  ν™•μž₯성이 높아짐.

✨ λ‹€μš΄λ‘œλ“œ κΈ°λŠ₯은 λ‹€μŒ ν¬μŠ€νŒ…μ—μ„œ μžμ„Ένžˆ λ‹€λ£¨κ² μŠ΅λ‹ˆλ‹€!


πŸ”— μ°Έκ³  자료


profile
Here, My Pale Blue.🌏

0개의 λŒ“κΈ€