HashMap 서블릿 코드 (exam7_4.java) 해석

1. 서블릿 코드 (exam7_4.java) 해석

패키지와 임포트

package chapter07;
// WHY: 파일을 그룹화하여 관리하기 위해
// WHAT: 이 클래스가 chapter07 폴더에 속한다는 의미

import java.io.*;           // File, IOException 등 파일 관련 클래스
import java.util.*;         // List, Iterator 등 컬렉션 클래스
import jakarta.servlet.*;   // 서블릿 기본 클래스들
import jakarta.servlet.annotation.WebServlet;  // @WebServlet 어노테이션
import jakarta.servlet.http.*;  // HttpServlet, HttpServletRequest 등
import org.apache.commons.fileupload.*;  // DiskFileUpload, FileItem 등

클래스 선언과 어노테이션

@WebServlet("/exam7_4")
// WHY: web.xml에 매핑 설정 안 하고 어노테이션으로 간단히 URL 매핑
// WHAT: 브라우저에서 /exam7_4로 요청하면 이 서블릿이 처리

public class exam7_4 extends HttpServlet {
// WHY: HTTP 요청을 처리하기 위해 HttpServlet을 상속
// WHAT: exam7_4라는 이름의 서블릿 클래스 생성

doGet 메소드

protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
        throws ServletException, IOException {
// WHY: GET 요청(폼 페이지 보여주기)을 처리하기 위해
// WHAT: req=요청정보, resp=응답정보를 매개변수로 받음

    RequestDispatcher dispatcher = req.getRequestDispatcher("chapter07/fileupload04.jsp");
    // WHY: 다른 JSP 페이지로 요청을 전달하기 위해
    // WHAT: dispatcher = 배송원, fileupload04.jsp로 이동할 준비

    dispatcher.forward(req, resp);
    // WHY: 실제로 JSP 페이지를 보여주기 위해
    // WHAT: 요청과 응답을 JSP에게 전달
}

doPost 메소드 - 변수 설정

protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
        throws ServletException, IOException {
// WHY: POST 요청(파일 업로드)을 처리하기 위해

    String path = "C:\\upload";
    // WHY: 파일을 저장할 위치를 정하기 위해
    // WHAT: path = 경로, C드라이브의 upload 폴더
    // 변수명 이유: 파일 경로를 나타내는 일반적인 이름

    File uploadDir = new File(path);
    // WHY: 폴더가 존재하는지 확인하고 생성하기 위해
    // WHAT: uploadDir = 업로드 디렉토리, File 객체로 생성
    // 변수명 이유: upload + Directory의 줄임말

    if (!uploadDir.exists()) {
        uploadDir.mkdirs();
    }
    // WHY: 폴더가 없으면 만들어야 파일 저장 가능
    // WHAT: exists()=존재하는지 확인, mkdirs()=폴더 생성

파일 업로드 처리

    DiskFileUpload upload = new DiskFileUpload();
    // WHY: 파일 업로드를 처리하는 객체가 필요해서
    // WHAT: upload = 업로드 처리기, 디스크에 파일 저장 방식
    // 변수명 이유: 업로드 기능을 담당한다는 의미

    try {
        List items = upload.parseRequest(req);
        // WHY: 요청에서 폼 데이터와 파일을 분리해서 추출하기 위해
        // WHAT: items = 항목들, 폼의 모든 입력값들을 리스트로 저장
        // 변수명 이유: 여러 개의 항목(폼필드+파일)을 담기 때문

        req.setAttribute("items", items);
        req.setAttribute("uploadPath", path);
        // WHY: JSP에서 사용할 수 있도록 데이터를 전달하기 위해
        // WHAT: setAttribute = 속성 설정, JSP에서 꺼내서 사용 가능

    } catch(Exception e) {
        req.setAttribute("error", e.getMessage());
        // WHY: 오류가 발생하면 JSP에서 오류 메시지를 보여주기 위해
        // WHAT: error = 오류, 오류 메시지를 JSP로 전달
    }

2. JSP 처리 페이지 (fileupload04_process.jsp) 해석

기본 설정과 변수 선언

<%@ page contentType="text/html; charset=utf-8" %>
// WHY: 한글이 깨지지 않게 하기 위해
// WHAT: 페이지 인코딩을 UTF-8로 설정

List items = (List) request.getAttribute("items");
// WHY: 서블릿에서 전달받은 데이터를 사용하기 위해
// WHAT: items = 서블릿에서 넘어온 폼 데이터들
// 변수명 이유: 서블릿에서 "items"라는 이름으로 전달했기 때문

String path = (String) request.getAttribute("uploadPath");
String error = (String) request.getAttribute("error");
// WHY: 서블릿에서 전달한 경로와 오류 정보를 받기 위해
// WHAT: path = 파일 저장 경로, error = 오류 메시지

HashMap 생성

HashMap<String, String> formData = new HashMap<String, String>();
HashMap<String, String> fileData = new HashMap<String, String>();
// WHY: 데이터를 구조화해서 관리하기 위해
// WHAT: formData = 폼 입력값들, fileData = 파일 정보들
// 변수명 이유: 
//   - formData: 폼에서 입력한 데이터라는 의미
//   - fileData: 파일과 관련된 데이터라는 의미
//   - <String, String>: 키도 문자열, 값도 문자열

반복문과 데이터 처리

Iterator params = items.iterator();
// WHY: 리스트의 모든 항목을 하나씩 꺼내서 처리하기 위해
// WHAT: params = 매개변수들, iterator = 반복자
// 변수명 이유: parameter의 줄임말, 폼의 매개변수들을 순회

int fileCounter = 1;
// WHY: 파일명을 file1, file2... 형식으로 만들기 위해
// WHAT: fileCounter = 파일 카운터, 1부터 시작해서 1씩 증가
// 변수명 이유: file + Counter, 파일 개수를 세는 변수

폼 필드 처리

if (item.isFormField()) {
    // WHY: 일반 입력 필드(텍스트, 체크박스 등)인지 확인
    // WHAT: isFormField() = 폼 필드인지 판단하는 메소드

    String name = item.getFieldName();
    String value = item.getString("utf-8");
    // WHY: 입력 필드의 이름과 값을 추출하기 위해
    // WHAT: name = 필드명(title, username), value = 입력값
    // 변수명 이유: HTML의 name 속성과 입력한 value를 의미

    formData.put(name, value);
    // WHY: HashMap에 저장해서 나중에 쉽게 사용하기 위해
    // WHAT: put(키, 값) = HashMap에 데이터 저장
}

파일 처리

else {
    String fileName = item.getName();
    String newName = null;
    // WHY: 원본 파일명과 새로운 파일명을 구분하기 위해
    // WHAT: fileName = 원본파일명, newName = 새파일명
    // 변수명 이유: 
    //   - fileName: 파일의 이름
    //   - newName: 새로운 이름 (null로 초기화)

    if (fileName != null && !fileName.equals("")) {
        // WHY: 실제로 파일이 선택되었는지 확인하기 위해
        // WHAT: null이 아니고 빈 문자열도 아닌 경우만 처리

        String extension = "";
        if (fileName.lastIndexOf(".") > 0) {
            extension = fileName.substring(fileName.lastIndexOf("."));
        }
        // WHY: 파일 확장자(.jpg, .txt 등)를 보존하기 위해
        // WHAT: extension = 확장자, 마지막 . 이후의 문자열
        // 변수명 이유: 파일 확장자를 의미하는 일반적인 단어

        newName = "file" + fileCounter + extension;
        fileCounter++;
        // WHY: 중복되지 않는 새로운 파일명을 만들기 위해
        // WHAT: file1.jpg, file2.txt 형식으로 생성
        // 변수명 이유: 새로운 이름이라는 의미

파일 저장과 HashMap 저장

        File file = new File(path + "/" + newName);
        item.write(file);
        // WHY: 실제로 파일을 디스크에 저장하기 위해
        // WHAT: File 객체 생성하고 write()로 저장
        // 변수명 이유: 파일을 나타내는 가장 일반적인 이름

        fileData.put("originalName", fileName);
        fileData.put("newName", newName);
        fileData.put("fileSize", String.valueOf(item.getSize()));
        fileData.put("uploadPath", path + "/" + newName);
        // WHY: 파일 정보를 HashMap에 정리해서 저장하기 위해
        // WHAT: 원본명, 새이름, 크기, 경로를 키-값으로 저장
        // 키 이름 이유:
        //   - originalName: 원본 이름
        //   - newName: 새 이름  
        //   - fileSize: 파일 크기
        //   - uploadPath: 업로드 경로

디버깅 출력

System.out.println("=== 폼 데이터 ===");
for(String key : formData.keySet()) {
    System.out.println(key + " : " + formData.get(key));
}
// WHY: 개발자가 콘솔에서 데이터를 확인하기 위해
// WHAT: HashMap의 모든 키-값 쌍을 콘솔에 출력
// 변수명 이유: key = 키(열쇠), HashMap의 키를 의미

3. 주요 변수명 선택 이유 정리

변수명 이유 다른 가능한 이름
path 경로를 의미하는 일반적 단어 uploadPath, savePath
uploadDir upload + Directory 조합 saveDir, targetDir
items 여러 항목들을 담는다는 의미 formItems, uploadItems
formData 폼에서 온 데이터라는 의미 textFields, inputData
fileData 파일 관련 데이터라는 의미 fileInfo, uploadedFile
fileCounter 파일 개수를 센다는 의미 count, index
newName 새로운 이름이라는 의미 renamedFile, safeFileName