1. 程式人生 > >java http大檔案上傳,斷點續傳專案研究,Github上傳原始碼

java http大檔案上傳,斷點續傳專案研究,Github上傳原始碼

1,專案調研

因為需要研究下斷點上傳的問題。找了很久終於找到一個比較好的專案。

在GoogleCode上面,程式碼弄下來超級不方便,還是配置hosts才好,把程式碼重新上傳到了github上面。

效果:

上傳中,顯示進度,時間,百分比。


點選【Pause】暫停,點選【Resume】繼續。


2,程式碼分析

原始專案:

這個專案最後更新的時間是 2012 年,專案進行了封裝使用最簡單的方法實現了http的斷點上傳。

因為html5 裡面有讀取檔案分割檔案的類庫,所以才可以支援斷點上傳,所以這個只能在html5 支援的瀏覽器上面展示。

同時,在js 和 java 同時使用 cr32 進行檔案塊的校驗,保證資料上傳正確。

程式碼在使用了最新的servlet 3.0 的api,使用了非同步執行,監聽等方法。

上傳類UploadServlet

@Component("javaLargeFileUploaderServlet")
@WebServlet(name = "javaLargeFileUploaderServlet", urlPatterns = { "/javaLargeFileUploaderServlet" })
public class UploadServlet extends HttpRequestHandlerServlet
		implements HttpRequestHandler {

	private static final Logger log = LoggerFactory.getLogger(UploadServlet.class);

	@Autowired
	UploadProcessor uploadProcessor;

	@Autowired
	FileUploaderHelper fileUploaderHelper;

	@Autowired
	ExceptionCodeMappingHelper exceptionCodeMappingHelper;

	@Autowired
	Authorizer authorizer;

	@Autowired
	StaticStateIdentifierManager staticStateIdentifierManager;



	@Override
	public void handleRequest(HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		log.trace("Handling request");

		Serializable jsonObject = null;
		try {
			// extract the action from the request
			UploadServletAction actionByParameterName =
					UploadServletAction.valueOf(fileUploaderHelper.getParameterValue(request, UploadServletParameter.action));

			// check authorization
			checkAuthorization(request, actionByParameterName);

			// then process the asked action
			jsonObject = processAction(actionByParameterName, request);


			// if something has to be written to the response
			if (jsonObject != null) {
				fileUploaderHelper.writeToResponse(jsonObject, response);
			}

		}
		// If exception, write it
		catch (Exception e) {
			exceptionCodeMappingHelper.processException(e, response);
		}

	}


	private void checkAuthorization(HttpServletRequest request, UploadServletAction actionByParameterName)
			throws MissingParameterException, AuthorizationException {

		// check authorization
		// if its not get progress (because we do not really care about authorization for get
		// progress and it uses an array of file ids)
		if (!actionByParameterName.equals(UploadServletAction.getProgress)) {

			// extract uuid
			final String fileIdFieldValue = fileUploaderHelper.getParameterValue(request, UploadServletParameter.fileId, false);

			// if this is init, the identifier is the one in parameter
			UUID clientOrJobId;
			String parameter = fileUploaderHelper.getParameterValue(request, UploadServletParameter.clientId, false);
			if (actionByParameterName.equals(UploadServletAction.getConfig) && parameter != null) {
				clientOrJobId = UUID.fromString(parameter);
			}
			// if not, get it from manager
			else {
				clientOrJobId = staticStateIdentifierManager.getIdentifier();
			}

			
			// call authorizer
			authorizer.getAuthorization(
					request,
					actionByParameterName,
					clientOrJobId,
					fileIdFieldValue != null ? getFileIdsFromString(fileIdFieldValue).toArray(new UUID[] {}) : null);

		}
	}


	private Serializable processAction(UploadServletAction actionByParameterName, HttpServletRequest request)
			throws Exception {
		log.debug("Processing action " + actionByParameterName.name());

		Serializable returnObject = null;
		switch (actionByParameterName) {
			case getConfig:
				String parameterValue = fileUploaderHelper.getParameterValue(request, UploadServletParameter.clientId, false);
				returnObject =
						uploadProcessor.getConfig(
								parameterValue != null ? UUID.fromString(parameterValue) : null);
				break;
			case verifyCrcOfUncheckedPart:
				returnObject = verifyCrcOfUncheckedPart(request);
				break;
			case prepareUpload:
				returnObject = prepareUpload(request);
				break;
			case clearFile:
				uploadProcessor.clearFile(UUID.fromString(fileUploaderHelper.getParameterValue(request, UploadServletParameter.fileId)));
				break;
			case clearAll:
				uploadProcessor.clearAll();
				break;
			case pauseFile:
				List<UUID> uuids = getFileIdsFromString(fileUploaderHelper.getParameterValue(request, UploadServletParameter.fileId));
				uploadProcessor.pauseFile(uuids);
				break;
			case resumeFile:
				returnObject =
						uploadProcessor.resumeFile(UUID.fromString(fileUploaderHelper.getParameterValue(request, UploadServletParameter.fileId)));
				break;
			case setRate:
				uploadProcessor.setUploadRate(UUID.fromString(fileUploaderHelper.getParameterValue(request, UploadServletParameter.fileId)),
						Long.valueOf(fileUploaderHelper.getParameterValue(request, UploadServletParameter.rate)));
				break;
			case getProgress:
				returnObject = getProgress(request);
				break;
		}
		return returnObject;
	}


	List<UUID> getFileIdsFromString(String fileIds) {
		String[] splittedFileIds = fileIds.split(",");
		List<UUID> uuids = Lists.newArrayList();
		for (int i = 0; i < splittedFileIds.length; i++) {
			uuids.add(UUID.fromString(splittedFileIds[i]));
		} 
		return uuids;
	}


	private Serializable getProgress(HttpServletRequest request)
			throws MissingParameterException {
		Serializable returnObject;
		String[] ids =
				new Gson()
						.fromJson(fileUploaderHelper.getParameterValue(request, UploadServletParameter.fileId), String[].class);
		Collection<UUID> uuids = Collections2.transform(Arrays.asList(ids), new Function<String, UUID>() {

			@Override
			public UUID apply(String input) {
				return UUID.fromString(input);
			}

		});
		returnObject = Maps.newHashMap();
		for (UUID fileId : uuids) {
			try {
				ProgressJson progress = uploadProcessor.getProgress(fileId);
				((HashMap<String, ProgressJson>) returnObject).put(fileId.toString(), progress);
			}
			catch (FileNotFoundException e) {
				log.debug("No progress will be retrieved for " + fileId + " because " + e.getMessage());
			}
		}
		return returnObject;
	}


	private Serializable prepareUpload(HttpServletRequest request)
			throws MissingParameterException, IOException {

		// extract file information
		PrepareUploadJson[] fromJson =
				new Gson()
						.fromJson(fileUploaderHelper.getParameterValue(request, UploadServletParameter.newFiles), PrepareUploadJson[].class);

		// prepare them
		final HashMap<String, UUID> prepareUpload = uploadProcessor.prepareUpload(fromJson);

		// return them
		return Maps.newHashMap(Maps.transformValues(prepareUpload, new Function<UUID, String>() {

			public String apply(UUID input) {
				return input.toString();
			};
		}));
	}


	private Boolean verifyCrcOfUncheckedPart(HttpServletRequest request)
			throws IOException, MissingParameterException, FileCorruptedException, FileStillProcessingException {
		UUID fileId = UUID.fromString(fileUploaderHelper.getParameterValue(request, UploadServletParameter.fileId));
		try {
			uploadProcessor.verifyCrcOfUncheckedPart(fileId,
					fileUploaderHelper.getParameterValue(request, UploadServletParameter.crc));
		}
		catch (InvalidCrcException e) {
			// no need to log this exception, a fallback behaviour is defined in the
			// throwing method.
			// but we need to return something!
			return Boolean.FALSE;
		}
		return Boolean.TRUE;
	}
}

非同步上傳UploadServletAsync

@Component("javaLargeFileUploaderAsyncServlet")
@WebServlet(name = "javaLargeFileUploaderAsyncServlet", urlPatterns = { "/javaLargeFileUploaderAsyncServlet" }, asyncSupported = true)
public class UploadServletAsync extends HttpRequestHandlerServlet
		implements HttpRequestHandler {

	private static final Logger log = LoggerFactory.getLogger(UploadServletAsync.class);

	@Autowired
	ExceptionCodeMappingHelper exceptionCodeMappingHelper;

	@Autowired
	UploadServletAsyncProcessor uploadServletAsyncProcessor;
	
	@Autowired
	StaticStateIdentifierManager staticStateIdentifierManager;

	@Autowired
	StaticStateManager<StaticStatePersistedOnFileSystemEntity> staticStateManager;

	@Autowired
	FileUploaderHelper fileUploaderHelper;

	@Autowired
	Authorizer authorizer;

	/**
	 * Maximum time that a streaming request can take.<br>
	 */
	private long taskTimeOut = DateUtils.MILLIS_PER_HOUR;


	@Override
	public void handleRequest(final HttpServletRequest request, final HttpServletResponse response)
			throws ServletException, IOException {

		// process the request
		try {

			//check if uploads are allowed
			if (!uploadServletAsyncProcessor.isEnabled()) {
				throw new UploadIsCurrentlyDisabled();
			}
			
			// extract stuff from request
			final FileUploadConfiguration process = fileUploaderHelper.extractFileUploadConfiguration(request);

			log.debug("received upload request with config: "+process);

			// verify authorization
			final UUID clientId = staticStateIdentifierManager.getIdentifier();
			authorizer.getAuthorization(request, UploadServletAction.upload, clientId, process.getFileId());

			//check if that file is not paused
			if (uploadServletAsyncProcessor.isFilePaused(process.getFileId())) {
				log.debug("file "+process.getFileId()+" is paused, ignoring async request.");
				return;
			}
			
			// get the model
			StaticFileState fileState = staticStateManager.getEntityIfPresent().getFileStates().get(process.getFileId());
			if (fileState == null) {
				throw new FileNotFoundException("File with id " + process.getFileId() + " not found");
			}

			// process the request asynchronously
			final AsyncContext asyncContext = request.startAsync();
			asyncContext.setTimeout(taskTimeOut);


			// add a listener to clear bucket and close inputstream when process is complete or
			// with
			// error
			asyncContext.addListener(new UploadServletAsyncListenerAdapter(process.getFileId()) {

				@Override
				void clean() {
					log.debug("request " + request + " completed.");
					// we do not need to clear the inputstream here.
					// and tell processor to clean its shit!
					uploadServletAsyncProcessor.clean(clientId, process.getFileId());
				}
			});

			// then process
			uploadServletAsyncProcessor.process(fileState, process.getFileId(), process.getCrc(), process.getInputStream(),
					new WriteChunkCompletionListener() {

						@Override
						public void success() {
							asyncContext.complete();
						}


						@Override
						public void error(Exception exception) {
							// handles a stream ended unexpectedly , it just means the user has
							// stopped the
							// stream
							if (exception.getMessage() != null) {
								if (exception.getMessage().equals("Stream ended unexpectedly")) {
									log.warn("User has stopped streaming for file " + process.getFileId());
								}
								else if (exception.getMessage().equals("User cancellation")) {
									log.warn("User has cancelled streaming for file id " + process.getFileId());
									// do nothing
								}
								else {
									exceptionCodeMappingHelper.processException(exception, response);
								}
							}
							else {
								exceptionCodeMappingHelper.processException(exception, response);
							}

							asyncContext.complete();
						}

					});
		}
		catch (Exception e) {
			exceptionCodeMappingHelper.processException(e, response);
		}

	}

}


3,請求流程圖:


主要思路就是將檔案切分,然後分塊上傳。

相關推薦

java http檔案斷點專案研究Github原始碼

1,專案調研 因為需要研究下斷點上傳的問題。找了很久終於找到一個比較好的專案。 在GoogleCode上面,程式碼弄下來超級不方便,還是配置hosts才好,把程式碼重新上傳到了github上面。 效果: 上傳中,顯示進度,時間,百分比。 點選【Pause】暫停,點選

java http檔案斷點

1,專案調研 因為需要研究下斷點上傳的問題。找了很久終於找到一個比較好的專案。 在GoogleCode上面,程式碼弄下來超級不方便,還是配置hosts才好,把程式碼重新上傳到了github上面。 效果: 上傳中,顯示進度,時間,百分比。 點選【Pause

H5+JAVA檔案斷點

斷點上傳能夠防止意外情況導致上傳一半的檔案下次上傳時還要從頭下載,網上有很多關於斷點的實現,這篇文章只是從前到後完整的記錄下一個可用的例項,由於生產環境要求不高,而且就是提供給一兩個人用,所以我簡化了諸多過程,不用flash,也不用applet,只是通過html5的新特性進行瀏覽器端的處理。

檔案分塊第二彈(秒斷點)

關鍵部分 前端用file.slice()分塊 前端用FileReader獲取每一分塊的md5值 後端用MultipartFile接受分塊檔案 後端用FileOutputStream拼裝分塊檔案 話不多說,直接上程式碼,我想這是你們最喜歡的 html &l

springboot 整合 gridfs 、webUploader實現檔案分塊斷點、秒

主要的pom.xml: <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId>

網頁內實現檔案分片斷點

最近做公司的專案,需要在後臺控制系統中新增一個功能-------向伺服器傳送程式更新包;這些程式更新包大小不固定,但基本都在1G到4G之間,剛開始還真是難倒我了,因為之前的專案中沒有上傳過這麼大的檔案,還要斷點續傳,後來經過查資料,寫DEMO,這個問題終於解決了; 解決辦法: 使用XMLHt

java springboot 檔案分片處理

這裡只寫後端的程式碼,基本的思想就是,前端將檔案分片,然後每次訪問上傳介面的時候,向後端傳入引數:當前為第幾塊問價,和分片總數 下面直接貼程式碼吧,一些難懂的我大部分都加上註釋了: 上傳檔案實體類: /** * 檔案傳輸物件 * @ApiModel和@ApiModelProperty及C

java實現檔案

檔案上傳是最古老的網際網路操作之一,20多年來幾乎沒有怎麼變化,還是操作麻煩、缺乏互動、使用者體驗差。 一、前端程式碼 英國程式設計師Remy Sharp總結了這些新的介面 ,本文在他的基礎之上,討論在前端採用HTML5的API,對檔案上傳進行漸進式增強: * iframe上傳    *

檔案分塊以及斷點

var fileMd5; //檔案唯一標識 /******************下面的引數是自定義的*************************/ var fileName;//檔名稱 var oldJindu;//如果該檔案之前上傳過 已經上傳的進度

檔案那些事兒:多圖檔案斷點功能實現與分析

簡介 看了不少的教程,在系統整合搭建的過程中一般寫到檔案上傳這一節時,基本上實現一個檔案上傳功能就不再繼續拓展,而是就此截止轉而去講解其他的內容了,因為企業級應用開發中這些功能肯定會使用到,企業網站的檔案上傳不可能只有一個單圖上傳,也不可能不實現大檔案的功能處

iOS檔案分片斷點

總結一下大檔案分片上傳和斷點續傳的問題。因為檔案過大(比如1G以上),必須要考慮上傳過程網路中斷的情況。http的網路請求中本身就已經具備了分片上傳功能,當傳輸的檔案比較大時,http協議自動會將檔案切片(分塊),但這不是我們現在說的重點,我們要做的事是保證在網路中斷後1G

java實現檔案

 最近專案經理逼著讓偶做樹的展開,表巢狀表,可惜偶剛參加工作,水平低,這不在查資料嘛,可是不多久就傳來了經理的叫囂聲,這麼簡單的東西,都一天了,你還沒做完..................,哎真是鬱悶,誰讓咱水平低呢(心想,什麼時候等我水平提高了,看我怎麼收拾你,又一想,等

檔案第二彈(分片、秒斷點)

關鍵部分 前端用file.slice()分塊 前端用FileReader獲取每一分塊的md5值 後端用MultipartFile接受分塊檔案 後端用FileOutputStream拼裝分塊檔案 話不多說,直接上程式碼,我想這是你們最喜歡的

java 多執行緒檔案下載斷點

1,把阿里旺旺傳到伺服器上 2,分3個執行緒,分別下載不同位置的檔案 3,用3個檔案記錄每次下載的位置,停止後再次下載時,直接從已下載的位置開始繼續下載,當檔案下載完成後刪除記錄的檔案 測試成功,下面是實現程式碼: package com.zhuyu.utils; i

檔案斷點、秒、beego、vue

## 大檔案上傳 ### 0、專案原始碼地址 原始碼地址 :https://github.com/zhuchangwu/large-file-upload > 它是個demo,僅供參考 前端基於 vue-simple-uploader (感謝這個大佬)實現: https://github.com/s

PHP加JS實現分片斷點

index ech start prevent control stat 選擇 pen append <!DOCTYPE html> <html> <head> <meta charset="U

java獲取檔案的MD5、SHA1CRC32碼

import org.apache.commons.codec.digest.DigestUtils; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.

超大檔案斷點的實現

隨著視訊網站和大資料應用的普及,特別是高清視訊和4K視訊應用的到來,超大檔案上傳已經成為了日常的基礎應用需求。但是在很多情況下,平臺運營方並沒有大檔案上傳和斷點續傳的開發經驗,往往在網上找一些簡單的PHP或者Java程式來實現基本的上傳功能,然而在實際使用中就會發現,這些基於

Java中使用多執行緒結合斷點實現一個簡單的檔案下載器

這篇部落格介紹在android中使用多執行緒和斷點續傳實現一個簡單的檔案下載器 第一步:啟動Tomcat伺服器,將需要下載的檔案部署到Tomcat伺服器上 第二步:使用eclipse建立一個Java工程,並且在工程中新增下面的程式碼 package com.fyt.mul

忘了pull直接修改並且commit的問題--github內容前先檢查別人有沒有推送新代碼的解決方法

本地 最新 修改 完成 開始 找到 hub 沖突 span 早上來公司之後,忘了pull下最新的代碼,就直接開始在本地做更改了,而且還給commit上去了,結果推不上去,然後看見“pull”那裏顯示了有內容沒有pull下來,這下可糟了,當場就蒙圈了,不知道咋辦,幸好有學長助