700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Java 文件分块上传服务器端源代码

Java 文件分块上传服务器端源代码

时间:2019-10-16 16:46:44

相关推荐

Java 文件分块上传服务器端源代码

分享一下我老师大神的人工智能教程!零基础,通俗易懂!/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

本博客将介绍如何进行文件的分块上传。如果读者还想了解文件的“分块”下载相关内容可以去参考博客《 Java 服务器端支持断点续传的源代码【支持快车、迅雷】》。

本文侧重介绍服务器端,客户端端请参考本篇博客的姊妹篇《 Java 文件分块上传客户端源代码》,关于分块上传的思想及其流程,已在该博客中进行了详细说明,这里不再赘述。

直接上代码。接收客户端 HTTP 分块上传请求的 Spring MVC 控制器源代码如下:

@Controllerpublic class UploadController extends BaseController {private static final Log log = LogFactory.getLog(UploadController.class);private UploadService uploadService;private AuthService authService;/** * 大文件分成小文件块上传,一次传递一块,最后一块上传成功后,将合并所有已经上传的块,保存到File Server * 上相应的位置,并返回已经成功上传的文件的详细属性. 当最后一块上传完毕,返回上传成功的信息。此时用getFileList查询该文件, * 该文件的uploadStatus为2。client请自行处理该状态下文件如何显示。(for UPS Server) * */@RequestMapping("/core/v1/file/upload")@ResponseBodypublic Object upload(HttpServletResponse response,@RequestParam(value = "client_id", required = false) String appkey,@RequestParam(value = "sig", required = false) String appsig,@RequestParam(value = "token", required = false) String token,@RequestParam(value = "uuid", required = false) String uuid,@RequestParam(value = "block", required = false) String blockIndex,@RequestParam(value = "file", required = false) MultipartFile multipartFile,@RequestParam Map<String, String> parameters) {checkEmpty(appkey, BaseException.ERROR_CODE_16002);checkEmpty(token, BaseException.ERROR_CODE_16007);checkEmpty(uuid, BaseException.ERROR_CODE_20016);checkEmpty(blockIndex, BaseException.ERROR_CODE_20006);checkEmpty(appsig, BaseException.ERROR_CODE_10010);if (multipartFile == null) {throw new BaseException(BaseException.ERROR_CODE_20020);// 上传文件不存在}Long uuidL = parseLong(uuid, BaseException.ERROR_CODE_20016);Integer blockIndexI = parseInt(blockIndex, BaseException.ERROR_CODE_20006);Map<String, Object> appMap = getAuthService().validateSigature(parameters);AccessToken accessToken = CasUtil.checkAccessToken(token, appMap);Long uid = accessToken.getUid();String bucketUrl = accessToken.getBucketUrl();// 从上传目录拷贝文件到工作目录String fileAbsulutePath = null;try {fileAbsulutePath = this.copyFile(multipartFile.getInputStream(), multipartFile.getOriginalFilename());} catch (IOException ioe) {log.error(ioe.getMessage(), ioe);throw new BaseException(BaseException.ERROR_CODE_20020);// 上传文件不存在}File uploadedFile = new File(Global.UPLOAD_TEMP_DIR + fileAbsulutePath);checkEmptyFile(uploadedFile);// file 非空验证Object rs = uploadService.upload(uuidL, blockIndexI, uid, uploadedFile, bucketUrl);setHttpStatusOk(response);return rs;}// TODO 查看下这里是否有问题// 上传文件非空验证private void checkEmptyFile(File file) {if (file == null || file.getAbsolutePath() == null) {throw new BaseException(BaseException.ERROR_CODE_20020);// 上传文件不存在}}/** * 写文件到本地文件夹 * * @throws IOException * 返回生成的文件名 */private String copyFile(InputStream inputStream, String fileName) {OutputStream outputStream = null;String tempFileName = null;int pointPosition = fileName.lastIndexOf(".");if (pointPosition < 0) {// myvediotempFileName = UUID.randomUUID().toString();// 94d1d2e0-9aad-4dd8-a0f6-494b0099ff26} else {// myvedio.flvtempFileName = UUID.randomUUID() + fileName.substring(pointPosition);// 94d1d2e0-9aad-4dd8-a0f6-494b0099ff26.flv}try {outputStream = new FileOutputStream(Global.UPLOAD_TEMP_DIR + tempFileName);int readBytes = 0;byte[] buffer = new byte[10000];while ((readBytes = inputStream.read(buffer, 0, 10000)) != -1) {outputStream.write(buffer, 0, readBytes);}return tempFileName;} catch (IOException ioe) {// log.error(ioe.getMessage(), ioe);throw new BaseException(BaseException.ERROR_CODE_20020);// 上传文件不存在} finally {if (outputStream != null) {try {outputStream.close();} catch (IOException e) {}}if (inputStream != null) {try {inputStream.close();} catch (IOException e) {}}}}/** * 测试此服务是否可用 * * @param response * @return * @author zwq7978 */@RequestMapping("/core/v1/file/testServer")@ResponseBodypublic Object testServer(HttpServletResponse response) {setHttpStatusOk(response);return Global.SUCCESS_RESPONSE;}public UploadService getUploadService() {return uploadService;}public void setUploadService(UploadService uploadService) {this.uploadService = uploadService;}public void setAuthService(AuthService authService) {this.authService = authService;}public AuthService getAuthService() {return authService;}}

比如要上传的文件是 test450k.mp4。对照《 Java 文件分块上传客户端源代码》中分块上传服务器对分块文件参数定义的名字"file",upload 方法里使用的是 MultipartFile 接收该对象。对于每次的 HTTP 请求,使用 copyFile 方法将文件流输出到服务器本地的一个临时文件夹里,比如作者的是 D:/defonds/syncPath/uploadTemp,该文件下会有50127019-b63b-4a54-8f53-14efd1e58ada.mp4 临时文件生成用于保存上传文件流。

分块依次上传。当所有块都上传完毕之后,将这些临时文件都转移到服务器指定目录中,比如作者的这个目录是 D:/defonds/syncPath/file,在该文件夹下会有/1/temp_dir_5_1 目录生成,而 uploadTemp 的临时文件则被挨个转移到这个文件夹下,生成形如 5.part0001 的文件。以下是文件转移的源代码:

/** * 把所有块从临时文件目录移到指定本地目录或S2/S3 * * @param preUpload */private void moveBlockFiles(BlockPreuploadFileInfo preUpload) {@SuppressWarnings("unchecked")String[] s3BlockUrl=new String[preUpload.getBlockNumber()];String[] localBlockUrl=new String[preUpload.getBlockNumber()];//本地的块文件路径 以便以后删除List<BlockUploadInfo> blocks = (List<BlockUploadInfo>) getBaseDao().queryForList("upload.getBlockUploadFileByUuid", preUpload.getUuid());String tempDirName = SyncUtil.getTempDirName(preUpload.getUuid(), preUpload.getUid());String parentPath = Global.UPLOAD_ABSOLUTE_PAHT_ + Global.PATH_SEPARATIVE_SIGN+ String.valueOf(preUpload.getUid());String dirPath = parentPath + Global.PATH_SEPARATIVE_SIGN + tempDirName;new File(dirPath).mkdirs();//创建存放块文件的文件夹 (本地)int j=0;for (BlockUploadInfo info : blocks) {try {String strBlockIndex = createStrBlockIndex(info.getBlockIndex());String suffixPath = preUpload.getUuid() + ".part" + strBlockIndex;String tempFilePath = info.getTempFile();File tempFile = new File(tempFilePath);File tmpFile = new File(dirPath + suffixPath);if (tmpFile.exists()) {FileUtils.deleteQuietly(tmpFile);}FileUtils.moveFile(tempFile, tmpFile);localBlockUrl[j]=dirPath + suffixPath;j++;info.setStatus(Global.MOVED_TO_NEWDIR);getBaseDao().update("upload.updateBlockUpload", info);if (log.isInfoEnabled())log.info(preUpload.getUuid() + " " + info.getBuId() + " moveBlockFiles");} catch (IOException e) {log.error(e.getMessage(), e);throw new BaseException("file not found");}}preUpload.setLocalBlockUrl(localBlockUrl);preUpload.setDirPath(dirPath);preUpload.setStatus(Global.MOVED_TO_NEWDIR);getBaseDao().update("upload.updatePreUploadInfo", preUpload);}private String createStrBlockIndex(int blockIndex) {String strBlockIndex;if (blockIndex < 10) {strBlockIndex = "000" + blockIndex;} else if (10 <= blockIndex && blockIndex < 100) {strBlockIndex = "00" + blockIndex;} else if (100 <= blockIndex && blockIndex < 1000) {strBlockIndex = "0" + blockIndex;} else {strBlockIndex = "" + blockIndex;}return strBlockIndex;}

最后是文件的组装源代码:

/** * 组装文件 * */private void assembleFileWithBlock(BlockPreuploadFileInfo preUpload) {String dirPath = preUpload.getDirPath();// 开始在指定目录组装文件String uploadedUrl = null;String[] separatedFiles;String[][] separatedFilesAndSize;int fileNum = 0;File file = new File(dirPath);separatedFiles = file.list();separatedFilesAndSize = new String[separatedFiles.length][2];Arrays.sort(separatedFiles);fileNum = separatedFiles.length;for (int i = 0; i < fileNum; i++) {separatedFilesAndSize[i][0] = separatedFiles[i];String fileName = dirPath + separatedFiles[i];File tmpFile = new File(fileName);long fileSize = tmpFile.length();separatedFilesAndSize[i][1] = String.valueOf(fileSize);}RandomAccessFile fileReader = null;RandomAccessFile fileWrite = null;long alreadyWrite = 0;int len = 0;byte[] buf = new byte[1024];try {uploadedUrl = Global.UPLOAD_ABSOLUTE_PAHT_ + Global.PATH_SEPARATIVE_SIGN + preUpload.getUid() + Global.PATH_SEPARATIVE_SIGN + preUpload.getUuid();fileWrite = new RandomAccessFile(uploadedUrl, "rw");for (int i = 0; i < fileNum; i++) {fileWrite.seek(alreadyWrite);// 读取fileReader = new RandomAccessFile((dirPath + separatedFilesAndSize[i][0]), "r");// 写入while ((len = fileReader.read(buf)) != -1) {fileWrite.write(buf, 0, len);}fileReader.close();alreadyWrite += Long.parseLong(separatedFilesAndSize[i][1]);}fileWrite.close();preUpload.setStatus(Global.ASSEMBLED);preUpload.setServerPath(uploadedUrl);getBaseDao().update("upload.updatePreUploadInfo", preUpload);if(Global.BLOCK_UPLOAD_TO!=Global.BLOCK_UPLOAD_TO_LOCAL){//组装完毕没有问题 删除掉S2/S3上的blockString[] path=preUpload.getS3BlockUrl();for (String string : path) {try {if(Global.BLOCK_UPLOAD_TO==Global.BLOCK_UPLOAD_TO_S2){S2Util.deleteFile(preUpload.getBucketUrl(), string);}else{S3Util.deleteFile(preUpload.getBucketUrl(), string);}} catch (Exception e) {log.error(e.getMessage(), e);}}}if (log.isInfoEnabled())log.info(preUpload.getUuid() + " assembleFileWithBlock");} catch (IOException e) {log.error(e.getMessage(), e);try {if (fileReader != null) {fileReader.close();}if (fileWrite != null) {fileWrite.close();}} catch (IOException ex) {log.error(e.getMessage(), e);}}}

BlockPreuploadFileInfo 是我们自定义的业务文件处理 bean。

OK,分块上传的服务器、客户端源代码及其工作流程至此已全部介绍完毕,以上源代码全部是经过项目实践过的,大部分现在仍运行于一些项目之中。有兴趣的朋友可以自己动手,将以上代码自行改造,看看能否运行成功。如果遇到问题可以在本博客下跟帖留言,大家一起讨论讨论。

给我老师的人工智能教程打call!/jiangjunshow
你好! 这是你第一次使用 **Markdown编辑器** 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

新的改变

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

全新的界面设计,将会带来全新的写作体验;在创作中心设置你喜爱的代码高亮样式,Markdown将代码片显示选择的高亮样式进行展示;增加了图片拖拽功能,你可以将本地的图片直接拖拽到编辑区域直接展示;全新的KaTeX数学公式语法;增加了支持甘特图的mermaid语法1功能;增加了多屏幕编辑Markdown文章功能;增加了焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置等功能,功能按钮位于编辑区域与预览区域中间;增加了检查列表功能。

功能快捷键

撤销:Ctrl/Command+Z

重做:Ctrl/Command+Y

加粗:Ctrl/Command+B

斜体:Ctrl/Command+I

标题:Ctrl/Command+Shift+H

无序列表:Ctrl/Command+Shift+U

有序列表:Ctrl/Command+Shift+O

检查列表:Ctrl/Command+Shift+C

插入代码:Ctrl/Command+Shift+K

插入链接:Ctrl/Command+Shift+L

插入图片:Ctrl/Command+Shift+G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。

输入2次#,并按下space后,将生成2级标题。

以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本强调文本

加粗文本加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片:

带尺寸的图片:

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的代码片.

// An highlighted block var foo = 'bar';

生成一个适合你的列表

项目 项目 项目 项目1项目2项目3计划任务完成任务

创建一个表格

一个简单的表格是这么创建的:

设定内容居中、居左、居右

使用:---------:居中

使用:----------居左

使用----------:居右

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

创建一个自定义列表

Markdown Text-to- HTMLconversion tool Authors John Luke

如何创建一个注脚

一个具有注脚的文本。2

注释也是必不可少的

Markdown将文本转换为 HTML。

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n−1)!∀n∈N 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t &ThinSpace; . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=∫0∞​tz−1e−tdt.

你可以找到更多关于的信息LaTeX数学表达式here.

新的甘特图功能,丰富你的文章

ganttdateFormat YYYY-MM-DDtitle Adding GANTT diagram functionality to mermaidsection 现有任务已完成:done, des1, -01-06,-01-08进行中:active, des2, -01-09, 3d计划一: des3, after des2, 5d计划二: des4, after des3, 5d

关于甘特图语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图::

这将产生一个流程图。:

关于Mermaid语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

关于Flowchart流程图语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到文章导出,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件或者.html文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,

继续你的创作。

mermaid语法说明 ↩︎

注脚的解释 ↩︎

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。