java+struts上传文件夹文件
这里只写后端的代码,基本的思想就是,前端将文件分片,然后每次访问上传接口的时候,向后端传入参数:当前为第几块文件,和分片总数
下面直接贴代码吧,一些难懂的我大部分都加上注释了:
上传文件实体类:
看得出来,实体类中已经有很多我们需要的功能了,还有实用的属性。如MD5秒传的信息。
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;
}
首先是文件数据接收逻辑,负责接收控件上传的文件块数据,然后写到服务器的文件中。控件已经提供了块的索引,大小,MD5和长度信息,我们可以根据需要来灵活进行处理,也可以将文件块的数据保存到分布式存储系统中。
<%
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;
}
// Check that we have a file upload request
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);
%>
文件初始化部分
<%
out.clear();
WebBase web = new WebBase(pageContext);
String id = web.queryString("id");
String md5 = web.queryString("md5");
String uid = web.queryString("uid");
String lenLoc = web.queryString("lenLoc");//数字化的文件大小。12021
String sizeLoc = web.queryString("sizeLoc");//格式化的文件大小。10MB
String callback = web.queryString("callback");
String pathLoc = web.queryString("pathLoc");
pathLoc = PathTool.url_decode(pathLoc);
//参数为空
if (StringUtils.isBlank(md5)
&& StringUtils.isBlank(uid)
&& StringUtils.isBlank(sizeLoc))
{
out.write(callback + "({\"value\":null})");
return;
}
FileInf fileSvr= new FileInf();
fileSvr.id = id;
fileSvr.fdChild = false;
fileSvr.uid = Integer.parseInt(uid);
fileSvr.nameLoc = PathTool.getName(pathLoc);
fileSvr.pathLoc = pathLoc;
fileSvr.lenLoc = Long.parseLong(lenLoc);
fileSvr.sizeLoc = sizeLoc;
fileSvr.deleted = false;
fileSvr.md5 = md5;
fileSvr.nameSvr = fileSvr.nameLoc;
//所有单个文件均以uuid/file方式存储
PathBuilderUuid pb = new PathBuilderUuid();
fileSvr.pathSvr = pb.genFile(fileSvr.uid,fileSvr);
fileSvr.pathSvr = fileSvr.pathSvr.replace("\\","/");
DBConfig cfg = new DBConfig();
DBFile db = cfg.db();
FileInf fileExist = new FileInf();
boolean exist = db.exist_file(md5,fileExist);
//数据库已存在相同文件,且有上传进度,则直接使用此信息
if(exist && fileExist.lenSvr > 1)
{
fileSvr.nameSvr = fileExist.nameSvr;
fileSvr.pathSvr = fileExist.pathSvr;
fileSvr.perSvr = fileExist.perSvr;
fileSvr.lenSvr = fileExist.lenSvr;
fileSvr.complete = fileExist.complete;
db.Add(fileSvr);
//触发事件
up6_biz_event.file_create_same(fileSvr);
}//此文件不存在
else
{
db.Add(fileSvr);
//触发事件
up6_biz_event.file_create(fileSvr);
FileBlockWriter fr = new FileBlockWriter();
fr.CreateFile(fileSvr.pathSvr,fileSvr.lenLoc);
}
Gson gson = new Gson();
String json = gson.toJson(fileSvr);
json = URLEncoder.encode(json,"UTF-8");//编码,防止中文乱码
json = json.replace("+","%20");
json = callback + "({\"value\":\"" + json + "\"})";//返回jsonp格式数据。
out.write(json);%>
第一步:获取RandomAccessFile,随机访问文件类的对象
第二步:调用RandomAccessFile的getChannel()方法,打开文件通道 FileChannel,这块逻辑可以优化,如果以后有分布式存储需求,可以改为分布式存储,减轻单台服务器的压力。
public class FileBlockWriter {
public FileBlockWriter(){}
public void CreateFile(String pathSvr,long lenLoc)
{
try
{
File ps = new File(pathSvr);
PathTool.createDirectory(ps.getParent());
RandomAccessFile raf = new RandomAccessFile(pathSvr, "rw");
raf.setLength(lenLoc);//fix:以原始大小创建文件
raf.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void write(long offset,String pathSvr,FileItem block)
{
try
{
InputStream stream = block.getInputStream();
byte[] data = new byte[(int)block.getSize()];
stream.read(data);
stream.close();
RandomAccessFile raf = new RandomAccessFile(pathSvr,"rw");
raf.seek(offset);
raf.write(data);
raf.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
第三步:获取当前是第几个分块,计算文件的最后偏移量
第四步:获取当前文件分块的字节数组,用于获取文件字节长度
第五步:使用文件通道FileChannel类的 map()方法创建直接字节缓冲器 MappedByteBuffer
第六步:将分块的字节数组放入到当前位置的缓冲区内 mappedByteBuffer.put(byte[] b);
第七步:释放缓冲区
第八步:检查文件是否全部完成上传

文件夹扫描类

存储路径生成类

好了,到此就全部结束了,如果有疑问或批评,欢迎评论和私信,我们一起成长一起学习。
最后放一张实现的效果图

后端代码逻辑大部分是相同的,目前能够支持MySQL,Oracle,SQL。在使用前需要配置一下数据库,可以参考我写的这篇文章:http://blog.ncmem.com/wordpress/2019/08/07/java超大文件上传与下载/
java+struts上传文件夹文件的更多相关文章
- java 解析上传的Excel文件
java poi解析上传的Excel文件 package com.zhl.push.Utils; /** * @Author TAO * @ClassName ExcelData * @Descrip ...
- java FTP 上传下载删除文件
在JAVA程序中,经常需要和FTP打交道,比如向FTP服务器上传文件.下载文件,本文简单介绍如何利用jakarta commons中的FTPClient(在commons-net包中)实现上传下载文件 ...
- Fine Uploader + Spring3.2.2(Java+html5上传) SpringMVC+jquery-fineuploader 文件上传
需求:要实现多文件上传,且要支持手机等移动设备... springmvc文件上传真头疼,网上搜了半天没发现都是TMD的用submit按钮提交到后台的,就没有插件的吗?最后发现了fineUploader ...
- java+服务器上传和下载文件
1.介绍enctype enctype 属性规定发送到服务器之前应该如何对表单数据进行编码. enctype作用是告知服务器请求正文的MIME类型(请求消息头content-type的作用一样) 1. ...
- java Ftp上传创建多层文件的代码片段
StringBuilder sBuilder = new StringBuilder(); String[] pah = path.split("/"); ...
- FastDfs java客户端上传、删除文件
#配置文件 connect_timeout = 2 network_timeout = 30 charset = UTF-8 http.tracker_http_port = 9090 http.an ...
- Struts上传文件
Struts上传文件分为两个步骤: 1). 首先将客户端上传的文件保存到Struts.multipart.saveDir键所指定的目录中,如果该键所对应的目录不存在,那么就保存到javax.servl ...
- struts文件上传(多文件)
第01步:配置web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app version= ...
- Java Sftp上传下载文件
需要使用jar包 jsch-0.1.50.jar sftp上传下载实现类 package com.bstek.transit.sftp; import java.io.File; import ja ...
随机推荐
- jQ的toggle() 方法
语法:$(selector).toggle(speed,callback,switch) 实例: <script src="js/jquery.min.js">< ...
- excel常用公式--关联匹配类
index: 根据位置返回单元格的值. match: 根据单元格的值返回位置. index+match替代vlookup rank:返回一列数字的数字排位.数字的排位是其相对于列表中其他值的大小.
- 【转帖】技术选型之Docker容器引擎
技术选型之Docker容器引擎 https://segmentfault.com/a/1190000019462392 图过不来的 原作者写的挺好的 题外话 最近对Docker和Kubernetes进 ...
- mysql(中)
mysql(中) 一.数据库配置 1.登录mysql 2.在mysql安装目录下:创建my.ini(my.cnf) 3.设置配置信息并保存 ''' [mysqld] character-set-ser ...
- vue单页(spa)前端git工程拆分实践
背景 随着项目的成长,单页spa逐渐包含了许多业务线 商城系统 售后系统 会员系统 ... 当项目页面超过一定数量(150+)之后,会产生一系列的问题 可扩展性 项目编译的时间(启动server,修改 ...
- SQL语句中*号的缺点
我觉得这篇博客说的比较好,参考借鉴一下:https://blog.csdn.net/weixin_44588186/article/details/87263756
- 高效开发之使用Cmder替换cmd
一.为什么要更换为cmder 在做项目时,有些时候我想复制控制台上面的代码时,cmd有的时候复制粘贴很麻烦,Cmder则不会,并且Cmder可以分屏多开窗口,可以设置窗口颜色,字体大小,并且很多快捷键 ...
- JS 一位数左边补零
- 关于jQuery获取不到动态添加的元素节点的问题
遇到问题: 当我获取 $("#art-list")页面元素后去在后面追加标签的时候(append),在下面用 $(selector) 获取刚刚添加的标签,发现怎么都获取不到. 问题 ...
- Vue基础第一章
Vue的简单示例 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> < ...