Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 225|回复: 0

[默认分类] HTML5应用之文件上传

[复制链接]
  • TA的每日心情
    开心
    2021-12-13 21:45
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    发表于 2018-5-30 12:22:49 | 显示全部楼层 |阅读模式


      HTML5解决了以往网页编写的一个难题:带有上传进度的文件上传。
      
      本文的代码全部来自http://www.matlus.com/html5-file-upload-with-progress/,如在技术细节上有任何疑问,请以原文为主。
      长期以来,开发者们一直为此苦恼,大部分为解决这个问题都采用了flash作为解决方案,但flash并非灵丹妙药,因为flash版本,割据造成的问题有时反倒成为了噩梦。有些网站则采用了
    1. form
    复制代码
    标签的
    1. enctype=multipart/form-data
    复制代码
    属性,但这一属性要求服务器作出特殊的设置才能够显示进度,而且本身也比较复杂,复杂就意味着容易出现错误,这可不是我们想要的。
      现在我们来看看HTML5为什么能够解决这个问题,以及,它到底能做的多好。
      用HTML5上传文件
      在HTML5标准中,XMLHttpRequest对象被重新定义,被称为“XMLHttpRequest Level 2”,其中包含了以下5个新特性

       支持上传、下载字节流,比如文件、blob以及表单数据
       增加了上传、下载中的进度事件
       跨域请求的支持
       允许发送匿名请求(即不发送HTTP的Referer部分)
       允许设置请求的超时
      
      在这篇教程中,我们主要关注第一和第二项特性,尤其是第二项——它能够提供我们想要的上传进度。和之前的方案不同,这个方案并不要求服务器作出特殊的设置,因此大家边看教程就可以边动手试试了。

      
      上面图示的就是我们能够实现的内容:

       显示上传的文件信息,比如文件名、类型、尺寸
       一个能够显示真实进度的进度条
       上传的速度
       剩余时间的估算
       已上传的数据量
       上传结束后服务器返回的响应
      
      另外,凭借
    1. XMLHttpRequest
    复制代码
    ,我们的上传过程整个都是异步的,因此用户在上传文件的时候,依然可以操作网页当中的其它元素,并不需要专门等待上传的完成。而在上传结束后,我们能够获取服务器发回的响应,因此整个上传过程都显得相当顺理成章。
      HTML5的进度事件
      HTML5当中新增了一个进度事件(Progress Events),这个事件为我们提供了以下信息:

       total – 文件大小
       loaded – 已上传的大小
       lengthComputable – 进度是否可计算
      
      信息并不多,但是在计算文件进度上已经足够了。当然,也还有很多东西它没有直接给出,这非常遗憾。
      HTML
      与普通的文件上传代码并没有太大差异。不过注意,
    1. input
    复制代码
    标签关联了一个javaScript函数在onchange上。
    1. [/code]
    2. [code]
    复制代码

    1. <!DOCTYPE html>
    2. <html>
    3. <head>
    4.     <title>使用XMLHttpRequest上传文件</title>
    5. </head>
    6. <body>
    7. <form id="form1" enctype="multipart/form-data" method="post" action="upload.php">
    8. <div class="row">
    9.       <label for="fileToUpload">Select a File to Upload</label>
    10. <input type="file" name="fileToUpload" id="fileToUpload" onchange="fileSelected();"/>
    11.     </div>
    12. <div id="fileName"></div>
    13. <div id="fileSize"></div>
    14. <div id="fileType"></div>
    15. <div class="row">
    16. <input type="button" onclick="uploadFile()" value="Upload" />
    17.     </div>
    18. <div id="progressNumber"></div>
    19. </form>
    20. </body>
    21. </html>
    复制代码

    1. [/code]
    2.   JavaScript
    3.   一旦我们在HTML中使用了[code]input
    复制代码
    ,我们就可以在JS代码中获取到一个
    1. FileList
    复制代码
    对象。这个对象是HTML5中新增加的文件API中的一部分,每一个
    1. FileList
    复制代码
    对象都是一组文件对象的集合,而文件对象则拥有下列的属性:

       name – 文件名(不包含路径)
       type – 文件的MIME类型(小写)
       size – 文件的尺寸(单位为字节)
      
      这正是我们所需要的。当然,HTML5中还有一个
    1. FileReader
    复制代码
    对象,但在这里我们并没有用它。现在,通过上面的三个内容,我们已经能够控制用户上传的文件大小和文件类型,以便减轻服务器再次检测时的压力,并提升安全系数。
    1. [/code]
    2. [code]
    复制代码

    1. function fileSelected() {
    2.   var file = document.getElementById("fileToUpload").files[0];
    3.   if (file) {
    4.     var fileSize = 0;
    5.     if (file.size > 1024 * 1024)
    6.       fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + "MB";
    7.     else
    8.       fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + "KB";
    9.     document.getElementById("fileName").innerHTML = "Name: " + file.name;
    10.     document.getElementById("fileSize").innerHTML = "Size: " + fileSize;
    11.     document.getElementById("fileType").innerHTML = "Type: " + file.type;
    12.   }
    13. }
    复制代码

    1. [/code]
    2.   那么当用户选择好文件,点击上传之后,又将发生什么呢?
    3.   [code]
    复制代码

    1. [/code]
    2. [code]function uploadFile() {
    3.   var xhr = new XMLHttpRequest();
    4.   var fd = document.getElementById("form1").getFormData();
    5.   /* event listners */
    6.   xhr.upload.addEventListener("progress", uploadProgress, false);
    7.   xhr.addEventListener("load", uploadComplete, false);
    8.   xhr.addEventListener("error", uploadFailed, false);
    9.   xhr.addEventListener("abort", uploadCanceled, false);
    10.   /* Be sure to change the url below to the url of your upload server side script */
    11.   xhr.open("POST", "upload.php");
    12.   xhr.send(fd);
    13. }
    14. function uploadProgress(evt) {
    15.   if (evt.lengthComputable) {
    16.     var percentComplete = Math.round(evt.loaded * 100 / evt.total);
    17.     document.getElementById("progressNumber").innerHTML = percentComplete.toString() + "%";
    18.   }
    19.   else {
    20.     document.getElementById("progressNumber").innerHTML = "unable to compute";
    21.   }
    22. }
    23. function uploadComplete(evt) {
    24.   /* This event is raised when the server send back a response */
    25.   alert(evt.target.responseText);
    26. }
    27. function uploadFailed(evt) {
    28.   alert("There was an error attempting to upload the file.");
    29. }
    30. function uploadCanceled(evt) {
    31.   alert("The upload has been canceled by the user or the browser dropped the connection.");
    32. }
    复制代码

    1. [/code]
    2.   在代码的第二行中,我们的JS代码又使用了另一个HTML5推出的新对象——[code]FormData
    复制代码
    1. FormData
    复制代码
    对象是用户的表单数据的集合,它以键值对的形式存储了表单数据,其值能够包括数字、字符串以及文件。我们通过辗转这个对象,来向服务器提交数据。
      当然,这个对象我们也可以在代码中手工构建,比如说像下面这样:
    1. [/code]
    2. [code]
    复制代码

    1. var fd = new FormData();
    2. fd.append("author", "Shiv Kumar");
    3. fd.append("name", "Html 5 File API/FormData");
    4. fd.append("fileToUpload", document.getElementById("fileToUpload").files[0]);
    复制代码

    1. [/code]
    2.   回到正题。回顾上一段代码,我们增加了许多有关[code]XMLHttpRequest
    复制代码
    的事件监听,其目的是为了获取文件上传的真实情况。尤其需要注意的是,我们所挂钩的,并不是
    1. XMLHttpRequest
    复制代码
    本身,而是其属性,比如
    1. uploadProgress
    复制代码

      完整代码
      最后,来看看完整的代码。
    1. [/code]
    2. [code]
    复制代码

    1. <!DOCTYPE html>
    2. <html>
    3. <head>
    4.     <title>Upload Files using XMLHttpRequest - Minimal</title>
    5.     <script type="text/javascript">
    6.       function fileSelected() {
    7.         var file = document.getElementById("fileToUpload").files[0];
    8.         if (file) {
    9.           var fileSize = 0;
    10.           if (file.size > 1024 * 1024)
    11.             fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + "MB";
    12.           else
    13.             fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + "KB";
    14.           document.getElementById("fileName").innerHTML = "Name: " + file.name;
    15.           document.getElementById("fileSize").innerHTML = "Size: " + fileSize;
    16.           document.getElementById("fileType").innerHTML = "Type: " + file.type;
    17.         }
    18.       }
    19.       function uploadFile() {
    20.         var fd = new FormData();
    21.         fd.append("fileToUpload", document.getElementById("fileToUpload").files[0]);
    22.         var xhr = new XMLHttpRequest();
    23.         xhr.upload.addEventListener("progress", uploadProgress, false);
    24.         xhr.addEventListener("load", uploadComplete, false);
    25.         xhr.addEventListener("error", uploadFailed, false);
    26.         xhr.addEventListener("abort", uploadCanceled, false);
    27.         xhr.open("POST", "UploadMinimal.aspx");
    28.         xhr.send(fd);
    29.       }
    30.       function uploadProgress(evt) {
    31.         if (evt.lengthComputable) {
    32.           var percentComplete = Math.round(evt.loaded * 100 / evt.total);
    33.           document.getElementById("progressNumber").innerHTML = percentComplete.toString() + "%";
    34.         }
    35.         else {
    36.           document.getElementById("progressNumber").innerHTML = "unable to compute";
    37.         }
    38.       }
    39.       function uploadComplete(evt) {
    40.         /* This event is raised when the server send back a response */
    41.         alert(evt.target.responseText);
    42.       }
    43.       function uploadFailed(evt) {
    44.         alert("There was an error attempting to upload the file.");
    45.       }
    46.       function uploadCanceled(evt) {
    47.         alert("The upload has been canceled by the user or the browser dropped the connection.");
    48.       }
    49.     </script>
    50. </head>
    51. <body>
    52. <form id="form1" enctype="multipart/form-data" method="post" action="upload.php">
    53. <div class="row">
    54.       <label for="fileToUpload">Select a File to Upload</label>
    55. <input type="file" name="fileToUpload" id="fileToUpload" onchange="fileSelected();"/>
    56.     </div>
    57. <div id="fileName"></div>
    58. <div id="fileSize"></div>
    59. <div id="fileType"></div>
    60. <div class="row">
    61. <input type="button" onclick="uploadFile()" value="Upload" />
    62.     </div>
    63. <div id="progressNumber"></div>
    64. </form>
    65. </body>
    66. </html>
    复制代码

      [code][/code]
      我们的任务完成了吗?可以说完成了,因为这段代码已经能够完成上传文件的任务,而且也能够显示上传的进度;但是理应说我们没有,因为除了这个骨架HTML之外,我们还有很多没有做的事情,比如CSS的美化等等。不过这就不是我们这篇文章的主题了。
      最后,提醒一下,教程的代码应当在支持新特性的浏览器之上运行,如果你不清楚自己的浏览器是否支持,可以在这里查询。
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-4-26 14:09 , Processed in 0.467310 second(s), 48 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表