JAVA WEB怎么实现大文件上传
javaweb上传文件
上传文件的jsp中的部分
上传文件同样可以使用form表单向后端发请求,也可以使用 ajax向后端发请求
1.通过form表单向后端发送请求
改进后的代码不需要form标签,直接由控件来实现。开发人员只需要关注业务逻辑即可。JS中已经帮我们封闭好了
this.post_file = function ()
{
$.each(this.ui.btn, function (i, n) { n.hide();});
this.ui.btn.stop.show();
this.State = this.Config.state.Posting;//
this.app.postFile({ id: this.fileSvr.id, pathLoc: this.fileSvr.pathLoc, pathSvr:this.fileSvr.pathSvr,lenSvr: this.fileSvr.lenSvr, fields: this.fields });
};
通过监控工具可以看到控件提交的数据,非常的清晰,调试也非常的简单。
2.通过ajax向后端发送请求
$.ajax({
url : "${pageContext.request.contextPath}/UploadServlet",
type : "POST",
data : $( '#postForm').serialize(),
success : function(data) {
$( '#serverResponse').html(data);
},
error : function(data) {
$( '#serverResponse').html(data.status + " : " + data.statusText + " : " + data.responseText);
}
});
ajax分为两部分,一部分是初始化,文件在上传前通过AJAX请求通知服务端进行初始化操作
this.md5_complete = function (json)
{
this.fileSvr.md5 = json.md5;
this.ui.msg.text("MD5计算完毕,开始连接服务器...");
this.event.md5Complete(this, json.md5);//biz event
var loc_path = encodeURIComponent(this.fileSvr.pathLoc);
var loc_len = this.fileSvr.lenLoc;
var loc_size = this.fileSvr.sizeLoc;
var param = jQuery.extend({}, this.fields, this.Config.bizData, { md5: json.md5, id: this.fileSvr.id, lenLoc: loc_len, sizeLoc: loc_size, pathLoc: loc_path, time: new Date().getTime() });
$.ajax({
type: "GET"
, dataType: 'jsonp'
, jsonp: "callback"//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名
, url: this.Config["UrlCreate"]
, data: param
, success: function (sv)
{
_this.svr_create(sv);
}
, error: function (req, txt, err)
{
_this.Manager.RemoveQueuePost(_this.fileSvr.id);
alert("向服务器发送MD5信息错误!" + req.responseText);
_this.ui.msg.text("向服务器发送MD5信息错误");
_this.ui.btn.cancel.show();
_this.ui.btn.stop.hide();
}
, complete: function (req, sta) { req = null; }
});
};
在文件上传完后向服务器发送通知
this.post_complete = function (json)
{
this.fileSvr.perSvr = "100%";
this.fileSvr.complete = true;
$.each(this.ui.btn, function (i, n)
{
n.hide();
});
this.ui.process.css("width", "100%");
this.ui.percent.text("(100%)");
this.ui.msg.text("上传完成");
this.Manager.arrFilesComplete.push(this);
this.State = this.Config.state.Complete;
//从上传列表中删除
this.Manager.RemoveQueuePost(this.fileSvr.id);
//从未上传列表中删除
this.Manager.RemoveQueueWait(this.fileSvr.id);
var param = { md5: this.fileSvr.md5, uid: this.uid, id: this.fileSvr.id, time: new Date().getTime() };
$.ajax({
type: "GET"
, dataType: 'jsonp'
, jsonp: "callback"//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名
, url: _this.Config["UrlComplete"]
, data: param
, success: function (msg)
{
_this.event.fileComplete(_this);//触发事件
_this.post_next();
}
, error: function (req, txt, err) { alert("文件-向服务器发送Complete信息错误!" + req.responseText); }
, complete: function (req, sta) { req = null; }
});
};
这里需要处理一个MD5秒传的逻辑,当服务器存在相同文件时,不需要用户再上传,而是直接通知用户秒传
this.post_complete_quick = function ()
{
this.fileSvr.perSvr = "100%";
this.fileSvr.complete = true;
this.ui.btn.stop.hide();
this.ui.process.css("width", "100%");
this.ui.percent.text("(100%)");
this.ui.msg.text("服务器存在相同文件,快速上传成功。");
this.Manager.arrFilesComplete.push(this);
this.State = this.Config.state.Complete;
//从上传列表中删除
this.Manager.RemoveQueuePost(this.fileSvr.id);
//从未上传列表中删除
this.Manager.RemoveQueueWait(this.fileSvr.id);
//添加到文件列表
this.post_next();
this.event.fileComplete(this);//触发事件
};
这里可以看到秒传的逻辑是非常 简单的,并不是特别的复杂。
var form = new FormData();
form.append("username","zxj");
form.append("avatar",file);
//var form = new FormData($("#postForm")[0]);
$.ajax({
url:"${pageContext.request.contextPath}/UploadServlet",
type:"post",
data:form,
processData:false,
contentType:false,
success:function(data){
console.log(data);
}
});
java部分
文件初始化的逻辑,主要代码如下
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);
}
接收文件块数据,在这个逻辑中我们接收文件块数据。控件对数据进行了优化,可以方便调试。如果用监控工具可以看到控件提交的数据。
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);
注:
1. 上面的java部分的代码可以直接使用,只需要将上传的图片路径及收集数据并将数据写入到数据库即可
2. 上面上传文件使用到了字节流,其实还可以使用别的流,这个需要读者自己在下面完善测试
3. BeanUtils是一个工具 便于将实体对应的属性赋给实体
4. 上传文件不能使用 request.getParameter("")获取参数了,而是直接将request解析,通过判断每一项是文件还是非文件,然后进行相应的操作(文件的话就是用流来读取,非文件的话,暂时保存到一个map中。)
后端代码逻辑大部分是相同的,目前能够支持MySQL,Oracle,SQL。在使用前需要配置一下数据库,可以参考我写的这篇文章:http://blog.ncmem.com/wordpress/2019/08/12/java-http%E5%A4%A7%E6%96%87%E4%BB%B6%E6%96%AD%E7%82%B9%E7%BB%AD%E4%BC%A0%E4%B8%8A%E4%BC%A0/
0人点赞
JAVA WEB怎么实现大文件上传的更多相关文章
- Java实现FTP批量大文件上传下载篇1
本文介绍了在Java中,如何使用Java现有的可用的库来编写FTP客户端代码,并开发成Applet控件,做成基于Web的批量.大文件的上传下载控件.文章在比较了一系列FTP客户库的基础上,就其中一个比 ...
- java web 怎么下载大文件(上百M)
Java代码 ; ]; , )) != -) { , bytesRead); 13. } 14. toClient.write(buffer ...
- java+web+大文件上传下载
文件上传是最古老的互联网操作之一,20多年来几乎没有怎么变化,还是操作麻烦.缺乏交互.用户体验差. 一.前端代码 英国程序员Remy Sharp总结了这些新的接口 ,本文在他的基础之上,讨论在前端采用 ...
- 使用原生Java Web来实现大文件的上传
版权所有 2009-2018荆门泽优软件有限公司 保留所有权利 官方网站:http://www.ncmem.com/ 产品首页:http://www.ncmem.com/webapp/up6.2/in ...
- 【原创】用JAVA实现大文件上传及显示进度信息
用JAVA实现大文件上传及显示进度信息 ---解析HTTP MultiPart协议 (本文提供全部源码下载,请访问 https://github.com/grayprince/UploadBigFil ...
- 用JAVA实现大文件上传及显示进度信息
一. 大文件上传基础描述: 各种WEB框架中,对于浏览器上传文件的请求,都有自己的处理对象负责对Http MultiPart协议内容进行解析,并供开发人员调用请求的表单内容. 比如: Spring 框 ...
- java 大文件上传 断点续传 完整版实例 (Socket、IO流)
ava两台服务器之间,大文件上传(续传),采用了Socket通信机制以及JavaIO流两个技术点,具体思路如下: 实现思路: 1.服:利用ServerSocket搭建服务器,开启相应端口,进行长连接操 ...
- web实现大文件上传分片上传断点续传
需求:项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在500M内,因此自己需要在项目中进行文件上传部分的调整和配置,自己将大小都以501M来进行限制. 第一步: 前端修改 由于项目使用的是 ...
- java+大文件上传解决方案
众所皆知,web上传大文件,一直是一个痛.上传文件大小限制,页面响应时间超时.这些都是web开发所必须直面的. 本文给出的解决方案是:前端实现数据流分片长传,后面接收完毕后合并文件的思路. 实现文件夹 ...
随机推荐
- QCOW2/RAW/qemu-img 概念浅析
目录 目录 扩展阅读 RAW QCOW2 QEMU-COW 2 QCOW2 Header QCOW2 的 COW 特性 QCOW2 的快照 qemu-img 的基本使用 RAW 与 QCOW2 的区别 ...
- 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_02 递归_4_练习_递归打印多级目录
递归所有的文件夹,并把文件都输出出来. 在最上面打印目录的名称
- 测开之路八十七:HTML之a标签的用法
初始化的HTML结构为,只需要在body里面加网页的标签和要显示的内容即可 <!DOCTYPE html><html lang="en"><head& ...
- js技巧之与或运算符 || && 妙用
如题: 假设对成长速度显示规定如下: 成长速度为5显示1个箭头: 成长速度为10显示2个箭头: 成长速度为12显示3个箭头: 成长速度为15显示4个箭头: 其他都显示都显示0各箭头. 用代码 ...
- chineseocr项目的配置阶段出现的问题及解决方案
chineseocr为GitHub上的一个开源项目,主要使用yolos,crnn等深度学习框架训练好后的模型使用.测试结果发现,不管是针对文本文件.表格文件.还是场景图,如身份证火车票,识别效果都比较 ...
- java面向对象基础总结
本周学习了java面向对象的一些基本概念,介绍了它三个主要特性,封装性.继承性.多态性,类与对象的关系,栈堆的关系,三个特性中主要讲了封装性,其他两个后面再讲. 类实际上是表示一个客观世界某类群体的一 ...
- 使用Vsftpd服务(匿名访问模式、本地用户模式)
FTP协议占用两个端口号: 21端口:命令控制,用于接收客户端执行的FTP命令. 20端口:数据传输,用于上传.下载文件数据.. FTP数据传输的类型: 主动模式:FTP服务端主动向FTP客户端发起连 ...
- 偏序问题及CDQ分治详解
CDQ用来解决分治时左半部分对右半部分造成影响的问题. CDQ分治的经典问题是三维偏序问题. 要想解决三维偏序问题,首先你要知道什么是偏序.(废话) 一维偏序: 给出直线上的n个点,问有多少对点满足x ...
- python学习笔记(13):python并发编程以及系统常用模块
一.进程与线程 1.进程:程序的一次执行(程序装载入内存,系统分配资源运行).n 每个进程有自己的内存空间.数据栈等,只能使用进程间通讯,而不能直接共享信息 2.线程:所有线程运行在同一个进程中,共享 ...
- 利用vsftpd在Linux构建安全的FTP服务
最近在机房搭建Linux环境,需要用到了FTP服务,查看了许多的资料,在这里做一下笔记 一.安装 方法一,使用yum命令安装,需要能够连接外网 # yum install vsftpd 方法二,使用安 ...