评论

收藏

[JavaScript] js+上传文件夹

开发技术 开发技术 发布于:2021-07-10 14:07 | 阅读数:351 | 评论:0

  
js+上传文件夹

  我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用。
  w3c称:空格会变成”+”加号,但是我这里没有发现,只有当get请求的时候,空格会变成”+”号
  进入正题
  完成上传需要满足3个必要的条件
  提供form表单,method必须是post,因为get请求的传输数据一般为2kb,不同浏览器不一样。
  form表单属性enctype的必须是multipart/form-data
  提供input type=”file”类的上传输入域
  大致实现原理:当enctype的值是multipart/form-data时,浏览器会把每个表单项进行分割,分割成不同的部件,以boundary的值为分割标识,这个标识的字符串是随机生成的,最后一个表单项的分割标识字符串末尾会多两个”- -“,代表结束。服务端用request.getHeader(“content-type”)获取分割字符串,然后进行解析。
  代码实现
  一、开发环境搭建
  准备两个第三方jar包
  commons-io包
  commons-upload包
  所有依赖包
  代码实现
  <%@page language="java" import="up6.DBFile" pageEncoding="UTF-8"%>
  <%@page contentType="text/html;charset=UTF-8"%>
  <%@page import="up6.FileBlockWriter" %>
  <%@page import="up6.XDebug" %>
  <%@page import="up6.*" %>
  <%@page import="up6.biz.*" %>
  <%@page import="org.apache.commons.fileupload.FileItem" %>
  <%@page import="org.apache.commons.fileupload.FileItemFactory" %>
  <%@page import="org.apache.commons.fileupload.FileUploadException" %>
  <%@page import="org.apache.commons.fileupload.disk.DiskFileItemFactory" %>
  <%@page import="org.apache.commons.fileupload.servlet.ServletFileUpload" %>
  <%@page import="org.apache.commons.lang.*" %>
  <%@page import="java.net.URLDecoder"%>
  <%@page import="java.util.Iterator"%>
  <%@page import="net.sf.json.JSONObject"%>
  <%@page import="java.util.List"%>
  <%
  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;
  }
  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);
  %>
  下载的必须条件
  两个头一个流
  content-type
  Content-Type是返回消息中非常重要的内容,表示文档内容属于什么MIME类型。
  浏览器会根据Content-Type来决定如何显示返回的消息体内容。
  默认值是text/html
  可以使用request.getServletContext().getMimeType(“文件名”)获取MIME类型。
  Content-Disposition
  Content-disposition 是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件。
  默认值是inline,表示在浏览器窗口中打开。
  服务端向客户端游览器发送文件时,如果是浏览器支持的文件类型,一般会默认使用浏览器打开,比如txt、jpg等,会直接在浏览器 中显示。
  如果需要提示用户保存,利用Content-Disposition进行一下处理,关键在于一定要加上attachment。
  例如:Content-Disposition:attachment;filename=xxx,浏览器就会激活下载框对话框, attachment 表示附件, filname 后面跟随的是显示在下载框中的文件名称。
  流
  下载就是向客户端响应字节数据! 将一个文件变成字节数组, 使用 response.getOutputStream()
  来响应给浏览器。
  代码如下,此代码已经实现了断点续传功能,用户在下载过程可以暂停,和继续下载,对服务器造成的压力也比较小。
  String fid             = request.getHeader("id");
  String blockIndex = request.getHeader("blockIndex");//基于1
  String blockOffset     = request.getHeader("blockOffset");//块偏移,相对于整个文件
  String blockSize   = request.getHeader("blockSize");//块大小(当前需要下载的大小)
  String pathSvr         = request.getHeader("pathSvr");//文件在服务器的位置
  pathSvr            = PathTool.url_decode(pathSvr);
  if (  StringUtils.isBlank(fid)
  ||StringUtils.isBlank(blockIndex)
  ||StringUtils.isEmpty(blockOffset)
  ||StringUtils.isBlank(blockSize)
  ||StringUtils.isBlank(pathSvr))
  {
  response.setStatus(500);
  response.setHeader("err","参数为空");
  return;
  }
  File f = new File(pathSvr);
  //文件不存在
  if(!f.exists())
  {
  response.setStatus(500);
  OutputStream os = response.getOutputStream();
  System.out.println(String.format("%s 文件不存在",pathSvr));
  os.close();
  return;
  }
  long fileLen = f.length();
  response.setContentType("application/x-download");
  response.setHeader("Pragma","No-cache"); 
  response.setHeader("Cache-Control","no-cache");
  response.addHeader("Content-Length",blockSize); 
  response.setDateHeader("Expires", 0);
  OutputStream os = response.getOutputStream();
  try
  {
  RandomAccessFile raf = new RandomAccessFile(pathSvr,"r");
  int readToLen = Integer.parseInt(blockSize);
  int readLen = 0;
  raf.seek( Long.parseLong(blockOffset) );//定位索引
  byte[] data = newbyte[1048576];
  while( readToLen > 0 )
  {
  readLen = raf.read(data,0,Math.min(1048576,readToLen) );
  readToLen -= readLen;
  os.write(data, 0, readLen);
  }
  os.flush();
  os.close();  
  raf.close();
  os = null;
  response.flushBuffer();
  out.clear();
  out = pageContext.pushBody();
  }
  catch(Exception e)
  {
  response.setStatus(500);
  os.close();
  out.close();
  e.printStackTrace();
  }
  finally
  {   
  if(os != null)
  {
  os.close();       
  os = null;
  }
  out.clear();
  out = pageContext.pushBody();
  }%>
  加载文件列表,在下载列表中显示出来
  后端代码逻辑大部分是相同的,目前能够支持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/
  

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