1. 程式人生 > >springmvc圖片上傳、jquery 圖片上傳預覽

springmvc圖片上傳、jquery 圖片上傳預覽

寬為限 緊用功 功夫到 滯塞通

簡介

專案需求,需要做圖片上傳功能,圖片上傳肯定得給個預覽嘛,然後就找了下面這個方案

ajaxfileupload外掛上傳

ajaxfileupload.js網上傳了好幾個版本,選擇自己可以使用的就好了。這個外掛是N多年前寫的了,估計後期作者沒有繼續維護,所以才出來多個版本吧,第一版的話現在最新jquery中使用的話會報錯 handleError not find

ajaxfileupload現在來講比較古老了,它以來jquery,而且是1.4.2版本的,那時候1.4.2版本的jQuery有handlerError方法,到了現在的1.9+就沒有了,所以會報handlerError找不到的錯誤,解決方法是:找到ajaxfileupload.js檔案,在 ” jQuery.extend({ “之後加上一下程式碼,就可以了!

所以在該檔案中新增上 handleError函式

handleError: function (s, xhr, status, e) {
        if (s.error) {
            s.error.call(s.context || s, xhr, status, e);
        }
        if (s.global) {
            (s.context ? jQuery(s.context) : jQuery.event).trigger("ajaxError", [xhr, s, e]);
        }
    },

前端頁面程式碼

jsp程式碼

<tr>
<td style="text-align:right;">產品詳情圖:</td>
<td>
 <input type="file"  multiple="multiple" accept="image/gif,image/jpeg,image/png,image/jpg,image/bmp" id="chanpinzhutu" name="chanpinzhutu" onchange="setImagePreviews()" class="hide"/>
 <label for="chanpinzhutu"
class="labelBtn2">
本地上傳(最多選擇6張)</label> </td> </tr> <tr> <td style="text-align:right;"></td> <td> <c:if test="${empty model.productPhotos['0'] }"> <img id="chanpinzhutu0" src="127.0.0.1:8080/test/images/empty_mid.png" width="80" height="80"/> <img id="chanpinzhutu1" src="127.0.0.1:8080/test/images/empty_mid.png" width="80" height="80"/> <img id="chanpinzhutu2" src="127.0.0.1:8080/test/images/empty_mid.png" width="80" height="80"/> <img id="chanpinzhutu3" src="127.0.0.1:8080/test/images/empty_mid.png" width="80" height="80"/> <img id="chanpinzhutu4" src="127.0.0.1:8080/test/images/empty_mid.png" width="80" height="80"/> <img id="chanpinzhutu5" src="127.0.0.1:8080/test/images/empty_mid.png" width="80" height="80"/> </c:if> <c:if test="${not empty model.productPhotos['0'] }"> <c:forEach varStatus="i" var="img0" items="${model.productPhotos['0'] }"> <img id="chanpinzhutu${i.index }" src="${img0.imageLink }" width="80" height="80"/> </c:forEach> </c:if> </td> </tr>

js程式碼

// 展示詳情圖
function ajaxFileUploadMax() {
    $.ajaxFileUpload ({
        url: '127.0.0.1:8080/test/imgUploadMax?model=${model.fdId}', //用於檔案上傳的伺服器端請求地址
        secureuri: false, //是否需要安全協議,一般設定為false
        fileElementId: 'chanpinzhutu', //檔案上傳域的ID
        dataType: 'json', //返回值型別 一般設定為json
        //伺服器成功響應處理函式
        success: function (data, status) {
            //轉換後的JSON物件
            var obj = new Function("return" + data)();
            var i = 0;
            for(i; i < obj.length; i++){  
                //顯示預覽
                 $("#chanpinzhutu"+i).attr("src", obj[i]);
            }

        },
        //伺服器響應失敗處理函式
        error: function (data, status, e){
            alert(e);
            console.log(e);
        }
    })
    return false;
}

springmvc後臺程式碼

/**
    * 多圖片上傳
    * @param files
    * @param request
    * @return
    * @throws Exception
    */
    @RequestMapping(value="/imgUploadMax", method=RequestMethod.POST)  
    @ResponseBody  
    public String imgUploadMax(@RequestParam(value = "chanpinzhutu", required = false) MultipartFile[] files,
        HttpServletRequest request) throws Exception {  

    String modelId = request.getParameter("model");

    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");  
    String dateNowStr = sdf.format(new Date()); 

    String path = "/soluser/official/upload/product/" + dateNowStr;

    JSONArray jsonArray = new JSONArray();
    // 最多存6張
    int fileSize = files.length > 6 ? 6 : files.length;
    for (int i = 0; i < fileSize; i++) {

        MultipartFile file = files[i];
        String originalFilename =  file.getOriginalFilename();
        String substring = originalFilename.substring(originalFilename.lastIndexOf("."));
        String fileNameStr = (new Date().getTime()) + substring;  
        File targetFile = new File(path, fileNameStr);  
        if(!targetFile.exists()){  
            targetFile.mkdirs();  
        }  
        //儲存  
        try {  
            file.transferTo(targetFile);
            String imageLink = path + "/" + fileNameStr;
            jsonArray.add(imageLink);

        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }

        return jsonArray.toString();  
    }  

後臺程式碼就是簡單springmvc檔案上傳,MultipartFile 獲取上傳檔案,儲存並返回儲存地址。
前端js獲取後臺傳過來的儲存地址,放到img標籤上,然後展示上傳的圖片。
這裡獲取返回資料是遇到了問題,就是返回的data 在ajaxfileupload外掛處理時報錯了
我們看看它是如何處理返回資料的

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" )
        {
            // If you add mimetype in your response,
            // you have to delete the '<pre></pre>' tag.
            // The pre tag in Chrome has attribute, so have to use regex to remove
            /*var data = r.responseText;
            var rx = new RegExp("<pre.*?>(.*?)</pre>","i");
            var am = rx.exec(data);
            //this is the desired data extracted
            var data = (am) ? am[1] : "";    //the only submatch or empty
            eval( "data = " + data );*/
            // data=eval('(' + data+ ')');        // evaluate scripts within html  
            return data;

        }
        // evaluate scripts within html
        if ( type == "html" )
            jQuery("<div>").html(data).evalScripts();
        //alert($('param', data).each(function(){alert($(this).attr('value'));}));
        return data;
    },

if ( type == "json" )這裡我把它所有的處理都去掉了,因為我知道後臺傳遞的資料所以這裡就不需要特殊處理了。

略講一下ajaxfileupload上傳的原理,看createUploadIframecreateUploadForm,大概你就能猜到它的原理了。沒錯,它就是在頁面上給你巢狀一個隱藏頁面,頁面裡有個用於上傳提交的Form,js程式碼將原來Form裡的檔案域裡的資訊放到隱藏頁面裡的Form中來,所以圖片上傳就被抽離出來了。

圖片時展示了,但這是上傳後再展示的,覺得有點彆扭,要是後面還要修改的話豈不是伺服器裡要存一堆的圖片!能不能先預覽,等form表單提交時圖片才儲存呢? 於是有了第二種方案:

方案2

主表單沒提交前就不儲存圖片,那麼如果是ajax提交上來的圖片後臺就不給它儲存,那前端這麼顯示預覽呢?,對了,返回base64編碼,瀏覽器可以解析base64編碼的圖片。然後後臺就講傳過來的檔案編碼後再返回過去,嗯!感覺挺OK的,嘚瑟中…
後面想想這樣是不是太傻逼了, 為什麼不直接再前端就轉碼呢!(⊙o⊙)…
由於技術不足,然後又是各種找js base64編碼方式,最後竟然沒有一個成功的,,,解碼的就隨試隨靈。(⊙﹏⊙)b,這個想法暫時放棄,然後突然記起以前學校時實現過圖片即時瀏覽的功能,最後找到了它了 URL.createObjectURL就這個東東,具體的看這裡URL.createObjectURL和URL.revokeObjectURL

第二版程式碼

jsp程式碼

<tr>
    <td style="text-align:right;">主頁展示圖:</td>
    <td>
     <input type="file" accept="image/gif,image/jpeg,image/png,image/jpg,image/bmp" 
        id="suoluetu" name="suoluetu"  onchange="setImagePreviews1('suoluetu', 'showLittle')" class="hide"/>
     <label for="suoluetu" class="labelBtnAdd">+</label>
     <%-- 舊圖片 --%>
     <div id="oldImg1">
     <c:if test="${not empty model.productPhotos['1'] }">
        <c:forEach varStatus="i" var="img1" items="${model.productPhotos['1'] }">
        <img id="suoluetu${i.index }" src="${img1.imageLink }"  width="60" height="60" style="margin-left: 3px;"/>
        </c:forEach>
     </c:if>
      </div>
     <%-- 臨時顯示 --%>
     <div id="showLittle"></div>

    </td>
   </tr>

js程式碼

/**
 * 圖片上傳預覽
 * @param files
 * @param show
 * @returns
 */
function setImagePreviews1(files1, show1) {
    // 編輯時隱藏之前的圖片
    $("#oldImg1").hide();

    var docObj = document.getElementById(files1);
    var dd = document.getElementById(show1);

    dd.innerHTML = "";

    var fileList = docObj.files;
    var size = fileList.length > 6 ? 6 : fileList.length;
    for (var i = 0; i < size; i++) {

        dd.innerHTML += "<div style='float:left; margin-left:5px;' > <img id='imgOne" + i
                + "'  /> </div>";
        var imgObjPreview = document.getElementById("imgOne" + i);

        if (docObj.files && docObj.files[i]) {

            // 火狐下,直接設img屬性
            imgObjPreview.style.display = 'block';
            imgObjPreview.style.width = '60px';
            imgObjPreview.style.height = '60px';
            // imgObjPreview.src = docObj.files[0].getAsDataURL();
            // 火狐7以上版本不能用上面的getAsDataURL()方式獲取,需要一下方式
            imgObjPreview.src = window.URL.createObjectURL(docObj.files[i]);

        } else {

            // IE下,使用濾鏡
            docObj.select();
            var imgSrc = document.selection.createRange().text;
            var localImagId = document.getElementById("imgOne" + i);

            // 必須設定初始大小
            localImagId.style.width = "60px";
            localImagId.style.height = "60px";

            // 圖片異常的捕捉,防止使用者修改後綴來偽造圖片
            try {
                localImagId.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale)";
                localImagId.filters
                        .item("DXImageTransform.Microsoft.AlphaImageLoader").src = imgSrc;

            } catch (e) {
                alert("您上傳的圖片格式不正確,請重新選擇!");
                return false;

            }

            imgObjPreview.style.display = 'none';
            document.selection.empty();

        }

    }
    return true;
}

圖片選擇時onchange="setImagePreviews1('suoluetu', 'showLittle')"觸發函式,這裡還有個梗 input file裡的JQ change() 事件的只生效一次 問題
這樣圖片瀏覽就是即時的了,提交時後臺獲取處理就OK了,這樣伺服器裡就存一次正確的圖片了,提交之前的圖片統統還在前端,隨瀏覽器的關閉而消失。就不用擔心重複上傳和無效檔案上傳問題了。O(∩_∩)O哈哈~

站在巨人的肩膀上