對於前端,本人不是太擅長,對於當前的一些網上的樣例,也許是習武悟性太差,不是太透,所以只能通過blog的方式記錄下一些武功套路,便於以后查詢使用
首先,我們需要知道這個武功適應的戰場。
什么是dropzone?
DropzoneJS是一個提供文件拖拽上傳並且提供圖片預覽的開源類庫,它是輕量級的,不依賴任何其他類庫(如JQuery)並且高度可定制.
支持瀏覽器:
- Chrome 7+
- Firefox 4+
- IE 10+
- Opera 12+ (Version 12 for MacOS is disabled because their API is buggy)
- Safari 6+
對於所有其他瀏覽器 , dropzone 提供了一個 file input 作為應對策略,對於老舊的瀏覽器,會出現file input,還是可以文件上傳的。
資源
官網:https://www.dropzonejs.com/
GitHub:https://github.com/enyo/dropzone
看demo:
dropzone.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- css 引用--> <link rel="stylesheet" type="text/css" th:href="@{~/static/css/basic.min.css}"/> <link rel="stylesheet" type="text/css" th:href="@{~/static/css/dropzone.min.css}"/> <!-- js 引用 --> <script th:src="@{~/static/js/jquery_3.1.0_jquery.min.js}"></script> <script th:src="@{~/static/js/dropzone.min.js}"></script> </head> <body> <input type="text" value="TASK20190309" id="taskKey"/> <div id="dropz" class="dropzone" style="width: 500px; height: 300px;"></div> <!-- 文件上傳縮略圖模板 --> <div id="preview-template" class="hide"> <div class="dz-preview dz-file-preview"> <div class="dz-image"> <img data-dz-thumbnail="" /> </div> <div class="dz-details"> <div class="dz-size"> <span data-dz-size=""></span> </div> <div class="dz-filename"> <span data-dz-name=""></span> </div> </div> <div class="dz-error-message"> <span data-dz-errormessage=""></span> </div> <div class="dz-success-mark"> <span class="fa-stack fa-lg bigger-150"> <i class="fa fa-circle fa-stack-2x white"></i> <i class="fa fa-check fa-stack-1x fa-inverse green"></i> </span> </div> <div class="dz-error-mark"> <span class="fa-stack fa-lg bigger-150"> <i class="fa fa-circle fa-stack-2x white"></i> <i class="fa fa-remove fa-stack-1x fa-inverse red"></i> </span> </div> </div> </div> <!--<div id="preview-template" style="display: none;"> <div class="dz-preview dz-file-preview "> <div class="dz-image"><img data-dz-thumbnail /></div> <div class="dz-details"> <div class="dz-filename"><span data-dz-name></span></div> <div class="dz-size" data-dz-size></div> </div> <div class="dz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div> <div class="dz-success-mark"><span>✔</span></div> <div class="dz-error-mark"><span>✘</span></div> <div class="dz-error-message"><span data-dz-errormessage></span></div> </div> </div>--> </body> <script th:inline="javascript"> Dropzone.autoDiscover = false;//解決兩次實例Dropzone錯誤,可在控制台看到該錯誤 var $taskKey = $("#taskKey"); try{ var myDropzone = new Dropzone("#dropz",{ url: "/uploadFile",//文件提交地址 method:"post", //也可用put paramName:"file", //默認為file maxFiles:2,//一次性上傳的文件數量上限 maxFilesize: 2, //文件大小,單位:MB acceptedFiles: ".jpg,.gif,.png,.jpeg", //上傳的類型 addRemoveLinks:true, //默認false。如果設為true,則會給文件添加一個刪除鏈接 uploadMultiple:true,//如果設為true,則相當於 HTML 表單添加 multiple 屬性 parallelUploads: 2,//一次上傳的文件數量 autoProcessQueue:true, //當設置 false 你必須自己像這樣 myDropzone.processQueue() previewTemplate: $('#preview-template').html(),//如果去掉該選項就會使用默認的 dictDefaultMessage : '<span class="bigger-150 bolder"><i class="ace-icon fa fa-caret-right red"></i> 拖拽文件到此處</span> \ <span class="smaller-80 grey">(或點擊下面的上傳按鈕選擇待上傳文件)</span> <br /> \ <i class="upload-icon ace-icon fa fa-cloud-upload blue fa-3x"></i>' , dictMaxFilesExceeded: "您最多只能上傳{{maxFiles}}個文件!", dictResponseError: '文件上傳失敗!', dictInvalidFileType: "文件類型只能是*.jpg,*.gif,*.png,*.jpeg", dictFallbackMessage:"瀏覽器不受支持", dictFileTooBig:"文件過大({{filesize}}MB). 上傳文件最大支持: {{maxFilesize}}MB.", dictRemoveLinks: "刪除", dictCancelUpload: "取消", dictRemoveFile: "移除", //文件信息預覽 thumbnail: function(file, dataUrl) { if (file.previewElement) { $(file.previewElement).removeClass("dz-file-preview"); var images = $(file.previewElement).find("[data-dz-thumbnail]").each(function() { var thumbnailElement = this; thumbnailElement.alt = file.name; thumbnailElement.src = dataUrl; }); setTimeout(function() { $(file.previewElement).addClass("dz-image-preview"); }, 1); } }, accept: function(file, done) { //此處可以在上傳前添加一些校驗 var taskKey = $taskKey.val(); if (taskKey === "" || taskKey == null) { done("任務不為空"); } else {done();} }, init:function(){ //添加文件觸發 this.on('addedfile',function(file){ console.log("addedfile ....."); }); this.on('successmultiple',function(files,reponse){ console.log("successmultiple ....."); $.each(files,function(index,file){ if(file.accepted){ if(reponse[file.name]!='0'){ //表示后台處理失敗 var $div = $(file.previewElement); $div.removeClass("dz-success").addClass("dz-error"); $div.find(".dz-error-message").find("span").text("上傳失敗"); } } }); }); this.on('sending',function(files, xhr, formData){ //此處可以添加自定義參數 formData.append("taskKey", $taskKey.val()); }); this.on('errormultiple',function(files,reponse){ console.log("errormultiple ....."); $.each(files,function(index,file){ if(file.accepted){ if(reponse[file.name]=='0'){ //表示后台處理成功 var $div = $(file.previewElement); $div.removeClass("dz-error").addClass("dz-success"); } } }); }); } }); //在以ajax模式離開此頁面時刪除dropzone實例 $(document).one('ajaxloadstart.page', function(e) { try { myDropzone.destroy(); } catch(e) {} }); }catch (e) { alert('瀏覽版本過低,不支持文件上傳!'); } </script> </html>
后台:
package com.paic.phssp.springtest.dropzone; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.mongodb.util.JSON; import com.paic.phssp.springtest.dto.Student; import com.rabbitmq.tools.json.JSONUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.json.JsonParser; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; /** * 文件上傳demo */ @Controller @EnableAutoConfiguration public class DropzoneController { private final Logger log = LoggerFactory.getLogger(getClass()); @Resource private Student student; @RequestMapping("/dropzone") private String toDropzonePage() { System.out.println("Hello World....."); return "dropzone"; } @RequestMapping("/uploadFile") private ResponseEntity<String> uploadFile(MultipartHttpServletRequest request) { log.info("start upload file ......"); HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;//status code 500 Map<String, Object> loadResultMap = new HashMap<String, Object>(); MultiValueMap<String, MultipartFile> multiMap = request.getMultiFileMap(); String taskKey = request.getParameter("taskKey"); log.info("taskKey = "+taskKey); String filePath = "F:\\test"; //TODO 異常 //int i = 9/0; for (Map.Entry<String, List<MultipartFile>> entry : multiMap.entrySet()) { List<MultipartFile> mFList = entry.getValue(); for (MultipartFile mFile : mFList) { int loadResult = loadFile(mFile, filePath); String fileName = mFile.getOriginalFilename(); loadResultMap.put(fileName, loadResult); } } //封裝返回 ObjectMapper objMapper = new ObjectMapper(); String body = ""; try { body = objMapper.writeValueAsString(loadResultMap); httpStatus = HttpStatus.OK; } catch (JsonProcessingException e) { log.error("load file error", e); } catch (Exception e) { log.error("load file error", e); } ResponseEntity responseEntity = new ResponseEntity(body, httpStatus); return responseEntity; } private int loadFile(MultipartFile mfile, String filePath) { log.error("load file param=", mfile.toString()); int result = 1; // 獲取上傳的原始文件名 String fileName = mfile.getOriginalFilename(); //TODO 制造有失敗上傳場景 /* if(fileName.equals("5a38b9ee3b7fb.jpg")){ return result; }*/ String fileSuffix = fileName.substring(fileName.lastIndexOf("."), fileName.length()); // 判斷並創建上傳用的文件夾 File file = new File(filePath); if (!file.exists()) { file.mkdir(); } // 重新設置文件名為 UUID,以確保唯一 file = new File(filePath, UUID.randomUUID() + fileSuffix); result = 0; try { // 寫入文件 mfile.transferTo(file); } catch (IOException e) { log.error("load file error", e); } return result; } }
可能的報錯:
org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: The field file exceeds its maximum permitted size of xxx bytes.
解決方案:
#springBoot自帶tomcat,Post請求參數默認限制1024,設置0就不限制大小了
server.tomcat.max-http-post-size=0
1)在配置文件(application.properties)加入如下代碼,一般這個方法解決不了問題
multipart.maxFileSize = 10Mb
multipart.maxRequestSize=100Mb
2)把如下代碼放在啟動類上,並在類上加入@Configuration
@Bean public MultipartConfigElement multipartConfigElement() { MultipartConfigFactory factory = new MultipartConfigFactory(); // 單個數據大小 factory.setMaxFileSize(DataSize.ofMegabytes(2L)); /// 總上傳數據大小 factory.setMaxRequestSize(DataSize.ofMegabytes(10L)); return factory.createMultipartConfig(); }
測試:
(1) 未寫就異常失敗了;//TODO 異常,放開
(2)因為uploadMultiple=true(一次請求可{{parallelUploads}}文件),成功與失敗都有,//TODO 制造有失敗上傳場景,放開
(3)成功,主要看下,前端file打印:
參考:
https://blog.csdn.net/weixin_40119256/article/details/81843361
http://wxb.github.io/dropzonejs.com.zh-CN/
https://blog.csdn.net/qq_25446311/article/details/78600354