HTML5 jQuery+FormData 异步上传文件,带进度条

利用jQueryHTML5的FormData异步上传文件的好处是:

  • 实现很简单
  • 很方便地支持进度条
  • 很方便地进行扩展和美化

先看看效果图:


图片上传后的结果:



实现步骤如下:

第一步:配置好SpringMVC + servlet3.0 文件上传所需要的各种资源,参考:http://blog.csdn.net/clementad/article/details/49533189


第二步:上传页面的html代码:

[html]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <link href="../resources/css/common.css" rel="stylesheet" />
  6. <script src="../resources/js/jquery-2.1.4.js"></script>
  7. </head>
  8. <body>
  9. <h2>HTML5异步上传文件,带进度条</h2>
  10. <form method="post" enctype="multipart/form-data">
  11. 其他需要提交的信息:<input type="text" name="otherInfo"/><br/><br/>
  12. 选择要上传的文件:<br/>
  13. <input type="file" name="file" /><span></span><br/>
  14. <input type="file" name="file" /><span></span><br/>
  15. </form>
  16. <br/><br/>
  17. <input type="button" value="上传吧" onclick="upload()"/>
  18. <br/><br/>
  19. 上传进度:<progress></progress><br/>
  20. <p id="progress">0 bytes</p>
  21. <p id="info"></p>
  22. </body>
  23. </html>
[html]  view plain  copy
 print ?
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4.     <meta charset="UTF-8">  
  5.     <link href="../resources/css/common.css" rel="stylesheet" />  
  6.     <script src="../resources/js/jquery-2.1.4.js"></script>  
  7.       
  8. </head>  
  9.   
  10. <body>  
  11.     <h2>HTML5异步上传文件,带进度条</h2>  
  12.     <form method="post" enctype="multipart/form-data">  
  13.         其他需要提交的信息:<input type="text" name="otherInfo"/><br/><br/>  
  14.         选择要上传的文件:<br/>  
  15.         <input type="file" name="file" /><span></span><br/>  
  16.         <input type="file" name="file" /><span></span><br/>  
  17.     </form>  
  18.       
  19.     <br/><br/>  
  20.     <input type="button" value="上传吧" onclick="upload()"/>  
  21.     <br/><br/>  
  22.     上传进度:<progress></progress><br/>  
  23.     <p id="progress">0 bytes</p>  
  24.     <p id="info"></p>  
  25. </body>  
  26. </html>  


第三步:异步上传的JavaScript代码(注释很详细):

[javascript]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <script>
  2. var totalSize = 0;
  3. //绑定所有type=file的元素的onchange事件的处理函数
  4. $(':file').change(function() {
  5. var file = this.files[0]; //假设file标签没打开multiple属性,那么只取第一个文件就行了
  6. name = file.name;
  7. size = file.size;
  8. type = file.type;
  9. url = window.URL.createObjectURL(file); //获取本地文件的url,如果是图片文件,可用于预览图片
  10. $(this).next().html("文件名:" + name + " 文件类型:" + type + " 文件大小:" + size + " url: " + url);
  11. totalSize += size;
  12. $("#info").html("总大小: " + totalSize + "bytes");
  13. });
  14. function upload() {
  15. //创建FormData对象,初始化为form表单中的数据。需要添加其他数据可使用formData.append("property", "value");
  16. var formData = new FormData($('form')[0]);
  17. //ajax异步上传
  18. $.ajax({
  19. url: "http://localhost:8080/MyJavaStudio/servlet/file/upload",
  20. type: "POST",
  21. data: formData,
  22. xhr: function(){ //获取ajaxSettings中的xhr对象,为它的upload属性绑定progress事件的处理函数
  23. myXhr = $.ajaxSettings.xhr();
  24. if(myXhr.upload){ //检查upload属性是否存在
  25. //绑定progress事件的回调函数
  26. myXhr.upload.addEventListener('progress',progressHandlingFunction, false);
  27. }
  28. return myXhr; //xhr对象返回给jQuery使用
  29. },
  30. success: function(result){
  31. $("#result").html(result.data);
  32. },
  33. contentType: false//必须false才会自动加上正确的Content-Type
  34. processData: false //必须false才会避开jQuery对 formdata 的默认处理
  35. });
  36. }
  37. //上传进度回调函数:
  38. function progressHandlingFunction(e) {
  39. if (e.lengthComputable) {
  40. $('progress').attr({value : e.loaded, max : e.total}); //更新数据到进度条
  41. var percent = e.loaded/e.total*100;
  42. $('#progress').html(e.loaded + "/" + e.total+" bytes. " + percent.toFixed(2) + "%");
  43. }
  44. }
  45. </script>
[javascript]  view plain  copy
 print ?
  1. <script>  
  2.     var totalSize = 0;  
  3.       
  4.     //绑定所有type=file的元素的onchange事件的处理函数  
  5.     $(':file').change(function() {  
  6.         var file = this.files[0]; //假设file标签没打开multiple属性,那么只取第一个文件就行了  
  7.         name = file.name;  
  8.         size = file.size;  
  9.         type = file.type;  
  10.         url = window.URL.createObjectURL(file); //获取本地文件的url,如果是图片文件,可用于预览图片  
  11.           
  12.         $(this).next().html("文件名:" + name + " 文件类型:" + type + " 文件大小:" + size + " url: " + url);  
  13.           
  14.         totalSize += size;  
  15.           
  16.         $("#info").html("总大小: " + totalSize + "bytes");  
  17.           
  18.     });  
  19.   
  20.     function upload() {  
  21.         //创建FormData对象,初始化为form表单中的数据。需要添加其他数据可使用formData.append("property", "value");  
  22.         var formData = new FormData($('form')[0]);  
  23.           
  24.         //ajax异步上传  
  25.         $.ajax({  
  26.             url: "http://localhost:8080/MyJavaStudio/servlet/file/upload",  
  27.             type: "POST",  
  28.             data: formData,  
  29.             xhr: function(){ //获取ajaxSettings中的xhr对象,为它的upload属性绑定progress事件的处理函数  
  30.               
  31.                 myXhr = $.ajaxSettings.xhr();  
  32.                 if(myXhr.upload){ //检查upload属性是否存在  
  33.                     //绑定progress事件的回调函数  
  34.                     myXhr.upload.addEventListener('progress',progressHandlingFunction, false);   
  35.                 }  
  36.                 return myXhr; //xhr对象返回给jQuery使用  
  37.             },  
  38.             success: function(result){  
  39.                 $("#result").html(result.data);  
  40.             },  
  41.             contentType: false//必须false才会自动加上正确的Content-Type  
  42.             processData: false  //必须false才会避开jQuery对 formdata 的默认处理  
  43.         });  
  44.     }         
  45.   
  46.     //上传进度回调函数:  
  47.     function progressHandlingFunction(e) {  
  48.         if (e.lengthComputable) {  
  49.             $('progress').attr({value : e.loaded, max : e.total}); //更新数据到进度条  
  50.             var percent = e.loaded/e.total*100;  
  51.             $('#progress').html(e.loaded + "/" + e.total+" bytes. " + percent.toFixed(2) + "%");  
  52.         }  
  53.     }  
  54. </script>  

第四步: SpringMVC写好接受和保持文件的Controller方法:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. /**
  2. * 文件上传
  3. * @author XuJijun
  4. *
  5. */
  6. @RestController
  7. @RequestMapping("/servlet/file")
  8. public class FileUploadController {
  9. /**
  10. * 保存文件的目录,放在web目录、或一个指定的绝对目录下
  11. */
  12. private static final String SAVE_DIR = "uploadFiles";
  13. /**
  14. *
  15. * @param request
  16. * @param response
  17. * @param p form表单中,type="text"的input控件,内容通过这个参数传送过来,以input控件中的name属性来区分
  18. * @return JSON表示的处理结果
  19. * @throws ServletException
  20. * @throws IOException
  21. */
  22. @RequestMapping("/upload")
  23. public JsonResult upload(HttpServletRequest request, HttpServletResponse response, @RequestParam Map<String, Object> p)
  24. throws ServletException, IOException {
  25. // 获取 web application的绝对路径
  26. String appPath = request.getServletContext().getRealPath("");
  27. // 构造文件存放的路径
  28. String savePath = appPath + File.separator + SAVE_DIR;
  29. // 如果文件存放路径不存在,则mkdir一个
  30. File fileSaveDir = new File(savePath);
  31. if (!fileSaveDir.exists()) {
  32. fileSaveDir.mkdirs();
  33. }
  34. List<String> fileNames = new ArrayList<>();
  35. //循环所有的part,把part中的文件保存到硬盘中
  36. for (Part part : request.getParts()) {
  37. String fileName = part.getSubmittedFileName();
  38. //form表单中的每个input,都在一个不同的part中,
  39. //所以需要判断通过fileName是否为空,过滤掉其他类型的input(比如type="text"):
  40. if(!StringUtils.isEmpty(fileName)){
  41. part.write(savePath + File.separator + fileName);
  42. fileNames.add(fileName);
  43. }
  44. }
  45. Map<String, Object> resultData = new HashMap<>();
  46. resultData.put("savePath", savePath);
  47. resultData.put("files", fileNames);
  48. return new JsonResult("200""文件上传成功!", resultData);
  49. }
  50. /**
  51. * 从content-disposition头中获取源文件名
  52. *
  53. * content-disposition头的格式如下:
  54. * form-data; name="dataFile"; filename="PHOTO.JPG"
  55. *
  56. * @param part
  57. * @return
  58. */
  59. @SuppressWarnings("unused")
  60. private String extractFileName(Part part) {
  61. String contentDisp = part.getHeader("content-disposition");
  62. String[] items = contentDisp.split(";");
  63. for (String s : items) {
  64. if (s.trim().startsWith("filename")) {
  65. return s.substring(s.indexOf("=") + 2, s.length()-1);
  66. }
  67. }
  68. return "";
  69. }
  70. }
[java]  view plain  copy
 print ?
  1. /** 
  2.  * 文件上传 
  3.  * @author XuJijun 
  4.  * 
  5.  */  
  6. @RestController  
  7. @RequestMapping("/servlet/file")  
  8. public class FileUploadController {  
  9.       
  10.     /** 
  11.      * 保存文件的目录,放在web目录、或一个指定的绝对目录下 
  12.      */  
  13.      private static final String SAVE_DIR = "uploadFiles";  
  14.       
  15.      /** 
  16.       *  
  17.       * @param request 
  18.       * @param response 
  19.       * @param p form表单中,type="text"的input控件,内容通过这个参数传送过来,以input控件中的name属性来区分 
  20.       * @return JSON表示的处理结果 
  21.       * @throws ServletException 
  22.       * @throws IOException 
  23.       */  
  24.     @RequestMapping("/upload")  
  25.     public JsonResult upload(HttpServletRequest request, HttpServletResponse response, @RequestParam Map<String, Object> p)  
  26.             throws ServletException, IOException {  
  27.   
  28.         // 获取 web application的绝对路径  
  29.         String appPath = request.getServletContext().getRealPath("");  
  30.           
  31.         // 构造文件存放的路径  
  32.         String savePath = appPath + File.separator + SAVE_DIR;  
  33.   
  34.         // 如果文件存放路径不存在,则mkdir一个  
  35.         File fileSaveDir = new File(savePath);  
  36.         if (!fileSaveDir.exists()) {  
  37.             fileSaveDir.mkdirs();  
  38.         }  
  39.   
  40.         List<String> fileNames = new ArrayList<>();  
  41.           
  42.         //循环所有的part,把part中的文件保存到硬盘中  
  43.         for (Part part : request.getParts()) {  
  44.             String fileName = part.getSubmittedFileName();  
  45.               
  46.             //form表单中的每个input,都在一个不同的part中,  
  47.             //所以需要判断通过fileName是否为空,过滤掉其他类型的input(比如type="text"):  
  48.             if(!StringUtils.isEmpty(fileName)){   
  49.                 part.write(savePath + File.separator + fileName);  
  50.                 fileNames.add(fileName);  
  51.             }  
  52.         }  
  53.   
  54.         Map<String, Object> resultData = new HashMap<>();  
  55.         resultData.put("savePath", savePath);  
  56.         resultData.put("files", fileNames);  
  57.           
  58.         return new JsonResult("200""文件上传成功!", resultData);  
  59.     }  
  60.        
  61.     /** 
  62.      * 从content-disposition头中获取源文件名 
  63.      *  
  64.      * content-disposition头的格式如下: 
  65.      * form-data; name="dataFile"; filename="PHOTO.JPG" 
  66.      *  
  67.      * @param part 
  68.      * @return 
  69.      */  
  70.     @SuppressWarnings("unused")  
  71.     private String extractFileName(Part part) {  
  72.         String contentDisp = part.getHeader("content-disposition");  
  73.         String[] items = contentDisp.split(";");  
  74.         for (String s : items) {  
  75.             if (s.trim().startsWith("filename")) {  
  76.                 return s.substring(s.indexOf("=") + 2, s.length()-1);  
  77.             }  
  78.         }  
  79.         return "";  
  80.     }  
  81.   
  82. }  

最后那个私有方法可以不用的,只是为了演示如何直接获取request header中的数据。


最后,验证上传过程中的网络消息:

上传的消息头和数据:


可见,对于表单中的3个input,http request payload中对应有3个part来上传数据。

Controller处理后的返回结果(JSON格式):


总结:代码很简单,结果很友好,html5和SpringMVC!


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值