JavaWeb项目实现文件上传动态显示进度实例
很久没有更新博客了,这段时间实在的忙的不可开交,项目马上就要上线了,要修补的东西太多了。当我在学习javaweb文件上传的时候,我就一直有一个疑问,网站上那些博客的图片是怎么上传的,因为当提交了表单之后网页就跳转了。后来我学习到了ajax,我知道了浏览器可以异步的发送响应,这时我又有新的疑问,那就是在我上传一些文件的时候,那些网站的上传进度是怎么做到的,因为servlet直到上传完成之后才完成响应。
最近我们的项目中有一个地方中需要用到一个功能,当用户点击一个处理按钮时,前台会实时的显示后台处理动态,由于servlet一次只能接受一个请求,而且在servlet的生命周期结束时才会把响应数据发送到前台(这一点大家可以做个这样的测试:
response.getwriter().print("hello"); thread.sleep(10000); response.getwriter().print("world");
你们会发现前台在等待了约10s后收到了"helloworld")。所以我想到了一个方法:使用单例保存实时信息。具体的实现方法就是,当用户点击了处理按钮时,在后台开启一个线程进行处理,并且每进行到一步,就向单例中写入当前状态信息。然后编写一个servlet,用于返回单例中的信息,前台循环发送请求,这样就能实现实时显示进度的效果。
好了,啰嗦了这么多,下面进入正题,如何实现上传文件动态显示进度,其实思想和上面的功能是一致的,我将这个功能分为三个点:
1.单例:用于保存进度信息;
2.上传servlet:用于上传文件并实时写入进度;
3.进度servlet:用于读取实时进度信息;
上代码,前台:
<!doctype html> <html> <head> <meta charset="utf-8"> <title>insert title here</title> <style type="text/css"> #progress:after { content: '%'; } </style> </head> <body> <h3>file upload demo</h3> <form action="testservlet" method="post" enctype="multipart/form-data" id="dataform"> <input type="file" name="file" id="fileinput"> <br> <input type="submit" value="submit" id="submit"> </form> <div id="progress"></div> <script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script> <script type="text/javascript"> (function () { var form = document.getelementbyid("dataform"); var progress = document.getelementbyid("progress"); $("#submit").click(function(event) { //阻止默认事件 event.preventdefault(); //循环查看状态 var t = setinterval(function(){ $.ajax({ url: 'progressservlet', type: 'post', datatype: 'text', data: { filename: fileinput.files[0].name, }, success: function (responsetext) { var data = json.parse(responsetext); //前台更新进度 progress.innertext = parseint((data.progress / data.size) * 100); }, error: function(){ console.log("error"); } }); }, 500); //上传文件 $.ajax({ url: 'uploadservlet', type: 'post', datatype: 'text', data: new formdata(form), processdata: false, contenttype: false, success: function (responsetext) { //上传完成,清除循环事件 clearinterval(t); //将进度更新至100% progress.innertext = 100; }, error: function(){ console.log("error"); } }); return false; }); })(); </script> </body> </html>
后台,单例:
import java.util.hashtable; public class progresssingleton { //为了防止多用户并发,使用线程安全的hashtable private static hashtable<object, object> table = new hashtable<>(); public static void put(object key, object value){ table.put(key, value); } public static object get(object key){ return table.get(key); } public static object remove(object key){ return table.remove(key); } }
上传servlet:
import java.io.file; import java.io.fileoutputstream; import java.io.ioexception; import java.io.inputstream; import java.util.list; import javax.servlet.servletexception; import javax.servlet.annotation.webservlet; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import org.apache.tomcat.util.http.fileupload.fileitem; import org.apache.tomcat.util.http.fileupload.fileuploadexception; import org.apache.tomcat.util.http.fileupload.disk.diskfileitemfactory; import org.apache.tomcat.util.http.fileupload.servlet.servletfileupload; import org.apache.tomcat.util.http.fileupload.servlet.servletrequestcontext; import singleton.progresssingleton; @webservlet("/uploadservlet") public class uploadservlet extends httpservlet { private static final long serialversionuid = 1l; public uploadservlet() { } protected void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { diskfileitemfactory factory = new diskfileitemfactory(); factory.setsizethreshold(4*1024); servletfileupload upload = new servletfileupload(factory); list<fileitem> fileitems; try { fileitems = upload.parserequest(new servletrequestcontext(request)); //获取文件域 fileitem fileitem = fileitems.get(0); //使用sessionid + 文件名生成文件号 string id = request.getsession().getid() + fileitem.getname(); //向单例哈希表写入文件长度和初始进度 progresssingleton.put(id + "size", fileitem.getsize()); //文件进度长度 long progress = 0; //用流的方式读取文件,以便可以实时的获取进度 inputstream in = fileitem.getinputstream(); file file = new file("d:/test"); file.createnewfile(); fileoutputstream out = new fileoutputstream(file); byte[] buffer = new byte[1024]; int readnumber = 0; while((readnumber = in.read(buffer)) != -1){ //每读取一次,更新一次进度大小 progress = progress + readnumber; //向单例哈希表写入进度 progresssingleton.put(id + "progress", progress); out.write(buffer); } //当文件上传完成之后,从单例中移除此次上传的状态信息 progresssingleton.remove(id + "size"); progresssingleton.remove(id + "progress"); in.close(); out.close(); } catch (fileuploadexception e) { e.printstacktrace(); } response.getwriter().print("done"); } protected void dopost(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { doget(request, response); } }
进度servlet:
import java.io.ioexception; import javax.servlet.servletexception; import javax.servlet.annotation.webservlet; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import net.sf.json.jsonobject; import singleton.progresssingleton; @webservlet("/progressservlet") public class progressservlet extends httpservlet { private static final long serialversionuid = 1l; public progressservlet() { super(); // todo auto-generated constructor stub } protected void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { string id = request.getsession().getid(); string filename = request.getparameter("filename"); //使用sessionid + 文件名生成文件号,与上传的文件保持一致 id = id + filename; object size = progresssingleton.get(id + "size"); size = size == null ? 100 : size; object progress = progresssingleton.get(id + "progress"); progress = progress == null ? 0 : progress; jsonobject json = new jsonobject(); json.put("size", size); json.put("progress", progress); response.getwriter().print(json.tostring()); } protected void dopost(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { doget(request, response); } }
效果图:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 《Linux内核设计与实现》读书笔记——内核数据结构
下一篇: Redis的字符串的底层实现SDS