文件上传这件小事

作者: leeyaf | 来源:发表于2016-09-02 01:00 被阅读733次

    起源

    我之前一直做的是单图上传,或者单图上传加预览的模式,实现起来都不是那么麻烦,下面都会提到。

    而今天给自己挖了个坑,批量上传多张图片,类似这样:

    选择上传文件.png

    然后我还特想装13,想研究下原理。

    从头说这件事

    文件上传,html的基础表单组件就提供了该功能的实现,使用非常简单的表单提交就能做。然而可能一些pm觉得图片能实时预览是非常好的用户体验,这时候可以用js来构建form表单异步上传。再往后推,就要求既能批量上传,又能实时预览。说白了感觉用户体验什么的借口感觉都是在挖坑给我们写代码的。

    cp1 表单上传

    代码优先发言:

    <form action="index.php" method="post" enctype="multipart/form-data">
      <input type="file" name="file">
      <input type="submit" value="提交">
    </form>
    

    效果图发言:

    表单文件上传效果.png

    这个体验确实不好,只有文件名,没有文件的内容预览。

    后端代码贴个servlet3的

    先把servlet加上 <code>@MultipartConfig(maxFileSize=1024x1024x10)</code> 注解,然后逻辑代码如下:

    Part part=request.getPart("file");
    if (null!=part&&part.getSize()>0) {
      InputStream inputStream=part.getInputStream();
      ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
      byte[] buffer = new byte[1024*100];
      int len=0;
      while ((len=inputStream.read(buffer,0,buffer.length))>0) {
        outputStream.write(buffer,0,len);
      }
      byte[] fileByte=outputStream.toByteArray();
    }
    

    拿到byte数组后面的操作代码我就不贴了,有的存本地文件,有的上传到文件服务器,这个因项目架构而定,反正servlet3的后端逻辑差不多就是这样,至于使用其他框架的自行查询对照实现。

    cp2 异步上传预览

    效果图优先发言:

    上传表情并预览.png

    这里我使用 jquery 的 fileupload 实现的,当然也有很多极简爱好者自己实现,原理也很简单。

    前端代码,跟上面结构一致

    <form action="index.php" method="post" enctype="multipart/form-data">
      <input id="selectFile" type="file" name="file">
      <input type="submit" value="提交">
    </form>
    

    js代码

    $("#selectFile").fileupload({
      dataType: "json",
      url: "/upload/singleFile",
      type: "POST",
      done: function(e, data) {
        $("#selectFile").before('<img src="'+data.result.result+'"/>');
      }
    });
    

    这里文件选择好后直接上传到后台,上传完成后插入一个img标签做预览效果。文件的上传和表单的提交是分开的!表单提交的时候只提交文件的编号或者地址,不包含任何文件。

    使用框架的好处就是简单方便,缺点是不了解原理,高级特性没办法用。

    异步上传文件的原理是,构造一个iframe进行上传,上传完成后获取iframe的内容,作为服务器的返回结果,前端拿到返回的结果后,构造img展示预览图。(这里本来要配代码,无奈之前收藏的书签丢失了,不过不重要,后面有更简单的方式)

    cp3 批量上传并预览

    虽然前面提到的 jquery 的 fileupload 插件能实现,但是作为一名极简主义者,自然是要自!己!开!发!

    前端代码,input加入multiple属性

    <form action="index.php" method="post" enctype="multipart/form-data">
      <input id="selectFile" type="file" name="file" multiple="multiple">
      <input type="submit" value="提交">
    </form>
    

    js代码:

    因为坑挖的奇葩,需要在图片上传之前做一些前置操作,拿到选择图片的信息:

    var files=$("#selectFile")[0].files;
    for (var i = 0; i < files.length; i++) {
      var file=files[i];
      console.log(file);
    }
    

    看下打印出来的信息

    lastModified:1471099234297
    lastModifiedDate:Sat Aug 13 2016 22:40:34 GMT+0800 (中国标准时间)
    name:"6.png"
    size:26476
    type:"image/png"
    webkitRelativePath:""
    

    不错,图片类型,大小,图片名都显示出来了,要做前置操作的在这里做抓紧做。

    那么我们拿到文件的dom了怎么上传?当是我是懵逼的,因为文件上传,包括插件,单位都是 input ,这是input 里面的东西,怎么上传?

    后来找到了一种方法,XMLHttpRequest,构造请求提交表单。构!造!请!求!这不是类似java的HttpClient吗?万能的工具!

    核心代码:

    var xhr = new XMLHttpRequest();
    xhr.open('POST', "index.php", true);
    var formData = new FormData();
    formData.append('file', file);  // file 为上面拿到的file对象
    xhr.onreadystatechange = function(response) {  // 文件上传完毕通知函数
      console.log(xhr.responseText);
    }
    xhr.send(formData);
    

    具体的实现参照前面cp2就能实现,这里篇幅有限,不多阐述。

    结语

    有时候js的原理确实该看看,反正又不难,半天的时间就能搞定。

    愿每位码农都能在天梯上披襟斩棘,一统逼界,千秋万载。

    相关文章

      网友评论

        本文标题:文件上传这件小事

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