-
Spring MVC02 - 다중파일 업로드Web/Spring 2023. 6. 30. 23:23
1. 파일 업로드를 위한 준비 API, servlet-context.xml설정
다중 파일 업로드를 위해 API를 다운받자.
commons-fileupload, commons-io
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.2.1</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>1.4</version> </dependency>
스프링 컨테이너에 servlet-context.xml 파일 업로드를 위한 클래스와 property를 설정해야한다.
<beans:bean id="multipartResolver" class ="org.springframework.web.multipart.commons.CommonsMultipartResolver" > <beans:property name="maxUpLoadSize" value="52428800"></beans:property> <beans:property name="maxInMemorySize" value="1000000"></beans:property> <beans:property name="defaultEncoding" value="utf-8"></beans:property> </beans:bean>
- 업로드할 파일의 최대사이즈와, 임시파일사이즈, 인코딩타입 등을 미리 정해두자
1.2 뷰 페이지 만들기
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name='viewport' content='width=device-width, initial-scale=1'> <link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css'> <script src='https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script> <script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js'></script> <script type="text/javascript"> var cnt=1; function delUploadDiv(cnt){ $("#f"+cnt+"").remove(); $("#c"+cnt+"").remove(); cnt--; } function file_add(){ //파일 추가 버튼 누를때 마다 file 넣을 수 있는 칸 생김 $("#d_file").append("<input type='file' id='f"+cnt+"' name='file"+cnt+"'/>"+"<input type='button' id='c"+cnt+"' value='삭제' onclick = 'delUploadDiv("+cnt+")'>"+"<br>"); cnt++; } </script> <title>Insert title here</title> </head> <body> <div class="container"> <h2>다중파일업로드</h2> <div class="panel panel-default"> <div class="panel-heading">스프링 이용한 다중 파일 업로드 구현 </div> <div class="panel-body">Panel Content <!-- 파일업로드를 위한 설정 인코딩타입 --> <form class="form-horizontal" action="<c:url value='/upload.do'/>" enctype="multipart/form-data" method="post"> <div class="form-group"> <label class="control-label col-sm-2" for="id">아이디:</label> <div class="col-sm-10"> <input type="text" class="form-control" id="id" name="id" placeholder="Enter id" style="width: 30%"> </div> </div> <div class="form-group"> <label class="control-label col-sm-2" for="name">이름:</label> <div class="col-sm-10"> <input type="password" class="form-control" id="name" name="name" placeholder="Enter name"> </div> </div> <div class="form-group"> <label class="control-label col-sm-2" for="">파일추가:</label> <div class="col-sm-10"> <input type="button" value="파일 추가" onclick="file_add()"><br> <div id="d_file"></div> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-primary">업로드</button> </div> </div> </form> </div> <div class="panel-footer">나프2탄고</div> </div> </div> </body> </html>
form에 enctype ="multipart/form-data"로 설정해두어야 한다.
1.3 서버 구현
- 폼에 있는 데이터는 body에 파일을 추가하면 들어갈 것이다.
- id = v, Name =v /// File1 =바이너리 데이터 , File2 = 바이너리 데이터
- 이런식으로 일반 파라미터와 파일정보 동시에 보내짐
- 따라서 서버에서는 이를 구분해서 읽어야 함
@RequestMapping("/upload.do") public String upload(MultipartHttpServletRequest multipartRequest, HttpServletRequest request) { Map map = new HashMap(); // KEY,Value //열거형 유사 배열 Enumeration<String> e= multipartRequest.getParameterNames(); // 첨부파일은 x id name같은것만읽음 //장점 배열과 달리 몇개인지 알필요없음 (배열길이) 있음 가지고오고 없음 말고 //데이터 유무만 판단해서 가져옴 데이터 처리에 편리함 있다. while(e.hasMoreElements()) { String Pname = e.nextElement(); //id String val= multipartRequest.getParameter(Pname); //System.out.println(Pname+" "+val); map.put(Pname, val); } //파일을 담고 있는 파라미터를 읽어오기 Iterator<String> it= multipartRequest.getFileNames();// 파일이름이 아니라-> 파일 담은 파라미터이름 while(it.hasNext()) { String paramFName =it.next(); MultipartFile mfile = multipartRequest.getFile(paramFName);//파일(이름,타입,크기...기타등등) 이걸 받아줘야함 String oName = mfile.getOriginalFilename(); //진짜 파일 이름 } return ""; }
- MultipartHttpServletRequest에 getParameterNames()를 통해 첨부파일x id,name 같은 것만 읽음
- MultipartHttpServletRequest에 getFilenames()를 통해 파일을 담은 파라미터들을 가져올 수 있다.
이를 .getFile("파라미터명")을 통해 MultipartFile객체로 바꿔주자.
파일 내용,파일의 이름,크기,타입 기타 등등 담고 있는 클래스이다.
- 이제 오리지널 파일명을 저장할 list타입과 파일을 저장할 dir을 지정하자
@RequestMapping("/upload.do") public String upload(MultipartHttpServletRequest multipartRequest, HttpServletRequest request, Model model) throws Exception{ String UPLOAD_DIR="epo"; // \\, / String uploadPath=request.getServletContext().getRealPath("")+File.separator+UPLOAD_DIR; Map map = new HashMap(); // KEY,Value Enumeration<String> e= multipartRequest.getParameterNames(); // 첨부파일은 x id name같은것만읽음 while(e.hasMoreElements()) { String Pname = e.nextElement(); //id String val= multipartRequest.getParameter(Pname); //파일 쓰기 map.put(Pname, val); } Iterator<String> it= multipartRequest.getFileNames();// 파일이름이 아니라-> 파일 담은 파라미터이름 List<String> fileList = new ArrayList<>(); while(it.hasNext()) { String paramFName =it.next(); MultipartFile mfile = multipartRequest.getFile(paramFName);//파일(이름,타입,크기...기타등등) 이걸 받아줘야함 String oName = mfile.getOriginalFilename(); //진짜 파일 이름 //오리지널 파일명 저장 fileList.add(oName); //파일 업로드 폴더 업로드 디렉토리 확인 File file = new File(uploadPath+File.separator+paramFName); //file1 if(mfile.getSize()!=0) { if(!file.exists()) { //파일이 존재하지 않으면, if(file.getParentFile().mkdir()) { //dir생성 file.createNewFile(); // 임시로 파일을 생성한다. } } mfile.transferTo(new File(uploadPath+File.separator+oName)); //파일업로드 } } map.put("fileList", fileList); model.addAttribute("map", map); return "result"; } }
- DIR, path 지정 File 인스턴스 만들고, 넘어온 파일 사이즈가 0보다 크다면,
-> File 인스턴스 존재 확인 -> 없으면 상위폴더 생성(UPLOAD_DIR) -> 임시파일 생성
-> MultipartFile을 통한 파일 업로드
-> 클라이언트 요청으로 넘어온 일반 요청과 오리지널 파일명 담은 map을 view로 전달
2. view페이지와 파일 다운로드
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE html> <html> <head> <meta name='viewport' content='width=device-width, initial-scale=1'> <link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css'> <script src='https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script> <script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js'></script> <meta charset="UTF-8"> <title>결과창</title> </head> <body> <div class="container"> <h2>업로드 완료</h2> <div class="panel panel-default"> <div class="panel-heading">스프링을 이용한 다중 파일 업로드</div> <div class="panel-body"> <table class ="table table-bordered table-hover"> <tr> <td>아이디</td> <td>${map.id}</td> </tr> <tr> <td>이름</td> <td>${map.name}</td> </tr> <c:forEach var="fName" items="${map.fileList}"> <tr> <td>${fName} </td> <td>다운로드</td> </tr> </c:forEach> </table> </div> <div class="panel-footer">인퍼런 홧팅</div> </div> </div> </body> </html>
파일 업로드 완료 후 view페이지 간단구현
<tr> <td>{fName}</td> <td><a href="javascript:getfile('${fName}')"><span class="glyphicon glyphicon-file"></span></a></td> </tr>
다운로드 버튼 추가
function getfile(filename){ location.href = "<c:url value='download.do'/>?filename="+filename; }
다운로드 컨트롤러 쪽 구현 내용은 MVC07에서 했던 파일 다운로드에서 몇가지만 수정함
@RequestMapping("/download.do") public void download(@RequestParam("filename")String filename, HttpServletResponse response, HttpServletRequest request ) throws Exception { //파일 저장된 폴더 위치 및, 넘어온 파일 명으로 파일 객체생성 String UPLOAD_DIR="epo"; String uploadPath=request.getServletContext().getRealPath("")+File.separator+UPLOAD_DIR; File f=new File(uploadPath+"\\"+filename); // 클라이언트로 부터 넘어오는 파일이름에 한글이 있는경우 깨지지 않게하기 위함 // File에 넣을 때는 인코딩 설정안해도 괜춘한가봄 filename=URLEncoder.encode(filename, "UTF-8"); filename=filename.replace("+"," "); // 다운로드 준비로 서버에서 클라이언트에게 다운로드 준비를 시키는 부분(다운로드 창을 띄운다) response.setContentLength((int)f.length()); response.setContentType("application/x-msdownload;charset=utf-8"); //이것 떄문에 설정한거임 헤더에 넣을 때 한글 안깨지게 하려고 response.setHeader("Content-Disposition", "attachment;filename="+filename+";"); response.setHeader("Content-Transfer-Encoding", "binary"); response.setHeader("Pragma", "no-cache"); response.setHeader("Expires", "0"); // 실제 다운로드를 하는 부분 FileInputStream in=new FileInputStream(f); //파일읽기 준비 OutputStream out=response.getOutputStream(); byte[] buffer=new byte[104]; while(true) { int count=in.read(buffer); if(count==-1) { break; } out.write(buffer, 0, count); //다운로드(0%......100%) }//_while_ in.close(); out.close(); } }
참고자료: 나프2탄 (인프런) - 박매일
https://www.inflearn.com/course/%EB%82%98%ED%94%84-mvc-2
'Web > Spring' 카테고리의 다른 글
나프 - 게시판 만들기(2) (0) 2023.08.02 나프 - 게시판 만들기(1) (0) 2023.08.02 Spring MVC02 - Ajax MemberList (0) 2023.06.29 Spring MVC02 - 어노테이션을 이용한 Mapper 인터페이스 사용 (0) 2023.06.29 Spring MVC02 - Mapper Interface와 XML이용한 CRUD (0) 2023.06.29