22.06.24 이미지 파일 업로드하는 방법을 알아보기, UUID

브라우저 화면보기 위해서 간단히 controller구성
<li class="active"><a href="<c:url value='/' />">Main</a></li>
<li><a href="<c:url value='/freeboard/freeList' />">자유게시판</a></li>
<li><a href="<c:url value='/snsBoard/snsList' />">SNS</a></li>
package com.spring.myweb.controller;
@Controller
@RequestMapping("/snsBoard")
public class SnsBoardController {
@GetMapping("/snsList")
public void snsList() {}
}
1.Maven Repository - Apache Commons FileUpload
2.Maven Repository - Apache Commons IO » 2.4
<!-- 서블릿 3.0 이상 사용 가능한 파일 업로드 API -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!-- commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<!-- 파일 업로드 -->
<!-- 반드시 id를 "multipartResolver"로 선언
Multipart 형식으로 전달되는 데이터를 스프링 mvc에서 사용할 수 있도록 변환해 주는 객체-->
<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 최대 업로드 가능한 바이트 크기(바이트 단위), value에 -1을 주면 제한이 없음을 의미 -->
<beans:property name="maxUploadSize" value="1048576"/> <!-- 1메가바이트 -->
<!-- 업로드 요청을 변환할 때 사용할 문자 인코딩 방식 -->
<beans:property name="defaultEncoding" value="utf-8" />
</beans:bean>
연습용 jsp파일 생성.
파일 업로드에서는 enctype(인코딩타입)을 "multipart/form-data"로 반드시 지정해야 한다.
<body>
<form action="upload_ok" method="post" enctype="multipart/form-data">
파일 선택: <input type="file" name="file"> <br>
<input type="submit" value="전송">
</form>
</body>
연습용 컨트롤러 생성.
upload.jsp에서 사용자가 file을 선택후 controller로 보내진다.
MultipartFile 인터페이스 타입으로 file을 받는다.
UUID는 파일의 고유 번호로, 파일명 중복 방지를 위해 적용한다.
<script>
package com.spring.myweb.controller;
@Controller
@RequestMapping("/fileupload")
public class UploadController {
//업로드 화면요청
@GetMapping("/upload")
public void form() {}
//업로드 요청
@PostMapping("/upload_ok") //변수명 같으면 @RequestParam안써도 된다.
public String upload(@RequestParam("file") MultipartFile file) { //MultipartFile 인터페이스 타입
//실제 파일 저장 메서드(fileWriter 작업을 손쉽게 한방에 처리해 준다.)
try {
String fileRealName = file.getOriginalFilename(); //파일 원본명
long size = file.getSize(); //파일 크기
System.out.println("파일명: " + fileRealName);
System.out.println("사이즈: " + size);
//DB에는 파일 경로를 저장, 실제 파일은 서버 컴퓨터의 로컬 경로에 저장하는 방식.
String uploadFolder = "C:\\test\\upload"; //폴더 경로
String fileExtension = fileRealName.substring(fileRealName.lastIndexOf("."), fileRealName.length()); //확장자 얻기
/*
파일 업로드 시 파일명이 동일한 파일이 이미 존재할 수도 있고,
사용자가 업로드하는 파일명이 영어 이외의 언어로 되어있을 수 있습니다.
타 언어를 지원하지 않는 환경에서는 정상 동작이 되지 않습니다. (리눅스)
고유한 랜덤 문자를 통해 DB와 서버에 저장할 파일명을 새롭게 만들어 줍니다.
*/
UUID uuid = UUID.randomUUID(); //문자들이 - 으로 연결되어 있다.
System.out.println(uuid.toString()); //f99564fd-e7af-47a8-8f64-53d3d7496c3a
String[] uuids = uuid.toString().split("-"); //String[]로 리턴
System.out.println("생성된 고유 문자열: " + uuids[0]); //분할한 것중 한덩어리만 사용해도 충분.f99564fd
System.out.println("확장자명: " + fileExtension); //.png
//자바 객체(File) 활용해서 폴더 생성
File folder = new File(uploadFolder); //폴더 경로를 매개값으로 전달
if(!folder.exists()) { //폴더가 존재하는지 확인.
folder.mkdirs(); //폴더가 존재하지 않는다면 생성해라.
}
folder = new File(uploadFolder + "\\" + uuids[0] + fileExtension);
//새로운 파일 생성.폴더경로+파일명+확장자명
file.transferTo(folder); //파일 업로드.예외발생 try/catch
} catch (Exception e) {
e.printStackTrace();
}
return "fileupload/upload_ok";
}
}
</script>
이렇게 메서드가 실행되고 나면
실제 C:\test\upload경로에 폴더가 생성되고
생성한 파일명으로 파일이 경로에 저장된다.
MultipartHttpServletRequest 인터페이스 타입사용
input태그 속성에 multiple="multiple" 추가하면
사용자가 파일 여러개를 선택할 수 있다.
<form action="upload_ok2" mehtod="post" enctype="multipart/form-data">
파일 선택: <input type="file" multiple="multiple" name="files">
<input type="submit" value="전송">
</form>
"C:/test/upload" == "C:\test\upload" 정슬레시,백슬레시 둘다 사용가능.
<script>
@PostMapping("/upload_ok2")
public String upload2(MultipartHttpServletRequest files) { //MultipartHttpServletRequest 인터페이스 타입 사용
//서버에서 저장할 파일 경로
String uploadFolder = "C:/test/upload";
List<MultipartFile> list = files.getFiles("files");
/* 일반 for문 사용
for(int i=0; i<list.size(); i++) {
try {
String fileRealName = list.get(i).getOriginalFilename();
long size = list.get(i).getSize();
System.out.println("파일명: " + fileRealName);
System.out.println("사이즈: " + size);
File saveFile = new File(uploadFolder + "/" + fileRealName);
list.get(i).transferTo(saveFile);
} catch (Exception e) {
e.printStackTrace();
}
}*/
//향상 for문 사용
for(MultipartFile m : list) {
try {
String fileRealName = m.getOriginalFilename();
long size = m.getSize();
System.out.println("파일명: " + fileRealName);
System.out.println("사이즈: " + size);
File saveFile = new File(uploadFolder+ "/" + fileRealName);
m.transferTo(saveFile);
} catch (Exception e) {
e.printStackTrace();
}
}
return "fileupload/upload_ok";
}
</script>
List<MultipartFile> List타입으로 받기.
multiple="multiple" 속성 추가 하지 않고 하나씩
파일을 선택하게 해서 모든 파일들을 List로 받는다.
만약 input 태그가 3개인데 1개만보낸다면 에러가 발생하기 때문에
프론트 단에서 확인하거나 null이 들어온다면 실행하는 로직을 추가 해야한다.
<form action="upload_ok3" method="post" enctype="multipart/form-data">
파일 선택: <input type="file" name="file"> <br>
파일 선택: <input type="file" name="file"> <br>
파일 선택: <input type="file" name="file"> <br>
<input type="submit" value="전송">
</form>
<script>
@PostMapping("/upload_ok3")
public String upload3(@RequestParam("file") List<MultipartFile> list) {
String uploadFolder = "C:/test/upload";
for(MultipartFile m : list) {
try {
String fileRealName = m.getOriginalFilename();
long size = m.getSize();
System.out.println("파일명: " + fileRealName);
System.out.println("사이즈: " + size);
File saveFile = new File(uploadFolder+ "/" + fileRealName);
m.transferTo(saveFile);
} catch (Exception e) {
e.printStackTrace();
}
}
return "fileupload/upload_ok";
}
</script>
커맨드 객체 사용
사용자에게 직접 파일명과 파일을 받는다.
<form action="upload_ok4" method="post" enctype="multipart/form-data">
원하시는 파일명: <input type="text" name="name">
파일 선택: <input type="file" name="file"> <br>
<input type="submit" value="전송">
</form>
사용자가 입력한 파일명과 파일을 저장할 수 있는 UploadVO생성
public class UploadVO {
private String name;
private MultipartFile file;
}
컨트롤러에서는 VO객체로 처리.
@PostMapping("/upload_ok4")
public String upload4(UploadVO vo) {
...
}
만약 사용자가 1개의 파일이 아니라 여러개의 파일을 업로드할때
커맨드 객체 사용하려면 여러파일을 받을수있는 MultiUploadVO 객체를 생성해서 이용한다.
public class MultiUploadVO {
private List<UploadVO> list;
}
list의 인덱스를 이용해서 값들을 저장.
<form action="upload_ok4" method="post" enctype="multipart/form-data">
원하시는 파일명: <input type="text" name="list[0].name">
파일 선택: <input type="file" name="list[0].file"> <br>
원하시는 파일명: <input type="text" name="list[1].name">
파일 선택: <input type="file" name="list[1].file"> <br>
원하시는 파일명: <input type="text" name="list[2].name">
파일 선택: <input type="file" name="list[2].file"> <br>
<input type="submit" value="전송">
</form>
vo에서 getList( )를 해서 list를 받고 반복문을 이용한다.
uvo.getName( )을 해서 사용자가 입력한 파일명을 받아오고
확장자명을 위해서 uvo.getFile().getOriginalFilename()도 진행.
<script>
@PostMapping("/upload_ok4")
public String upload4(MultiUploadVO vo) {
System.out.println(vo);
String uploadFolder = "C:/test/upload";
List<UploadVO> list = vo.getList();
for(UploadVO uvo : list) {
try {
String fileName = uvo.getName();
String realName = uvo.getFile().getOriginalFilename();
String fileExtention = realName.substring(realName.lastIndexOf("."), realName.length());
File saveFile = new File(uploadFolder+ "/" + fileName + fileExtention);
uvo.getFile().transferTo(saveFile);
} catch (Exception e) {
e.printStackTrace();
}
}
return "fileupload/upload_ok";
}
</script>