spring mvc + xmlHttpRequest2.0 实现无刷新上传文件,带进度条和剩余时间

1、springmvc支持文件上传,需要在spring-mvc.xml配置文件中加上下面的一段话:

<!-- 支持上传文件 -->  
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/> 

2、下面介绍下XMLHttpRequest2.0

  最早,微软在IE 5引进了这个接口。因为它太有用,其他浏览器也模仿部署了,ajax操作因此得以诞生。

  但是,这个接口一直没有标准化,每家浏览器的实现或多或少有点不同。HTML 5的概念形成后,W3C开始考虑标准化这个接口。2008年2月,就提出了XMLHttpRequest Level 2 草案。

这个XMLHttpRequest的新版本,提出了很多有用的新功能,将大大推动互联网革新。本文就对这个新版本进行详细介绍。

  老版本的XMLHttpRequest对象有以下几个缺点:

    * 只支持文本数据的传送,无法用来读取和上传二进制文件。

    * 传送和接收数据时,没有进度信息,只能提示有没有完成。

    * 受到"同域限制"(Same Origin Policy),只能向同一域名的服务器请求数据

  新版本的XMLHttpRequest对象,针对老版本的缺点,做出了大幅改进:   

    * 可以设置HTTP请求的时限。

    * 可以使用FormData对象管理表单数据。

    * 可以上传文件。

    * 可以请求不同域名下的数据(跨域请求)。

    * 可以获取服务器端的二进制数据。

    * 可以获得数据传输的进度信息。

  新版XMLHttpRequest对象,不仅可以发送文本信息,还可以上传文件。假定files是一个"选择文件"的表单元素(input[type="file"]),我们将它装入FormData对象。

var formData = new FormData();
for (var i = 0; i < files.length;i++) {
  formData.append('files[]', files[i]);
}

  然后,发送这个FormData对象

xhr.send(formData);

3、代码实现

废话不多说,上代码:

前端页面代码:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>XMLHttpRequest上传文件进度实现</title>
    <script type="text/javascript">
    var xhr;
    var ot; //
    var oloaded;
    //上传文件方法
    function UpladFile() {
        var fileObj = document.getElementById("uploadForm"); // js 获取文件对象
        var url = "http://192.168.0.116:8080/partnersys/service/uploadFile"; // 接收上传文件的后台地址 

        var form = new FormData(fileObj); // FormData 对象

        xhr = new XMLHttpRequest(); // XMLHttpRequest 对象
        xhr.open("post", url, true); //post方式,url为服务器请求地址,true 该参数规定请求是否异步处理。
        xhr.onload = uploadComplete; //请求完成
        xhr.onerror = uploadFailed; //请求失败
        xhr.upload.onprogress = progressFunction; //【上传进度调用方法实现】
        xhr.upload.onloadstart = function() { //上传开始执行方法
            ot = new Date().getTime(); //设置上传开始时间
            oloaded = 0; //设置上传开始时,以上传的文件大小为0
        };
        xhr.send(form); //开始上传,发送form数据
    }
    //上传进度实现方法,上传过程中会频繁调用该方法
    function progressFunction(evt) {

        var progressBar = document.getElementById("progressBar");
        var percentageDiv = document.getElementById("percentage");
        // event.total是需要传输的总字节,event.loaded是已经传输的字节。如果event.lengthComputable不为真,则event.total等于0
        if (evt.lengthComputable) { //
            progressBar.max = evt.total;
            progressBar.value = evt.loaded;
            percentageDiv.innerHTML = Math.round(evt.loaded / evt.total * 100) + "%";
        }

        var time = document.getElementById("time");
        var nt = new Date().getTime(); //获取当前时间
        var pertime = (nt - ot) / 1000; //计算出上次调用该方法时到现在的时间差,单位为s
        ot = new Date().getTime(); //重新赋值时间,用于下次计算

        var perload = evt.loaded - oloaded; //计算该分段上传的文件大小,单位b       
        oloaded = evt.loaded; //重新赋值已上传文件大小,用以下次计算

        //上传速度计算
        var speed = perload / pertime; //单位b/s
        var bspeed = speed;
        var units = 'b/s'; //单位名称
        if (speed / 1024 > 1) {
            speed = speed / 1024;
            units = 'k/s';
        }
        if (speed / 1024 > 1) {
            speed = speed / 1024;
            units = 'M/s';
        }
        speed = speed.toFixed(1);
        //剩余时间
        var resttime = ((evt.total - evt.loaded) / bspeed).toFixed(1);
        time.innerHTML = ',速度:' + speed + units + ',剩余时间:' + resttime + 's';
        if (bspeed == 0)
            time.innerHTML = '上传已取消';
    }
    //上传成功响应
    function uploadComplete(evt) {
        //服务断接收完文件返回的结果
        //    alert(evt.target.responseText);
        alert("上传成功!");
    }
    //上传失败
    function uploadFailed(evt) {
        alert("上传失败!");
    }
    //取消上传
    function cancleUploadFile() {
        xhr.abort();
    }
    </script>
</head>

<body>
    <progress id="progressBar" value="0" max="100" style="width: 300px;"></progress>
    <span id="percentage"></span><span id="time"></span>
    <br />
    <br />
    <form id="uploadForm" method="post" enctype="multipart/form-data">
        <input type="file" id="file" name="myfile" /><!-- input标签的name属性用于post传输,作为表单的键值,后台通过键值获取序列化后的表单数据。name属性值和springmvc中的“@RequestParam(value = "myfile", required = true)”的value值相同,通过该值反序列化成springmvc的MultipartFile对象 -->
        <input type="button" onclick="UpladFile()" value="上传" />
        <input type="button" onclick="cancleUploadFile()" value="取消" />
    </form>
</body>

</html>

 后端java代码:

@RequestMapping(value = "/uploadFile",method = RequestMethod.POST)
	public void upload(@RequestParam(value = "myfile", required = true) MultipartFile file, HttpServletRequest request,
			HttpServletResponse response)
	{
		String path = request.getSession().getServletContext().getRealPath("uploadFile");
		String fileName = file.getOriginalFilename();
		System.out.println("文件上传路径为:" + path);
		File targetFile = new File(path, fileName);
		if (!targetFile.exists())
		{
			targetFile.mkdirs();
		}
		// 保存
		try
		{
			file.transferTo(targetFile);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}
	

  

  

 

posted @ 2017-06-03 23:11  iwideal  阅读(736)  评论(0编辑  收藏  举报