一次dropzone體驗


對於前端,本人不是太擅長,對於當前的一些網上的樣例,也許是習武悟性太差,不是太透,所以只能通過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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM