iT邦幫忙

0

[ASP.NET]-[Highslide]-[Dropzone]-[AJAX UpdatePanel] 以拖曳的方式進行檔案上傳

  • 分享至 

  • xImage
  •  

【前言】

任何內部系統與電商,都會使用「檔案上傳」都用 input type="File" 來處理檔案的上傳,現在的系統大部份不外乎也都是這麼做。 但是,以需求不同透過「檔案上傳」一次要上傳多個檔,那系統就是提供多個 input type="File" 來做到批次上傳的動作,還是一個 zip 裡面就包裹著多個檔案,上傳後再來一次解開 zip 來達到需求。方法很多,但是...都不是很視覺化,上傳檔案在現今應該可以更視覺化更親民才對。

但網路上所提供的都是一知半解,那就只好自己寫一支較方便的上傳工具做為往後自己的利器,並且套用在自己的系統開發上,並取代那個醜不拉機的系統介面。

【您必須要有的技術底層】

  1. 必須會使用 System.IO , System.Web.HttpContext , System.Web.HttpPostedFile 操作
  2. 必須理解 .ashx 是在做什麼的
  3. 會用 Ajax UpdatePanel 與 Triggers

【應用技術與版型】

本人寫程式是比較往視覺化美觀設計,不想在自己的系統上看到一些醜不拉機管理介面,因為當您是使用者時,看到一些五顏六色操作畫面,說真的,我也不覺得程式的底層與邏輯可以寫的多少好。 尤其應用了一堆 EF 但卻連 TSQL 與 Stored Procedure 都不會寫,每次寫出來的 TSQL 卻只有一支程式可以用而己,說真的...貢獻度極低...又不寫文件的...說的多強那就自己去自嗨就好了...

[套版與上傳介面的部份]

檔案上傳版型,我會用套版的方式來進行整合,這次整合的版型是 Bootstrap 後台管理版型 Hyper >> Forms Dropzone File Upload

https://ithelp.ithome.com.tw/upload/images/20200912/20104851olJAErrdil.png

這個部份採用了 dropzone.min.js 所提供的 JS 程式來達到上傳的動作,Dropzone 所提供的 JS 也可以上傳整個目錄(您必須要用拖拉目錄的方式) 來進行上傳的動作,上傳後就會將圖片轉成Base64 ,但是他還沒有真正上傳到您的 Server 上喔!! 別以為這樣子就上傳完成了喔...

https://ithelp.ithome.com.tw/upload/images/20200912/20104851MDYOr0gSIU.png

這動作您只能進行預覽的動作,後續您必須要自行撰寫接收程式。 那上傳後您覺得這顯示並不喜歡,那您可以修改 dropzone.JS >> previewTemplate: 這個部份的 HTML 就可以有不同的顯示方式。

[Highslide 小工具]
Highslide 大部份都是拿來做「預覽圖片」,Highslide 有支援 iframe 的方式,您可以將您上傳介面按鈕掛在 Highslide 提供的 ifram 顯示您的介面,例如以下方法...


<a href="您設計的 Dropzone 頁面" 
class="btn btn-primary" 
onclick="return hs.htmlExpand(this, {objectType:'iframe',width:'1024',height:'600',fixedControls:false})"><i class="mdi mdi-square-edit-outline"></i>選擇要上傳的檔案</a>
 
fixedControls:false 會以您「按下的位置」顯示 Highslide 介面,您可以找網路上的相關範例有其他的設定方式


[Dropzone 參數設定]

<script type='text/javascript'>
        $(document).ready(function () {
            Dropzone.autoDiscover = true;
            //Simple Dropzonejs 
            $('#dZUpload').dropzone({
                url:'「檔案的接收端,這裡我是用 xxxx.ashx」',
                maxFiles:可以上傳多少個檔案 1~N 都可以,
                maxFilesize:上傳一個檔案最高 MB 1=1MB , 10=10MB,
                uploadMultiple:true,
                addRemoveLinks:true,
                acceptedFiles:'指定上傳的檔案格式 .jpg,.jpeg,.gif,.png,.mp4 ',
                //以下是各項事件的說明
                dictDefaultMessage: '將檔案拖放到這裡 (或這裡點擊)',
                dictFallbackMessage: '您的瀏覽器不支援拖放檔案上傳',
                dictFallbackText: '您的瀏覽器不支援拖放檔案上傳',
                dictFileTooBig: '檔案大小限制:{{maxFilesize}}MB, 檔案太大 ({{filesize}}MB)',
                dictInvalidFileType: '您可以上傳 jpg, jpeg, png 圖檔',
                dictCancelUpload: '取消上傳',
                dictCancelUploadConfirmation: '您確定取消上傳這張圖檔嗎?',
                dictRemoveFile:'清除記錄',
                dictRemoveFileConfirmation: '您確定刪除這張圖檔嗎?',
                dictMaxFilesExceeded:'檔案個數限制:10',
                success: function(file, response) {
                        var imgName = response;
                        file.previewElement.classList.add('dz-success');
                        console.log('Successfully uploaded :' + imgName);
                    },
                    error: function(file, response) {
                        //發生錯誤要執行的動作
                        file.previewElement.classList.add('dz-error');
                    },
                    init:function () {
                        //所有的檔案都己上傳完成
                        this.on('queuecomplete', function (file) {
                            //這裡您可以加上 ajax 事件
                            //您要自行取得您的 AJAX linkbutton 事件,
                            //例如像是 __doPostBack() 將 linkbutton onclick 
                            //事件整個貼到 "這裡"
                        });
                    }
                });                
            });
</script>

[Ajax 的設定]

所有的檔案都上傳完成,會觸發 init 程序。這時候您可以寫一段 Ajax 事件,那 Ajax 事件您要這樣子設計


<asp:ScriptManager ID="ScriptManager1" runat="server" />
<span style="display: none;"> //用 span 將這控制項藏起來不顯示在畫面上
    <asp:UpdatePanel ID=_UpdatePanel" runat="server">
        <Triggers> //這部份一定要加 linkButton 項目
            <asp:AsyncPostBackTrigger ControlID="_ReorganizePage" EventName="Click" />
        </Triggers>
            <ContentTemplate>
            <%--功能事項--%>
            <asp:LinkButton ID="_ReorganizePage" runat="server" Text="上傳完成觸發" OnClick="您的程序" />
            </ContentTemplate>
    </asp:UpdatePanel>
</span>

<asp:UpdatePanel ID="_Content_UpdatePanel_FilesUPLoad" runat="server">
    <ContentTemplate>
        將整個 HTML 全部包起來
        <asp:Panel ID="_Panel01">
            <DIV ID="dZUpload">
                這整個 DIV 接收使用者拖曳過來的檔案或是目錄
            </DIV>
        </asp:Panel>
        <asp:Panel ID="_Panel02">
            當 Dropzone 上傳完成後一定會觸發 init,您要詢問使用者下一步要做什麼事情
            例如上傳 10 張圖片後如果超過 10 張以上的圖片,那要使用者在操作介面上選擇
            要選擇那一些圖片 「以符合程序」
            
            我的做法是 >> 上傳完成 >> 穩藏 _Panel01 將 _Panel02 顯示出來,提供使用者確定
            「現在程序您只能選擇 10 張圖片」超過的圖示在關閉 Highslide 視窗時或是再提供按
            鈕來執行最後的程序,程式完成後就可以關閉 Highslide 的視窗
        </asp:Panel>
    </ContentTemplate>
</asp:UpdatePanel>

透過這樣子的設計,您就己經完成 「現在程序您只能選擇 10 張圖片」的需求,但要注意一件事情 >> 此 Dropzone 上傳介面是 "共用網頁程序" 所以在上傳時您必須要有 Temp 暫存的概念。

啟動上傳前,必須建立一個 Temp 目錄,我會用 GUID 來處理,例如 [A君] 12:00 要進行上傳,系統就要建立一個 Temp\20200912_6134CF5E357441AA8\ 而 [A君] 所上傳的檔案都會放在 "20200912_6134CF5E357441AA8" ,另一位 [B君] 12:01 也要透過介面進行檔案上傳動作,上傳前也是建立了一個目錄 "20200912_6111111111111" 來進行上傳的動作,這樣子檔案上傳時就不會 [A君] 在上傳而 [B君] 看到 [A君] 所上傳的檔案,那就是會很奇怪了...

另一個問題,建立目錄我會多加一個 [年月日] 最主要的目的,就是將過舊的目錄進行刪除的動作,當然您可以直接讀目錄建立的時間,然後再來刪除。看您自己如何處理過舊的目錄或檔案,不過真的記得要清掉不然數量一多,執行上會使得 Windows 跑很慢,那就會拖到執行效能了。 後續您如果要存到資料庫都可以,看您要如何做...

[ASP.NET ASHX 程式碼]

好了,最重要的接收源的方法如下,透過 Visual Studio 新增一個 [名稱自取].ASHX


using System;
using System.Web;
using System.IO;
using System.Drawing;
using System.Threading;

public class [您的 Class 名稱] : IHttpHandler
{
    /// <summary>
    /// 接收來源
    /// </summary>
    /// <param name="_HttpContext">接收資料源</param>
    public void ProcessRequest(HttpContext _HttpContext)
    {
        //這裡的程式碼就要看您的能力了
        // 1. 判斷檔案是否有重覆,建議重新取檔案名稱,取比較有意義的檔案名稱
        // 2. 判斷目錄是否有建立
        // 等等....其他的就看你如何做了
        
        // 指定要導出的資料流內容
        _HttpContext.Response.ContentType = "text/plain";
        
        //開始接收檔案內容了
        foreach (string s in _HttpContext.Request.Files)
        {
             //取得此檔案的內容
            HttpPostedFile _HttpPostedFile = _HttpContext.Request.Files[s];
            //將資料內容進行存檔的動作
            _HttpPostedFile.SaveAs("目錄+檔案名稱,例如: C:\TEMP\20200912_6134CF5E357441AA8\aaa.???");
        
        }
        
        //回傳檔案的名稱
        _HttpContext.Response.Write(_strWeb_InBoxFileName);
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

【使用情境】

  1. 程序一:可以上傳 10 個檔案,每一個檔案最高上傳 MB 容量只能 10 MB ,只能上傳 .JPG,JPEG,.gif,.png 等檔案格式

  2. 程序二:只能上傳 1 個檔案,每一個檔案最高上傳 MB 容量只能 1 MB ,只能上傳 .png 檔案格式

修改 Dropzone 參數設定

程序一:
$('#dZUpload').dropzone({
    maxFiles:10,
    maxFilesize:10,
    acceptedFiles:'.jpg,.jpeg,.gif,.png',
});

程序二:
$('#dZUpload').dropzone({
    maxFiles:1,
    maxFilesize:1,
    acceptedFiles:'.png',
});

你可以用任何方式帶參數進去,我的習慣會直接用

  1. Session >> 我可以直接帶參數就不用加密了
  2. URL >> FilesUpload.aspx?DropConfig=10|10|.jpg,.jpeg,.gif,.png

第二點可以提供給其他系統使用共同的上傳介面,自行控制上傳檔案後要做什麼事情,然而 DropConfig 後面帶的參數我會建議加密或是用其他的方式,最好有加密後有過期的動作,以免後續網址被瀏覽器記錄,或是因為被外流而使得有心人來亂搞,當然您還有更多的動作來處理這樣子的問題

[DEMO]
https://drive.google.com/file/d/1Cu_1ZlraxklVrA4rq99KHk_T55O4uGVO/view?usp=sharing

https://ithelp.ithome.com.tw/upload/images/20200913/20104851jidgPdnQWr.png

【總結】

上傳方式百百種,那種是最好的可以自行考量。 就算是您設計與開發都是後端,那也是可以去吸收國外版型的風格,來多改善設計上的美觀,這也是一種學習方式也是一種進步。 現在的設計講求的是整合,看看別人所提供的資訊,並加以導入並吸取別人的經驗來轉化成自己的能力,對自己都是一個成長不是嗎??

有任何問題可以詢問,除了 Dropzone 相關的項目我無法回答之外,其他的都能夠針對主題...


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言