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

首先我们需要了解的是上传文件三要素:

1.表单提交方式:post (get方式提交有大小限制,post没有)

2.表单的enctype属性:必须设置为multipart/form-data.

3.表单必须有文件上传项:file,且文件项需要给定name值

上传文件夹需要增加一个属性webkitdirectory,像这样:

<input id="fileFolder" name="fileFolder" type="file"  webkitdirectory>

不过webkitdirectory属性有个问题,只能支持高版本的chrome,不能支持低版本的IE,如ie6,ie7,ie8,不能做到全浏览器适配,运行环境比较单一。

js中可以判断文件夹中文件数量及文件夹大小是否符合要求,不符合要求不能向后台提交:

前台HTML模板

this.GetHtmlFiles = function()

{

var acx = "";

acx += '<div class="file-item" id="tmpFile" name="fileItem">\

<div class="img-box"><img name="file" src="js/file.png"/></div>\

<div class="area-l">\

<div class="file-head">\

<div name="fileName" class="name">HttpUploader程序开发.pdf</div>\

<div name="percent" class="percent">(35%)</div>\

<div name="fileSize" class="size" child="1">1000.23MB</div>\

</div>\

<div class="process-border"><div name="process" class="process"></div></div>\

<div name="msg" class="msg top-space">15.3MB 20KB/S 10:02:00</div>\

</div>\

<div class="area-r">\

<span class="btn-box" name="cancel" title="取消"><img name="stop" src="js/stop.png"/><div>取消</div></span>\

<span class="btn-box hide" name="post" title="继续"><img name="post" src="js/post.png"/><div>继续</div></span>\

<span class="btn-box hide" name="stop" title="停止"><img name="stop" src="js/stop.png"/><div>停止</div></span>\

<span class="btn-box hide" name="del" title="删除"><img name="del" src="js/del.png"/><div>删除</div></span>\

</div>';

acx += '</div>';

//文件夹模板

acx += '<div class="file-item" name="folderItem">\

<div class="img-box"><img name="folder" src="js/folder.png"/></div>\

<div class="area-l">\

<div class="file-head">\

<div name="fileName" class="name">HttpUploader程序开发.pdf</div>\

<div name="percent" class="percent">(35%)</div>\

<div name="fileSize" class="size" child="1">1000.23MB</div>\

</div>\

<div class="process-border top-space"><div name="process" class="process"></div></div>\

<div name="msg" class="msg top-space">15.3MB 20KB/S 10:02:00</div>\

</div>\

<div class="area-r">\

<span class="btn-box" name="cancel" title="取消"><img name="stop" src="js/stop.png"/><div>取消</div></span>\

<span class="btn-box hide" name="post" title="继续"><img name="post" src="js/post.png"/><div>继续</div></span>\

<span class="btn-box hide" name="stop" title="停止"><img name="stop" src="js/stop.png"/><div>停止</div></span>\

<span class="btn-box hide" name="del" title="删除"><img name="del" src="js/del.png"/><div>删除</div></span>\

</div>';

acx += '</div>';

//上传列表

acx += '<div class="files-panel" name="post_panel">\

<div name="post_head" class="toolbar">\

<span class="btn" name="btnAddFiles">选择多个文件</span>\

<span class="btn" name="btnAddFolder">选择文件夹</span>\

<span class="btn" name="btnPasteFile">粘贴文件和目录</span>\

<span class="btn" name="btnSetup">安装控件</span>\

</div>\

<div class="content" name="post_content">\

<div name="post_body" class="file-post-view"></div>\

</div>\

<div class="footer" name="post_footer">\

<span class="btn-footer" name="btnClear">清除已完成文件</span>\

</div>\

</div>';

return acx;

};

选择文件,选择文件夹,粘贴文件和文件夹的逻辑

this.open_files = function (json)

{

for (var i = 0, l = json.files.length; i < l; ++i)

{

this.addFileLoc(json.files[i]);

}

setTimeout(function () { _this.PostFirst(); },500);

};

this.open_folders = function (json)

{

for (var i = 0, l = json.folders.length; i < l; ++i) {

this.addFolderLoc(json.folders[i]);

}

setTimeout(function () { _this.PostFirst(); }, 500);

};

this.paste_files = function (json)

{

for (var i = 0, l = json.files.length; i < l; ++i)

{

this.addFileLoc(json.files[i]);

}

};

后台在接收文件夹时不同之处在需要用MultipartHttpServletRequest

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);

}

}

server端的包和类

文件块处页面,验证代码部分

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);

生成文件名称的逻辑

publicString genFile(int uid, String md5,String nameLoc) throws IOException

{

SimpleDateFormat fmtDD = newSimpleDateFormat("dd");

SimpleDateFormat fmtMM = newSimpleDateFormat("MM");

SimpleDateFormat fmtYY = newSimpleDateFormat("yyyy");

Date date = newDate();

String strDD = fmtDD.format(date);

String strMM = fmtMM.format(date);

String strYY = fmtYY.format(date);

String path = this.getRoot() + "/";

path = path.concat(strYY);

path = path.concat("/");

path = path.concat(strMM);

path = path.concat("/");

path = path.concat(strDD);

path = path.concat("/");

path = path.concat(md5);

path = path.concat(".");

path = path.concat(PathTool.getExtention(nameLoc));

File fl = newFile(path);

return fl.getCanonicalPath();//

}

以下是service层做的处理:

整体模块划分如下:

其中数据类实体逻辑处理如下

publicclassFileInf {

public FileInf(){}

publicStringid="";

publicStringpid="";

publicStringpidRoot="";

/**  * 表示当前项是否是一个文件夹项。    */

publicbooleanfdTask=false;

//   /// 是否是文件夹中的子文件  /// </summary>

publicbooleanfdChild=false;

/**  * 用户ID。与第三方系统整合使用。    */

publicintuid=0;

/**  * 文件在本地电脑中的名称   */

publicStringnameLoc="";

/**  * 文件在服务器中的名称。   */

publicStringnameSvr="";

/**  * 文件在本地电脑中的完整路径。示例:D:\Soft\QQ2012.exe */

publicStringpathLoc="";

/**  * 文件在服务器中的完整路径。示例:F:\\ftp\\uer\\md5.exe     */

publicStringpathSvr="";

/**  * 文件在服务器中的相对路径。示例:/www/web/upload/md5.exe   */

publicStringpathRel="";

/**  * 文件MD5    */

publicStringmd5="";

/**  * 数字化的文件长度。以字节为单位,示例:120125    */

publiclonglenLoc=0;

/**  * 格式化的文件尺寸。示例:10.03MB   */

publicStringsizeLoc="";

/**  * 文件续传位置。  */

publiclongoffset=0;

/**  * 已上传大小。以字节为单位 */

publiclonglenSvr=0;

/**  * 已上传百分比。示例:10%  */

publicStringperSvr="0%";

publicbooleancomplete=false;

publicDatePostedTime = newDate();

publicbooleandeleted=false;

/**  * 是否已经扫描完毕,提供给大型文件夹使用,大型文件夹上传完毕后开始扫描。  */

publicbooleanscaned=false;

}

后台数据库中的逻辑基本上都用到了上面的实体类

文件数据表操作类如下

加载所有未完成的文件列表

publicString GetAllUnComplete(int f_uid)

{

StringBuilder sb = newStringBuilder();

sb.append("select ");

sb.append(" f_id");

sb.append(",f_fdTask");

sb.append(",f_nameLoc");

sb.append(",f_pathLoc");

sb.append(",f_md5");

sb.append(",f_lenLoc");

sb.append(",f_sizeLoc");

sb.append(",f_pos");

sb.append(",f_lenSvr");

sb.append(",f_perSvr");

sb.append(",f_complete");

sb.append(",f_pathSvr");//fix(2015-03-16):修复无法续传文件的问题。

sb.append(" from up6_files ");//change(2015-03-18):联合查询文件夹数据

sb.append(" where f_uid=? and f_deleted=0 and f_fdChild=0 and f_complete=0 and f_scan=0");//fix(2015-03-18):只加载未完成列表

ArrayList<FileInf> files = newArrayList<FileInf>();

DbHelper db = newDbHelper();

PreparedStatement cmd = db.GetCommand(sb.toString());

try {

cmd.setInt(1, f_uid);

ResultSet r = db.ExecuteDataSet(cmd);

while(r.next())

{

FileInf f          = newFileInf();

f.uid              = f_uid;

f.id              = r.getString(1);

f.fdTask     = r.getBoolean(2);

f.nameLoc         = r.getString(3);

f.pathLoc         = r.getString(4);

f.md5             = r.getString(5);

f.lenLoc     = r.getLong(6);

f.sizeLoc         = r.getString(7);

f.offset     = r.getLong(8);

f.lenSvr     = r.getLong(9);

f.perSvr     = r.getString(10);

f.complete        = r.getBoolean(11);

f.pathSvr     = r.getString(12);//fix(2015-03-19):修复无法续传文件的问题。

files.add(f);

}

r.close();

cmd.getConnection().close();

cmd.close();

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

if(files.size() < 1) returnnull;

Gson g = newGson();

return g.toJson( files);//bug:arrFiles为空时,此行代码有异常

}

实现后的整体效果如下

文件夹上传完后的效果

服务器保存的文件夹数据,而且层级结构与本地客户端是一致的。这在OA系统中,或者网盘系统中使用时是非常有用的

后端代码逻辑大部分是相同的,目前能够支持MySQL,Oracle,SQL。在使用前需要配置一下数据库,可以参考我写的这篇文章:http://blog.ncmem.com/wordpress/2019/08/11/java%E5%AE%9E%E7%8E%B0%E4%B8%8A%E4%BC%A0%E6%96%87%E4%BB%B6%E5%A4%B9/

java实现上传文件夹的更多相关文章

  1. java+struts上传文件夹文件

    这里只写后端的代码,基本的思想就是,前端将文件分片,然后每次访问上传接口的时候,向后端传入参数:当前为第几块文件,和分片总数 下面直接贴代码吧,一些难懂的我大部分都加上注释了: 上传文件实体类: 看得 ...

  2. java+实现上传文件夹

    我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用. 首先我们需要了解的是上传文件三要素: 1.表单提交方式:post (get方式提交有大小 ...

  3. java http 上传文件夹

    用JAVA实现大文件上传及显示进度信息 ---解析HTTP MultiPart协议 (本文提供全部源码下载,请访问 https://github.com/1269085759/up6-jsp-mysq ...

  4. Java+web+上传文件夹

    用JAVA实现大文件上传及显示进度信息 ---解析HTTP MultiPart协议 (本文提供全部源码下载,请访问 https://github.com/1269085759/up6-jsp-mysq ...

  5. java+web上传文件夹内的所有文件

    javaweb上传文件 上传文件的jsp中的部分 上传文件同样可以使用form表单向后端发请求,也可以使用 ajax向后端发请求 1.通过form表单向后端发送请求 <form id=" ...

  6. java上传文件夹文件

    这里只写后端的代码,基本的思想就是,前端将文件分片,然后每次访问上传接口的时候,向后端传入参数:当前为第几块文件,和分片总数 下面直接贴代码吧,一些难懂的我大部分都加上注释了: 上传文件实体类: 看得 ...

  7. java+上传+文件夹

    我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用. 首先我们需要了解的是上传文件三要素:   1.表单提交方式:post (get方式提交有 ...

  8. java上传文件夹

    我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用.此控件PC全平台支持包括mac,linux系统的文件上传,文章末尾将附上控件下载与教程链接 ...

  9. SFTP 上传文件夹

    使用sftp上传文件夹时若使用如下命令并不work: put /media/Research/GWAS_Class/* Desktop/ 此时,需要添加一个参数 -r, 另外在目标文件夹下面建立一个同 ...

随机推荐

  1. ubuntu18上传代码到github

    其实在github上建仓库时候就提示你步骤了: 1.注册个github账号并登录 创建一个仓库 https://github.com/ 2.创建SSH Key ssh-keygen -t rsa -C ...

  2. Vufuria入门 1 图片识别和选择

    Vufutia中的图片识别功能,底层主要是识别特征点来实现的.特征点,即那些棱角分明的点.尖锐的而不是圆滑的.对比度大的而不是小的. *** 步骤: 进入vofuria官网,登录,点击develop. ...

  3. # Ubuntu子系统安装配置

    目录 Ubuntu子系统安装配置 安装配置 终端美化 卸载 和win10之间的交互 Ubuntu子系统安装配置 亲测启动速度毫秒之间 安装配置 系统升级到一周年正式版及以上(1607) 依次在 设置 ...

  4. 三分钟搞定Python中的装饰器

    python的装饰器是python的特色高级功能之一,言简意赅得说,其作用是在不改变其原有函数和类的定义的基础上,给他们增添新的功能. 装饰器存在的意义是什么呢?我们知道,在python中函数可以调用 ...

  5. 编写函数实现strcmp( )函数功能

    strcmp(字符串1,字符串2) 作用是比较字符串1和字符串2.两个字符串从左至右逐个字符比较(按照字符的ASCII码值的大小)(即减法比较),直到字符不同或者遇见’\0’为止 如果全部字符都相同, ...

  6. php实现只需要一个QQ号就可以获得用户信息

    <?php // 通过QQ号即可获取用户信息 // 获取QQ头像接口 // http://q1.qlogo.cn/g?b=qq&nk=QQ号&s=100&t=154790 ...

  7. 【转】STM32的FSMC详解

    STM32的FSMC真是一个万能的总线控制器,不仅可以控制SRAM,NOR FLASH,NAND FLASH,PC Card,还能控制LCD,TFT. 一般越是复杂的东西,理解起来就很困难,但是使用上 ...

  8. hdu 3364 高斯入门。。

    扣了一个高斯的介绍 比较全面(来自http://blog.csdn.net/duanxian0621/article/details/7408887) 高斯消元法,是线性代数中的一个算法,可用来求解线 ...

  9. [转载]IMDB文件格式

    [转载]IMDB文件格式 来源:LMDB的全称是Lightning Memory-Mapped Database,闪电般的内存映射数据库.它文件结构简单,一个文件夹,里面一个数据文件,一个锁文件.数据 ...

  10. gulp 实现sass自动化 ,监听同步

    实现功能 监听scss文件 sass自动化 准备条件 1 .安装gulp npm init   ---->一直enter,会在当前目录下生成一个package.json文件,记录安装的依赖模块 ...