ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JSP] - Ajax 파일 업로드
    JSP 2025. 3. 25. 22:39
    반응형

     

    @Override
    public String requestHandler(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    
        String UPLOAD_DIR = "file_repo";
        String uploadPath = request.getServletContext().getRealPath("") + File.separator + UPLOAD_DIR;
    
        // 실제 파일 경로 객체 생성
        File currentDirPath = new File(uploadPath);
    
        // 디렉터리가 존재하지 않으면 생성
        if (!currentDirPath.exists()) {
            currentDirPath.mkdir();
        }
    
        // 파일 업로드 관련 설정
        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setRepository(currentDirPath);
        factory.setSizeThreshold(1024 * 1024);
    
        String fileName = null;
    
        ServletFileUpload upload = new ServletFileUpload(factory);
    
        try {
            // 업로드된 항목 처리
            List<FileItem> items = upload.parseRequest(request);
            for (FileItem fileItem : items) {
                if (fileItem.isFormField()) {
                    System.out.println(fileItem.getFieldName() + "=" + fileItem.getString("utf-8"));
                } else { // 파일이면
                    if (fileItem.getSize() > 0) {
                        // 파일 이름 추출
                        int idx = fileItem.getName().lastIndexOf(File.separator); // 운영체제에 맞는 경로 구분자 사용
                        if (idx == -1) {
                            idx = fileItem.getName().lastIndexOf("/"); // 리눅스에서 경로 구분자 처리
                        }
    
                        // 파일 이름만 추출
                        fileName = fileItem.getName().substring(idx + 1);
                        File uploadFile = new File(currentDirPath + File.separator + fileName);
    
                        // 파일 중복 체크
                        if (uploadFile.exists()) {
                            fileName = System.currentTimeMillis() + "_" + fileName;
                            uploadFile = new File(currentDirPath + File.separator + fileName);
                        }
    
                        // 파일 저장
                        fileItem.write(uploadFile);
                    }
                }
            }
    
        } catch (Exception e) {
            e.printStackTrace();
            // 오류 발생 시 사용자에게 알림을 위한 응답 처리
            response.setContentType("text/html;charset=euc-kr");
            response.getWriter().print("error"); // 파일 업로드 오류 시
            return null;
        }
    
        // 업로드된 파일 이름을 응답으로 반환
        if (fileName != null && !fileName.isEmpty()) {
            response.setContentType("text/html;charset=euc-kr");
            response.getWriter().print(fileName); // 파일 이름을 클라이언트로 반환
        } else {
            response.setContentType("text/html;charset=euc-kr");
            response.getWriter().print("error"); // 파일 업로드 실패 시
        }
    
        return null;
    }

     


    1. 파일 업로드 디렉터리 설정

    String UPLOAD_DIR = "file_repo";
    String uploadPath = request.getServletContext().getRealPath("") + File.separator + UPLOAD_DIR;
    • UPLOAD_DIR는 업로드된 파일들이 저장될 디렉토리의 이름입니다.
    • getServletContext().getRealPath("")는 웹 애플리케이션의 루트 디렉토리 경로를 반환합니다. 이 경로 뒤에 file_repo 폴더를 붙여서 실제 파일 저장 경로를 설정합니다.
    • File.separator는 운영 체제에 맞는 경로 구분자(\ 또는 /)를 자동으로 사용합니다.

    2. 파일 업로드 경로가 존재하지 않으면 디렉터리 생성

    File currentDirPath = new File(uploadPath);
    if (!currentDirPath.exists()) {
        currentDirPath.mkdir();
    }
    • uploadPath로 지정된 경로가 실제로 존재하는지 확인합니다.
    • 만약 경로가 존재하지 않으면, mkdir() 메서드를 통해 해당 디렉터리를 새로 생성합니다.

    3. 파일 업로드 설정

    DiskFileItemFactory factory = new DiskFileItemFactory();
    factory.setRepository(currentDirPath);
    factory.setSizeThreshold(1024 * 1024);
    • DiskFileItemFactory는 파일 업로드 시 파일 항목을 처리하기 위한 공장 클래스입니다.
    • setRepository(currentDirPath)는 파일을 업로드할 때 임시로 저장할 디렉터리를 지정합니다. 이 디렉터리는 업로드된 파일을 메모리로 처리하기 전에 임시로 저장할 위치입니다.
    • setSizeThreshold(1024 * 1024)는 임시 저장할 수 있는 최대 파일 크기(여기서는 1MB)입니다. 이 크기를 초과하는 파일은 실제 파일 시스템에 저장됩니다.

    4. 파일 업로드 처리

    ServletFileUpload upload = new ServletFileUpload(factory);
    List<FileItem> items = upload.parseRequest(request);
     
    • ServletFileUpload는 DiskFileItemFactory를 이용하여 파일 업로드를 처리하는 클래스입니다.
    • parseRequest(request)는 HTTP 요청에서 파일 데이터를 파싱하여 FileItem 객체 리스트를 반환합니다. 이 리스트에는 파일과 폼 필드 데이터가 모두 포함됩니다.

    5. 파일 항목 처리

    for (FileItem fileItem : items) {
        if (fileItem.isFormField()) {
            System.out.println(fileItem.getFieldName() + "=" + fileItem.getString("utf-8"));
        } else { // 파일이면
            if (fileItem.getSize() > 0) {
                // 파일 이름 추출
                int idx = fileItem.getName().lastIndexOf(File.separator);
                if (idx == -1) {
                    idx = fileItem.getName().lastIndexOf("/");
                }
    
                fileName = fileItem.getName().substring(idx + 1);
                File uploadFile = new File(currentDirPath + File.separator + fileName);
    
                // 파일 중복 체크
                if (uploadFile.exists()) {
                    fileName = System.currentTimeMillis() + "_" + fileName;
                    uploadFile = new File(currentDirPath + File.separator + fileName);
                }
    
                // 파일 저장
                fileItem.write(uploadFile);
            }
        }
    }
    • for 루프는 items 리스트를 순회하면서 각 항목이 폼 필드인지 파일인지 확인합니다.
      • 폼 필드일 경우 isFormField()가 true로 반환되며, 이 경우 파일 외의 다른 데이터를 처리합니다.
      • 파일일 경우, isFormField()가 false이고, 파일이 실제로 선택되었으면(fileItem.getSize() > 0), 파일을 처리합니다.
    • 파일 이름 추출:
      • fileItem.getName()은 파일의 전체 경로를 반환하는데, 이를 분리하여 파일 이름만 추출합니다.
      • lastIndexOf(File.separator)와 lastIndexOf("/")를 사용하여 경로에서 파일 이름만 추출합니다. (File.separator를 사용하면 운영체제에 맞는 경로 구분자(\ 또는 /)를 처리합니다.)
    • 파일 중복 처리:
      • 동일한 이름의 파일이 이미 존재하는지 확인하고, 존재할 경우 파일 이름에 현재 시간을 덧붙여 중복을 피합니다.
    • 파일 저장:
      • fileItem.write(uploadFile)로 업로드된 파일을 지정된 경로(uploadFile)에 저장합니다.

    6. 예외 처리

    } catch (Exception e) {
        e.printStackTrace();
        response.setContentType("text/html;charset=euc-kr");
        response.getWriter().print("error"); // 파일 업로드 오류 시
        return null;
    }
    • try-catch 블록을 사용하여 예외가 발생하면 이를 처리합니다.
    • 예외가 발생한 경우, e.printStackTrace()로 예외를 출력하고, 클라이언트에게 "error" 메시지를 반환합니다.
    • 파일 업로드 도중 발생할 수 있는 오류(파일 시스템 오류, 파싱 오류 등)를 처리합니다.

    7. 업로드된 파일 이름 반환

    if (fileName != null && !fileName.isEmpty()) {
        response.setContentType("text/html;charset=euc-kr");
        response.getWriter().print(fileName); // 파일 이름을 클라이언트로 반환
    } else {
        response.setContentType("text/html;charset=euc-kr");
        response.getWriter().print("error"); // 파일 업로드 실패 시
    }
    • 파일 업로드가 성공적으로 완료되면, 업로드된 파일의 이름을 클라이언트에게 응답으로 반환합니다.
    • 만약 파일 이름이 null이거나 비어 있다면 업로드가 실패했으므로 "error" 메시지를 반환합니다.

    8. 최종 반환값

    return null;
    • requestHandler 메서드는 최종적으로 null을 반환합니다. 이는 Servlet이나 Controller에서 다른 페이지로 포워딩하거나 리다이렉트하는 로직이 없다면 문제가 되지 않지만, 페이지 이동이 필요하다면 다른 반환값을 처리할 수도 있습니다.

     


     

    필요한 JAR 파일

    1. commons-fileupload.jar:
      • 이 JAR 파일은 파일 업로드를 처리하는 핵심적인 라이브러리입니다. ServletFileUpload와 DiskFileItemFactory와 같은 클래스를 제공하여 파일 업로드 기능을 쉽게 구현할 수 있습니다.
    2. commons-io.jar:
      • 이 JAR 파일은 commons-fileupload 라이브러리가 의존하는 파일 입출력 관련 유틸리티를 제공합니다. 예를 들어, 파일 시스템 경로 관리 등에서 유용한 메서드를 포함하고 있습니다.

     

    Maven의 경우

    <dependencies>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.4</version> <!-- 최신 버전 확인 필요 -->
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.7</version> <!-- 최신 버전 확인 필요 -->
        </dependency>
    </dependencies>

     

    1. HTML 부분: 파일 입력 필드

    <div class="form-group">
        <label class="control-label col-sm-2" for="">첨부 파일:</label>
        <div class="col-sm-10">
            <input type="file" class="form-Lebel" id="file" name="file">
        </div>
    </div>
    <input type="hidden" name="filename" id="filename" value=""><!-- file이름이 하나 넘어가야하기 때문에 hidden으로 해둠 -->
    • 파일 입력 필드 (<input type="file" id="file" name="file">):
      • 사용자가 파일을 선택할 수 있도록 하는 HTML input 요소입니다.
      • id="file": 자바스크립트에서 이 파일 입력 필드를 쉽게 선택할 수 있도록 고유한 ID 값을 지정합니다.
      • name="file": 서버에 전송할 때 이 파일을 나타내는 키 이름입니다. 파일을 서버로 전송할 때 이 이름을 사용하여 파일을 처리합니다.
    • 숨겨진 입력 필드 (<input type="hidden" name="filename" id="filename" value="">):
      • 파일 업로드 후, 실제 파일 이름을 저장하는 숨겨진 입력 필드입니다. 파일 이름을 서버로 전송할 때 사용됩니다. AJAX 요청을 통해 파일을 업로드하고 그 결과로 받은 파일 이름을 이 필드에 저장한 후, 폼을 제출합니다.

    2. JavaScript: 파일 업로드 로직

    function uploadFile(){
        if($("#file").val() != '') { // 파일이 첨부된 경우
            var formData = new FormData(); // formData를 생성할 수 있음
            formData.append("file", $("input[name=file]")[0].files[0]); // 첫번째 file을 가지고와 file이라는 이름으로 formData에 넣어줌
            $.ajax({
                url : "<c:url value='/fileAdd.do'/>", // formData를 전송해야 함
                type : "post",
                data : formData,
                processData : false, // formData이라는 하나의 바이너리 데이터가 넘어간다. 이 경우 이렇게 값을 설정
                contentType : false, // contentType도 false값을 주어야 한다.
                success : function(data) { // 업로드된 실제 파일 이름을 전달받기
                    $('#filename').val(data); // 숨겨진 파일 이름 필드에 파일 이름 저장
                    document.form1.action = "<c:url value='/memberInsert.do'/>"; // 텍스트 데이터를 저장하는 부분
                    document.form.submit(); // 폼을 제출
                },
                error : function() {
                    alert("error");
                }
            });
        } else { // 파일이 첨부되지 않은 경우
            // 파일이 없을 때 처리할 로직
        }
    }

    설명:

    1. 파일이 첨부된 경우:
      • $("#file").val()을 사용하여 파일 입력 필드에 파일이 선택되었는지 확인합니다. 선택된 파일이 있으면 FormData 객체를 생성하여 파일을 담습니다.
      • formData.append("file", $("input[name=file]")[0].files[0]):
        • FormData 객체는 폼 데이터를 제어하는 객체로, 파일과 같은 바이너리 데이터를 전송할 수 있게 도와줍니다.
        • $("input[name=file]")[0].files[0]은 파일 입력 필드에서 사용자가 선택한 첫 번째 파일을 가져옵니다.
    2. AJAX 요청:
      • $.ajax()를 사용하여 비동기적으로 서버에 파일을 전송합니다.
      • url에는 파일을 처리할 서버의 URL인 "/fileAdd.do"를 지정합니다.
      • type: "post"로 POST 방식으로 요청을 보냅니다.
      • data: formData로 FormData 객체를 전송합니다. 이 객체는 파일 데이터를 포함하고 있습니다.
      • processData: false와 contentType: false는 FormData 객체를 사용할 때 필수 설정입니다. 이 설정들이 없으면 파일이 제대로 전송되지 않습니다.
    3. 서버로부터 응답받은 후:
      • success 콜백 함수에서 서버에서 반환한 데이터를 받습니다. 여기서 data는 서버에서 처리된 파일 이름일 가능성이 높습니다.
      • 이 파일 이름을 숨겨진 필드인 #filename에 저장하고, 이후 document.form.submit()을 호출하여 회원가입 폼을 제출합니다. 이때 숨겨진 파일 이름 필드도 함께 제출됩니다.
    4. 파일이 첨부되지 않은 경우:
      • 파일이 첨부되지 않은 경우, 아무런 처리가 이루어지지 않도록 되어 있습니다. 이 부분에 추가적인 로직을 넣어 파일이 없어도 폼을 제출하도록 처리할 수 있습니다.
    반응형

    댓글

Designed by Tistory.