使用 apache fileupload ,spring MVC jquery1.6x , bootstrap 实现一个带进度条的多文件上传,由于fileupload 的局限,暂不能实现每个上传文件都显示进度条,只能实现一个总的进度条,效果如图:
1、jsp 页面
<!DOCTYPE html><%@ page contentType="text/htmlcharset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html charset=UTF-8" />
<script src="../js/jquery-1.6.4.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="../css/bootstrap.css"/>
</head>
<body>
<form id='fForm' class="form-actions form-horizontal" action="../upload.html"
encType="multipart/form-data" target="uploadf" method="post">
<div class="control-group">
<label class="control-label">上传文件:</label>
<div class="controls">
<input type="file" name="file" style="width:550">
</div>
<div class="controls">
<input type="file" name="file" style="width:550">
</div>
<div class="controls">
<input type="file" name="file" style="width:550">
</div>
<label class="control-label">上传进度:</label>
<div class="controls">
<div class="progress progress-success progress-striped" style="width:50%">
<div id = 'proBar' class="bar" style="width: 0%"></div>
</div>
</div>
</div>
<div class="control-group">
<div class="controls">
<button type="button" id="subbut" class="btn">submit</button>
</div>
</div>
</form>
<iframe name="uploadf" style="display:none"></iframe>
</body>
</html>
<script >
$(document).ready(function(){
$('#subbut').bind('click',
function(){
$('#fForm').submit()
var eventFun = function(){
$.ajax({
type: 'GET',
url: '../process.json',
data: {},
dataType: 'json',
success : function(data){
$('#proBar').css('width',data.rate+''+'%')
$('#proBar').empty()
$('#proBar').append(data.show)
if(data.rate == 100){
window.clearInterval(intId)
}
}})}
var intId = window.setInterval(eventFun,500)
})
})
</script>
2、java 代码
package com.controller
import java.util.List
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import javax.servlet.http.HttpSession
import org.apache.commons.fileupload.FileItemFactory
import org.apache.commons.fileupload.ProgressListener
import org.apache.commons.fileupload.disk.DiskFileItemFactory
import org.apache.commons.fileupload.servlet.ServletFileUpload
import org.apache.log4j.Logger
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.servlet.ModelAndView
@Controller
public class FileUploadController {
Logger log = Logger.getLogger(FileUploadController.class)
/**
* upload 上传文件
* @param request
* @param response
* @return
* @throws Exception
*/
@RequestMapping(value = "/upload.html", method = RequestMethod.POST)
public ModelAndView upload(HttpServletRequest request,
HttpServletResponse response) throws Exception {
final HttpSession hs = request.getSession()
ModelAndView mv = new ModelAndView()
boolean isMultipart = ServletFileUpload.isMultipartContent(request)
if(!isMultipart){
return mv
}
// Create a factory for disk-based file items
FileItemFactory factory = new DiskFileItemFactory()
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory)
upload.setProgressListener(new ProgressListener(){
public void update(long pBytesRead, long pContentLength, int pItems) {
ProcessInfo pri = new ProcessInfo()
pri.itemNum = pItems
pri.readSize = pBytesRead
pri.totalSize = pContentLength
pri.show = pBytesRead+"/"+pContentLength+" byte"
pri.rate = Math.round(new Float(pBytesRead) / new Float(pContentLength)*100)
hs.setAttribute("proInfo", pri)
}
})
List items = upload.parseRequest(request)
// Parse the request
// Process the uploaded items
// Iterator iter = items.iterator()
// while (iter.hasNext()) {
// FileItem item = (FileItem) iter.next()
// if (item.isFormField()) {
// String name = item.getFieldName()
// String value = item.getString()
// System.out.println("this is common feild!"+name+"="+value)
// } else {
// System.out.println("this is file feild!")
// String fieldName = item.getFieldName()
// String fileName = item.getName()
// String contentType = item.getContentType()
// boolean isInMemory = item.isInMemory()
// long sizeInBytes = item.getSize()
// File uploadedFile = new File("c://"+fileName)
// item.write(uploadedFile)
// }
// }
return mv
}
/**
* process 获取进度
* @param request
* @param response
* @return
* @throws Exception
*/
@RequestMapping(value = "/process.json", method = RequestMethod.GET)
@ResponseBody
public Object process(HttpServletRequest request,
HttpServletResponse response) throws Exception {
return ( ProcessInfo)request.getSession().getAttribute("proInfo")
}
class ProcessInfo{
public long totalSize = 1
public long readSize = 0
public String show = ""
public int itemNum = 0
public int rate = 0
}
}
4、刚刚提醒了我,还可以直接开发浏览器插件。 上述四种方法的比较: 1、开发简单,由于要定时起一个HTTP 连接去获得进度信息,因此,发生的连接请求也增多 ,另外,在低速的情况下,常常会出各种各样的BUG,网络环境的差异,还造成那个周期很 难选择。 2、开发较复杂,COMET 本身需要服务器的支持,这样TOMCAT 至少得选6.0,否则服务器长连 接,压力肯定受不了,但是,性能相对好一些,由于一次上传实际上只启动了两个HTTP 链接 请求,比起AJAX 来说,那是要少很多请求了。另外一个优点是,COMET 将使得服务器可以主 动将进度情况汇报给客户端,因此,客户端的进度条相对来说,要准确一点。 3、目前看来解决方案最好的一个了,虽然开发需要涉及到 FLASH、JAVASCRIPT、以及 JAVA 的 开发,但是代码量都不是很多,因此,复杂程度相对属于中等程度。但是FLASH 也有几个问 题:第一、浏览器 FLASH 版本兼容问题,第二、FLASH 是通过获得发送数据的进度来体现进度 条的,因此虽然不需要服务器端开发进度部分的代码,但是进度的展现有些不是很准确,经 常会有一开始速度很快,但是后面越来越慢的情况。 4、就不说了,开发肯定是最麻烦的,但是进度条效果肯定是最好的,但要给每种浏览器都 要搞个插件,还是比较痛苦的。 总结一下,希望对大家有帮助。 2 其实很麻烦的,之前试过,会有下面几个问题: 第一、服务器端一定要选择支持HTTP 长连接的服务器,否则 *** 作系统的线程限制,会导致并 发降低。 第二、除非原来就采用的是COMET 的进度方式,否则,你要把周期获得进度的方式,改成 COMET 的方式,那很郁闷的,COMET 要服务器主动把进度信息用JAVASCRIPT 的方式发回客户端 ,所以需要把结构转化为JAVASCRIPT 调用才行。 第三、对于不同的浏览器,处理 JAVASCRIPT 的方式是不一样的,我试验的结果是,IE 会在收 到一定数量的JAVASCRIPT 之后才执行,所以虽然我在服务器端每次都调用了flush 方法,但 是界面上还是需要等一段时间才能响应。而这段时间又不好控制了,因为上传文件大小的不 一样,导致了下发的JAVASCRIPT 数量也不一样,所以基本很难达到FLASH 那样的效果。 其实如果已经决定采用flash 了,那就不需要再去修改服务器端的代码了,因为那个进度信 息服务器发不发都不会影响到代码的执行,反正FLASH 本身已经提供了进度指示了,所以, 说简单地,要改成FLASH 上传,你直接做个FLASH 客户端就好了,不需要再改服务器端了。 对了,还有一种情况需要改服务器端,那就是FLASH 上传多个文件是采用多线程上传的,因 此如果你一次上传多个文件,那就需要改服务器端了。需要在所有线程上传完成的情况下, 再去修改数据库。上述四种方法的比较: 1、开发简单,由于要定时起一个HTTP 连接去获得进度信息,因此,发生的连接请求也增多 ,另外,在低速的情况下,常常会出各种各样的BUG,网络环境的差异,还造成那个周期很 难选择。 2、开发较复杂,COMET 本身需要服务器的支持,这样TOMCAT 至少得选6.0,否则服务器长连 接,压力肯定受不了,但是,性能相对好一些,由于一次上传实际上只启动了两个HTTP 链接 请求,比起AJAX 来说,那是要少很多请求了。另外一个优点是,COMET 将使得服务器可以主 动将进度情况汇报给客户端,因此,客户端的进度条相对来说,要准确一点。 3、目前看来解决方案最好的一个了,虽然开发需要涉及到 FLASH、JAVASCRIPT、以及 JAVA 的 开发,但是代码量都不是很多,因此,复杂程度相对属于中等程度。但是FLASH 也有几个问 题:第一、浏览器 FLASH 版本兼容问题,第二、FLASH 是通过获得发送数据的进度来体现进度 条的,因此虽然不需要服务器端开发进度部分的代码,但是进度的展现有些不是很准确,经 常会有一开始速度很快,但是后面越来越慢的情况。 4、就不说了,开发肯定是最麻烦的,但是进度条效果肯定是最好的,但要给每种浏览器都 要搞个插件,还是比较痛苦的。 总结一下,希望对大家有帮助。 2 其实很麻烦的,之前试过,会有下面几个问题: 第一、服务器端一定要选择支持HTTP 长连接的服务器,否则 *** 作系统的线程限制,会导致并 发降低。 第二、除非原来就采用的是COMET 的进度方式,否则,你要把周期获得进度的方式,改成 COMET 的方式,那很郁闷的,COMET 要服务器主动把进度信息用JAVASCRIPT 的方式发回客户端 ,所以需要把结构转化为JAVASCRIPT 调用才行。 第三、对于不同的浏览器,处理 JAVASCRIPT 的方式是不一样的,我试验的结果是,IE 会在收 到一定数量的JAVASCRIPT 之后才执行,所以虽然我在服务器端每次都调用了flush 方法,但 是界面上还是需要等一段时间才能响应。而这段时间又不好控制了,因为上传文件大小的不 一样,导致了下发的JAVASCRIPT 数量也不一样,所以基本很难达到FLASH 那样的效果。 其实如果已经决定采用flash 了,那就不需要再去修改服务器端的代码了,因为那个进度信 息服务器发不发都不会影响到代码的执行,反正FLASH 本身已经提供了进度指示了,所以, 说简单地,要改成FLASH 上传,你直接做个FLASH 客户端就好了,不需要再改服务器端了。 对了,还有一种情况需要改服务器端,那就是FLASH 上传多个文件是采用多线程上传的,因 此如果你一次上传多个文件,那就需要改服务器端了。需要在所有线程上传完成的情况下, 再去修改数据库。欢迎分享,转载请注明来源:内存溢出
评论列表(0条)