ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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

     

    [NarP Series] MVC 프레임워크는 내 손에 [나프2탄] - 인프런 | 강의

    본 과정은 WEB MVC 프레임워크가 무엇이고 WEB MVC 프레임워크가 어떻게 변형이 되면서 Spring WEB MVC 프레임워크로 넘어가는지 TPC(생각하고-표현하고-코딩하고) 기법을 통해 단계적으로 학습하고 이

    www.inflearn.com

     

     

Designed by Tistory.