评论

收藏

[JavaScript] 前端文件上传下载组件

开发技术 开发技术 发布于:2021-07-08 14:53 | 阅读数:396 | 评论:0

  
前端文件上传下载组件

  javaweb上传文件
  上传文件的jsp中的部分
  上传文件同样可以使用form表单向后端发请求,也可以使用 ajax向后端发请求
  1.通过form表单向后端发送请求
  <form id="postForm" action="${pageContext.request.contextPath}/UploadServlet" method="post" enctype="multipart/form-data">
  <div class="bbxx wrap">
  <inputtype="text" id="side-profile-name" name="username" class="form-control">
  <inputtype="file" id="example-file-input" name="avatar">
  <button type="submit" class="btn btn-effect-ripple btn-primary">Save</button>
  </div>
  </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/

  
关注下面的标签,发现更多相似文章