본문 바로가기
JAVA/Java

파일 업로드 및 저장 - 02, servlet/jsp, @MultipartConfig, part

by sihyeong 2023. 9. 16.

 

이전글: https://coding-chronicle.tistory.com/101

 

파일 업로드 및 저장 - 01, html

개요 수작업으로 게시글처럼 보이도록 개행문자를 기준으로 나눠 태그를 작성하던 중 우연히 위그지그 를 발견하게 되어 관련 에디터 CKEditor의 이미지 업로드를 구현하기 위해 공부한 파일 업

coding-chronicle.tistory.com

 


이전글에서 알아본 html을 토대로 파일을 전송해서 실제 내 컴퓨터에 저장하는 방법을 알아보겠다.

 

HTML

<form action="FileUploadTest" method="post" enctype="multipart/form-data">
	작성자<input type="text" name="fileWriter"><br>
	파일<input type="file" name="fileName"><br>
	파일설명<br/><textarea name="fileDescription" rows="5" cols="30"></textarea><br/><br/>
	<input type="submit" value="업로드">
</form>
  • 위의 HTML을 토대로 서버에 파일 데이터를 전송한다.

Servlet

이전 포스팅에서 확인 했듯이 enctype="multipart/form-data"으로 form 데이터를 전송한 경우 file의 데이터는 request.getParameter()로 확인할 수 없다.

 

file의 데이터는 getParameter() 사용 시 null값이 반환된다.

이렇듯 getParameter()로 확인할 수 없는 file 데이터는 Part 인터페이스를 사용하여 값을 수신한다.

 

 


Part 인터페이스를 사용하기 전 데이터의 해석 방식을 변경하기 위해 선행 처리 작업이 필요하다.

 

 

파일의 데이터 수신 시 form의 전송방식이 달라지기 때문에 enctype을 지정하지 않았을 경우의 form 속성인  enctype="application/www-form-urlencoded" 데이터 해석 방식으로 실제 전송된 데이터 형식인 multipart/form-data 데이터를 해석하게 되면 잘못된 값으로 해석할 수 있는 여지가 있기에 Servlet에게 해석 방법을 알려줄 필요가 있다.

 

만약 해석방법을 알려주지 않고 multipart/form-data를 수신한 경우엔 아래와 같은 오류를 만나게 될 것이다.

servlet에게 multipart/form-data로 전송한 데이터의 해석방식을 알려주지 않았을 경우 발생함


multipart/form-data로 해석하라고 알려주는법:

 

MultipartConfig()

  • 클래스에 @MultipartConfig()를 작성해 주면 알아서 multipart/form-data로 방식으로 해석한다.
@WebServlet("/FileUploadTest")
@MultipartConfig(	// 이부분을 작성해야 file 해석 가능
		maxFileSize = 1024 * 1024 * 3,
		maxRequestSize = 1024 * 1024 * 3)
public class Test extends HttpServlet{
	// ... 수신, 응답 처리
}
  • 속성값은 아래와 같다.
  • 자세한 내용은 공식 문서를 확인하길 바란다.

docs: https://docs.oracle.com/javaee/7/api/javax/servlet/annotation/MultipartConfig.html

 

MultipartConfig (Java(TM) EE 7 Specification APIs)

The maximum size allowed for uploaded files. The default is -1L, which means unlimited.

docs.oracle.com

 

@MultipartConfig(

fileSizeThreshold= 파일이 디스크에 임시 저장되기 전까지의 파일 크기,
기본크기는 0바이트

location= fileSizeThreshold 설정을 초고하는 경우 파일을 임시로 저장할 디렉터리 위치,
기본값="" 

maxFileSize = 업로드 파일 허용 최대 크기,
파일의 크기가 이 값보다 크면 예외(IllegalStateException)이 발생

maxRequestSize = 요청 허용 최대 크기
모든 파일의 전체 크기가 이 값 보다 크면 예외 발생, 기본크기는 무제한

)

 

  • 어노테이션을 사용하지 않고, web.xml에 아래와 같이 명시할 수도 있다.
  <multipart-config>
  	<max-file-size>123456</max-file-size>
  	<max-request-size>123456</max-request-size>
  	<file-size-threshold>0</file-size-threshold>
  </multipart-config>

 


file 데이터를 해석해 보자

 

Part 인터페이스

  • multipart/form-data로 들어온 file 데이터를 해석할 때 사용한다.
This class represents a part or form item that was received within a multipart/form-data POST request.
이 클래스는 multipart/form-data POST 요청 내에서 수신된 부분 또는 양식 항목을 나타냅니다.

docs: https://docs.oracle.com/javaee/7/api/javax/servlet/http/Part.html

 

Part (Java(TM) EE 7 Specification APIs)

A convenience method to write this uploaded item to disk. This method is not guaranteed to succeed if called more than once for the same part. This allows a particular implementation to use, for example, file renaming, where possible, rather than copying a

docs.oracle.com

 

  • Part에 대한 여러 메서드가 있는데 정확히 무슨 역할을 하는지 잘 모르겠으니 출력해보자.
Collection<Part> parts = request.getParts();
for(Part part: parts) {
	System.out.println("headerNames: " + part.getHeaderNames());
	System.out.println("contentType: " + part.getContentType());
	System.out.println("name: " + part.getName());
	System.out.println("size: " + part.getSize());
	System.out.println("sybmittedFileName: " + part.getSubmittedFileName());
	System.out.println("content-disposition: " + part.getHeader("content-disposition"));
	System.out.println();
}

출력값

 

  • 제일 앞과 제일 뒤의 데이터는 input text 데이터이므로 무시하고 중간의 file 데이터만 확인하자.
  • 파일의 크기를 알 수 있는 getSize와 파일의 이름인 getSybmittedFileName 정도만 알고 있으면 될 것 같다.

서버에 저장

 

final Part part = request.getPart("fileName");	// form의 name값인 fileName 데이터 얻기
final String getFileName = part.getSubmittedFileName();
final String uuidFileName = UUID.randomUUID().toString();	// 파일명이 중복되지 않도록 uuid 랜덤값을 파일명으로 지정
final String extentionName = getFileName.substring(getFileName.lastIndexOf(".")); // 확장자 얻기
final Path path = Paths.get("C:\\uploadTest");	// 저장 경로
if(!Files.exists(path)) {	// 저장 경로 폴더가 없다면
	Files.createDirectory(path);	// 폴더 생성
}
		
part.write(path + "\\" + uuidFileName + extentionName);	  // 해당 경로에 파일 저장