很久没有更新博客了,这段时间实在的忙的不可开交,项目马上就要上线了,要修补的东西太多了。当我在学习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);
} }

  效果图:

  

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. HTML第二课

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  2. 关于Storm tick

    关于Storm tick 1. tick的功能 Apache Storm中内置了一种定时机制——tick,它能够让任何bolt的所有task每隔一段时间(精确到秒级,用户可以自定义)收到一个来自__s ...

  3. smarty模板做人员表信息删除,修改 里面的性别单选按钮民族下拉,另外登录进去可以显示姓名

    首先登录进去可以显示姓名 smarty模板做人员表信息删除,删除的时候有提示框确定删除吗. 修改 里面的性别单选按钮,要修改谁有默认选中,用了变量调节器 民族位置做下拉,用<{foreach}& ...

  4. 算法模板——平衡树Treap 2

    实现功能:同平衡树Treap 1(BZOJ3224 / tyvj1728) 这次的模板有了不少的改进,显然更加美观了,几乎每个部分都有了不少简化,尤其是删除部分,这个参照了hzwer神犇的写法,在此鸣 ...

  5. java中的递归

    所谓递归,是指程序调用自身,当然,递归不会无休止地调用下去,它必然有一个出口,当满足条件时程序也就结束了,不然的话,那就是死循环了. 看下面这个类,有几个递归方法,看了之后肯定会对你学习递归很有帮助的 ...

  6. iTunes Documents 文件共享指导手册

    金田 p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Helvetica; min-height: 13.0px } p.p2 { margi ...

  7. js动态加载的蒙板弹框

    我们访问一些网站时总会遇到这种点击后,背景像被打上一层模板一样,这个是怎么做到的呢? 它是将这个弹框div独立于页面容器wrap,设置position为absolute,将其水平垂直之后都居中,设置弹 ...

  8. js面向对象总结

    原型链 新创建的xiaoming的原型链是: xiaoming ----> Student.prototype ----> Object.prototype ----> null 也 ...

  9. 在SSRS的每一页重复显示table header

    现在在做一个关于SSRS报表展示的项目,但是我困顿在如何在table的每一页让table header重复显示.因为我在table属性中勾选了"Report header columns o ...

  10. sass 学习

    本来看了阮一峰和于江水两位老师的博客,有看了ionic自带的sass文件,原以为自己已经是很熟悉,精通了.可是我居然连ruby都不知道真实惭愧啊,辛亏看了www.sass.hk  我想这篇官方文档肯定 ...