<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<!-- => 파일 업로드 기능을 제공하기 위한 라이브러리 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.5</version>
</dependency>
<!-- [multipart/form-data] 형식으로 전달되는 값 또는 파일을 처리하는 기능을 제공하는
클래스(CommonsMultipartResolver)를 Spring Bean으로 등록 -->
<!-- => Spring Bean의 식별자(beanName)을 반드시 [multipartResolver]로 설정 -->
<beans:bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
<!-- maxUploadSize 필드에 최대 업로드 가능한 파일의 제한용량이 저장되도록 값 주입 -->
<beans:property name="maxUploadSize" value="20971520"/>
<!-- defaultEncoding 필드에 전달값에 대한 문자형태가 저장되도록 값 주입 -->
<beans:property name="defaultEncoding" value="utf-8"/>
</beans:bean>
요청 처리 메소드의 매개변수를 MultipartHttpServletRequest 인터페이스로 작성하면 Front Controller로부터 MultipartHttpServletRequest객체를 제공받아 사용
@RequestMapping(value = "/upload1", method = RequestMethod.POST)
public String uploadOne(MultipartHttpServletRequest request) throws IOException {
String uploaderName=request.getParameter("uploaderName");
//MultipartHttpServletRequest.getFile(String name) : 전달파일의 정보가 저장된
//MultipartFile 객체를 반환하는 메소드
MultipartFile uploaderFile=request.getFile("uploaderFile");
//MultipartFile 객체에 저장된 전달파일에 대한 검증
//MultipartFile.isEmpty() : MultipartFile 객체에 파일정보가 저장되어 있는 경우 [false]를
//반환하고 파일정보가 저장되어 있지 않은 경우 [true]를 반환하는 메소드
if(uploaderFile.isEmpty()) {
return "file/upload_fail";
}
//MultipartFile.getContentType() : MultipartFile 객체에 저장된 전달파일의 형태(MimeType)를
//반환하는 메소드
System.out.println("파일 형태(MimeType) = "+uploaderFile.getContentType());
//MultipartFile.getBytes() : MultipartFile 객체에 저장된 전달파일의 내용을 byte 배열로
//반환하는 메소드
System.out.println("파일 크기(Byte) = "+uploaderFile.getBytes().length);
//전달파일이 저장될 서버 디렉토리(폴더)의 시스템 경로를 반환받아 저장
String uploadDirectory=request.getServletContext().getRealPath("/resources/images/upload");
System.out.println("uploadDirectory = "+uploadDirectory);
//MultipartFile.getOriginalFilename() : MultipartFile 객체에 저장된 전달파일의 이름을
//반환하는 메소드 - 원본 파일명
String uploadFilename=uploaderFile.getOriginalFilename();
//서버 디렉토리에 저장될 파일에 대한 정보가 저장된 File 객체 생성 - 업로드 처리될 파일 설정
File file=new File(uploadDirectory, uploadFilename);
//MultipartFile.transferTo(File file) : MultipartFile 객체에 저장된 전달파일의 내용을
//File 객체에 저장된 파일에 저장되도록 업로드 처리하는 메소드
// => 서버 디렉토리에 업로드 처리되는 파일과 같은 이름의 파일이 있는 경우 기존 파일
//대신 업로드 파일이 서버 디렉토리에 저장 - 덮어씌우기(OverWrite)
uploaderFile.transferTo(file);
request.setAttribute("uploaderName", uploaderName);
request.setAttribute("uploadFilename", uploadFilename);
return "file/upload_success_one";
}
jsp에서는 form 태그에 설정해줘야 된다.
사용자로부터 입력받은 파일을 form 태그를 사용해 요청 페이지에 전달하기 위해 enctype 속성값을 반드시 [multipart/form-data]로 설정해야 클라이언트가 올린 파일을 서버로 전달가능
말 그대로 전달 파일의 이름과 같은 이름의 파일이 서버 디렉토리에 있는 경우 기존 파일 대신 전달파일로 덮어씌워 저장된다.
이걸 해결하는 방법은 전달파일의 이름으로 서버 디렉토리에 저장하지 않고 전달파일의 이름을 중복되지 않는 이름으로 변경해 저장되도록 업로드 처리하면 된다.
//WebApplicationContext 객체(스프링 컨테이너)를 제공받아 필드에 저장되도록 의존성 주입
private final WebApplicationContext context;
@RequestMapping(value = "/upload1", method = RequestMethod.POST)
public String uploadOne(@RequestParam String uploaderName
, @RequestParam MultipartFile uploaderFile, Model model) throws IOException {
if(uploaderFile.isEmpty()) {
return "file/upload_fail";
}
//WebApplicationContext.getServletContext() : WebApplicationContext 객체(스프링 컨테이너)를
//사용해 ServletContext 객체를 반환하는 메소드
String uploadDirectory=context.getServletContext().getRealPath("/resources/images/upload");
//UUID.randomUUID() : 36Byte 크기의 식별자가 저장된 UUID 객체를 생성하여 반환하는 정적메소드
//UUID.toString() : UUID 객체에 저장된 36Byte 크기의 식별자를 문자열로 반환하는 메소드
String uploadFilename=UUID.randomUUID().toString()+"_"+uploaderFile.getOriginalFilename();
File file=new File(uploadDirectory, uploadFilename);
uploaderFile.transferTo(file);
model.addAttribute("uploaderName", uploaderName);
model.addAttribute("uploadFilename", uploadFilename);
return "file/upload_success_one";
}
jsp 파일에서 input 태그에 multiple 속성을 사용하면 된다.
<td>
<input type="file" name="uploaderFileList" multiple="multiple">
<span style="color: red;">* 파일을 여러개 입력할 수 있습니다.</span>
</td>
@RequestMapping(value = "/upload2", method = RequestMethod.POST)
public String uploadTwo(@RequestParam String uploaderName
, @RequestParam List<MultipartFile> uploaderFileList, Model model) throws IOException {
String uploadDirectory=context.getServletContext().getRealPath("/resources/images/upload");
//업로드 처리된 파일의 이름을 저장하기 위한 List 객체 생성
List<String> filenameList=new ArrayList<String>();
//List 객체에 저장된 요소값(MultipartFile 객체)을 차례대로 제공받아 변수에 저장해 반복 처리
for(MultipartFile multipartFile : uploaderFileList) {
if(multipartFile.isEmpty()) {
return "file/upload_fail";
}
String uploadFilename=UUID.randomUUID().toString()+"_"+multipartFile.getOriginalFilename();
File file=new File(uploadDirectory, uploadFilename);
multipartFile.transferTo(file);
//List 객체의 요소값으로 업로드 처리된 파일을 추가하여 저장
filenameList.add(uploadFilename);
}
model.addAttribute("uploaderName", uploaderName);
model.addAttribute("filenameList", filenameList);
return "file/upload_success_two";
}
여러 개의 전달값을 받을 때는 <c:forEach>를 사용해서 받으면 됨
<h1>파일 업로드 성공</h1>
<hr>
<h2>업로더 이름 = ${uploaderName }</h2>
<c:forEach var="filename" items="${filenameList }" varStatus="status">
<h2>업로드 파일명-${status.count } : ${filename }</h2>
</c:forEach>
<hr>
<c:forEach var="filename" items="${filenameList }">
<img src="<c:url value="/images/upload/${filename }"/>" width="200">
</c:forEach>