H5異步上傳文件

最近項(xiàng)目上有遇到需要在手機(jī)APP端嵌入HTML5頁面并選取照片上傳,網(wǎng)上有很多方式實(shí)現(xiàn),原本使用了百度的webupload插件,但是需要依賴flash,所以我使用了H5自帶的FileReader API來讀取文件流轉(zhuǎn)換成base64字符串,然后使用ajax無刷新方式上傳到服務(wù)器。

HTML5頁面編寫

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
    <script type="text/javascript" src="assets/aries/lib/jquery.js"></script>
    <script type="text/javascript" src="js/json2/json2.js"></script>
    <style>
        .divImg{ border:1px solid #000; width:auto; height:auto;max-width: 100%;max-height: 100%}
        .divImg img{width:100px; height:100px}
    </style>
    <script type="text/javascript">
        var imgFiles = null;//用于存放base64字符串的數(shù)組

        $(function(){
            var input = $("#imgFile");
            var result,div;

            if(typeof FileReader==='undefined'){
                input.setAttribute('disabled','disabled');
                return alert("抱歉,你的瀏覽器不支持 FileReader");
            }else{
                $("#imgFile").bind('change',readFile);
            }

            function readFile(){
                imgFiles = new Array();
                for(var i=0;i<this.files.length;i++){
                    var imgName = $("#imgFile").val().toLocaleLowerCase();
                    if (!imgName.match(/.jpg|.jpeg|.gif|.png|.bmp/i)){  //判斷上傳文件格式
                        return alert("上傳的圖片格式不正確,請(qǐng)重新選擇");
                    }
                    var reader = new FileReader();
                    reader.readAsDataURL(this.files[i]);
                    var picId = 0;
                    reader.onload = function(e){
                        imgFiles.push(this.result);//this.result就是圖片轉(zhuǎn)換后的base64字符串
                        result = '<div id="preview'+picId+'" class="divImg">![]('+this.result+')</div>';
                        div = document.createElement('div');
                        div.innerHTML = result;
                        document.getElementById('body').appendChild(div);//插入dom樹
                        picId++;
                    }
                }
            }

            $('#btnUpload').bind('click',uploadImg);
            $('#btnReset').bind('click',reset);
        })

        /**
         * 上傳文件
         */
        function uploadImg(){
            for(var i=0;i<imgFiles.length;i++){
                var base64 = imgFiles[i];
                $.ajax({
                    url : 'http://192.168.1.102:8083/uploadFile',
                    type : 'post',
                    contentType: 'application/x-www-form-urlencoded; charset=utf-8',
                    async: false,
                    cache: false,
                    data : base64,
                    success : function(data){
                        console.log(data)
                        var result = JSON.parse(data);
                        if(result.isSuccess){
                            alert('第'+(i+1)+'張圖片上傳成功');
                            $('#preview'+i).remove();
                        }else{
                            alert('第'+(i+1)+'張圖片上傳失敗:'+result.resultDesc);
                        }
                    }
                })
            }
            reset();
        }

        /**
         * 重置表單
         */
        function reset(){
            $('#imgFile').val('');
            $('.divImg').each(function(index,domEle){
                $(this).remove();
            })
        }

    </script>
</head>
<body id="body">
<form id="imgForm" action="http://localhost:8083/uploadFile" method="post" enctype="multipart/form-data"></form>
<label>請(qǐng)選擇一個(gè)圖像文件:</label>
<input type="file" id="imgFile" name="imgFile" accept="image/*" multiple />

<button id="btnUpload">上傳圖片</button>
<button id="btnReset">重置</button>
</body>
</html>

服務(wù)端處理

后臺(tái)使用原生的Java Servlet來接收處理

從HttpServletRequest中讀取前端傳來的InputStream并轉(zhuǎn)換成字符串

/**
     * 從HttpServletRequest中讀取前端傳來的InputStream并轉(zhuǎn)換成base64字符串
     *
     * @param request
     * @return
     * @throws Exception
     */
    private String getBase64Str(HttpServletRequest request) throws Exception {
        try {
            String imgStr = getRequestPayload(request);
            if (imgStr == null || "".equals(imgStr)) {
                return null;
            }
            /**
             * 由于前端轉(zhuǎn)過來的數(shù)據(jù)格式為data:image/jpeg;base64,圖像base64字符串,因此需要處理一下
             */
            final String subStr = "base64,";
            String base64Str = imgStr.substring(imgStr.indexOf(subStr) + subStr.length(), imgStr.length());
            return base64Str;
        } catch (Exception ex) {
            throw ex;
        }
    }

    /**
     * 從Request中讀取二進(jìn)制數(shù)據(jù)流,并轉(zhuǎn)換成字符串
     * @param request
     * @return
     * @throws Exception
     */
    private String getRequestPayload(HttpServletRequest request) throws Exception{
        StringBuilder sb = new StringBuilder();
        BufferedReader reader = null;
        try {
            reader = request.getReader();
            char[] buff = new char[1024];
            int len;
            while ((len = reader.read(buff)) != -1) {
                sb.append(buff, 0, len);
            }
        } catch (IOException e) {
            throw e;
        }finally {
            if(reader != null){
                reader.close();
            }
        }
        return sb.toString();
    }

將base64字符串轉(zhuǎn)換成圖片并寫入磁盤,最終完整的代碼如下

import net.sf.json.JSONObject;
import org.apache.commons.io.IOUtils;
import sun.misc.BASE64Decoder;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;

/**
 * Created by qianlong on 2017/1/12.
 */
public class FileUploadServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        service(req,resp);
    }

    public void service(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {

        JSONObject result = new JSONObject();
        res.setContentType("text/html;charset=UTF-8");

        // Create path components to save the file
        final String path = "/home/bluecoffee/upload";//保存路徑可以從配置文件中讀取
        final PrintWriter writer = res.getWriter();

        try {
            String base64Str = this.getBase64Str(req);
            if(base64Str == null || base64Str.equals("")){
                result.put("isSuccess", false);
                result.put("resultDesc", "請(qǐng)選擇需要上傳的圖片");
                writer.print(result.toString());
                return;
            }
            System.out.println("base64Str=" + base64Str);
            //生成一個(gè)新的文件名
            String newImgName = path + File.separator + System.currentTimeMillis() + ".jpg";
            boolean isWrite = this.writeImage(base64Str, newImgName);
            if (isWrite) {
                result.put("isSuccess", true);
                result.put("resultDesc", "圖片上傳成功");
                writer.print(result.toString());
            }else{
                result.put("isSuccess", false);
                result.put("resultDesc", "寫入磁盤文件失敗");
                writer.print(result.toString());
            }
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
            result.put("isSuccess", false);
            result.put("resultDesc", "圖片不存在:"+ex);
            writer.print(result.toString());
        } catch (Exception ex){
            ex.printStackTrace();
            result.put("isSuccess", false);
            result.put("resultDesc", "圖片上傳失敗:"+ex);
            writer.print(result.toString());
        }

    }

    /**
     * 從HttpServletRequest中讀取前端傳來的InputStream并轉(zhuǎn)換成真正的圖片base64字符串
     *
     * @param request
     * @return
     * @throws Exception
     */
    private String getBase64Str(HttpServletRequest request) throws Exception {
        try {
            String imgStr = getRequestPayload(request);
            if (imgStr == null || "".equals(imgStr)) {
                return null;
            }
            /**
             * 由于前端轉(zhuǎn)過來的數(shù)據(jù)格式為data:image/jpeg;base64,圖像base64字符串,因此需要處理一下
             */
            final String subStr = "base64,";
            String base64Str = imgStr.substring(imgStr.indexOf(subStr) + subStr.length(), imgStr.length());
            return base64Str;
        } catch (Exception ex) {
            throw ex;
        }
    }

    /**
     * 從Request中讀取二進(jìn)制數(shù)據(jù)流,并轉(zhuǎn)換成字符串
     * @param request
     * @return
     * @throws Exception
     */
    private String getRequestPayload(HttpServletRequest request) throws Exception{
        StringBuilder sb = new StringBuilder();
        BufferedReader reader = null;
        try {
            reader = request.getReader();
            char[] buff = new char[1024];
            int len;
            while ((len = reader.read(buff)) != -1) {
                sb.append(buff, 0, len);
            }
        } catch (IOException e) {
            throw e;
        }finally {
            if(reader != null){
                reader.close();
            }
        }
        return sb.toString();
    }
    
    /**
     * 將base64字符串轉(zhuǎn)換成圖片并按新文件名寫入磁盤,
     * @param base64Str
     * @param newImgName
     * @return
     * @throws Exception
     */
    private boolean writeImage(String base64Str, String newImgName) throws Exception {
        if (base64Str == null) // 圖像數(shù)據(jù)為空
            return false;

        BASE64Decoder decoder = new BASE64Decoder();
        OutputStream out = null;
        try {
            // Base64解碼
            byte[] bytes = decoder.decodeBuffer(base64Str);
            for (int i = 0; i < bytes.length; ++i) {
                if (bytes[i] < 0) {// 調(diào)整異常數(shù)據(jù)
                    bytes[i] += 256;
                }
            }
            //將圖片寫入磁盤
            out = new FileOutputStream(newImgName);
            out.write(bytes);
            return true;
        } catch (Exception e) {
            return false;
        } finally {
            if (out != null) {
                out.flush();
                out.close();
            }
        }
    }

}

web.xml中配置

    <servlet>
        <servlet-name>FileUploadServlet</servlet-name>
        <servlet-class>com.bluecoffee.web.servlets.FileUploadServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>FileUploadServlet</servlet-name>
        <url-pattern>/pc/uploadFile</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>FileUploadServlet</servlet-name>
        <url-pattern>/phone/uploadFile</url-pattern>
    </servlet-mapping>

小結(jié)

該示例在iPhone的safari瀏覽器、小米手機(jī)的瀏覽器測(cè)試過,還需要在更多移動(dòng)端測(cè)試。下一步準(zhǔn)備加入在移動(dòng)端壓縮base64數(shù)據(jù),提高傳輸效率。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容