發表於 程式分享

fineupload整批上傳成base64檔案

一、實作功能為: 因需將每個檔案於browser端簽章,並於server端驗章,
且需多個檔案同時上傳以取得同一批次序號

二、使用工具:
1.jquery套件fine uploader : 下載的url為https://fineuploader.com/
有API文件可參考.
2.struts2
3.Tomcat

三、基本的程式
1.browser端請直接參考https://fineuploader.com/demos.html
2.server端即為endpoint的連結

   $('#bootstrapped-fine-uploader').fineUploader({
        template: 'qq-template-bootstrap',
        request: {
            endpoint: '/server/uploads'
        }
    });

1) qqfile為傳入的檔案,型態為File,
取得檔案內容為byte[]方式如下,
我將byte[]存入MySQL資料庫mediumblob型態的欄位

   if (qqfile != null && allowedFileTypes.indexOf(sExtension.toLowerCase()) >= 0) {
        try {
            fis = new FileInputStream(qqfile);
            byte[] bFile = new byte[(int) qqfile.length()];
            fis.read(bFile);
        } catch (FileNotFoundException e) {
            logger.error(e.getStackTrace());
            message = e.getMessage();
        } catch (IOException e) {
            logger.error(e.getStackTrace());
            message = e.getMessage();
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException e) {
                logger.error(e.getStackTrace());
            }
        }
    }

2) qqfileFileName為傳入的檔案名稱,型態為String

四、遇到的問題及解法
1.於fine uploader 如何設定不自動上傳檔案?

    $('#bootstrapped-fine-uploader').fineUploader({
        template: 'qq-template-bootstrap',
        autoUpload: false, //client端改為false,不需先上傳
        ...
    });

2.fine uploader如何不將檔案上傳至server端即顯示檔案大小?

   $('#bootstrapped-fine-uploader').fineUploader({
        ...
        callbacks: {
            ...
            onSubmitted: function(id, name) {
                var file = this.getItemByFileId(id);
                //thumbnail為file template內某個class為qq-thumbnail-selector的element
                var thumbnail = $(file).find('.qq-thumbnail-selector');                    
                //檔名
                $(thumbnail).attr('docFileName', name);                    
                //檔案大小
                var uploadSize = $(file).find('.qq-upload-size-selector');                    
                    $(uploadSize).html(formatSize(this.getSize(id)));
            },
            ...
        },
        ...
    });
    
    function formatSize(bytes){
        var sizeSymbols = ["kB", "MB", "GB", "TB", "PB", "EB"];
        var i = -1;
        do {
            bytes = bytes / 1000;
            i++;
        } while (bytes > 999);

        return Math.max(bytes, 0.1).toFixed(1) + sizeSymbols[i];
    }

3.fine uploader顯示的內容如何不顯示縮圖,即其圖檔的顯示以原圖大小顯示?

   $('#bootstrapped-fine-uploader').fineUploader({
        ...
        callbacks: {
            ...
            onSubmitted: function(id, name) {
                var file = this.getItemByFileId(id);
                //thumbnail為file template內某個class為qq-thumbnail-selector的element
                var thumbnail = $(file).find('.qq-thumbnail-selector');
                                    
                var blob = $('#bootstrapped-fine-uploader').fineUploader('getFile', id);
                var reader = new window.FileReader();
                reader.readAsDataURL(blob); 
                reader.onloadend = function() {
                    var base64data = reader.result;
                    //將src設為檔案的base64格式,若thumbnail為img,則直接顯示圖檔於browser端
                    $(thumbnail).attr('src', base64data);
                }
                ...
            },
            ...
        },
        ...
    });

4.批次上傳檔案超過HTTP POST Limit size,如何調整Tomcat限制使其可上傳成功? (此問題是以某個變數為null呈現,其根本原因是超過HTTP POST Limit size)
於server.xml / Connector element內port="8080″內加上maxPostSize="20971520″
其中20971520 (= 20 * 1024 * 1024),即20MB,可自行調整

5.base64字串如何存入MySQL blobimage欄位?
將傳入的base64字串(String)轉成byte[]存入資料庫,Ex.base64Str.getBytes()

6.圖檔如何直接呈現於brower?
以我使用的struts套件說明如何回傳給browser端說明
1) struts.xml
<action …>

<result name$eq;"{1}" type$eq;"json">
<param name$eq;"root">dataMap</param>
</result>
</action>

2) server直接用dataMap.put將資料庫blobimage欄位取出為byte[]格式,
並回傳browser端為json格式,此json資料為int array

   private Map dataMap = new LinkedHashMap();
    ...
    //binaryStr為由MySQL blobimage欄位取得,為byte[]格式
    dataMap.put("binaryStr", binaryStr);

3) browser取得json int array的處理方式如下
myData.binarytoString(json資料為int array)取得img element src attr的內容,
即可呈現於browser端圖檔

   function binarytoString(array) {
        var result = "";
        for (var i = 0; i < array.length; i++) {
            //result += String.fromCharCode(parseInt(array[i], 2));
            result += String.fromCharCode(array[i]);
        }
        return result;
    }

7.如何將取出存成檔案於brower下載 (檔案有可能是圖檔、pdf、excel、word…) ?

   import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import javax.xml.bind.DatatypeConverter;
    ...

    public class ShowFileAction extends BaseAction {
        private int seqno;
        
        public ShowFileAction() {
            super();
        }

        public int getSeqno() {
            return seqno;
        }
        
        public void setSeqno(int seqno) {
            this.seqno = seqno;
        }

        @Override
        public String execute() throws Exception {
            if (seqno <= 0) {
                logger.error("No Docment match");
                response.getWriter().println("No Docment match");
                return NONE;
            }
            
            //由資料庫取得base64 string,格式為byte[]
            String docType = null;
            byte[] docSrc = null;
            ...
            
            if (docSrc != null) {
                byte[] decodeBytes = docSrc;
                String base64Str = new String(docSrc);
                //截取base64Str內,以後的資料,,之前的為檔案格式內容,非檔案資料
                String tmpBase64Str = base64Str.substring(base64Str.indexOf(",") + 1);
                decodeBytes = DatatypeConverter.parseBase64Binary(tmpBase64Str);

                FileOutputStream fos = null;
                try {
                    //2.顯示檔案                
                    String docFileName = java.net.URLEncoder.encode(fileName, "UTF-8");
                    response.setHeader("Content-Disposition", "attachment;filename=".concat(docFileName));
                    response.setContentType(getContentType(docType));
                    OutputStream out = response.getOutputStream();
                    out.write(decodeBytes);
                    out.close();            
                } catch (IOException e) {
                    logger.error("seqno: " + seqno + " -- " + e.getMessage());
                    response.getWriter().println("Get Docment error");
                } finally {
                    if (fos != null)
                        fos.close();
                }   
                    
            } else {
                logger.error("No Docment - seqno: " + seqno);
                response.getWriter().println("No Docment");
            }
                
            return NONE;
        } 
        
        /**
         * 取得content Type
         * @param docType
         * @return
         */
        private static String getContentType(String docType) {
            if (docType.compareToIgnoreCase("doc") == 0 || docType.compareToIgnoreCase("docx") == 0)
                return "application/vnd.ms-word";
            else if (docType.compareToIgnoreCase("xls") == 0 || docType.compareToIgnoreCase("xlsx") == 0 ||
                    docType.compareToIgnoreCase("csv") == 0)
                return "application/vnd.ms-excel";
            else if (docType.compareToIgnoreCase("pdf") == 0)
                return "application/pdf";
            else if (docType.compareToIgnoreCase("txt") == 0)
                return "text/plain";
            else if (docType.compareToIgnoreCase("jpg") == 0 || docType.compareToIgnoreCase("jpeg") == 0)
                return "image/jpeg";
            else if (docType.compareToIgnoreCase("png") == 0)
                return "image/png";
            else if (docType.compareToIgnoreCase("gif") == 0)
                return "image/gif";
            return "application/vnd.ms-word";
        }   
    }

8.圖檔縮圖及放大呈現?
用javascript (jquery)處理

   $(document).ready(function() {
        //click 第4項產生的小圖(其設定的width較小)時觸發
        //小圖的class為sealImg
        //需注意若小圖是用javascript動態產生,需於小圖產生後再重bind此行,否則不work
        $('.sealImg').bind('click', showImgFunc);
    }); 
    
    function showImgFunc(e) {        
        e.preventDefault();
        
        var imgSrc = $(this).attr('src');        
        var htmlSrc = '';
        
        //modal是用bootstrap3產生,此處不說明
        $('#modal-body-image').html(htmlSrc);
        $('#imageModal').on('shown.bs.modal', function(e) {
                $("#messageBtn").focus();
        });  
        $('#imageModal').modal('show');
    }