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上傳的原理,看createUploadIframe
和createUploadForm
,大概你就能猜到它的原理了。沒錯,它就是在頁面上給你巢狀一個隱藏頁面,頁面裡有個用於上傳提交的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哈哈~