MUI 上傳圖片
時隔上次寫部落格有個把月了,主要最近一段時間上班很忙,加上帶娃,各種雜碎的事情繁多,一下子一天一下子一週一下子一個月就過去了,心中也有愧疚,所以為什麼說奮鬥要在30歲前,因為那時候你最年輕,有活力,有時間,有精力,沒房貸,沒車貸,沒孩子,沒老婆,父母年輕,一天到晚出了上班沒點P事,如果能回到五年前,說實話,我也想改變點生活狀態,比如去健身,去旅行,還有大把的時間學習新知識,否則,就只能像我一樣,現在有了鬥志的心,卻每天被柴米油鹽的瑣事困擾著,有些朋友會說,都是你自己給自己找藉口,責任這種東西怎麼說,你去付了,就是有責任感,你去負了,就是沒責任感,看個人吧,至少,我喜歡我的小家庭,疼愛我的老婆,小女兒,我希望能陪她們,等到女兒睡了,基本時間就不多了,你說可以熬夜,也是個人問題吧,我有乙肝大三陽,病毒指數也是8次方級別的,醫生也建議不要熬夜,我也希望健康第一位,所以,所以,哈哈哈,家家有本難唸的經,好了,閒扯幾句,反正都不認識,反正只是瞎bb,說正事。
除去前面一些個人原因,這次這麼久更新,主要是因為這次的功能是上傳頭像,其實就是上傳圖片,這個功能在任何web開發或者是app開發都是至關重要的,導致,這裡面有許多坑,我也是花了好久,查了好多資料,才順利解決,而且你的技術選型不一樣,導致很多程式碼不一樣,網上資料也非常少,走了不少彎路,開心的是,還是解決了,還是那句老話,之所以貼程式碼,只是為了幫助那些需要的人,我相信在這個地球的某處還是有人被一樣的問題困擾,或者說沒有我那麼幸運找到最終解決方案,所以自己記錄,順便做做善事。
先說邏輯吧,上傳圖片(或者上傳檔案,邏輯類似),既然我們使用的是MUI+SPRING MVC,首先我們要考慮的是,前臺如何上傳,我考慮過兩種方式,第一種就是前臺將圖片轉換成BASE64編碼,然後mui.post直接傳送到後臺,後臺解析BASE64編碼的圖片,儲存,這種方法理論是可行的,缺點很明顯,你上傳的圖片要足夠小,不然那個BASE64的編碼能噁心死你,所以我直接說第二種方法,就是使用H5的upload方法,位元組流的方式上傳圖片,後臺按位元組流接收圖片。當然為了考慮圖片上傳效率,和使用價效比,我們在上傳前,進行壓縮。程式碼如下:
//點選頭像,彈出【拍照,從相簿選擇】,因為用到很多H5的函式,則在plusReady裡執行 mui.plusReady(function(){ // 上傳檔案 var filepath; var newUrlAfterCompress; imgdiv.addEventListener('tap',function(){ if(mui.os.plus){ var a=[{ title:'拍照' },{ title:'從手機相簿選擇' }]; plus.nativeUI.actionSheet({ title:'修改頭像', cancel:'取消', buttons:a },function(b){ switch(b.index){ case 0: break; case 1: //拍照 getImages(); break; case 2: //開啟相簿 galleryImages(); break; default: break; } },false); } }); //拍照 function getImages(){ var mobileCamera=plus.camera.getCamera(); mobileCamera.captureImage(function(e){ plus.io.resolveLocalFileSystemURL(e,function(entry){ var path=entry.toLocalURL()+'?version='+new Date().getTime(); // console.log("camera:"+path); var dstname="_downloads/"+getUid()+".jpg";//設定壓縮後圖片的路徑 compressImage(path,dstname,0); // filepath = newUrlAfterCompress; },function(err){ console.log("讀取拍照檔案錯誤"); }); },function(e){ console.log("er",err); },function(){ filename:'_doc/head.png'; }); } //從本地相簿選擇 function galleryImages(){ console.log("你選擇了從相簿選擇"); plus.gallery.pick(function(a){ plus.io.resolveLocalFileSystemURL(a,function(entry){ plus.io.resolveLocalFileSystemURL('_doc/',function(root){ root.getFile('head.png',{},function(file){ //檔案已經存在 file.remove(function(){ console.log("檔案移除成功"); entry.copyTo(root,'head.png',function(e){ var path=e.fullPath+'?version='+new Date().getTime(); var dstname="_downloads/"+getUid()+".jpg";//設定壓縮後圖片的路徑 compressImage(path,dstname,270); // filepath = dstname; //upload(); },function(err){ console.log("copy image fail: ",err); }); },function(err){ console.log("刪除圖片失敗:("+JSON.stringify(err)+")"); }); },function(err){ //開啟檔案失敗 entry.copyTo(root,'head.png',function(e){ var path=e.fullPath+'?version='+new Date().getTime(); uploadHeadImg(path); },function(err){ console.log("上傳圖片失敗:("+JSON.stringify(err)+")"); }); }); },function(e){ console.log("讀取資料夾失敗:("+JSON.stringify(err)+")"); }); }); },function(err){ console.log("讀取拍照檔案失敗: ",err); },{ filter:'image' }); }; // 產生一個隨機數 function getUid() { return Math.floor(Math.random() * 100000000 + 10000000).toString(); } function upload() { var task = plus.uploader.createUpload('http://47.96.239.47:8080/yqrcbapp/userInfo/uploadImage', { method: "POST" }, function(t, status) { //上傳完成 if (status == 200) { console.log(t.responseText); imgdiv.innerHTML = '<img id="userImg" src="'+t.responseText+'"/>'; } else { console.log("上傳失敗:" + status); } } ); task.addData('username',username); task.addFile(filepath, { key:filepath }); task.start(); } //壓縮圖片,這個比較變態的方法,無法return function compressImage(src,dstname,rotate) { //var dstname="_downloads/"+getUid()+".jpg"; plus.zip.compressImage({ src: src, dst: dstname, overwrite:true, quality: 20 , rotate: rotate }, function(event) { console.log("Compress success:"+event.target); filepath = event.target; upload(); }, function(error) { console.log(error); // filepath = src; //alert("Compress error!"); }); } });
前臺上傳了圖片,後臺如何接收呢?每種框架接收方式不一樣,我選擇的是JAVA的MVC框架,所以後臺程式碼如下
@RequestMapping(value="/uploadImage", method=RequestMethod.POST)
@ResponseBody
private String uploadImage(HttpServletRequest request){
String username = (String)request.getParameter("username");
// 複雜型別的request物件
MultipartHttpServletRequest mRequest = (MultipartHttpServletRequest) request;
// 獲取檔名集合放入迭代器
Iterator<String> files = mRequest.getFileNames();
while (files.hasNext()) {
//獲取上傳檔案的物件
MultipartFile mFile = mRequest.getFile(files.next());
if (mFile != null) {
//
// String path= "";
try {
byte[] bytes = mFile.getBytes();
// // 當前app根目錄
// String rootPath = request.getServletContext().getRealPath("/");
//
// // 需要上傳的相對地址(application.properties中獲取)
// String relativePath = "img";
//
// // 資料夾是否存在,不存在就建立
// File dir = new File(rootPath + File.separator + relativePath);
// if (!dir.exists())
// dir.mkdirs();
// // String fileExtension = getFileExtension(file);
String filename1 = mFile.getOriginalFilename();
String fileExtension = filename1.substring(filename1.lastIndexOf(".")+1);
//
// 生成UUID樣式的檔名
String filename = java.util.UUID.randomUUID().toString() + "." + fileExtension;
//
// // 檔案全名
// String fullFilename = dir.getAbsolutePath() + File.separator + filename;
//
//
//
// // 儲存圖片
// File serverFile = new File(fullFilename);
// BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(serverFile));
// stream.write(bytes);
// stream.close();
//儲存圖片到圖片OSS伺服器,然後返回訪問地址
String endpoint = "http://oss-cn-beijing.aliyuncs.com";
// 阿里雲主賬號AccessKey擁有所有API的訪問許可權,風險很高。強烈建議您建立並使用RAM賬號進行API訪問或日常運維,請登入 https://ram.console.aliyun.com 建立RAM賬號。
String accessKeyId = "***";
String accessKeySecret = "***";
String bucketName = "dreamxieimg";
String objectName = filename;
// 建立OSSClient例項。
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
// 上傳檔案。<yourLocalFile>由本地檔案路徑加檔名包括字尾組成,例如/users/local/myfile.txt。
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
Date expiration = new Date(new Date().getTime() + 3600 * 1000*24);
// 生成以GET方法訪問的簽名URL,訪客可以直接通過瀏覽器訪問相關內容。
URL url = ossClient.generatePresignedUrl(bucketName,objectName , expiration);
// 關閉OSSClient。
ossClient.shutdown();
Map<String,Object> params = new HashMap<String, Object>();
params.put("img", url.toString());
params.put("username", username);
userInfoService.changeimg(params);
// //將圖片訪問路徑儲存在資料庫中
// String serverPath = new URL(request.getScheme(), request.getServerName(), request.getServerPort(),
// request.getContextPath()).toString();
return url.toString();
} catch (Exception e) {
e.printStackTrace();
// LOGGER.info("error: {}", e);
}
}
}
return null;
}
注意幾點,
1.阿里的OSS伺服器提供的jar包可能會與專案jar包衝突,需要自己刪除老版本jar包
2.controller只能用request接收,不能用mutiFile接收
具體的都自己看程式碼吧