首页 > 其他分享 >百度WebUploader实现浏览器端大文件分片上传

百度WebUploader实现浏览器端大文件分片上传

时间:2023-07-17 12:00:47浏览次数:40  
标签:浏览器 String 端大 getHeader request WebUploader 源码 分片 pathSvr

 我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用。

这次项目的需求:

支持大文件的上传和续传,要求续传支持所有浏览器,包括ie6,ie7,ie8,ie9,Chrome,Firefox,360安全浏览器,并且刷新浏览器后仍然能够续传,重启浏览器(关闭浏览器后再打开)仍然能够继续上传,重启电脑后仍然能够上传

支持文件夹的上传,要求服务端能够保留层级结构,并且能够续传。需要支持10万个以上的文件夹上传。

支持低版本的系统和浏览器,因为这个项目的最终运行环境在政府,政府的配置都一般,职员都是办公用,内存都不大,基本上以Windows XP的系统为主。

 

1、介绍enctype

enctype 属性规定发送到服务器之前应该如何对表单数据进行编码。

enctype作用是告知服务器请求正文的MIME类型(请求消息头content-type的作用一样)

1、1 enctype的取值有三种

描述

application/x-www-form-urlencoded

在发送前编码所有字符(默认)

multipart/form-data

不对字符编码。每一个表单项分割为一个部件

text/plain

空格转换为 “+” 加号,但不对特殊字符编码。

1. 当enctype=’application/x-www-form-urlencoded’

2.当enctype=’multipart/form-data’

 

通过观察发现这个的请求体就发生了变化。这种请求体被称之为多部件请求体。

什么是多部件请求体:就是把每一个表单项分割为一个部件。

以请求头的content-type的boundary后面的一串随机字符串作为分割标识

普通表单项:

//name的意思是文本框里面name的属性值,而admin是我们输入的文本值

Content-Disposition: form-data; name="username"

admin

文件表单项

//filename的意思是:我们上传的文件名称,content-Type的意思是:MIME类型,asdasdas的意思是:文件里面的内容

Content-Disposition: form-data; name="upload"; filename="a.txt"

Content-Type: text/plain

asdasdas

3. 当enctype=’text/plain’

 

编辑

w3c称:空格会变成”+”加号,但是我这里没有发现,只有当get请求的时候,空格会变成”+”号

 

编辑

进入正题

完成上传需要满足3个必要的条件

提供form表单,method必须是post,因为get请求的传输数据一般为2kb,不同浏览器不一样。

form表单属性enctype的必须是multipart/form-data

提供input type=”file”类的上传输入域

大致实现原理:当enctype的值是multipart/form-data时,浏览器会把每个表单项进行分割,分割成不同的部件,以boundary的值为分割标识,这个标识的字符串是随机生成的,最后一个表单项的分割标识字符串末尾会多两个”- -“,代表结束。服务端用request.getHeader(“content-type”)获取分割字符串,然后进行解析。

 

编辑

 

代码实现

一、开发环境搭建

准备两个第三方jar包

commons-io包

commons-upload包

所有依赖包

 

编辑

代码实现

<%@ page language="java" import="up6.DBFile" pageEncoding="UTF-8"%>

<%@ page contentType="text/html;charset=UTF-8"%>

<%@ page import="up6.FileBlockWriter" %>

<%@ page import="up6.XDebug" %>

<%@ page import="up6.*" %>

<%@ page import="up6.biz.*" %>

<%@ page import="org.apache.commons.fileupload.FileItem" %>

<%@ page import="org.apache.commons.fileupload.FileItemFactory" %>

<%@ page import="org.apache.commons.fileupload.FileUploadException" %>

<%@ page import="org.apache.commons.fileupload.disk.DiskFileItemFactory" %>

<%@ page import="org.apache.commons.fileupload.servlet.ServletFileUpload" %>

<%@ page import="org.apache.commons.lang.*" %>

<%@ page import="java.net.URLDecoder"%>

<%@ page import="java.util.Iterator"%>

<%@ page import="net.sf.json.JSONObject"%>

<%@ page import="java.util.List"%>

<%

out.clear();

String uid             = request.getHeader("uid");//

String id              = request.getHeader("id");

String lenSvr      = request.getHeader("lenSvr");

String lenLoc      = request.getHeader("lenLoc");

String blockOffset = request.getHeader("blockOffset");

String blockSize   = request.getHeader("blockSize");

String blockIndex  = request.getHeader("blockIndex");

String blockMd5        = request.getHeader("blockMd5");

String complete        = request.getHeader("complete");

String pathSvr         = "";

 

//参数为空

if(  StringUtils.isBlank( uid )

     || StringUtils.isBlank( id )

     || StringUtils.isBlank( blockOffset ))

{

     XDebug.Output("param is null");return;

}

boolean isMultipart = ServletFileUpload.isMultipartContent(request);

FileItemFactory factory = new DiskFileItemFactory();  

ServletFileUpload upload = new ServletFileUpload(factory);

List files = null;

try {files = upload.parseRequest(request);}

catch (FileUploadException e)

{out.println("read file data error:" + e.toString());return;}

 

FileItem rangeFile = null;

Iterator fileItr = files.iterator();

while (fileItr.hasNext())

{

     rangeFile = (FileItem) fileItr.next();

     if(StringUtils.equals( rangeFile.getFieldName(),"pathSvr"))

     {

         pathSvr = rangeFile.getString();

         pathSvr = PathTool.url_decode(pathSvr);

     }

}

 

boolean verify = false;

String msg = "";

String md5Svr = "";

long blockSizeSvr = rangeFile.getSize();

if(!StringUtils.isBlank(blockMd5)){md5Svr = Md5Tool.fileToMD5(rangeFile.getInputStream());}

verify = Integer.parseInt(blockSize) == blockSizeSvr;

if(!verify){ msg = "block size error sizeSvr:" + blockSizeSvr + "sizeLoc:" + blockSize;}

if(verify && !StringUtils.isBlank(blockMd5))

{

     verify = md5Svr.equals(blockMd5); if(!verify) msg = "block md5 error";

}

if(verify)

{

     FileBlockWriter res = new FileBlockWriter();

     if( Integer.parseInt(blockIndex)==1) res.CreateFile(pathSvr,Long.parseLong(lenLoc));

     res.write( Long.parseLong(blockOffset),pathSvr,rangeFile);

     up6_biz_event.file_post_block(id,Integer.parseInt(blockIndex));

    

     JSONObject o = new JSONObject();

     o.put("msg", "ok");

     o.put("md5", md5Svr); 

     o.put("offset", blockOffset);

     msg = o.toString();

}

rangeFile.delete();

out.write(msg);

%>

下载的必须条件

两个头一个流

content-type

Content-Type是返回消息中非常重要的内容,表示文档内容属于什么MIME类型。

浏览器会根据Content-Type来决定如何显示返回的消息体内容。

默认值是text/html

可以使用request.getServletContext().getMimeType(“文件名”)获取MIME类型。

Content-Disposition

Content-disposition 是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件。

默认值是inline,表示在浏览器窗口中打开。

服务端向客户端游览器发送文件时,如果是浏览器支持的文件类型,一般会默认使用浏览器打开,比如txt、jpg等,会直接在浏览器 中显示。

如果需要提示用户保存,利用Content-Disposition进行一下处理,关键在于一定要加上attachment。

例如:Content-Disposition:attachment;filename=xxx,浏览器就会激活下载框对话框, attachment 表示附件, filname 后面跟随的是显示在下载框中的文件名称。

下载就是向客户端响应字节数据! 将一个文件变成字节数组, 使用 response.getOutputStream()

来响应给浏览器。

代码如下,此代码已经实现了断点续传功能,用户在下载过程可以暂停,和继续下载,对服务器造成的压力也比较小。

String fid             = request.getHeader("id");

String blockIndex = request.getHeader("blockIndex");//基于1

String blockOffset     = request.getHeader("blockOffset");//块偏移,相对于整个文件

String blockSize   = request.getHeader("blockSize");//块大小(当前需要下载的大小)

String pathSvr         = request.getHeader("pathSvr");//文件在服务器的位置

pathSvr            = PathTool.url_decode(pathSvr);

 

if (  StringUtils.isBlank(fid)

     ||StringUtils.isBlank(blockIndex)

     ||StringUtils.isEmpty(blockOffset)

     ||StringUtils.isBlank(blockSize)

     ||StringUtils.isBlank(pathSvr))

{

     response.setStatus(500);

     response.setHeader("err","参数为空");

     return;

}

File f = new File(pathSvr);

//文件不存在

if(!f.exists())

{

     response.setStatus(500);

     OutputStream os = response.getOutputStream();

     System.out.println(String.format("%s 文件不存在",pathSvr));

     os.close();

     return;

}

long fileLen = f.length();

 

response.setContentType("application/x-download");

response.setHeader("Pragma","No-cache"); 

response.setHeader("Cache-Control","no-cache");

response.addHeader("Content-Length",blockSize); 

response.setDateHeader("Expires", 0);

 

OutputStream os = response.getOutputStream();

try

{

     RandomAccessFile raf = new RandomAccessFile(pathSvr,"r");

    

     int readToLen = Integer.parseInt(blockSize);

     int readLen = 0;

     raf.seek( Long.parseLong(blockOffset) );//定位索引

     byte[] data = new byte[1048576];

    

     while( readToLen > 0 )

     {

         readLen = raf.read(data,0,Math.min(1048576,readToLen) );

         readToLen -= readLen;

         os.write(data, 0, readLen);

        

     }

     os.flush();

     os.close();  

     raf.close();

     os = null;

     response.flushBuffer();

    

     out.clear();

     out = pageContext.pushBody();

}

catch(Exception e)

{

     response.setStatus(500);

     os.close();

     out.close();

     e.printStackTrace();

}

finally

{   

     if(os != null)

     {

         os.close();       

         os = null;

     }

     out.clear();

     out = pageContext.pushBody();

}%>

 

加载文件列表,在下载列表中显示出来

后端代码逻辑大部分是相同的,目前能够支持MySQL,Oracle,SQL。在使用前需要配置一下数据库

效果展示:

​编辑

​编辑

​编辑

​编辑

 

视频演示:

 

windows控件安装,,linux-deb控件包安装,linux-rpm控件包安装,php7测试,php5测试,vue-cli-测试,asp.net-IIS测试,asp.net-阿里云(oss)测试,asp.net-华为云(obs)测试,jsp-springboot测试,ActiveX(x86)源码编译,ActiveX(x64)源码编译,Windows(npapi)源码编译,macOS源码编译,Linux(x86_64)源码编译,Linux(arm)源码编译,Linux(mips-uos)源码编译,Linux(mips-kylin-涉密环境)源码编译,sm4加密传输,压缩传输,

示例下载地址

源代码文档

asp.net源码下载jsp-springboot源码下载jsp-eclipse源码下载jsp-myeclipse源码下载php源码下载csharp-winform源码下载vue-cli源码下载c++源码下载

详细配置信息及思路

标签:浏览器,String,端大,getHeader,request,WebUploader,源码,分片,pathSvr
From: https://www.cnblogs.com/songsu/p/17559700.html

相关文章

  • c#.net实现浏览器端大文件分片上传
    ​ 前言文件上传是一个老生常谈的话题了,在文件相对比较小的情况下,可以直接把文件转化为字节流上传到服务器,但在文件比较大的情况下,用普通的方式进行上传,这可不是一个好的办法,毕竟很少有人会忍受,当文件上传到一半中断后,继续上传却只能重头开始上传,这种让人不爽的体验。那有没有......
  • SpringCloud实现浏览器端大文件分片上传
    ​ 1,项目调研 因为需要研究下断点上传的问题。找了很久终于找到一个比较好的项目。 在GoogleCode上面,代码弄下来超级不方便,还是配置hosts才好,把代码重新上传到了github上面。 https://github.com/freewebsys/java-large-file-uploader-demo 效果: 上传中,显示进度,......
  • jsp实现浏览器端大文件分片上传
    ​ 在web项目中上传文件夹现在已经成为了一个主流的需求。在OA,或者企业ERP系统中都有类似的需求。上传文件夹并且保留层级结构能够对用户行成很好的引导,用户使用起来也更方便。能够提供更高级的应用支撑。数据表结构文件​编辑文件夹数据表结构​编辑文件数据表结构......
  • Java实现浏览器端大文件分片上传解决方案
    ​ 上周遇到这样一个问题,客户上传高清视频(1G以上)的时候上传失败。一开始以为是session过期或者文件大小受系统限制,导致的错误。查看了系统的配置文件没有看到文件大小限制,web.xml中seesiontimeout是30,我把它改成了120。但还是不行,有时候10分钟就崩了。同事说,可能是客户这里......
  • Java实现浏览器端大文件分片上传功能
    ​ 第一点:Java代码实现文件上传FormFilefile=manform.getFile();StringnewfileName= null;Stringnewpathname= null;StringfileAddre= "/numUp";try{    InputStreamstream=file.getInputStream();// 把文件读入    StringfilePath=request.......
  • Java实现浏览器端大文件分片上传方案
    ​ 这里只写后端的代码,基本的思想就是,前端将文件分片,然后每次访问上传接口的时候,向后端传入参数:当前为第几块文件,和分片总数下面直接贴代码吧,一些难懂的我大部分都加上注释了:上传文件实体类:看得出来,实体类中已经有很多我们需要的功能了,还有实用的属性。如MD5秒传的信息。pub......
  • Java实现浏览器端大文件分片上传技术
    ​ javaweb上传文件上传文件的jsp中的部分上传文件同样可以使用form表单向后端发请求,也可以使用ajax向后端发请求    1.通过form表单向后端发送请求         <formid="postForm"action="${pageContext.request.contextPath}/UploadServlet"method="post"e......
  • Java实现浏览器端大文件分片上传实例解析
    ​ 我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用。首先我们需要了解的是上传文件三要素:1.表单提交方式:post(get方式提交有大小限制,post没有)2.表单的enctype属性:必须设置为multipart/form-data.3.表单必须......
  • Java实现浏览器端大文件分片上传实例
    ​ 上周遇到这样一个问题,客户上传高清视频(1G以上)的时候上传失败。一开始以为是session过期或者文件大小受系统限制,导致的错误。查看了系统的配置文件没有看到文件大小限制,web.xml中seesiontimeout是30,我把它改成了120。但还是不行,有时候10分钟就崩了。同事说,可能是客户这里......
  • Java实现浏览器端大文件分片上传源代码
    ​ 我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用。这次项目的需求:支持大文件的上传和续传,要求续传支持所有浏览器,包括ie6,ie7,ie8,ie9,Chrome,Firefox,360安全浏览器,并且刷新浏览器后仍然能够续传,重启浏览器(关闭......