dropzone 사용법 SPRING MVC 다중파일 멀티파일

웹프로그램 제작시 파일을 여러개 올리고 받아야할 경우가 발생해요.

이경우 dropzone라는 라이브러리를 사용하면 편리하게 구현할수 있어요. 

https://www.dropzonejs.com/

 

Dropzone.js

dropzone.js DropzoneJS is an open source library that provides drag’n’drop file uploads with image previews. It’s lightweight, doesn’t depend on any other library (like jQuery) and is highly customizable. Scroll down!

www.dropzonejs.com

사이트로 이동해서 라이브러리 파일을 다운로드 받아요. 

저는 게시판에 dropzone를 달았어요. 

<table class="table table-write" id="add_mt">
					<colgroup>			
					<col style="width:120px" />
					<col style="width:*" />											
					</colgroup>
					<tr>						
						<th>날짜</th>
						<td>
							<div class="input-group date form_date col-md-5" data-date="" data-date-format="yyyy-MM-dd" data-link-field="dtp_input2" data-link-format="yyyy-MM-dd">
				                    <input class="form-control" size="16" type="text" id ="mt_wdate" name="mt_wdate" value="${mt_wdate}" style="text-align:left;">                   
									<span class="input-group-addon" style="padding:0 10px;border-top:1px solid #ccc;border-right:1px solid #ccc;border-bottom:1px solid #ccc;">
										<span class="glyphicon glyphicon-calendar"></span>
									</span>
				              </div>
						</td>
					</tr>
					<tr>						
						<th>제목</th>
						<td><input type="text" class="form-control" id=mt_subject name="mt_subject" placeholder="제목" value="${mt_subject}" required></td>
					</tr>
					<tr>
						<th>내용</th>
						<td>
							<div id="summernote">${mt_content}</div>
						</td>
					</tr>
					<tr>
						<th>파일첨부</th>
						<td>
							<div id="my_file_upload" class="dropzone">
								<div class="fallback">
									<input name="file" type="file" multiple />
								</div>
							</div>
						</td>
					</tr>
				</table>

summernote와 같이 사용하고 있었는데요. 

dropzone.css와 dropzone.js를 선언해요.

<link href="../../resources/sms/dropzone/dropzone.css" rel="stylesheet">
<script src="../../resources/sms/dropzone/dropzone.js"></script>

그리고 $(document).ready(function() 로 dropzone에 대한 설정을 해요. 

Dropzone.autoDiscover = false;
$(document).ready(function() {	
	edit_mode_note();
	//$("div#my_file_upload").dropzone({ url: "/editor/file_upload" });
	$(".file-dropzone").on('dragover', handleDragEnter);
	$(".file-dropzone").on('dragleave', handleDragLeave);
	$(".file-dropzone").on('drop', handleDragLeave);

	function handleDragEnter(e) {
		this.classList.add('drag-over');
	}

	function handleDragLeave(e) {
		this.classList.remove('drag-over');
	}

	Dropzone.autoDiscover = false;
	
	$("div#my_file_upload").dropzone({ url: "/editor/file_uploads" ,
		addRemoveLinks : true,
			maxFilesize : 256,
		  dictResponseError: 'Error uploading file!',
		  headers: {
		    'X-CSRF-TOKEN': $("#csrf_token").val()
		    , uid : $('#i_uid').val()
		  },
		  params: {
		         uid: $('#i_uid').val()
		    },
		  uploadMultiple : true,
		  thumbnailWidth: 180,
		  thumbnailHeight: 120,
		  parallelUploads: 100,		
		  maxFiles: 255,
		  autoProcessQueue : true,
		  accept: function(file, done) {
			    if (file.name == "") {
			      done("제한사항 없어도 될듯 한뎅?");
			    }
			    else {			    	
			    	done(); 
			    	}
			  },
	init : function() {
		var myDropzone = this;
		var count = myDropzone.options.maxFiles;
		var url = "/editor/file_list";
		var data = JSON.stringify({ 
			uid : $('#i_uid').val()
		});
		
		var callback_init=function (data) {
            if (data.data != '' && data.data != undefined) {
            	var existingFileCount = 0;
                $.each(data.data, function (index, item) {
                    var mockFile = {
                        name: item.mt_filename,
                        size: item.mt_contentlength,
                        seq: item.idx
                    };
                    var filePath = "/editor/get_editor_thumbnail_image/?idx="+item.idx;
                    myDropzone.emit("addedfile", mockFile);
                    myDropzone.emit("thumbnail", mockFile, filePath);
                    myDropzone.emit("success", mockFile);
                    myDropzone.emit("complete", mockFile);                    
                    myDropzone.files.push(mockFile);
                    //file.previewElement.classList.add("dz-processing"); //sms;
                    //file.previewElement.classList.add("dz-complete");
                    existingFileCount = existingFileCount + 1;
                });
                myDropzone.options.maxFiles = myDropzone.options.maxFiles - existingFileCount;
            }
        };
		getPostData(url,data,callback_init);
		
		this.on("maxfilesexceeded", function (file) {
			showmessage("알림","한번에 올릴수 있는 파일의 갯수 제한을 넘었습니다",2000,'');
			myDropzone.removeFile(file);
		});
        
        this.on("success", function( file, resp, formData ){
        	existingFileCount=0;
        	var type = $("#"+id).data("type");
        	if(resp != null && resp != '' && resp != undefined) {
	        	if(resp.data != null && resp.data != '' && resp.data != undefined) {
	    			var existingFileCount = 0;
	    			$.each(resp.data, function(){
	    				if(this.mt_filename==file.name)
	    				{
	    					file.previewElement.appendChild(Dropzone.createElement("<input type='hidden' name='fileId' value='" + this.fileId + "'/>"));
	    					existingFileCount = existingFileCount + 1;
	    				}
	    			});
	    		}
        	}
        	if(file.seq != null && file.seq != '' && file.seq != undefined) {
				file.previewElement.appendChild(Dropzone.createElement("<input type='hidden' name='fileId' value='" + file.seq + "'/>"));
    		}
        });
        
        this.on("removedfile", function (data) {
        	var id = $(data.previewElement).find('input[name=fileId]').val();
    		var sql_state_value = 'delete';
    		var data = JSON.stringify({
    			   sql_state : sql_state_value		 
    			 , idx : id    	
    			 , uid : $('#i_uid').val()
    		   	 , mt_input_id : $('#login_mt_id').val()
    			 , mt_update_id : $('#login_mt_id').val()
    		});
    		var url ='/editor/editor_note_delete_img';
    		getPostData(url,data,null);
    		myDropzone.options.maxFiles = myDropzone.options.maxFiles + 1;
    		if(count < myDropzone.options.maxFiles) myDropzone.options.maxFiles = count;
    	    });
		}
	
	});
	$('.push').click(function() {
		$('.dropzone').each(function() {
			alert("어휴.");
		});
	});


});

headers: {
    'X-CSRF-TOKEN': $("#csrf_token").val()
    , uid : $('#i_uid').val()
  },

스프링부트 사용시 csrf-token을 headers에 넣어주시면 되요.

스프링쪽 컨트롤러는 /file_uploads는 이렇게 만들었어요. 

//멀티파일..
  @ResponseBody
  @RequestMapping(value ="/file_uploads", method=RequestMethod.POST, 
                  produces = "application/json;charset=UTF-8")
  public  Map<String, List<Map<String, String>>> file_uploads(MultipartFile nfile,MultipartHttpServletRequest  request)throws Exception{
	
	String uid=null;
	Map<String, String[]> paramMap1=request.getParameterMap();
	 Iterator keyData1 = paramMap1.keySet().iterator();	
    while (keyData1.hasNext()) {
        String key = ((String)keyData1.next());
        String[] value = paramMap1.get(key);
        logger.info("key : " + key + ", value : " + value[0].toString());
        if(key.equals("uid"))
        {
        	uid=value[0].toString().trim();
        }
    }    
	Map <String, MultipartFile > paramMap = request.getFileMap ();
	 Iterator keyData = paramMap.keySet().iterator();
	 CommonData dto = new CommonData();
	 
	 Map<String, List<Map<String, String>>> result = new HashMap<>();
	 List<Map<String, String>> data_list = new ArrayList();
	 
    while (keyData.hasNext()) {
    	Map<String, String> data = new HashMap<>();
        String key = ((String)keyData.next());
        MultipartFile file = paramMap.get(key);
        
        file_upload_ex(dto, data, file,uid);  //return ResponseEntity.ok().body(result);
        data_list.add(data);
        dto.clear();
    }
    result.put("data", data_list);
    return result;
  }

file_upload_ex부분은 이렇게 만들었어요. 

private String file_upload_ex(CommonData dto, Map<String, String> result, MultipartFile file, String uid)
		throws IOException, Exception {
	logger.info("originalName: " + file.getOriginalFilename());
    MediaUtils MediaUtils = new MediaUtils();
    String formatName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")+1);
    MediaType mType = MediaUtils.getMediaType(formatName);
    if(mType!=null)
    {
	    UploadFileUtils f_util = new UploadFileUtils();
	    BufferedImage  descimg = f_util.cropImageSquare(file.getBytes());
	    BufferedImage srcImg = ImageIO.read(file.getInputStream());
	    BufferedImage destImg = 
	            Scalr.resize(srcImg, 
	            		Scalr.Method.BALANCED, 
	                180,180
	                ,Scalr.OP_ANTIALIAS);
	    ByteArrayOutputStream baos = new ByteArrayOutputStream();
	    boolean foundWriter = ImageIO.write(destImg, "png", baos);
		baos.flush();
		byte[] imageInByte = baos.toByteArray();
		dto.put("mt_s_data", imageInByte);
		baos.close();
    }
	
	    dto.put("mt_filename",file.getOriginalFilename());
	    dto.put("mt_type",file.getContentType());
	    dto.put("mt_contentlength",file.getBytes().length);
	    dto.put("mt_data", file.getBytes());
	    dto.put("uid", uid);
	    
	
	    z_service.insert(dto, "File_UpDown_Mapper.insert_editor_image_upload");    
	    int idx= z_service.listSearchCount(dto, "File_UpDown_Mapper.select_editor_image_upload");
		result.put("result", "UPDATE_OK");
	    String url = "/editor/get_editor_image/?idx="+idx;
	    String id = ""+idx;
	    result.put("url", url);
	    result.put("id", id);	    
	    result.put("fileId", id);
	    result.put("mt_filename", file.getOriginalFilename());
	    result.put("mt_type", file.getContentType());
	    result.put("formatName", formatName);	 
	    result.put("uid", uid);	    
	    return id;
}

/file_list 쪽 컨트롤러 에요. 

@RequestMapping("/file_list")
public Map<String, List<Map<String, Object>>> file_list(@RequestBody CommonData dto) throws Exception {
	  Iterator keyData = dto.keySet().iterator();
      while (keyData.hasNext()) {
          String key = ((String)keyData.next());
          String value = dto.get(key);          
          logger.info("key : " + key + ", value : " + value);
      }
      List<Map<String, Object>> list = z_service.select(dto, "File_UpDown_Mapper.get_editor_image_uid_list");
      Map<String, List<Map<String, Object>>> result = new HashMap<>();
      result.put("data", list);
      return result;
  
}

/get_editor_thumbnail_image 컨트롤러 에요. 

@RequestMapping(value = "/get_editor_thumbnail_image", method = RequestMethod.GET)
  public ResponseEntity<byte[]> get_thumbnail_image(HttpServletRequest request, Model model) throws Exception {
	  	 MediaUtils MediaUtils = new MediaUtils();
		 Map<String, String[]> paramMap=request.getParameterMap();		 
		 Iterator keyData = paramMap.keySet().iterator();
		 CommonData dto = new CommonData();
	     while (keyData.hasNext()) {
	         String key = ((String)keyData.next());
	         String[] value = paramMap.get(key);
	         dto.put(key, value[0].toString());        
	         logger.info("key : " + key + ", value : " + value[0].toString());
	     }
	     List<Map<String, Object>> result_list;
	     result_list=z_service.select(dto,"File_UpDown_Mapper.get_editor_thumbnail_image");
	     /*
	     if(result_list.size() < 1)
	     {
	    	 dto.put("idx", "108");
	    	 result_list=z_service.select(dto,"File_UpDown_Mapper.get_editor_image");
	     }
	     */
	     logger.info(""+result_list.size());
	     if(result_list.size() > 0)
	     {
	    	  Iterator list_object = result_list.iterator();
	          Map<String, Object> e_object = (Map<String, Object>) list_object.next();
	          
	          String idx = e_object.get("idx").toString();
	          String mt_filename = (String)e_object.get("mt_filename");
	          byte[] mt_data = (byte[])e_object.get("mt_s_data");	
	          HttpHeaders headers = new HttpHeaders(); 
	          mt_filename = URLEncoder.encode(mt_filename,"UTF-8");
  	        //response.setContentType("application/ms-excel; charset=UTF-8");
  	        //response.setCharacterEncoding("UTF-8");
  	       // response.setHeader("Content-Disposition","attachment; filename="+mt_filename);
	          String formatName = mt_filename.substring(mt_filename.lastIndexOf(".")+1);	      
		      MediaType mType = MediaUtils.getMediaType(formatName);
		      if(mType != null){
			        headers.setContentType(mType);
			      }else{
			    	   String icon_idx= "1";
			    	   formatName = formatName.toUpperCase();
			    	   if(formatName.equals("TXT"))
			    	   {
			    		   icon_idx = "9";
			    	   }
			    	   else if(formatName.equals("XLS")||formatName.equals("XLSX")||formatName.equals("XLSM")||formatName.equals("XLSB")||formatName.equals("XLTX")||formatName.equals("XLTM"))
			    	   {
			    		   icon_idx = "2";
			    	   }
			    	   else if(formatName.equals("MP3"))
			    	   {
			    		   icon_idx = "3";
			    	   }
			    	   else if(formatName.equals("MP4"))
			    	   {
			    		   icon_idx = "4";
			    	   }
			    	   else if(formatName.equals("PDF"))
			    	   {
			    		   icon_idx = "5";
			    	   }
			    	   else if(formatName.equals("PPT")||formatName.equals("PPTX"))
			    	   {
			    		   icon_idx = "6";
			    	   }
			    	   else if(formatName.equals("XML"))
			    	   {
			    		   icon_idx = "7";
			    	   }
			    	   else if(formatName.equals("ZIP"))
			    	   {
			    		   icon_idx = "8";
			    	   }
			    	   else if(formatName.equals("DOC"))
			    	   {
			    		   icon_idx = "10";
			    	   }
			    	   dto.put("idx", icon_idx);
			    	   result_list=z_service.select(dto,"File_UpDown_Mapper.get_editor_thumbnail_image");
			    	   if(result_list.size() > 0)
				  	   {
				  	    	  list_object = result_list.iterator();
				  	          e_object = (Map<String, Object>) list_object.next();
				  	          
				  	          idx = e_object.get("idx").toString();
				  	          mt_filename = (String)e_object.get("mt_filename");
				  	          mt_data = (byte[])e_object.get("mt_s_data");	
				  	          headers = new HttpHeaders(); 
				  	          formatName = mt_filename.substring(mt_filename.lastIndexOf(".")+1);	      
				  		      mType = MediaUtils.getMediaType(formatName);
				  		      if(mType != null){
				  		    	  headers.setContentType(mType);
				  		      }
				  	   }
			      }
	         
		      return new ResponseEntity<byte[]>(mt_data, headers,HttpStatus.OK);
	      }
	     return new ResponseEntity<byte[]>(HttpStatus.BAD_REQUEST);
  	}

저는 위에 등록된파일들을 썸네일 아이콘으로 등록해뒀어요. 파일종류에 따라서 아이콘을 다르게 보이게 할려구요.

/editor_note_delete_img 파일 삭제 컨트롤러 에요.

  @RequestMapping("/editor_note_delete_img")
  public Map<String, String> editor_note_delete_img(@RequestBody CommonData dto) throws Exception {
	  Map<String, String> paramMap = new HashMap<>();
	  
	  Iterator keyData = dto.keySet().iterator();
      while (keyData.hasNext()) {
          String key = ((String)keyData.next());
          String value = dto.get(key);          
          logger.info("key : " + key + ", value : " + value);
      }
      z_service.update(dto, "File_UpDown_Mapper.editor_note_delete_img");
      paramMap.put("result", "IMAGE_DELETE_OK");     
      return paramMap;
  }

파일다운로드는 게시판을 읽어올때 받아와요. 

<div class="view">
				<input type="hidden" class="form-control" id="i_idx" value="${idx}">
				<input type="hidden" class="form-control" id="i_uid" value="${uid}">
				<input type="hidden" class="form-control" id="mt_class" value="${mt_class}">
				<br style="clear: both">
				<!-- 
				<h3 style="margin-bottom: 25px;">뭘 이렇게 까지 자료가.. @@</h3>
				-->
				<div id="mt_subject" class="title">
					${mt_subject}
					<!-- input type="text" class="form-control" id=mt_subject name="mt_subject" placeholder="제목" value="${mt_subject}" required-->
				</div>
				<div id="date" class="date">
					${mt_wdate}
				</div>
				<div id="summernote" class="contents">
					${mt_content}
					<!--  div id="summernote">${mt_content}</div-->
				</div>
               <!-- 파일정보에요. -->
				<div id="mt_file_list" class="filt_list">
					<p class="attachment">첨부파일 다운로드</p>
							
					<c:forEach items="${file_list}" var="file_list"  varStatus="status">
						<a href="/editor/get_editor_image/?idx=${file_list.idx}" download="${file_list.mt_filename}">
						<img src="/editor/get_editor_thumbnail_image/?idx=${file_list.idx}"/>
						${file_list.mt_filename}
						</a>						
					</c:forEach>						
				</div>				  
			</div>

첨부파일 다운로드에서 파일리스트를 가져와서 뿌려주고 아이콘을 클릭하면 다운로드 되요. 

@RequestMapping(value = "/get_editor_image", method = RequestMethod.GET)
  public ResponseEntity<byte[]> get_image(HttpServletRequest request, Model model) throws Exception {
	  	 MediaUtils MediaUtils = new MediaUtils();
		 Map<String, String[]> paramMap=request.getParameterMap();		 
		 Iterator keyData = paramMap.keySet().iterator();
		 CommonData dto = new CommonData();
	     while (keyData.hasNext()) {
	         String key = ((String)keyData.next());
	         String[] value = paramMap.get(key);
	         dto.put(key, value[0].toString());        
	         logger.info("key : " + key + ", value : " + value[0].toString());
	     }
	     List<Map<String, Object>> result_list;
	     result_list=z_service.select(dto,"File_UpDown_Mapper.get_editor_image");
	    
	     logger.info(""+result_list.size());
	     if(result_list.size() > 0)
	     {
	    	  Iterator list_object = result_list.iterator();
	          Map<String, Object> e_object = (Map<String, Object>) list_object.next();
	          
	          String idx = e_object.get("idx").toString();
	          String mt_filename = (String)e_object.get("mt_filename");
	          mt_filename = URLEncoder.encode(mt_filename,"UTF-8");
	          byte[] mt_data = (byte[])e_object.get("mt_data");	
	          HttpHeaders headers = new HttpHeaders(); 
	          String formatName = mt_filename.substring(mt_filename.lastIndexOf(".")+1);	      
		      MediaType mType = MediaUtils.getMediaType(formatName);
		      if(mType != null){
			        headers.setContentType(mType);
			      }else{
			    	mt_filename = new String(mt_filename.getBytes("UTF-8"), "ISO-8859-1");
			        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
			        headers.add("Content-Disposition", "attachment;filename=\""+mt_filename+"\";");
			        headers.add("Content-Transfer-Encoding", "binary");
			      }
	         
		      return new ResponseEntity<byte[]>(mt_data, headers,HttpStatus.OK);
	      }
	     return new ResponseEntity<byte[]>(HttpStatus.BAD_REQUEST);
  	}
  

이상으로 dropzone.js를 사용하여 파일을 업로드 삭제 하고 다운로드 하는 것을 해보았어요.

 

블로그 이미지

은호아빠

여행, 맛집, 일상, 프로그래밍, 개발자, 윈도우, 웹, jsp, spring, db, mysql, oracle, c#

,