πŸ“Œβ€νŒŒμΌ ν•˜λ‚˜ μ €μž₯ν•˜λŠ” 일에도, ν™•μž₯μ„±κ³Ό λ³΄μ•ˆμ„ λ‹΄μ•˜λ‹€ – FileUploadUtil 섀계기”

πŸ—“ 2025λ…„ 4μ›” 28일 ✍️ by 박찬희

🧭 μ™œ λ§Œλ“€μ—ˆλ‚˜? λ‹¨μˆœ μ €μž₯μœΌλ‘œλŠ” λΆ€μ‘±ν–ˆλ‹€

κ°•μ˜ ν”Œλž«νΌμ—μ„  파일 μ—…λ‘œλ“œκ°€ 일상이닀.

썸넀일, μ˜μƒ, μžλ§‰, PDF λ“± 각기 λ‹€λ₯Έ λ¦¬μ†ŒμŠ€λ“€μ΄ μ‚¬μš©μž 손을 타고 μ„œλ²„μ— μ €μž₯λœλ‹€.

그런데, λ‹¨μˆœνžˆ FileOutputStream으둜 μ €μž₯만 ν•œλ‹€λ©΄?

κ·Έλž˜μ„œ λ‚˜λŠ” β€˜μ§„μ§œ μœ ν‹Έλ¦¬ν‹°λ‹΅κ²Œ μž‘λ™ν•˜λŠ” 파일 μ €μž₯ ν΄λž˜μŠ€β€™λ₯Ό λ§Œλ“€κΈ°λ‘œ ν–ˆλ‹€.

경둜 관리, λ³΄μ•ˆ, ν™•μž₯μ„±, JSP μΆ”μƒν™”κΉŒμ§€ λͺ¨λ‘ ν•œ λ²ˆμ— μž‘μ„ 수 μžˆλ„λ‘.


🎯 κ΅¬ν˜„ λͺ©ν‘œ μš”μ•½

μš”κ΅¬μ‚¬ν•­ μ„€λͺ…
πŸ“ κ΅¬μ‘°ν™”λœ μ €μž₯ 경둜 thumb/, video/, subtitle/ λ“±μœΌλ‘œ ꡬ뢄 μ €μž₯
πŸ”‘ UUID 파일λͺ… 쀑볡 λ°©μ§€ + μ‚¬μš©μž 파일λͺ… λ³΄μ•ˆ 좔상화
🌐 JSP μ ‘κ·Ό 경둜 μžλ™ 생성 μ„œλ²„ 디렉토리 ꡬ쑰와 λ¬΄κ΄€ν•œ /upload/... 경둜 λ°˜ν™˜
πŸ’₯ μ˜ˆμ™Έ 처리 μ €μž₯ μ‹€νŒ¨μ‹œ μ •ν™•ν•œ μ˜ˆμ™Έ throw
πŸ”§ ν™•μž₯μ„± 둜컬 μ™Έ S3, NAS λ“±μœΌλ‘œ μ‰½κ²Œ μ „ν™˜ κ°€λŠ₯ν•΄μ•Ό 함

🧩 κ΅¬ν˜„ μ½”λ“œ (핡심 μš”μ•½)

public class FileUploadUtil {

  public static String saveFileToLocal(String subDir, String fileName, byte[] fileBytes, String baseDir) throws IOException {
    File dir = new File(baseDir + "/" + subDir);
    if (!dir.exists()) dir.mkdirs();  // ⛏ ν•˜μœ„ λ””λ ‰ν† λ¦¬κΉŒμ§€ μžλ™ 생성

    File file = new File(dir, fileName);
    try (FileOutputStream fos = new FileOutputStream(file)) {
      fos.write(fileBytes);  // βœ… μ‹€μ œ 파일 μ €μž₯
    }

    return "/upload/" + subDir + "/" + fileName;  // 🌐 JSP μ ‘κ·Όμš© μƒλŒ€ 경둜 λ°˜ν™˜
  }
}

πŸ’‘ κ΅¬ν˜„ μ² ν•™


πŸ” λ³΄μ•ˆμ„ κ³ λ €ν•œ 섀계 μš”μ†Œ

λ³΄μ•ˆ 리슀크 λŒ€μ‘ μ „λž΅
디렉토리 νŠΈλž˜λ²„μ„€ (../) subDir, fileNameμ—μ„œ .. λ“± 특수 문자 필터링 (μΆ”ν›„ κ°œμ„  κ°€λŠ₯)
μ‹€ν–‰ 파일 μ—…λ‘œλ“œ .exe, .jsp λ“± ν—ˆμš©λ˜μ§€ μ•Šμ€ ν™•μž₯자 β†’ Controllerμ—μ„œ reject
μ €μž₯ 경둜 λ…ΈμΆœ /upload/**λŠ” Tomcat static λ¦¬μ†ŒμŠ€λ‘œλ§Œ λ§€ν•‘, λ‚΄λΆ€ μ €μž₯ κ΅¬μ‘°λŠ” 감좀
ν•˜λ“œμ½”λ”© μœ„ν—˜ baseDir은 application.properties λ“±μœΌλ‘œ μ™ΈλΆ€ μ„€μ •ν™” μ˜ˆμ •

πŸ§ͺ ν…ŒμŠ€νŠΈ μ‹œλ‚˜λ¦¬μ˜€ & 검증 κ²°κ³Ό

μ‹œλ‚˜λ¦¬μ˜€ κΈ°λŒ€ κ²°κ³Ό
썸넀일 μ €μž₯ /upload/thumb/lecture-uuid.png 경둜 λ°˜ν™˜
10MB μ˜μƒ μ €μž₯ C:/lecture_uploads/video/uuid.mp4 정상 μ €μž₯ 확인
λ””μŠ€ν¬ full IOException λ°œμƒ β†’ μ»¨νŠΈλ‘€λŸ¬μ—μ„œ μ‚¬μš©μž μ—λŸ¬ 처리
ν•œκΈ€ 파일λͺ… ν•œκΈ€κ°•μ˜.mp4 문제 없이 μ €μž₯ (UTF-8 보μž₯ ν™˜κ²½)

🧱 μ‹€μ œ μ‚¬μš© μ˜ˆμ‹œ

πŸ’Ό Controller 단

String uuid = UUID.randomUUID().toString();
String fileName = "lecture-" + uuid + ".jpg";
String savedUrl = FileUploadUtil.saveFileToLocal("thumb", fileName, imageBytes, BASE_DIR);

πŸ–Ό JSP 단

<img src="${savedUrl}" alt="κ°•μ˜ 썸넀일">

βœ… JSPλŠ” 더 이상 μ €μž₯ 경둜λ₯Ό λͺ°λΌλ„ λœλ‹€.

단지 /upload/둜 μ‹œμž‘ν•˜λŠ” μƒλŒ€ URL만 μ•Œλ©΄ 끝이닀.


🧠 기술적 ν‚€μ›Œλ“œ μš”μ•½

ν‚€μ›Œλ“œ 의미
FileOutputStream Java I/O 기반 파일 μ €μž₯의 κΈ°λ³Έ
try-with-resources μžμ› μžλ™ ν•΄μ œ β†’ λ©”λͺ¨λ¦¬ λˆ„μˆ˜ 예방
mkdirs() μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” λͺ¨λ“  ν•˜μœ„ λ””λ ‰ν† λ¦¬κΉŒμ§€ 생성
JSP 경둜 좔상화 μ €μž₯μ†Œ κ²½λ‘œμ™€ ν΄λΌμ΄μ–ΈνŠΈ μ ‘κ·Ό 경둜 뢄리
순수 μœ ν‹Έλ¦¬ν‹°ν™” μƒνƒœ μ—†λŠ” static ν•¨μˆ˜ β†’ ν…ŒμŠ€νŠΈμ™€ ν™•μž₯에 졜적

🌱 ν–₯ν›„ ν™•μž₯ κ³„νš


βœ… μ΅œμ’… κ²°κ³Ό & 회고


β€œνŒŒμΌ μ €μž₯은 λ‹¨μˆœν•œ μž‘μ—…μ²˜λŸΌ λ³΄μ΄μ§€λ§Œ,

경둜 섀계, μ˜ˆμ™Έ 흐름, λ³΄μ•ˆ, 좔상화λ₯Ό κ³ λ―Όν•˜μ§€ μ•ŠμœΌλ©΄ κΈˆμ„Έ μœ μ§€λ³΄μˆ˜ μ§€μ˜₯이 λœλ‹€.”

이 μœ ν‹Έ ν•˜λ‚˜λ‘œ, 파일 μ €μž₯ λ‘œμ§μ€ 이제 더 이상 λ‚˜λ₯Ό κ΄΄λ‘­νžˆμ§€ μ•ŠλŠ”λ‹€.