MultipartRequest

MultipartRequest를 사용한 다중 파일 업로드!

MultipartRequest

What & Why**

전체 흐름:

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

Why MultipartRequest vs DiskFileUpload?

  • MultipartRequest: 간단하고 직관적, 코드가 짧음
  • DiskFileUpload: 더 세밀한 제어 가능, 복잡함
  • 다중 파일: 한 번에 여러 파일 + 텍스트 처리

Key 차이점:

  • 자동 저장: MultipartRequest는 생성하는 순간 파일이 자동 저장됨
  • 웹앱 내부: resources/images 폴더에 저장 (웹에서 바로 접근 가능)

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="exam7_2">
        <p> 이름: <input type="text" name="name1">
        <p> 제목: <input type="text" name="subject1">
        <p> 파일: <input type="file" name="filename1">
        <p> <input type="submit" value="업로드">
    </form>
</body>
</html>

🔍 핵심 포인트:

  • action="exam7_2" ← 서블릿 이름 (자유롭게 변경 가능)
  • name="name1", "subject1", "filename1" ← 변수명 (자유롭게 변경 가능)

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

package chapter07;

import java.io.IOException;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import com.oreilly.servlet.MultipartRequest;  // ✨ 핵심!
import com.oreilly.servlet.multipart.DefaultFileRenamePolicy;  // ✨ 중복 파일명 처리

@WebServlet("/exam7_2")  // ← URL 패턴 (자유롭게 변경 가능)
public class exam7_2 extends HttpServlet {

    // GET: 폼 페이지 보여주기
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        System.out.println("7_2 doget 예제 연결.");

        RequestDispatcher ds = req.getRequestDispatcher("chapter07/fileupload02.jsp");
        ds.forward(req, resp);
    }

    // POST: 파일 업로드 처리 (단일 파일)
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        System.out.println("7_2 dopost 예제 연결.");

        // ✨ MultipartRequest 5개 매개변수 설정
        String save = req.getServletContext().getRealPath("/resources/images");  // 저장 경로
        int max = 1024*1024*5;  // 최대 크기 5MB (변경 가능)
        String encoding = "utf-8";  // 인코딩 (변경 가능)
        DefaultFileRenamePolicy rename = new DefaultFileRenamePolicy();  // 중복 파일명 처리

        // ✨ 핵심: MultipartRequest 생성 = 파일 자동 저장!
        MultipartRequest multi = new MultipartRequest(req, save, max, encoding, rename);

        // 데이터 가져오기
        String name1 = multi.getParameter("name1");
        String subject1 = multi.getParameter("subject1");
        String filename1 = multi.getFilesystemName("filename1");  // 파일명

        System.out.println("이름: " + name1 + ", 제목: " + subject1 + ", 파일: " + filename1);

        // JSP로 데이터 전달
        req.setAttribute("name1", name1);
        req.setAttribute("subject1", subject1);
        req.setAttribute("filename1", filename1);

        RequestDispatcher ds = req.getRequestDispatcher("chapter07/fileupload02_process.jsp");
        ds.forward(req, resp);
    }
}

🔍 핵심 포인트:

  • MultipartRequest 5개 매개변수: (request, 저장폴더, 크기, 인코딩, 이름중복정책)
  • 자동 저장: new MultipartRequest() 하는 순간 파일이 저장됨!
  • getParameter(): 텍스트 데이터
  • getFilesystemName(): 실제 저장된 파일명

📄 3단계: 결과 페이지

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>업로드 결과</title>
</head>
<body>
    <%
    String name1 = (String) request.getAttribute("name1");
    String subject1 = (String) request.getAttribute("subject1");
    String filename1 = (String) request.getAttribute("filename1");
    %>

    <h2>업로드 결과</h2>
    <h3>이름: <%= name1 %>, 제목: <%= subject1 %>, 파일: <%= filename1 %></h3>

    <!-- ✨ 이미지 표시 (웹앱 내부라서 바로 접근 가능!) -->
    <img src="/JSPBook/resources/images/<%= filename1 %>" width="300" height="300">

    <br><br>
    <a href="exam7_2">다시 업로드하기</a>
</body>
</html>

🔍 핵심 포인트:

  • 이미지 경로: /JSPBook/resources/images/파일명
  • 웹에서 바로 접근: resources 폴더는 웹에서 직접 접근 가능
  • C드라이브 vs 웹앱: DiskFileUpload는 C드라이브(웹 접근 불가), MultipartRequest는 웹앱 내부(웹 접근 가능)

4단계: 다중 파일로 확장 ⭐⭐⭐

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="exam7_2">
        <!-- ✨ 첫 번째 파일 세트 -->
        <p> 이름1: <input type="text" name="name1">
        <p> 제목1: <input type="text" name="subject1">
        <p> 파일1: <input type="file" name="filename1">

        <!-- ✨ 두 번째 파일 세트 -->
        <p> 이름2: <input type="text" name="name2">
        <p> 제목2: <input type="text" name="subject2">
        <p> 파일2: <input type="file" name="filename2">

        <!-- ✨ 세 번째 파일 세트 -->
        <p> 이름3: <input type="text" name="name3">
        <p> 제목3: <input type="text" name="subject3">
        <p> 파일3: <input type="file" name="filename3">

        <p> <input type="submit" value="파일올리기">
    </form>
</body>
</html>

🔍 변경사항:

  • name 속성: name1, name2, name3 / subject1, subject2, subject3 / filename1, filename2, filename3
  • 패턴: 숫자로 구분해서 여러 세트

4-2: 서블릿에서 다중 파일 처리

package chapter07;

import java.io.IOException;
import java.util.Enumeration;  // ✨ 추가
import java.util.HashMap;       // ✨ 추가

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import com.oreilly.servlet.MultipartRequest;
import com.oreilly.servlet.multipart.DefaultFileRenamePolicy;

@WebServlet("/exam7_2")
public class exam7_2 extends HttpServlet {

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        System.out.println("7_2 doget 예제 연결.");

        RequestDispatcher ds = req.getRequestDispatcher("chapter07/fileupload02.jsp");
        ds.forward(req, resp);
    }

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        System.out.println("7_2 dopost 예제 연결.");

        // MultipartRequest 설정 (동일)
        String save = req.getServletContext().getRealPath("/resources/images");
        System.out.println("저장 경로: " + save);
        int max = 1024*1024*5;  // 5MB
        String encoding = "utf-8";
        DefaultFileRenamePolicy rename = new DefaultFileRenamePolicy();
        MultipartRequest multi = new MultipartRequest(req, save, max, encoding, rename);

        // ✨ 방법 1: 직접 하나씩 가져오기
        String name1 = multi.getParameter("name1");
        String subject1 = multi.getParameter("subject1");
        String filename1 = multi.getFilesystemName("filename1");

        String name2 = multi.getParameter("name2");
        String subject2 = multi.getParameter("subject2");
        String filename2 = multi.getFilesystemName("filename2");

        String name3 = multi.getParameter("name3");
        String subject3 = multi.getParameter("subject3");
        String filename3 = multi.getFilesystemName("filename3");

        System.out.println("파일1: " + filename1);
        System.out.println("파일2: " + filename2);
        System.out.println("파일3: " + filename3);

        // ✨ 방법 2: Enumeration으로 모든 매개변수 확인 (디버깅용)
        Enumeration keys = multi.getParameterNames();
        HashMap<String,String> hm = new HashMap<String,String>();

        while(keys.hasMoreElements()) {
            String key = (String) keys.nextElement();
            String value = multi.getParameter(key);
            hm.put(key, value);
            System.out.println("키: " + key + ", 값: " + value);
        }

        // JSP로 데이터 전달
        req.setAttribute("name1", name1);
        req.setAttribute("subject1", subject1);
        req.setAttribute("filename1", filename1);

        req.setAttribute("name2", name2);
        req.setAttribute("subject2", subject2);
        req.setAttribute("filename2", filename2);

        req.setAttribute("name3", name3);
        req.setAttribute("subject3", subject3);
        req.setAttribute("filename3", filename3);

        RequestDispatcher ds = req.getRequestDispatcher("chapter07/fileupload02_process.jsp");
        ds.forward(req, resp);
    }
}

🔍 핵심 추가사항:

  • 방법 1: 직접 getParameter(), getFilesystemName() 하나씩
  • 방법 2: Enumeration으로 모든 매개변수 확인 (디버깅용)
  • HashMap: 데이터 관리 (필수는 아님)

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

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>다중 파일 업로드 결과</title>
</head>
<body>
    <%
    // ✨ 서블릿에서 전달받은 모든 데이터
    String name1 = (String) request.getAttribute("name1");
    String subject1 = (String) request.getAttribute("subject1");
    String filename1 = (String) request.getAttribute("filename1");

    String name2 = (String) request.getAttribute("name2");
    String subject2 = (String) request.getAttribute("subject2");
    String filename2 = (String) request.getAttribute("filename2");

    String name3 = (String) request.getAttribute("name3");
    String subject3 = (String) request.getAttribute("subject3");
    String filename3 = (String) request.getAttribute("filename3");
    %>

    <h2>다중 파일 업로드 결과</h2>

    <!-- ✨ 텍스트 정보 표시 -->
    <h3>이름1: <%= name1 %>, 제목1: <%= subject1 %>, 파일1: <%= filename1 %></h3>
    <h3>이름2: <%= name2 %>, 제목2: <%= subject2 %>, 파일2: <%= filename2 %></h3>
    <h3>이름3: <%= name3 %>, 제목3: <%= subject3 %>, 파일3: <%= filename3 %></h3>

    <!-- ✨ 이미지 표시 (3개 나란히) -->
    <div style="display: flex; gap: 10px;">
        <div>
            <h4>파일 1</h4>
            <img src="/JSPBook/resources/images/<%= filename1 %>" width="300" height="300">
        </div>
        <div>
            <h4>파일 2</h4>
            <img src="/JSPBook/resources/images/<%= filename2 %>" width="300" height="300">
        </div>
        <div>
            <h4>파일 3</h4>
            <img src="/JSPBook/resources/images/<%= filename3 %>" width="300" height="300">
        </div>
    </div>

    <br><br>
    <a href="exam7_2">다시 업로드하기</a>
</body>
</html>

🔍 핵심 포인트:

  • 개별 처리: 각 파일을 개별적으로 request.getAttribute()
  • 이미지 표시: /JSPBook/resources/images/파일명 경로로 바로 접근
  • 스타일: display: flex로 3개 이미지 나란히 배치

🎯 다음에 작성할 때 순서

Step 1: 단일 파일부터

  1. : 하나의 텍스트 + 하나의 파일
  2. 서블릿: MultipartRequest 기본 사용법
  3. 결과: 텍스트 + 이미지 1개 표시
  4. 테스트: 파일이 resources/images에 저장되는지 확인

Step 2: 다중 파일로 확장

  1. : name1, name2, name3... 패턴으로 확장
  2. 서블릿: 개별적으로 getParameter() 반복
  3. 결과: 여러 이미지 표시
  4. 테스트: 3개 파일 모두 잘 업로드되는지 확인

Step 3: 고급 기능

  • Enumeration: 모든 매개변수 동적 처리
  • 에러 처리: 파일 크기 초과, 빈 파일 등
  • 반복문: for문으로 코드 간소화

🔄 DiskFileUpload vs MultipartRequest 비교

구분 DiskFileUpload MultipartRequest
저장 위치 C드라이브 (외부) 웹앱 내부
이미지 표시 ❌ (웹 접근 불가) ✅ (바로 접근)
코드 복잡도 복잡 (Iterator 필요) 간단 (getParameter)
파일 저장 시점 item.write() 호출 시 객체 생성 시 자동
실무 용도 대용량, 외부 저장소 간단한 이미지 업로드

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

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

  • 서블릿 이름: exam7_2MultiFileUpload
  • 변수명: name1, name2, name3user1, user2, user3
  • 파일 크기: 1024*1024*5 → 다른 크기
  • 저장 경로: /resources/images/resources/uploads

❌ 정확히 써야 하는 것:

  • MultipartRequest 생성자 5개 매개변수 순서
  • getParameter() vs getFilesystemName() 구분
  • request.getAttribute()req.setAttribute() 이름 일치
  • enctype="multipart/form-data"