java儲存H5上傳的圖片
最近的業務需要配合前端提供一個上傳圖片的介面,前端是一個Html5的頁面,使用的上傳方式和原有上傳方式不太一樣,因此特別記錄一下。
第一種,頁面使用表單提交,後臺使用commons-fileupload.jar來接收。
其實這種方法就是傳統的表單提交方式,前端頁面如下:
<form id="form" action="http://localhost:8080/emission/SaveImage" method="post" enctype="multipart/form-data">
<input class="m_camera" type="file" accept="image/*" name="file_img" capture="camera" id="cameraInput" >
<input type="hidden" value="123455788" name="orderid" />
<input type="hidden" value="" name="hidden" id="j_thumb" />
<!-- input type="submit" value="submit" name="sbt" id="sbt" -->
</form>
JS中獲得圖片壓縮一下,然後放到表單中傳過來,其實這個東西本來是個很簡單的業務,但由於其中的兩行JS程式碼的誤會,導致這個東西搞了很久,這兩行程式碼時這樣的
var r = i.toDataURL("image/jpeg", .8);
document.getElementById("j_thumb").value = r.substr(22)
看起來是給”j_thumb“這個input賦值,然後提交到頁面,實際上並不是這樣的。當我在後臺使用commons-fileupload外掛解析request時,在 ”j_thumb“這個物件中,並沒有看到對應的檔案,直到最後把整個request輸出出來,才發現原來這個東西是在file_img這個物件中傳過來的,可能是因為瀏覽器自動處理吧,把圖片放到了這個type為file的標籤中。得到這個物件後就簡單很多了。直接讀取一下解析後的檔案流,這裡沒有嘗試判斷是否文字域的方法,如何使用判斷文字域的方法來處理圖片,請參見前文:
以下是後臺接收圖片的程式碼:
Data.writeLog(Global.errPath1, "訪問到SaveImage+test\r\n");
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(8192);
factory.setRepository(tempPath);
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setSizeMax(1000000 * 20);
String orderid = "";
String suffix = "";
try {
/* 解析request 取得表單域迭代器 */
FileItemIterator fii = upload.getItemIterator(request);
/* 遍歷迭代器 ,這裡也可以使用while迴圈*/
for (final FileItemIterator itemIterator = fii; itemIterator.hasNext();) {
final FileItemStream item = itemIterator.next();
/*直接根據物件name進行篩選*/
if ("orderid".equals(item.getFieldName())) {
/*讀取request的輸入流*/
BufferedReader responseReader = new BufferedReader(
new InputStreamReader(item.openStream(), "UTF-8"));
String readLine;
StringBuffer responseSb = new StringBuffer();
while ((readLine = responseReader.readLine()) != null) {
responseSb.append(readLine);
}
/*獲得表單文字域*/
orderid = responseSb.toString();
}
if ("file_img".equals(item.getFieldName())) {
/*擷取name獲得檔案字尾名*/
String fileName = item.getName();
int index = fileName.indexOf(".");
suffix = fileName.substring(index, fileName.length());
/*從request流中獲得輸入流*/
BufferedInputStream inputStream = new BufferedInputStream(item.openStream());
/*定義輸出流*/
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
/*複製輸入流到輸出流*/
Streams.copy(inputStream, outputStream, true);
/*生成檔案圖片*/
File picFile = new File(
"D:\\feng\\perl-work\\zzq\\emission\\imageUpload\\" + directory + "\\" + saveName + suffix);
if (picFile.getParentFile() != null && !picFile.getParentFile().exists()) {
picFile.getParentFile().mkdirs();
}
if (!picFile.exists()) {
picFile.createNewFile();
}
/*寫入檔案並關閉流*/
OutputStream fileOutputStream = new FileOutputStream(picFile);
outputStream.writeTo(fileOutputStream);
inputStream.close();
outputStream.close();
fileOutputStream.close();
}
}
} catch (Exception e) {
message.put("code", "-1");
message.put("message", "接收檔案失敗" + e.getMessage());
message.put("id", request.getParameter("orderid"));
writer.println(new JSONObject(message).toString());
request.setAttribute("orderId", orderid);
}
這種正規化的一個問題就是對app不太友好,因為表單提交就意味著url跳轉,只能在伺服器端的網頁上使用這種上傳圖片的方法。
第二種,使用ajax非同步呼叫圖片儲存介面
ajax也是現在很流行圖片上傳方法,即將圖片處理成二進位制文字,然後作為字串傳輸給後臺。前臺程式碼如下:
function saveImage(txt) {
var id = "";
alert(txt)
$.ajax({
url: "http://localhost:8080/emission/SaveImage2",
type: "post",
data: {
orderId: 39,
file_img: txt
},
success: function(response) {
alert(response);
var dataobj = eval("(" + response + ")")
}
})
}
txt即為處理過的二進位制文字圖片。
後端接收程式碼如下:
String orderid = request.getParameter("orderId");
String image = request.getParameter("file_img");
/*進行base64解碼*/
byte[] images = Base64.decodeBase64(image);
File picFile = new File(
"D:\\feng\\perl-work\\zzq\\emission\\imageUpload\\" + directory + "\\" + saveName + ".png");
if (picFile.getParentFile() != null && !picFile.getParentFile().exists()) {
picFile.getParentFile().mkdirs();
}
if (!picFile.exists()) {
picFile.createNewFile();
}
/*將bytes寫入檔案*/
FileOutputStream fos = new FileOutputStream(picFile);
fos.write(images);
fos.close();
由於前臺有一個簡單的壓縮演算法,使用了canvas物件的toDataURL方法,會將圖片進行base64編碼,因此後臺接收的時候需要將對應的字串進行解碼。
小結:其實壓縮圖片上傳是個很常見的業務,但是這其中的細節確實值得了解。最開始我們使用介面的形式,但是由於前後端不在一個伺服器上,js呼叫的時候出現了跨域的問題。當我們使用jsonp傳遞引數試圖解決這個問題的時候,由於圖片壓縮完是一個很長的字串,因此可能超出了jsonp的限制,傳輸失敗。這時候我們轉用表單提交圖片。由於對H5方法不熟悉,並且JS程式碼中壓縮完的圖片賦值給了一個hidden標籤,對後臺解析造成了很大的影響。事後推測,應該是瀏覽器對enctype=”multipart/form-data”形式的表單有自動的封裝定義,即使將檔案形式字元傳給了hidden域,最終完成傳遞工作的還是type=“file”型別的input,而發現這個問題足足用了兩天的時間,可以說是一個比較深刻的教訓了。