<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%String contextPath = request.getContextPath();%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>upload.jsp</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script src="<%=contextPath%>/js/uploadjq.js"></script>

</head>
<body>
<form method="post" enctype="multipart/form-data" action="<%=contextPath%>/upload">
  <input type="text" name="t" value="tValue"><br>
  <input type="file" name="f1">
  <button>첨부하기</button>
  
</form>

</body>
</html>

multiple : 파일 선택을 여러개 할 수 있다.


enctype="multipart/form-data"

  • 한줄요약 : 위의 코드를 써줘야 파일 첨부가 된다.

enctype="multipart/form-data"는 HTML <form> 태그의 속성 중 하나입니다. 이 속성은 웹페이지에서 폼을 제출할 때 데이터가 어떤 형태로 인코딩되어 서버로 전송될지를 지정합니다.

여기서 enctype="multipart/form-data"는 특히 파일이나 이미지와 같은 비텍스트 데이터를 폼을 통해 서버로 전송할 때 사용됩니다. 이때 각 부분은 multipart/form-data 인코딩을 사용하여 서버로 전송됩니다.

기본적으로 HTML 폼은 application/x-www-form-urlencoded 방식을 사용하여 데이터를 인코딩합니다. 이 방식은 모든 문자들을 서버로 전송하기 전에 URL 안전 문자(URL-safe characters)로 인코딩합니다. 그러나 이 방식은 텍스트 데이터를 처리하기 위한 것으로, 파일과 같은 비텍스트 데이터를 처리하기에는 부적합합니다.

따라서 파일을 폼을 통해 서버로 전송하려면 enctypemultipart/form-data로 설정해야 합니다. 이 방식은 파일 데이터를 부분(part)으로 분리하고 각 부분을 별도로 인코딩하여 전송합니다.

아래는 파일 업로드를 위한 HTML 폼의 예시입니다:

<form action="/upload" method="post" enctype="multipart/form-data">
    Select image to upload:
    <input type="file" name="fileToUpload" id="fileToUpload">
    <input type="submit" value="Upload Image" name="submit">
</form>

이 폼은 POST 메소드를 사용하여 /upload 경로로 데이터를 전송하며, multipart/form-data 인코딩을 사용합니다. 사용자가 'Upload Image' 버튼을 클릭하면 선택한 파일이 서버로 전송됩니다.


fileItemFactory.setSizeThreshold(LIMIT_SIZE_BYTES);

fileItemFactory.setSizeThreshold(LIMIT_SIZE_BYTES);에서 setSizeThreshold 메소드는 메모리에 저장할 파일 데이터의 최대 크기를 설정하는 역할을 합니다. 이 크기를 넘는 파일은 디스크에 임시 파일로 저장됩니다.

LIMIT_SIZE_BYTES로 설정된 값은 메모리에 데이터를 쓸 때 사용되는 버퍼의 크기를 설정하는 것이 아니라, 언제 디스크 기반의 파일 처리로 전환해야 하는지를 결정하는 임계값입니다.

예를 들어, LIMIT_SIZE_BYTES가 1MB로 설정되어 있다면, 파일의 크기가 1MB를 초과하는 경우, 파일의 데이터는 디스크에 저장되는 임시 파일로 쓰여집니다. 만약 파일의 크기가 1MB 이하라면, 이 데이터는 메모리에 저장됩니다.

따라서, "LIMIT_SIZE_BYTES만큼 읽겠다"는 설명은 정확하지 않습니다. 오히려 "파일의 크기가 LIMIT_SIZE_BYTES를 초과하면 디스크에 임시 파일로 저장하고, 그렇지 않으면 메모리에 데이터를 저장하겠다"라는 설명이 더 정확하다고 할 수 있습니다.

fileUpload.setFileSizeMax(LIMIT_SIZE_BYTES);

fileUpload.setFileSizeMax(LIMIT_SIZE_BYTES);는 Apache Commons FileUpload 라이브러리에서 제공하는 메서드로, 한 파일이 가질 수 있는 최대 크기를 설정하는데 사용됩니다.

LIMIT_SIZE_BYTES 값에 설정된 바이트 수 이상의 크기를 가진 파일이 업로드를 시도하면, FileUploadBase.FileSizeLimitExceededException이 발생합니다. 이 예외는 클라이언트가 지정된 파일 크기 제한을 초과하는 파일을 업로드하려고 시도했음을 나타내는 예외입니다.

이는 서버에 대한 잠재적인 DOS 공격을 방지하고, 서버의 디스크 공간을 보호하는 데 중요한 역할을 합니다. 파일 업로드에 제한을 두지 않으면 사용자가 매우 큰 파일을 업로드하거나 대량의 파일을 업로드하여 서버의 리소스를 고갈시킬 수 있기 때문입니다.

따라서, fileUpload.setFileSizeMax(LIMIT_SIZE_BYTES);는 업로드할 수 있는 파일 크기에 제한을 두는 방법입니다.


위의 파일이 <form method="post" enctype="multipart/form-data" action="<%=contextPath%>/upload"> 와 같이 post방식으로 데이터를 전송한다.

UploadServlet에서는 이를 받아 처리한다.

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		File attachesDir = new File(ATTACHES_DIR);
		if(!attachesDir.exists()) {
			attachesDir.mkdir();
		}
		 
        DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
        fileItemFactory.setRepository(attachesDir); // 첨부파일저장 경로
        //fileItemFactory.setSizeThreshold(LIMIT_SIZE_BYTES); // 첨부파일내용을 읽는 단위.
        ServletFileUpload fileUpload = 
        		new ServletFileUpload(fileItemFactory);
        
	 
        try {
        	fileUpload.setFileSizeMax(LIMIT_SIZE_BYTES); //첨부파일 최대크기 설정
            
        	List<FileItem> items = fileUpload.parseRequest(request); 
            for (FileItem item : items) {
                if (item.isFormField()) { // 일반 요청 전달 데이터
                    System.out.println("파라미터 명 : " + item.getFieldName() 
                                    +", 파라미터 값 :  "+ item.getString(CHARSET));
                }else { //첨부데이터
                	System.out.println(
                			"파일 파라미터 명 : "+ item.getFieldName() // 요청전달데이터 이름:ex) t
                			+ ", 파일 명 : "+item.getName() //첨부파일이름
                			+ ",  파일 크기 : "+ item.getSize()); //첨부파일크기
                    if (item.getSize() > 0) { // 파일들의 정보가 0인건 필요없음
                        //String separator = File.separator;
                        //int index =  item.getName().lastIndexOf(separator); 
                        //String fileName = item.getName().substring(index  + 1);
                    	
                    	//UUID.randomUUID();
                    	
                    	
                        String fileName = item.getName();
                    	File uploadFile = new File(ATTACHES_DIR, fileName);
                        item.write(uploadFile);
                    }
                }
            }
            System.out.println("파일 업로드 완료"); // 정말 크기가 큰파일
            
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("파일 업로드 중 오류가 발생하였습니다"); //파일 최대 크기 넘어서면
        } 
    }

위 파일을 직접 주소창에 쓰면 405 오류가 뜨는 이유?

UploadServlet 클래스는 HTTP POST 요청을 처리하기 위해 작성되었습니다. doPost() 메소드는 클라이언트에서 서버로 HTTP POST 요청이 보내졌을 때 호출됩니다.

웹 브라우저의 주소창에 URL을 입력하고 Enter를 누르는 행동은 HTTP GET 요청을 생성하고 서버에 전송하는 것입니다. 이 서블릿에서는 HTTP GET 요청을 처리하는 doGet() 메소드가 정의되지 않았으므로, GET 요청이 이 서블릿에 도달하면 405 오류(HTTP Method Not Allowed)가 발생합니다.

다시 말해, 이 서블릿은 POST 요청만 처리하도록 작성되었고, GET 요청에 대해서는 "허용되지 않는 메소드(Method Not Allowed)" 오류를 반환하게 됩니다.

POST 요청은 주로 사용자가 웹 폼을 통해 서버로 데이터를 전송할 때 사용되며, 이 때문에 웹 브라우저의 주소창에서 직접 POST 요청을 생성하는 것은 불가능합니다. POST 요청을 보내기 위해서는 HTML 폼이나 AJAX를 사용하거나, Postman과 같은 HTTP 클라이언트 도구를 사용해야 합니다.

이 서블릿을 테스트하려면, <form> 태그를 사용하여 HTML 페이지를 만들고, 이 페이지에서 POST 요청을 생성할 수 있습니다. 아니면 Postman 같은 툴을 사용하여 POST 요청을 직접 보낼 수도 있습니다.

그럼 여기서 form의 post형식으로 보낸 데이터는 어떻게 받아?

위의 코드에서 보이는 것처럼, HTML <form> 태그를 사용하여 웹 브라우저에서 서버로 데이터를 전송하고 있습니다. 이 때 사용되는 메소드는 HTTP POST입니다.

form의 action 속성에 설정된 URL("<%=contextPath%>/upload")로 POST 요청이 보내집니다. 이 요청에 포함된 데이터는 enctype="multipart/form-data" 속성에 의해 multipart 형식으로 인코딩됩니다. 이 형식은 파일 첨부 등 바이너리 데이터를 전송하기에 적합합니다.

POST 요청을 서버에서 받는 부분은 위에서 보여주신 Java의 UploadServlet에 있습니다. UploadServletdoPost 메소드가 HTTP POST 요청을 처리합니다.

Servlet에서는 HttpServletRequest 객체를 통해 클라이언트로부터 전송된 데이터에 접근할 수 있습니다. 이 객체는 HTTP 요청 정보를 담고 있으며, 클라이언트에서 전송된 데이터를 가져오는 데 사용됩니다.

이 경우에는 Apache Commons FileUpload 라이브러리를 사용하여 multipart 데이터를 파싱합니다. fileUpload.parseRequest(request)를 호출하여 FileItem 리스트를 얻고, 각 FileItem에서 데이터를 읽어오는 방식으로 처리하고 있습니다.

FileItem은 요청에서 보내진 하나의 파트를 나타냅니다. item.isFormField() 메소드를 호출하여 해당 파트가 일반 폼 필드인지 아니면 첨부 파일인지 확인할 수 있습니다. 이에 따라 필요한 처리를 수행합니다.

0개의 댓글