1. 程式人生 > >java儲存H5上傳的圖片

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的標籤中。得到這個物件後就簡單很多了。直接讀取一下解析後的檔案流,這裡沒有嘗試判斷是否文字域的方法,如何使用判斷文字域的方法來處理圖片,請參見前文:

微軟雲+Servlet實現圖片上傳介面 所需jar包commons-fileupload也可以在前文中找到。

以下是後臺接收圖片的程式碼:

        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,而發現這個問題足足用了兩天的時間,可以說是一個比較深刻的教訓了。