很久没有更新博客了,这段时间实在的忙的不可开交,项目马上就要上线了,要修补的东西太多了。当我在学习JavaWeb文件上传的时候,我就一直有一个疑问,网站上那些博客的图片是怎么上传的,因为当提交了表单之后网页就跳转了。后来我学习到了Ajax,我知道了浏览器可以异步的发送响应,这时我又有新的疑问,那就是在我上传一些文件的时候,那些网站的上传进度是怎么做到的,因为servlet直到上传完成之后才完成响应。

  最近我们的项目中有一个地方中需要用到一个功能,当用户点击一个处理按钮时,前台会实时的显示后台处理动态,由于servlet一次只能接受一个请求,而且在servlet的生命周期结束时才会把响应数据发送到前台(这一点大家可以做个这样的测试:

  1. response.getWriter().print("hello");
  2. Thread.sleep(10000);
  3. response.getWriter().print("world");

,你们会发现前台在等待了约10s后收到了"helloworld")。所以我想到了一个方法:使用单例保存实时信息。具体的实现方法就是,当用户点击了处理按钮时,在后台开启一个线程进行处理,并且每进行到一步,就向单例中写入当前状态信息。然后编写一个servlet,用于返回单例中的信息,前台循环发送请求,这样就能实现实时显示进度的效果。

  好了,啰嗦了这么多,下面进入正题,如何实现上传文件动态显示进度,其实思想和上面的功能是一致的,我将这个功能分为三个点:

  1. 单例:用于保存进度信息;
  2. 上传servlet:用于上传文件并实时写入进度;
  3. 进度servlet:用于读取实时进度信息;

  上代码,前台:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Insert title here</title>
  6. <style type="text/css">
  7. #progress:after {
  8. content: '%';
  9. }
  10. </style>
  11. </head>
  12. <body>
  13. <h3>File upload demo</h3>
  14. <form action="TestServlet" method="post" enctype="multipart/form-data" id="dataForm">
  15. <input type="file" name="file" id="fileInput"> <br>
  16. <input type="submit" value="submit" id="submit">
  17. </form>
  18. <div id="progress"></div>
  19. <script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
  20. <script type="text/javascript">
  21. (function () {
  22. var form = document.getElementById("dataForm");
  23. var progress = document.getElementById("progress");
  24.  
  25. $("#submit").click(function(event) {
  26. //阻止默认事件
  27. event.preventDefault();
  28. //循环查看状态
  29. var t = setInterval(function(){
  30. $.ajax({
  31. url: 'ProgressServlet',
  32. type: 'POST',
  33. dataType: 'text',
  34. data: {
  35. filename: fileInput.files[0].name,
  36. },
  37. success: function (responseText) {
  38. var data = JSON.parse(responseText);
  39. //前台更新进度
  40. progress.innerText = parseInt((data.progress / data.size) * 100);
  41. },
  42. error: function(){
  43. console.log("error");
  44. }
  45. });
  46. }, 500);
  47. //上传文件
  48. $.ajax({
  49. url: 'UploadServlet',
  50. type: 'POST',
  51. dataType: 'text',
  52. data: new FormData(form),
  53. processData: false,
  54. contentType: false,
  55. success: function (responseText) {
  56. //上传完成,清除循环事件
  57. clearInterval(t);
  58. //将进度更新至100%
  59. progress.innerText = 100;
  60. },
  61. error: function(){
  62. console.log("error");
  63. }
  64. });
  65. return false;
  66. });
  67. })();
  68. </script>
  69. </body>
  70. </html>

  后台,单例:

  1. import java.util.Hashtable;
  2.  
  3. public class ProgressSingleton {
  4. //为了防止多用户并发,使用线程安全的Hashtable
  5. private static Hashtable<Object, Object> table = new Hashtable<>();
  6.  
  7. public static void put(Object key, Object value){
  8. table.put(key, value);
  9. }
  10.  
  11. public static Object get(Object key){
  12. return table.get(key);
  13. }
  14.  
  15. public static Object remove(Object key){
  16. return table.remove(key);
  17. }
  18. }

  上传servlet:

  1. import java.io.File;
  2. import java.io.FileOutputStream;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.util.List;
  6.  
  7. import javax.servlet.ServletException;
  8. import javax.servlet.annotation.WebServlet;
  9. import javax.servlet.http.HttpServlet;
  10. import javax.servlet.http.HttpServletRequest;
  11. import javax.servlet.http.HttpServletResponse;
  12.  
  13. import org.apache.tomcat.util.http.fileupload.FileItem;
  14. import org.apache.tomcat.util.http.fileupload.FileUploadException;
  15. import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
  16. import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
  17. import org.apache.tomcat.util.http.fileupload.servlet.ServletRequestContext;
  18.  
  19. import singleton.ProgressSingleton;
  20.  
  21. @WebServlet("/UploadServlet")
  22. public class UploadServlet extends HttpServlet {
  23. private static final long serialVersionUID = 1L;
  24.  
  25. public UploadServlet() {
  26. }
  27.  
  28. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  29.  
  30. DiskFileItemFactory factory = new DiskFileItemFactory();
  31. factory.setSizeThreshold(4*1024);
  32.  
  33. ServletFileUpload upload = new ServletFileUpload(factory);
  34.  
  35. List<FileItem> fileItems;
  36. try {
  37. fileItems = upload.parseRequest(new ServletRequestContext(request));
  38. //获取文件域
  39. FileItem fileItem = fileItems.get(0);
  40. //使用sessionid + 文件名生成文件号
  41. String id = request.getSession().getId() + fileItem.getName();
  42. //向单例哈希表写入文件长度和初始进度
  43. ProgressSingleton.put(id + "Size", fileItem.getSize());
  44. //文件进度长度
  45. long progress = 0;
  46. //用流的方式读取文件,以便可以实时的获取进度
  47. InputStream in = fileItem.getInputStream();
  48. File file = new File("D:/test");
  49. file.createNewFile();
  50. FileOutputStream out = new FileOutputStream(file);
  51. byte[] buffer = new byte[1024];
  52. int readNumber = 0;
  53. while((readNumber = in.read(buffer)) != -1){
  54. //每读取一次,更新一次进度大小
  55. progress = progress + readNumber;
  56. //向单例哈希表写入进度
  57. ProgressSingleton.put(id + "Progress", progress);
  58. out.write(buffer);
  59. }
  60. //当文件上传完成之后,从单例中移除此次上传的状态信息
  61. ProgressSingleton.remove(id + "Size");
  62. ProgressSingleton.remove(id + "Progress");
  63. in.close();
  64. out.close();
  65. } catch (FileUploadException e) {
  66. e.printStackTrace();
  67. }
  68.  
  69. response.getWriter().print("done");
  70. }
  71.  
  72. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  73. doGet(request, response);
  74. }
  75.  
  76. }

  进度servlet:

  1. import java.io.IOException;
  2.  
  3. import javax.servlet.ServletException;
  4. import javax.servlet.annotation.WebServlet;
  5. import javax.servlet.http.HttpServlet;
  6. import javax.servlet.http.HttpServletRequest;
  7. import javax.servlet.http.HttpServletResponse;
  8.  
  9. import net.sf.json.JSONObject;
  10. import singleton.ProgressSingleton;
  11.  
  12. @WebServlet("/ProgressServlet")
  13. public class ProgressServlet extends HttpServlet {
  14. private static final long serialVersionUID = 1L;
  15.  
  16. public ProgressServlet() {
  17. super();
  18. // TODO Auto-generated constructor stub
  19. }
  20.  
  21. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  22.  
  23. String id = request.getSession().getId();
  24. String filename = request.getParameter("filename");
  25. //使用sessionid + 文件名生成文件号,与上传的文件保持一致
  26. id = id + filename;
  27. Object size = ProgressSingleton.get(id + "Size");
  28. size = size == null ? 100 : size;
  29. Object progress = ProgressSingleton.get(id + "Progress");
  30. progress = progress == null ? 0 : progress;
  31. JSONObject json = new JSONObject();
  32. json.put("size", size);
  33. json.put("progress", progress);
  34. response.getWriter().print(json.toString());
  35. }
  36.  
  37. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  38. doGet(request, response);
  39. }
  40.  
  41. }

  效果图:

  

JavaWeb项目实现文件上传动态显示进度的更多相关文章

  1. JavaWeb学习总结——文件上传和下载

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...

  2. javaWeb中,文件上传和下载

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...

  3. JavaWeb中的文件上传和下载功能的实现

    导入相关支持jar包:commons-fileupload.jar,commons-io.jar 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上 ...

  4. javaWeb中的文件上传下载

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...

  5. 使用Typescript重构axios(二十五)——文件上传下载进度监控

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  6. atitit.文件上传带进度条的实现原理and组件选型and最佳实践总结O7

    atitit.文件上传带进度条的实现原理and组件选型and最佳实践总结O7 1. 实现原理 1 2. 大的文件上传原理::使用applet 1 3. 新的bp 2 1. 性能提升---分割小文件上传 ...

  7. atitit. 文件上传带进度条 atiUP 设计 java c# php

    atitit. 文件上传带进度条 atiUP 设计 java c# php 1. 设计要求 1 2. 原理and 架构 1 3. ui 2 4. spring mvc 2 5. springMVC.x ...

  8. SpringBoot项目实现文件上传和邮件发送

    前言 本篇文章主要介绍的是SpringBoot项目实现文件上传和邮件发送的功能. SpringBoot 文件上传 说明:如果想直接获取工程那么可以直接跳到底部,通过链接下载工程代码. 开发准备 环境要 ...

  9. web项目的文件上传和 下载

    文件上传和下载在web应用中非常普遍,要在jsp环境中实现文件上传功能是非常容易的,因为网上有许多用Java开发的文件上传组件,本文以commons-fileupload组件为例,为jsp应用添加文件 ...

随机推荐

  1. HDU---Labyrinth

    Labyrinth Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  2. c++文件读取(一)---输入类使用和查找当前程序路径

    鉴于公司人员流动大,设计一个小的日志定位器,首先要读取日志文件 用输入输出流类操作文件比c的stdio更安全和容易,当然任何此类观点都是对大牛除外 首先是查找当前文件路径,如果用GetCurrentD ...

  3. NDK 开发(Android.mk配置)

         在我写这篇文章的时候,Android Studio已经是2.3版本了,已经集成CMake 编译工具, 用户只需在 新建项目的时候,添加选项(Include C++ support),Andr ...

  4. 从零开始部署小型企业级虚拟桌面 -- Vmware Horizon View 6 For Linux VDI -- 概念简介

    什么是桌面虚拟化? 桌面虚拟化有很多概念,此处谈论的,是指的一般企业使用的“服务器 + 虚拟机 + 云终端”的方式来实现的. 桌面虚拟化的原理是什么? 桌面虚拟化看上去高大上,实际上原理非常的简单.拿 ...

  5. oracle目录操作

    1.创建目录 create directory dir_name as 'dir_path'  (dir_path必须事先手动创建) 2.授权 grant read,write on director ...

  6. java Thread和Runable的深刻理解

    线程(Thread)是指程序的运行流程,多线程机制指同时运行多个程序块. Java中实现多线程有两种方法:继承Thread类:实现Runnable接口. Thread类的run()方法的制定者:接口R ...

  7. MD5加密 32位

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Menlo } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; ...

  8. struts2(二) 表单参数自动封装和参数类型自动转换

    前篇文章对struts2的一个入门,重点是对struts2的架构图有一个大概的了解即可,之后的几篇文章,就是细化struts2,将struts2中的各种功能进行梳理,其实学完之后,对struts2的使 ...

  9. 设置border属性变化不同形状:三角形、圆形、弧形 2017-03-20

    一.通过设置边框----正方形.三角形 <style> .c{ height: 0px; width: 0px; border-top: 50px solid red; border-ri ...

  10. Linux下httpd服务与Apache服务的查看和启动

    转:http://jingyan.baidu.com/article/63f236282d43170209ab3d43.html 这里简要介绍Linux环境中Apache也就是httpd服务的启动,查 ...