周嵐

摘要:基于傳統的HTML5多文件上傳采用FormData方式,將文件數據編譯成鍵值對,用異步請求方式上傳文件,但是不同瀏覽器對FormData對象的支持情況并不容樂觀,導致不支持FormData的瀏覽器文件上傳失敗。該文針對瀏覽器不支持FormData對象操作,提出在基于瀏覽器客戶端對圖片進行Base64編碼,將圖片轉換為字符串提交,在服務器端再對其進行解碼后再生成圖片文件的通用圖片上傳方法。
關鍵詞:HTML5;FormData;Base64;文件上傳
中圖分類號:TP393? ? 文獻標識碼:A? ? ? 文章編號:1009-3044(2018)31-0106-03
Research on Multi Image Uploading Technology Based on Base64 Encoding
ZHOU Lan
(Department of information technology, Xuzhou Vocational College of Finance and economics, Jiangsu, Xuzhou 221008,China)
Abstract: Based on the traditional HTML5 multi-file uploading method, the file data is compiled into key-value pairs and uploaded asynchronously. However, the support of different browsers for FormData objects is not optimistic, which leads to the failure of file uploading in browsers that do not support FormData. In view of the fact that browsers do not support the operation of FormData objects, this paper proposes a general image uploading method based on browser client to encode pictures by Base64, convert pictures to string submission, decode them on the server and regenerate them into picture files.
Key words: HTML5; FormData; Base64; file upload
1 背景
基于瀏覽器的圖片上傳是Web應用開發中的通用功能,傳統的圖片上傳通過表單選擇客戶端圖片,在提交表單時將圖片轉換為二進制方式上傳到服務器。在HTML5標準中,增加了一個新的接口FormData,可以通過JavaScript采用鍵值對的方式來模擬表單控件,并可以通過異步方式提交,大大提高了用戶體驗。目前大部分瀏覽器都能支持FormData對象,但是有的瀏覽器只部分支持FormData對象,比如蘋果系統的safari瀏覽器,在進行圖片上傳時就不能采用FormData對象。而目前尤其是基于手機端圖片上傳的廣泛應用,為了設計通用圖片上傳功能,就不能采用FormData對象,針對這種情況該文提出一種跨瀏覽器的多圖片上傳方法,在客戶端通過JavaScript對用戶選擇的圖片進行Base64編碼,通過Post方式將編碼后的字符串發送到服務器端,然后在服務器端對字符串進行Base64解碼,并生成圖片文件[1]。這種圖片上傳方法一方面兼容了瀏覽器,同時方便了用戶體驗。
2 基于Base64編碼的圖片上傳方法簡介
基于Base64編碼的圖片上傳方法,主要包括客戶端對圖片文件編碼,服務器端解碼并生成圖片文件兩個部分,如圖1所示。
當用戶選擇要上傳的圖片后,先對圖片進行壓縮,利用HTML5的canvas對象,重新繪制圖片,根據要求設置壓縮比例,重新生成新的圖片數據,并對其進行Base64編碼,將圖片文件的原始文件名和生成的Base64編碼保存到Json數據格式的對象數組中,最后上傳時只要將Json文件發送到服務器端即可。在服務器端,接收到客戶端請求的Json數據后,先對其進行解析,分離出原文件名和圖片對應的Base64編碼,并圖片數據進行Base64解碼,重新生成新的圖片文件,并將新的文件名返回到客戶端。
3 基于Base64編碼的圖片上傳方法實現
基于Base64編碼的圖片上傳分為客戶端壓縮編碼和服務器端解碼生成新的圖片文件并返回客戶端新圖片的文件名。
3.1 客戶端圖片壓縮及編碼
當用戶選擇完圖片后,通過調用ImageCompressor組件,首先對圖片進行壓縮,圖片壓縮的質量和生成圖片最大和最小尺寸自行設置,壓縮完成后使用HTML5的FileReader對象將圖片數據進行Base64編碼,同時將圖片的文件名和生成的編碼保存到Json對象數組中[2],具體代碼如程序1所示。
function compress(files,num)
{
var flen=files.length;
if(num==files.length)
{
return;//沒有圖片了需要壓縮了
}
new ImageCompressor(files[num], {
quality: .6,
maxWidth:1024,
maxHeight:1024,
minWidth:200,
minHeight:200,
success(result) {
var outputURL = window.URL.createObjectURL(result);
num++;
var objf={'id':index, 'value':outputURL ,'filename':result.name};
clientArr.push(objf);//臨時保存原始文件名
var fileReader = new FileReader();
fileReader.onload = function (e) {
var base64=e.target.result.replace(/^data:image\/(png|jpeg);base64,/,"")
//保存圖片數據到Json對象數組中
picarr.push({"filename":result.name,"base64":base64});
compress(files,num);//壓縮下一張圖片
}
fileReader.readAsDataURL(result);
},
error(e) {
console.log(e.message);
},
});
}
程序1? ?客戶端選擇圖片進行壓縮及保存
當所有圖片壓縮成功后,要上傳的圖片數據也保存到了Json對象數組中了,這時我們只需要將這個Json對象數組上傳到服務器端,同時在服務器上返回一個Json對象,包括圖片的原始文件名和新生成的文件名,具體實現如程序2所示。
$.ajax({
type:'post',
url:'/upload/multiPic',
data:JSON.stringify(picarr),
processData: false,
contentType: 'application/json',
success:function(res)
{
for(var key in res.data )
{
for(var i=0;i<contarr.length;i++)
{ ? ? if(contarr[i].filename==key)
{
clientArr[i].value=res.data[key];
}
}
}
//////////////保存數據
}
});
程序2? ?客戶端請求圖片數據
3.2 服務器端保存圖片
在服務器端,當接收到客戶端的圖片數據請求后,先對Json對象進行解析,取出圖片的Base64編碼,并對其進行解碼生成圖片文件[3],具體實現如程序3所示。
ResultData rs=new ResultData();
JSONArray ls=JSON.parseArray(str);
if(ls.isEmpty())
throw new Exception("上傳文件不能為空");
HashMap map=new HashMap();
for(int j=0;j<ls.size();j++)
{
JSONObject job = ls.getJSONObject(j);
String ofilename=job.getString("filename");
//原始文件名
String? type = ofilename.substring(ofilename.lastIndexO(".")); // 獲取文件的后綴
if(!".png".equals(type.toLowerCase()) && !".jpg".equals(type.toLowerCase()) && !".gif".equals(type.toLowerCase()))
{
throw new Exception("文件類型不匹配");
}//生成新測文件名,采用時間戳方式
String webFilename=common.getCTime()+"_"+String.valueOf(j)+type;
String nfilename=fileRoot+"/"+webFilename;
String baseStr=job.getString("base64"); if(common.base64StrToImage(baseStr, nfilename))
{
map.put(ofilename,"/upload/"+common.getMonth()+"/"+webFilename);
}
else
rs.setFaild(0,"error trans", null);
}
rs.setSuccess(1, "success",map);
}catch(Exception e){
e.printStackTrace();
}
renderJson(rs);//渲染Json格式到客戶端
程序3? ?服務器端對圖片數據進行Base64解碼
在程序3中,對客戶端請求的每個圖片數據進行Base64解碼,同時生成新的圖片文件保存到指定文件夾中,具體實現如程序4所示。
public static boolean base64StrToImage(String imgStr, String path) {
if (imgStr == null)
return false;
Base64.Decoder decoder = Base64.getDecoder();
try {// 解密
byte[] b = decoder.decode(imgStr);
for (int i = 0; i < b.length; ++i) {// 處理數據
if (b[i] < 0) {
b[i] += 256;
}
}
File tempFile = new File(path); //文件夾不存在則自動創建
if (!tempFile.getParentFile().exists()) {
tempFile.getParentFile().mkdirs();
}
OutputStream out = new FileOutputStream(tempFile);
out.write(b);
out.flush();
out.close();
return true;
} catch (Exception e) {
return false;
}}
程序4? ?服務器端對圖片Base64解碼
當服務器端處理圖像數據解碼時,并將圖片的原始文件名和生成的新文件名保存到Map集合中,最后以Json格式返回到客戶端,便于客戶端獲取新生成的圖片名保存到數據庫中[4]。
4 結束語
該文針對HTML5中圖片上傳的兼容性,提出對客戶端圖片進行Base64編碼為字符串方式提交,一方面彌補了瀏覽器對FormData對象不支持的缺陷,同時也滿足了動態多圖片上傳的功能。并在實際移動端得到了具體的應用,在蘋果瀏覽器和谷歌平臺下面的瀏覽器均得到了驗證,滿足了用戶圖片上傳通用性的要求。
參考文獻:
[1] 劉耀欽. 利用HTML5拖放技術實現多文件異步上傳[J]. 四川理工學院學報: 自然科學版, 2015(1): 1673-1549.
[2] 糜梅. 基于HTML5的文件上傳類設計[J]. 電腦知識與技術, 2015(2): 1009-3044.
[3] 王莉敏. 基于HTML5大文件斷點續傳的實現方案[J]. 計算機與現代化, 2016(3): 1006-2475.
[4] Joker_Ye. HTML5實現圖片壓縮上傳功能[EB/OL]. https://blog.csdn.net/hj7jay/article/details/51003926.