java http大文件断点续传上传

本文介绍了一个基于HTML5的断点上传项目,通过文件切分实现分块上传,并利用CRC32校验确保数据完整性。支持暂停及继续上传功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1,项目调研

因为需要研究下断点上传的问题。找了很久终于找到一个比较好的项目。

在GoogleCode上面,代码弄下来超级不方便,还是配置hosts才好,把代码重新上传到了github上面。


https://github.com/freewebsys/java-large-file-uploader-demo

效果:

上传中,显示进度,时间,百分比。

20141113102839281.png

点击【Pause】暂停,点击【Resume】继续。

20141113102836532.png

2,代码分析

原始项目:

https://code.google.com/p/java-large-file-uploader/

这个项目最后更新的时间是 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,请求流程图:


主要思路就是将文件切分,然后分块上传。
20141113114708718.jpg
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值