文件的上傳與下載、圖片的上傳和讀取


這幾天一直在做報表模塊。做報表的過程中,需要上傳本地CSV格式文件,以供后端解析,從而批量導入數據;同時,也需要從后端下載文件(格式多種:有CSV,PDF,以及JSON),用於本地瀏覽。

  上傳文件:文件的上傳基本都是采用 <input  type="file"  id="upload_files" name="upload_files"/>。通過 type="file"打開本地文件夾進行文件的選取(期間這個原理,沒鬧明白),文件選取完成后,就可以直接提交form表單或者獲取文件數據發送后端了。這期間試過幾種方式,最后選了一個。

<!--第一種:直接form表單提交。這種方式好處:在於不需要另外編寫數據提交方法,簡單、快速;
壞處:在於form表單提交后,頁面會跳轉到form表單的action鏈接上,雖然自動跳轉可以避免,但是還是需要另外編寫方法,同時數據不好處理-->
<form id="uploadForm" action="http://192.168.0.120:9090/lampinfo/device/importCsv" enctype="multipart/form-data"
      method="post">
    <input type="file" id="upload_files" name="upload_files"/>
    <input id="data_upload_button" type="submit" value="Upload"/>
</form>
<!--第二種:將文件的選擇和數據提交分開。這種方式好處:文件選擇后,在文件選擇的后面,能清楚知道選擇的是哪個文件。
數據單獨提交,便於對數據的封裝和處理。同時在采用ajax異步提交數據后,界面不會切換;壞處:在於文件選擇、數據提交是分開進行,在操作上有些繁瑣。-->
<form id="uploadForm" enctype="multipart/form-data"
      style="width: 45px;height: 26px">
    <input type="file" id="upload_files" name="upload_files"/>
</form>
<button type="button" class="btn btn-default dropdown-toggle"
        data-toggle="dropdown" aria-expanded="false"
        ng-click="saveReport()">
    <i class="fa fa-cloud-upload" style="font-size: 14px"></i>
</button>


/***
 * 功能:文件上傳,格式不限
 * 說明:FormData 對象是XMLHttpRequest 2級定義的,它為序列化表單以及創建與表單格式相同的數據(當然是用於XHR傳輸)提供便利。
 * 利用 FormData 對象,可以通過對象鍵值對來模擬一系列表單格式的數據,以前上傳文件需要用form表單封裝起來(即和后端約定一個數據傳輸格式),現在FormData對象就是按照規定的格式,把form表單中所有表單元素的name與value組裝成一個queryString,省去了手工拼接的工作。
* JQ里面有個表單序列化的函數,FormData對象的作用和它是一樣的。 * FormData對象還提供了更多的操作方法,但全部都在其原型對象中,自己本身沒任何的屬性及方法。同時還可以使用 XMLHttpRequest的send()方法來異步提交表單。與普通的Ajax相比,使用FormData的最大優點就是可以異步上傳二進制文件。 * 由於FormData是 XMLHttpRequest Level 2 新增的接口,現在 低於IE10 的IE瀏覽器不支持 FormData
*/ $scope.saveReport = function () { var formData = new FormData(); //新建一個FormData對象實例 /* 調用append方法添加數據,參數兩個,以鍵值對形式,相當於手工拼接。此處將文件添加到表單對象里*/ formData.append('upload_files', $('#upload_files')[0].files[0]); /* 也可以直接把form表單作為參數傳遞給FormData對象。new FormData的參數是一個DOM對象(即一個DOM節點),而非jQuery對象;這兩種方式也可以混用*/ var uploadForm = document.getElementById("uploadForm"); var formData = new FormData(uploadForm); formData.append('data', "fengling");
/* 注意通過JQ ajax提交數據的時候,屬性設置有講究 */ $.ajax({ url: url, type: 'POST', cache: false, //不緩存 data: formData, //上傳formData封裝的數據 processData: false, //告訴jQuery不要去處理發送的數據 contentType: false //告訴jQuery不要去設置Content-Type請求頭 }).done(function (res) { layer.msg("File upload or data interpretation failed!", { //layer.msg是 layer插件 的一個信息提示模板。此處用來提示用戶文件上傳成功 area: ['600', '70px'], icon: 1, time: 2000, //2秒關閉(如果不配置,默認是3秒) anim: 6, skin: 'customStyle' }); }).fail(function (res) { layer.msg("File upload or data interpretation failed!", { //layer.msg是 layer插件 的一個信息提示模板。此處用來提示用戶文件上傳失敗。當然這兩個layer.msg可以寫成一個方法,減少代碼冗余 area: ['600', '70px'], icon: 2, //0表示提醒,1表示成功,2表示失敗! time: 2000, //2秒關閉(如果不配置,默認是3秒) anim: 6, skin: 'customStyle' }); }); };

  導出文件:前端通過模擬表單,用瀏覽器將文件導出來。當然在導出文件之前后端需要根據查詢參數查詢到正確數據后,建立一個內容格式正確的文件!

/**
 * 功能:導出文檔,文檔下載
 * 把CSV文件上傳到后端之后,那么前端就算是完事了,至於后端怎么玩的,我們不管;接下來就是導出文件了,相比於上傳文件,導出文件就相當簡單了。
 * 前端將需要查詢數據的參數發送到后端,后端根據參數將需要的數據查詢出來以后,按固定格式生成CSV,PDF等格式的文件(生成PDF文件時,如果需要展示報表的圖形界面,則前端需要將報表圖形轉換成base64位編碼發送給后端,后端自己解析編碼並完成構圖),
 * 接下來就是文件導出了。注意:由於ajax請求下載的時候,后端是以數據流的形式將文件數據返回回來,那么前端就無法獲取到固定格式的文件(就是一串編碼)。
 * 這時候又該表單上場了,我們以模擬表單的方式,將文件導出來。模擬表單就是在頁面上新建一個from表單,然后將該表單添加到頁面的隨意一個節點下(此處直接掛載在了body下,當然它是隱藏的,界面上不會顯示),然后通過form表單的submit方法,通過瀏覽器將文件導出來。
 */
$scope.export = function () {
    var parameter = {};   //查詢數據的參數
    $http({
        url: url,           //查詢數據,后端生成文件的鏈接,不是下載鏈接
        method: "POST",
        dataType: "JSON",
        headers: {
            "Accept": "application/json",
            "Content-type": "application/json;charset=UTF-8"
        },
        data: parameter,
        cache: false,
        timeout: 15000  //超時設置為15秒
    }).then(function (response) {
        if (response.data.message == "success") {
            var downloadtype = "",value = "";
            if ($scope.inside.exportType == "pdf") {
                downloadtype = "PDF";
            } else {
                downloadtype = "CSV";
                value = parameter.name + ".csv";
            }
            $("body").find(".download").remove();
            var $eleForm = $("<form method='POST' class='download'><input type='hidden' name='csvFileName'></form>");
            $eleForm.attr("action", $scope.inside.STL_Inventory + "/lampinfo/deviceStatusReport/export" + downloadtype);   //文件導出鏈接在這
            $("body").append($eleForm);
            $("body").find("input[name='csvFileName']").attr("value", value);
            $eleForm.submit();    //通過表單submit方法,模擬表單將文件導出
        } else {
            Confirmation.confirm("Export Failed!", 0, "OK");
        }
    }).catch(function (response) {
        Confirmation.confirm("Export Failed!", 0, "OK");
    });
};

 

 

在完成了文件的上傳和導出以后,接下來就是圖片的上傳和下載
  圖片的上傳和下載前面在PDF文件的構建時有需要將報表的圖形部分上傳到后端。圖片的上傳是一樣的,就是將本地圖片獲取到以后轉換成base64位編碼,然后將編碼發送到后端,后端獲取到編碼以后存入數據庫,則圖片上傳完成。
  顯示圖片,則是一個反向工程,從后端將base64編碼獲取到以后,解碼顯示成圖片就成。至於下載圖片,form表單嚴陣以待!

/**
 * 功能:選擇圖片,獲取本地圖片的base64位編碼
 * 這應該是文件上傳的第三種方式:前兩種都是顯視 type='file' ,這一種是模擬一個表單。將type='file'封裝在方法內部,避免了type='file' 顯視顯示,出現樣式上的不協調
 * 在方法內新建一個表單(當然樣式是隱視的),然后將該表單添加到頁面的隨意一個節點下(此處還是直接掛載在了body下),然后自點擊一下,通過自點擊打開 type='file', 進行圖片的選取。
 * 需要注意的是:在方法的最后面需要將這個掛載上去的節點移除,不然添加的圖片永遠都是第一次添加的那張。
*/
$scope.addPicture = function () {
    var file = $("<input type='file' name='file' id='file'>"), form = $("<form id='uploadForm' class='uploadfile' enctype='multipart/form-data' style='display: none'></form>");
    file.appendTo(form);
    $("body").append(form);
    file.click();           //自點擊表單 type='file'
    file.change(function () {       //圖片更換執行回調方法
        var file = document.getElementById("file").files[0];
        // if (!/image\/\w+/.test(file.type))           //判斷獲取的是否為圖片文件,jpg和png格式
        // {
        //     Confirmation.confirm("請確保文件為圖像文件!", 0, "OK");
        //     return false;
        // }
        var reader = new FileReader();
        reader.readAsDataURL(file);     //將文件讀取為DataURL,讀取的內容是加密以后的本地文件路徑
        reader.onload = function (e) {      //文件讀取成功完成后,執行方法;其讀取回的所有數據都在事件對象e內
            $scope.inside.pictureList.push({"deviceType":"LampPoleModel","picture": e.target.result});
            $("#buttonList img").eq(0).click();
        };
        $("body").find(".uploadfile").remove();     //在方法的最后面需要將這個掛載上去的節點移除,不然添加的圖片永遠都是第一次添加的那張

        /**  這里需要介紹下FileReader對象(免得下次讀代碼,又要去度娘)
         * FileReader:是window對象的一個構造函數,用於讀取文件選擇標簽(type='file')選擇的File的Dom對象。即用來把文件選擇的信息讀入內存,並且讀取文件中的數據。
         * 其接口提供了一個異步API,使用該API可以在瀏覽器主線程中異步訪問文件系統,讀取文件中的數據。
         * 為了安全FileReader可以讀取表單上已經選擇的文件,不能讀取本地文件,它以二進制信息的方式讀取表單文件:主要用於大文件的信息讀取。
         * 特點:1、讀取后,二進制信息在瀏覽器內存中,批量的向服務器進行傳輸。2、一般要配合后台程序,第三方插件共同完成,3、斷點下載和斷點上傳
         *
         * FileReader接口有5個方法,其中4個用來讀取文件,另一個用來中斷讀取。無論讀取成功或失敗,方法並不會直接返回讀取結果,這一結果存儲在result屬性中。
         * FileReader接口的方法:
         * 方法名                參數            描述
         readAsArrayBuffer     file    將文件讀取為一個ArrayBuffer對象以表示所讀取文件的內容.
         readAsBinaryString    file    將文件讀取為二進制編碼
         readAsText            file,[encoding]        將文件讀取為文本
         readAsDataURL         file    將文件讀取為DataURL,讀取的內容是加密以后的本地文件路徑
         abort                 (none)    終端讀取操作
         *
         * FileReader接口事件:FileReader接口包含了一套完整的事件模型,用於捕獲讀取文件時的狀態。
         FileReader接口的事件:
         事件               描述
         onabort          中斷
         onerror          出錯
         onloadstart      開始
         onprogress        正在讀取
         onload            成功讀取
         onloadend         讀取完成,無論成功失敗
         */
    });
};


免責聲明!

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



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