1. 程式人生 > >springmvc mybatis fileupload實現檔案斷點續傳

springmvc mybatis fileupload實現檔案斷點續傳

為什麼要斷點續傳:在傳輸較大檔案沒傳輸完成時若出現斷網或者伺服器異常等情況則檔案會上傳失敗,使用者需要重新開始上傳檔案,這樣會使使用者體驗十分不好,所以需要有斷點續傳。斷點續傳好的方法是將檔案分為N個片段進行上傳,這樣即使後面的片段還未上傳完畢之前已上傳的片段也會得以保留。

本文使用jquery fileupload外掛進行,它負責將檔案分為N個片段進行傳輸,同時會在http請求頭部新增一個請求頭:Content-Range;此請求頭用於告訴伺服器此時傳輸的是哪個區間的片段。

jsp頁面:

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@include file="WEB-INF/jsp/common/taglibs.jsp"%>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>使用者登入</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,Chrome=1" />
<meta http-equiv="X-UA-Compatible" content="IE=9" />
<!-- Bootstrap -->


<!--end Bootstrap -->
<!--[if lt IE 9]>
      <script src="http://cdn.bootcss.com/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="http://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->
<link href="${ctx}/resources/css/bootstrap.min.css" rel="stylesheet">
<link href="${ctx}/resources/css/bootstrap-theme.min.css"
	rel="stylesheet">
<link rel="stylesheet" href="${ctx}/resources/css/jquery.fileupload.css">  
<link rel="stylesheet" href="${ctx}/resources/css/jquery.fileupload-ui.css">  

</head>
<body>
<div class="row fileupload-buttonbar" style="padding-left:15px;">  
<div class="thumbnail col-sm-6">  
<!-- <img id="weixin_show" style="height:180px;margin-top:10px;margin-bottom:8px;"  src="__PUBLIC__/images/game/game_1.png" data-holder-rendered="true">  
 --><div class="progress progress-striped active" role="progressbar" aria-valuemin="10" aria-valuemax="100" aria-valuenow="0"><div id="weixin_progress" class="progress-bar progress-bar-success" style="width:0%;"></div></div>  
<div class="caption" align="center">  
<span id="weixin_upload" class="btn btn-primary fileinput-button">  
<span>上傳</span>  
<input type="file" id="myFile" name="myFile" multiple>  
</span>  
<a id="weixin_cancle" href="javascript:void(0)" class="btn btn-warning" role="button" onclick="cancelUpload
()" style="display:none">刪除</a> <span class="btn btn-warning" id="ase">暫停</span> </div> </div> </div> <script src="${ctx}/resources/js/jquery.min.js"></script> <script src="${ctx}/resources/js/bootstrap.min.js"></script> <script src="${ctx}/resources/js/jquery.ui.widget.js"></script> <script src="${ctx}/resources/js/jquery.fileupload.js"></script> <script src="${ctx}/resources/js/jquery.iframe-transport.js"></script> <script> $(function() {
    var jqXHR;
    
    $("#myFile").fileupload({  
url: 'uploadDemo/doUpload', limitConcurrentUploads: 1, sequentialUploads: true, progressInterval: 100, maxChunkSize: 100000, //設定上傳片段大小,不設定則為整個檔案上傳 dataType: "json", add: function (e, data) {
jqXHR = data.submit();
} }).bind('fileuploadprogress', function (e, data) { var progress = parseInt(data.loaded / data.total * 100, 10)-1; $("#weixin_progress").css('width',progress + '%'); $("#weixin_progress").html(progress + '%'); }).bind('fileuploaddone', function (e, data) { $("#weixin_progress").css('width',100 + '%'); $("#weixin_progress").html(100 + '%'); /* $("#weixin_show").attr("src","resource/"+data.result); */ $("#weixin_upload").css({display:"none"}); $("#weixin_cancle").css({display:""}); }).bind('fileuploadpaste', function (e, data) {alert("aaa");}); }); //取消上傳 function cancelUpload(){
    	jqXHR.abort();
    }
</script>
</body> 


</html>

伺服器程式碼:
	@RequestMapping("/doUpload")
	public @ResponseBody
	void upload(HttpServletRequest request, PrintWriter writer,
			HttpServletResponse response) throws Exception {

		MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
		// 獲取傳入檔案
		multipartRequest.setCharacterEncoding("utf-8");
		MultipartFile file = multipartRequest.getFile("myFile");

		this.SaveAs("uploadDemo/" + file.getOriginalFilename(), file, request,
				response);
		// 設定返回值
		Map<String, String> map = new HashMap<String, String>();
		map.put("name", file.getOriginalFilename());
		response.setStatus(200);
		writer.write(JSON.toJSONString(map));
	}

	private void SaveAs(String saveFilePath, MultipartFile file,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {

		long lStartPos = 0;
		int startPosition = 0;
		int endPosition = 0;
		int fileLength = 100000;
		OutputStream fs = null;
		
		String contentRange = request.getHeader("Content-Range");
System.out.println(contentRange);
		if (!new File("uploadDemo").exists()) {
			new File("uploadDemo").mkdirs();
		}
		if (contentRange == null) {
			FileUtils.writeByteArrayToFile(new File(saveFilePath),
					file.getBytes());

		} else {
			// bytes 10000-19999/1157632     將獲取到的資料進行處理截取出開始跟結束位置
			if (contentRange != null && contentRange.length() > 0) {
				contentRange = contentRange.replace("bytes", "").trim();
				contentRange = contentRange.substring(0,
						contentRange.indexOf("/"));
				String[] ranges = contentRange.split("-");
				startPosition = Integer.parseInt(ranges[0]);
				endPosition = Integer.parseInt(ranges[1]);
			}
			
			//判斷所上傳檔案是否已經存在,若存在則返回存在檔案的大小
			if (new File(saveFilePath).exists()) {
				fs = new FileOutputStream(saveFilePath, true);
				FileInputStream fi = new FileInputStream(saveFilePath);
				lStartPos = fi.available();
				fi.close();
			} else {
				fs = new FileOutputStream(saveFilePath);
				lStartPos = 0;
			}
			
			//判斷所上傳檔案片段是否存在,若存在則直接返回
			if (lStartPos > endPosition) {
				fs.close();
				return;
			} else if (lStartPos < startPosition) {
				byte[] nbytes = new byte[fileLength];
				int nReadSize = 0;
				file.getInputStream().skip(startPosition);
				nReadSize = file.getInputStream().read(nbytes, 0, fileLength);
				if (nReadSize > 0) {
					fs.write(nbytes, 0, nReadSize);
					nReadSize = file.getInputStream().read(nbytes, 0,
							fileLength);
				}
			} else if (lStartPos > startPosition && lStartPos < endPosition) {
				byte[] nbytes = new byte[fileLength];
				int nReadSize = 0;
				file.getInputStream().skip(lStartPos);
				int end = (int) (endPosition - lStartPos);
				nReadSize = file.getInputStream().read(nbytes, 0, end);
				if (nReadSize > 0) {
					fs.write(nbytes, 0, nReadSize);
					nReadSize = file.getInputStream().read(nbytes, 0, end);
				}
			}
		}
		if (fs != null) {
			fs.flush();
			fs.close();
			fs = null;
		}

	}