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 |