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

利用jQuery和HTML5的FormData异步上传文件的好处是:

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

先看看效果图:


图片上传后的结果:



实现步骤如下:

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


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

[html]  view plain  copy
 print ?
  1. >
  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 bytesp>
  21. <p id="info">p>
  22. body>
  23. html>
[html]  view plain  copy
 print ?
  1. >  
  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 bytesp>  
  24.     <p id="info">p>  
  25. body>  
  26. html>  


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

[javascript]  view plain  copy
 print ?
[javascript]  view plain  copy
 print ?
  1.   

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

[java]  view plain  copy
 print ?
  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 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 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 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 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 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 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!


你可能感兴趣的:(文件上传和下载)