DiskFileUpload 순서도 (시험 X)

📚 기본 이해: What & Why

전체 흐름:

사용자 → 폼(JSP) → 서블릿 → 결과페이지(JSP)

Why 파일 업로드가 특별한가?

  • 일반 텍스트: application/x-www-form-urlencoded
  • 파일 업로드: multipart/form-data (특별한 형식 필요)
  • DiskFileUpload: C드라이브 같은 외부 디스크에 저장하는 실무 방식

🚀 1단계: 가장 기본 폼부터

Why 폼부터?

가장 쉽고, 눈으로 바로 확인 가능

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>파일 업로드</title>
</head>
<body>
  <h2>파일을 선택하세요</h2>
  <form method="post" action="fileupload">
    <p> 이름: <input type="text" name="name">
    <p> 파일: <input type="file" name="filename">
    <p> <input type="submit" value="업로드">
  </form>
</body>
</html>

🔍 핵심 포인트:

  • action="fileupload" ← 서블릿 이름 (자유롭게 변경 가능)
  • name="filename" ← 변수명 (자유롭게 변경 가능)
  • 아직 enctype 없음 ← 나중에 추가할 예정

🛠️ 2단계: 서블릿 뼈대만 ⭐⭐

Why 뼈대부터?

복잡한 파일 처리 말고, 일단 폼과 연결되는지 확인

package fileupload;

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;
import java.io.*;

@WebServlet("/fileupload")  // ← URL 패턴 (자유롭게 변경 가능)
public class FileUploadServlet extends HttpServlet {  // ← 클래스명 (자유롭게 변경 가능)

    // GET: 폼 페이지 보여주기
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        RequestDispatcher dispatcher = req.getRequestDispatcher("fileupload.jsp");
        dispatcher.forward(req, resp);
    }

    // POST: 데이터 받기 (일단 간단하게)
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {

        req.setCharacterEncoding("UTF-8");  // 한글 깨짐 방지

        // 테스트용: 텍스트만 받아보기
        String name = req.getParameter("name");
        req.setAttribute("message", "안녕하세요 " + name + "님!");

        RequestDispatcher dispatcher = req.getRequestDispatcher("result.jsp");
        dispatcher.forward(req, resp);
    }
}

🔍 핵심 포인트:

  • doGet: 폼 보여주는 역할
  • doPost: 데이터 받는 역할
  • 아직 파일 처리 없음 ← 나중에 추가

📄 3단계: 결과 페이지 (간단 버전)

Why 간단 버전부터?

서블릿에서 데이터가 잘 넘어오는지 확인

<%@ page contentType="text/html; charset=utf-8" %>
<html>
<head>
<title>업로드 결과</title>
</head>
<body>
<h2>결과 확인</h2>
<%
    String message = (String) request.getAttribute("message");
    if(message != null) {
        out.println(message);
    }
%>
<br><br>
<a href="fileupload">다시 해보기</a>
</body>
</html>

🔍 핵심 포인트:

  • request.getAttribute("message") ← 서블릿에서 보낸 데이터 받기
  • 서블릿 ↔ JSP 연결 확인

4단계: 파일 업로드 추가 ⭐⭐⭐

Why 이제 파일?

기본 연결이 되면 이제 파일 처리 추가

4-1: 폼에 파일 업로드 설정 추가

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>파일 업로드</title>
</head>
<body>
  <h2>파일을 선택하세요</h2>
  <!-- ✨ 여기가 추가됨! -->
  <form method="post" enctype="multipart/form-data" action="fileupload">
    <p> 이름: <input type="text" name="name">
    <p> 파일: <input type="file" name="filename">
    <p> <input type="submit" value="업로드">
  </form>
</body>
</html>

🔍 변경사항:

  • enctype="multipart/form-data"필수! 파일 업로드용

4-2: 서블릿에 파일 처리 추가

package fileupload;

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;
import java.io.*;
import java.util.*;  // ✨ 추가
import org.apache.commons.fileupload.*;  // ✨ 추가

@WebServlet("/fileupload")
public class FileUploadServlet extends HttpServlet {

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        RequestDispatcher dispatcher = req.getRequestDispatcher("fileupload.jsp");
        dispatcher.forward(req, resp);
    }

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {

        req.setCharacterEncoding("UTF-8");

        // ✨ 여기부터 파일 처리 추가!
        String path = "C:\\upload";  // 저장할 폴더 (자유롭게 변경 가능)

        // 폴더 생성
        File uploadDir = new File(path);
        if (!uploadDir.exists()) {
            uploadDir.mkdirs();
        }

        // DiskFileUpload 설정
        DiskFileUpload upload = new DiskFileUpload();
        upload.setSizeMax(1000000);      // 최대 크기 1MB (변경 가능)
        upload.setSizeThreshold(4096);   // 메모리 임계값 (변경 가능)
        upload.setRepositoryPath(path);

        try {
            List items = upload.parseRequest(req);  // 파일 받기

            req.setAttribute("items", items);
            req.setAttribute("uploadPath", path);

        } catch(Exception e) {
            req.setAttribute("error", e.getMessage());
        }

        RequestDispatcher dispatcher = req.getRequestDispatcher("result.jsp");
        dispatcher.forward(req, resp);
    }
}

🔍 핵심 추가사항:

  • import 두 개 추가
  • C드라이브 폴더 생성 로직
  • DiskFileUpload 설정 및 파일 받기

📊 5단계: 결과 페이지에서 파일 정보 표시 ⭐⭐⭐⭐

Why 복잡해보이나?

파일과 텍스트가 섞여서 와서 구분해서 처리해야 함

<%@ page contentType="text/html; charset=utf-8" %>
<%@ page import="org.apache.commons.fileupload.*" %>  <!-- ✨ 추가 -->
<%@ page import="java.io.*" %>                        <!-- ✨ 추가 -->
<%@ page import="java.util.*" %>                      <!-- ✨ 추가 -->
<html>
<head>
<title>업로드 결과</title>
</head>
<body>
<h2>업로드 결과</h2>
<%
    // 1단계: 서블릿에서 데이터 받기
    List items = (List) request.getAttribute("items");
    String path = (String) request.getAttribute("uploadPath");
    String error = (String) request.getAttribute("error");

    // 2단계: 에러 체크
    if(error != null) {
        out.println("오류: " + error);
    } else if(items != null) {

        // 3단계: 파일 목록을 하나씩 처리
        Iterator params = items.iterator();

        while (params.hasNext()) {
            FileItem item = (FileItem) params.next();

            // 4단계: 텍스트 vs 파일 구분
            if (item.isFormField()) {
                // 텍스트 필드 (이름 등)
                String name = item.getFieldName();
                String value = item.getString("utf-8");
                out.println(name + " = " + value + "<br>");
            } else {
                // 파일 필드
                String fileFieldName = item.getFieldName();
                String fileName = item.getName();
                String contentType = item.getContentType();

                if(fileName != null && !fileName.equals("")) {
                    // 5단계: 파일명 정리 (경로 제거)
                    fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
                    long fileSize = item.getSize();

                    // 6단계: 실제 파일 저장
                    File file = new File(path + "/" + fileName);
                    item.write(file);

                    // 7단계: 결과 출력
                    out.println("------------------------------------------<br>");
                    out.println("요청 파라미터 이름 : " + fileFieldName + "<br>");
                    out.println("저장 파일 이름 : " + fileName + "<br>");
                    out.println("파일 콘텐츠 유형 : " + contentType + "<br>");
                    out.println("파일 크기 : " + fileSize + "<br>");
                    out.println("C드라이브 저장 완료: " + path + "/" + fileName);
                }
            }
        }
    }
%>
<br><br>
<a href="fileupload">다시 업로드하기</a>
</body>
</html>

🔍 단계별 이해:

  1. 데이터 받기: 서블릿에서 보낸 items, path, error 받기
  2. 에러 체크: 문제 있으면 에러 메시지 출력
  3. 반복 처리: Iterator로 업로드된 항목들 하나씩 처리
  4. 구분 처리: 텍스트(isFormField())와 파일 구분
  5. 파일명 정리: Windows 경로 제거
  6. 실제 저장: item.write(file)로 C드라이브에 저장
  7. 결과 출력: 파일 정보 화면에 표시

🎯 다음에 작성할 때 순서

Step 1: 기본 연결부터 확인

  1. 폼 (파일 업로드 설정 없이)
  2. 서블릿 뼈대 (파일 처리 없이)
  3. 결과 페이지 (간단하게)
  4. 테스트: 텍스트만 잘 전달되는지 확인

Step 2: 파일 업로드 추가

  1. 폼에 enctype="multipart/form-data" 추가
  2. 서블릿에 DiskFileUpload 추가
  3. 결과 페이지에 파일 처리 로직 추가
  4. 테스트: C드라이브에 파일이 저장되는지 확인

Step 3: 완성도 높이기

  • 에러 처리 강화
  • 파일 크기 제한
  • 이미지만 업로드 가능하게 등

🔄 자유롭게 변경 가능한 것들

✅ 마음대로 바꿔도 되는 것:

  • 서블릿 이름: fileuploadFileUpload
  • 클래스명: FileUploadServletUploadHandler
  • 변수명: name, filenameuserName, uploadFile
  • 폴더 경로: C:\uploadD:\myfiles
  • 파일 크기: setSizeMax(1000000) → 다른 크기

❌ 정확히 써야 하는 것:

  • enctype="multipart/form-data"
  • DiskFileUpload 클래스명
  • parseRequest(), write() 메서드명
  • @WebServlet 형식
  • request.getAttribute()req.setAttribute() 이름 일치

🚨 자주 하는 실수들

1. enctype 빼먹기

<!-- ❌ 틀림 -->
<form method="post" action="fileupload">

<!-- ✅ 맞음 -->
<form method="post" enctype="multipart/form-data" action="fileupload">

2. import 빼먹기

// ❌ 이것들 없으면 에러
import org.apache.commons.fileupload.*;
import java.util.*;

3. 폴더 생성 안하기

// ✅ 폴더 없으면 만들어주기
File uploadDir = new File(path);
if (!uploadDir.exists()) {
    uploadDir.mkdirs();
}