SpringMVC中Ajax非同步上傳圖片的方法

colorandsong發表於2014-10-24

        專案中遇到了上傳圖片的需求,最開始用的是傳統的同步上傳,在需要上傳圖片的地方定義iframe,如下

        <iframe id="uploadImg" frameborder=0 width=300 height=100 marginheight=0
marginwidth=0 scrolling=no src="jump_image_upload.xhtml">
 </iframe>

       這裡的src通過Controller將iframe內容扭轉至image_upload頁,再到該頁定義file控制元件進行圖片上傳。

       這樣會帶來一個問題,即瀏覽器不相容,提交後的樣式在ie下面不可控,因此需要將同步上傳改為非同步上傳,上網找了一些外掛,最終發現ajaxfileupload.js比較好用,使用步驟如下:

      1)下載ajaxfileupload.js,放到專案工程裡面,前端頁面使用如下:

            $(".uploadBtn").click(function() {
$.ajaxFileUpload({
url : 'image_upload.json', //需要連結到伺服器地址  
beforeSend:function(){$(".progress").show();},
secureuri : false,
fileElementId : 'uploadFile', //檔案選擇框的id屬性  
dataType : 'json', //伺服器返回的格式,可以是json  
success : function(data, status) //相當於java中try語句塊的用法  
{
},
error : function(data, status, e) //相當於java中catch語句塊的用法  
{
}
});
});

    2)後臺程式碼如下:

     @RequestMapping(value = "image_upload.json", method = RequestMethod.POST)
    public void upload(@RequestParam(value="uploadFile")MultipartFile file,HttpServletRequest request,HttpServletResponse response) throws IOException
    {
        Map<String,String> model = new HashMap<String, String>();
        String fileName = this.generateFileName(file.getOriginalFilename());
        String path = request.getSession().getServletContext().getRealPath("upload");
        File targetFile = this.imageUploadService.getTargetFile(path,fileName);
        try
        {
            file.transferTo(targetFile);
            this.imageUploadService.uploadImage(fileName, targetFile.getPath());
            model.put("fileUrl", request.getContextPath() + "/upload/" + fileName);
            model.put("file", fileName);
        }
        catch (Exception e)
        {
            logger.error("圖片上傳失敗!", e);
            model.put("errorMsg", "圖片上傳失敗!");
        }
        JSONObject json = JSONObject.fromObject(model);
        response.getWriter().write(json.toString());
        response.getWriter().close();
    }

      

    最開始使用時,出現了一些問題,據說該外掛針對jquery1.7+版本支援不好,如下:

             (1)控制檯提示少handerError方法;

                      具體解決方法是:上網找一個handlerError方法,新增到ajaxfileupload.js中。

             (2)後臺上傳成功,但js總跳轉到error邏輯;

                     具體解決辦法:eval對data的處理有問題,將uploadHttpData方法中的eval( "data = " + $(data).html() );  改為eval( "data = " + $(data).html() );  

             (3)IE瀏覽器下檔案上傳成功之後,總提示下載json資料

                    具體原因:針對非同步上傳檔案的請求,Controller後臺不能通過ResponseBody的方式返回json物件,而是要在後臺組裝成json資料格式,然後通過response物件write到前端頁面。

              (4)IE和Firefox、chrome瀏覽器不相容

                 具體原因:response後臺在write出前端頁面的json資料時,不要設定contentType,之前我設定了:

                         response.setContentType("text/html;charset=UTF-8");

              結果Firefox、chrome不正常,但IE正常;

               後來設定了

                         response.setContentType("application/json;charset=UTF-8");

                結果IE不正常,但Firefox、Chrome正常。

             (5)檔案上傳一次之後,不重新整理頁面再次上傳同一個檔案,提示 上傳失敗

                    具體原因:檔案上傳時沒有重新命名,導致 file.transferTo(targetFile);這句出異常,每次上傳時將圖片按時間重新命名就ok了。


一個能夠正常執行的ajaxFileUpload.js全文如下:

jQuery.extend({  
    handleError: function( s, xhr, status, e )      {  
        // If a local callback was specified, fire it  
                if ( s.error ) {  
                    s.error.call( s.context || s, xhr, status, e );  
                }  
  
                // Fire the global callback  
                if ( s.global ) {  
                    (s.context ? jQuery(s.context) : jQuery.event).trigger( "ajaxError", [xhr, s, e] );  
                }  
    },  
    createUploadIframe: function(id, uri)  
    {  
    
        var frameId = 'jUploadFrame' + id;  
          
        if(window.ActiveXObject) {  
            if(jQuery.browser.version=="9.0")  
            {  
                io = document.createElement('iframe');  
                io.id = frameId;  
                io.name = frameId;  
            }  
            else if(jQuery.browser.version=="6.0" || jQuery.browser.version=="7.0" || jQuery.browser.version=="8.0")  
            {  
              
                var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');  
                if(typeof uri== 'boolean'){  
                    io.src = 'javascript:false';  
                }  
                else if(typeof uri== 'string'){  
                    io.src = uri;  
                }  
            }  
        }  
        else {  
            var io = document.createElement('iframe');  
            io.id = frameId;  
            io.name = frameId;  
        }  
        io.style.position = 'absolute';  
        io.style.top = '-1000px';  
        io.style.left = '-1000px';  
  
        document.body.appendChild(io);  
  
        return io;        
    },  
    ajaxUpload:function(s,xml){  
        //if((fromFiles.nodeType&&!((fileList=fromFiles.files)&&fileList[0].name)))  
  
        var uid = new Date().getTime(),idIO='jUploadFrame'+uid,_this=this;  
        var jIO=$('<iframe name="'+idIO+'" id="'+idIO+'" style="display:none">').appendTo('body');  
        var jForm=$('<form action="'+s.url+'" target="'+idIO+'" method="post" enctype="multipart/form-data"></form>').appendTo('body');  
        var oldElement = $('#'+s.fileElementId);  
        var newElement = $(oldElement).clone();  
        $(oldElement).attr('id', 'jUploadFile'+uid);  
        $(oldElement).before(newElement);  
        $(oldElement).appendTo(jForm);  
  
        this.remove=function()  
        {  
            if(_this!==null)  
            {  
                jNewFile.before(jOldFile).remove();  
                jIO.remove();jForm.remove();  
                _this=null;  
            }  
        }  
        this.onLoad=function(){  
          
            var data=$(jIO[0].contentWindow.document.body).text();  
      
      
            try{  
  
                if(data!=undefined){  
                   data = eval('(' + data + ')');  
                    try {  
                         
                        if (s.success)  
                            s.success(data, status);  
      
                        // Fire the global callback  
                        if(s.global)  
                            jQuery.event.trigger("ajaxSuccess", [xml, s]);  
                        if (s.complete)  
                            s.complete(data, status);  
                        xml = null;  
                      } catch(e)   
                         {  
                       
                        status = "error";  
                        jQuery.handleError(s, xml, status, e);  
                      }  
  
                      // The request was completed  
                      if(s.global)  
                          jQuery.event.trigger( "ajaxComplete", [xml, s] );  
                      // Handle the global AJAX counter  
                      if (s.global && ! --jQuery.active )  
                          jQuery.event.trigger("ajaxStop");  
  
                      // Process result  
         
                }  
         }catch(ex){  
             alert(ex.message);  
         };  
        }  
        this.start=function(){jForm.submit();jIO.load(_this.onLoad);};  
        return this;  
            
    },  
    createUploadForm: function(id, url,fileElementId, data)  
    {  
        //create form     
        var formId = 'jUploadForm' + id;  
        var fileId = 'jUploadFile' + id;  
        var form = jQuery('<form  action="'+url+'" method="POST" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>');   
        if(data)  
        {  
            for(var i in data)  
            {  
                jQuery('<input type="hidden" name="' + i + '" value="' + data[i] + '" />').appendTo(form);  
            }             
        }     
  
        var oldElement = jQuery('#' + fileElementId);  
        var newElement = jQuery(oldElement).clone();  
        jQuery(oldElement).attr('id', fileId);  
        jQuery(oldElement).before(newElement);  
        jQuery(oldElement).appendTo(form);  
  
        //set attributes  
        jQuery(form).css('position', 'absolute');  
        jQuery(form).css('top', '-1200px');  
        jQuery(form).css('left', '-1200px');  
        jQuery(form).appendTo('body');        
        return form;  
    },  
    ajaxFileUpload: function(s) {  
        // TODO introduce global settings, allowing the client to modify them for all requests, not only timeout      
        // Create the request object  
        var xml = {};  
        s = jQuery.extend({}, jQuery.ajaxSettings, s);  
        if(window.ActiveXObject){  
            var upload =  new jQuery.ajaxUpload(s,xml);  
            upload.start();  
            
       }else{  
        var id = new Date().getTime();  
        var form = jQuery.createUploadForm(id,s.url, s.fileElementId, (typeof(s.data)=='undefined'?false:s.data));  
        var io = jQuery.createUploadIframe(id, s.secureuri);  
        var frameId = 'jUploadFrame' + id;  
        var formId = 'jUploadForm' + id;          
        // Watch for a new set of requests  
        if ( s.global && ! jQuery.active++ )  
        {  
            jQuery.event.trigger( "ajaxStart" );  
        }              
        var requestDone = false;  
       
        if ( s.global )  
            jQuery.event.trigger("ajaxSend", [xml, s]);  
        // Wait for a response to come back  
        var uploadCallback = function(isTimeout)  
        {             
            var io = document.getElementById(frameId);  
      
            try   
            {                 
                if(io.contentWindow)  
                {  
                     xml.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;  
                     xml.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;  
                       
                }else if(io.contentDocument)  
                {  
                     xml.responseText = io.contentDocument.document.body?io.contentDocument.document.body.innerHTML:null;  
                     xml.responseXML = io.contentDocument.document.XMLDocument?io.contentDocument.document.XMLDocument:io.contentDocument.document;  
                }                         
            }catch(e)  
            {  
                jQuery.handleError(s, xml, null, e);  
            }  
            if ( xml || isTimeout == "timeout")   
            {                 
                requestDone = true;  
                var status;  
                try {  
                    status = isTimeout != "timeout" ? "success" : "error";  
                    // Make sure that the request was successful or notmodified  
                    if ( status != "error" )  
                    {  
                        // process the data (runs the xml through httpData regardless of callback)  
                        var data = jQuery.uploadHttpData(xml, s.dataType);      
                        // If a local callback was specified, fire it and pass it the data  
                        if (s.success)  
                            s.success(data, status);  
      
                        // Fire the global callback  
                        if(s.global)  
                            jQuery.event.trigger("ajaxSuccess", [xml, s]);  
                        if (s.complete)  
                            s.complete(data, status);  
                          
                    } else  
                        jQuery.handleError(s, xml, status);  
                } catch(e)   
                {  
                    status = "error";  
                    jQuery.handleError(s, xml, status, e);  
                }  
  
                // The request was completed  
                if(s.global)  
                    jQuery.event.trigger( "ajaxComplete", [xml, s] );  
                // Handle the global AJAX counter  
                if (s.global && ! --jQuery.active )  
                    jQuery.event.trigger("ajaxStop");  
  
                // Process result  
                jQuery(io).unbind();  
  
                setTimeout(function()  
                                    {   try   
                                        {  
                                            jQuery(io).remove();  
                                            jQuery(form).remove();    
                                              
                                        } catch(e)   
                                        {  
                                            jQuery.handleError(s, xml, null, e);  
                                        }                                     
  
                                    }, 100);  
  
                xml = null;  
  
            }  
        };  
        // Timeout checker  
        if (s.timeout>0)   
        {  
            setTimeout(function(){  
                // Check to see if the request is still happening  
                if( !requestDone ) uploadCallback("timeout");  
            }, s.timeout);  
        }  
        
            try   
                {  
          
                    var form = jQuery('#' + formId);  
                    jQuery(form).attr('action', s.url);  
                    jQuery(form).attr('method', 'POST');  
                    jQuery(form).attr('target', frameId);  
                      
                    if(form.encoding)  
                    {  
                        jQuery(form).attr('encoding', 'multipart/form-data');                 
                    }  
                    else  
                    {     
                        jQuery(form).attr('enctype', 'multipart/form-data');              
                    }     
             
                      
                    jQuery(form).submit();  
          
                } catch(e)   
                {     
                    jQuery.handleError(s, xml, null, e);  
                }  
                  
                jQuery('#'+ frameId).load(uploadCallback);  
                return {abort: function () {}};   
    
       }  
    },  
  
    uploadHttpData: function( r, type ) {  
          
        var data = !type;  
        data = type == "xml" || data ? r.responseXML : r.responseText;  
        // If the type is "script", eval it in global context  
        if ( type == "script" )  
            jQuery.globalEval( data );  
        // Get the JavaScript object, if JSON is used.  
        if ( type == "json" ){  
     
            eval( "data = " + $(data).html() );  
        }  
        // evaluate scripts within html  
        if ( type == "html" )  
            jQuery("<div>").html(data).evalScripts();  
   
        return data;  
    }  
});  

相關文章