美文网首页
H5异步上传文件

H5异步上传文件

作者: 蓝色的咖啡 | 来源:发表于2017-01-18 13:53 被阅读370次

    最近项目上有遇到需要在手机APP端嵌入HTML5页面并选取照片上传,网上有很多方式实现,原本使用了百度的webupload插件,但是需要依赖flash,所以我使用了H5自带的FileReader API来读取文件流转换成base64字符串,然后使用ajax无刷新方式上传到服务器。

    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字符串的数组
    
            $(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("上传的图片格式不正确,请重新选择");
                        }
                        var reader = new FileReader();
                        reader.readAsDataURL(this.files[i]);
                        var picId = 0;
                        reader.onload = function(e){
                            imgFiles.push(this.result);//this.result就是图片转换后的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>请选择一个图像文件:</label>
    <input type="file" id="imgFile" name="imgFile" accept="image/*" multiple />
    
    <button id="btnUpload">上传图片</button>
    <button id="btnReset">重置</button>
    </body>
    </html>
    

    服务端处理

    后台使用原生的Java Servlet来接收处理

    从HttpServletRequest中读取前端传来的InputStream并转换成字符串

    /**
         * 从HttpServletRequest中读取前端传来的InputStream并转换成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;
                }
                /**
                 * 由于前端转过来的数据格式为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中读取二进制数据流,并转换成字符串
         * @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字符串转换成图片并写入磁盘,最终完整的代码如下

    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", "请选择需要上传的图片");
                    writer.print(result.toString());
                    return;
                }
                System.out.println("base64Str=" + base64Str);
                //生成一个新的文件名
                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并转换成真正的图片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;
                }
                /**
                 * 由于前端转过来的数据格式为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中读取二进制数据流,并转换成字符串
         * @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字符串转换成图片并按新文件名写入磁盘,
         * @param base64Str
         * @param newImgName
         * @return
         * @throws Exception
         */
        private boolean writeImage(String base64Str, String newImgName) throws Exception {
            if (base64Str == null) // 图像数据为空
                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) {// 调整异常数据
                        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>
    

    小结

    该示例在iPhone的safari浏览器、小米手机的浏览器测试过,还需要在更多移动端测试。下一步准备加入在移动端压缩base64数据,提高传输效率。

    相关文章

      网友评论

          本文标题:H5异步上传文件

          本文链接:https://www.haomeiwen.com/subject/pnzvbttx.html