技术标签: java 传输 大文件
javaweb上传文件
上传文件的jsp中的部分
上传文件同样可以使用form表单向后端发请求,也可以使用 ajax向后端发请求
1.通过form表单向后端发送请求
Save
改进后的代码不需要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中。)
文章浏览阅读1k次。概念与操作描述一种用于在集成电路之间进行数据传输的串行通信协议。主设备(Master)发起通信并控制整个数据传输过程的设备。从设备(Slave)被动响应主设备请求的设备。数据线(SDA)双向的数据线,用于传输数据。时钟线(SCL)主设备通过时钟线控制数据的传输速率。地址每个从设备在总线上具有唯一的地址,用于识别设备。读写操作主设备向从设备发送读取或写入命令,用于读取从设备的数据或向从设备写入数据。应答(ACK/NACK)_esp32 mpu6050
文章浏览阅读736次。第5章 商品搜索学习目标Elasticsearch安装docker安装Elasticsearch系统参数问题跨域操作IK分词器配置Kibana的使用->DSL语句Kibana->DSL语句操作->ElasticsearchES导入商品搜索数据Sku数据导入到ElasticsearchMap数据类型->Object关键词搜索->能够实现搜索流程代码的编写分类统计搜索1. Elasticsearch 安装我们之前已经使_商城系统 es商品搜索排序
文章浏览阅读3.1k次,点赞4次,收藏16次。参考文章:百度AI攻略:出租车票识别_才能我浪费的博客-程序员宅基地附完整python源码)基于tensorflow、opencv的入门案例_发票识别一:关键区域定位_小白来搬家-程序员宅基地_python发票识别注:感谢一起完成项目的队友们大赛官网:出租车发票识别 Competitions - DataFountain一、赛题说明1.赛题背景出租车发票在日常财务发票报销中较为常见,由于这类发票样式丰富,区域性特点明显,并且包含大量模糊字迹和错位字迹,因此准确的定位发票_出租车发票识别ccf
文章浏览阅读2.6k次。#include #include #include #include using boost::coroutines::coroutine;void cooperative(coroutine>::pull_type &source){ auto args = source.get(); std::cout (args) (args) << '\n'; source()_c++ boost什么版本支持协程
文章浏览阅读5.3k次,点赞7次,收藏32次。样例输入:3 //输入一个数a,后面将输入a个数据元素8 9 3 //a个数据元素,依次插入尾结点后。形成单链表结点序列:8,9,33 //输入一个数b,后面将再输入b个数据元素10 89 22 //b个数据元素,依次插入0号结点后。形成单链表结点序列:8,22,89,10,9,389 //删除一个值为89的结点1 //删除1号结点样例输出:8 10 9 3#inc..._线性表完整程序代码
文章浏览阅读2.7k次,点赞2次,收藏2次。fastjson转换字符串自动过滤value为null的问题背景:使用 JSON.toJSONString(Object object)的时候发现打印出来的字符串少了几个字段,以为代码没走相应的逻辑,发现少的都是value为null的字段,发现是fastjson自动把value为null的字段过滤了。解决办法:设置SerializerFeature序列化属性 SerializerFeatu..._fastjson parseobject 过滤值为null的字段
文章浏览阅读76次。可以使用 Node.js 的子进程模块来调用电脑上的软件。例如,假设你想使用电脑上的 cat 命令来读取文件,你可以这样写:const { spawn } = require('child_process');const cat = spawn('cat', ['path/to/file']);cat.stdout.on('data', (data) => { console..._nodejs 打开软件
文章浏览阅读835次。KataKata源自希腊文Καταπίστευμα(ka-ta-PI-stev-ma),原意是值得信任的人,kata container正是解容器安全的问题而诞生的。传统的容器是基于namespace和cgroup进行隔离,在带来轻量简洁的同时,也带来了安全的隐患。事实上容器虽然提供一个与系统中的其它进程资源相隔离的执行环境,但是与宿主机系统是共享内核..._kata+stratovirt
文章浏览阅读131次。上面介绍了通讯的基类,下面就是使用那个类进行发送和接收的部分: 二、发送部分: 发送咱们使用了多线程,可以同时进行多个任务,比如发送文件、发送文本等,互不影响: 发送文本方法: private void StartSendText(string strHost,int iPort,string strInfo) { SendText stText = new SendText(strHost,iP..._c# edi 报文发送接收
文章浏览阅读179次。swift5.5异常的处理的三种的方式override func viewDidLoad() { super.viewDidLoad() method1() method2() method3() } func method3(){ //方式3 太危险,直接强制解包 不推荐 let pattern = "abc" let regex = try! NSRegularExpre_swift5 运行时异常
文章浏览阅读1.1w次,点赞14次,收藏87次。illumina 二代测序原理及过程_illumina测序原理及流程
文章浏览阅读2.1k次,点赞2次,收藏12次。看了某站古月居的ROS视频,听着视频,看老师操作感觉很简单,自己跟着做了一遍,发现并不简单,为啥出现了好多奇怪的问题。 下面是解决将.bag.active转换成.bag文件的详细步骤!其中cmd_record是文件名。1、先用 $ rosrun turtlesim turtlesim_node 命令调出小海龟,然后让它走两步。2、之后用命令 $ rosbag record -a -O cmd_record 记录数据。..._rosbag record生成bag