当前位置: 移动技术网 > IT编程>开发语言>Java > Java与WebUploader相结合实现文件上传功能(实例代码)

Java与WebUploader相结合实现文件上传功能(实例代码)

2019年07月22日  | 移动技术网IT编程  | 我要评论

之前自己写小项目的时候也碰到过文件上传的问题,没有找到很好的解决方案。虽然之前网找各种解决方案的时候也看到过webuploader,但没有进一步深究。这次稍微深入了解了些,这里也做个小结。

简单的文件和普通数据上传并保存

jsp页面:

<%@ page language="java" contenttype="text/html; charset=utf-8"
 pageencoding="utf-8"%>
<!doctype html public "-//w3c//dtd html 4.01 transitional//en" "http://www.w3.org/tr/html4/loose.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>insert title here</title>
</head>
<body>
 <form action="${pagecontext.request.contextpath }/fileuploadservlet" method="post" enctype="multipart/form-data">
  文件:<input type="file" value="请选择文件" name="file" /> <br/>
  信息:<input type="text" name="info" /> <br/>
  <input type="submit" value="提交" />
 </form>
</body>
</html>

servlet:

package com.yihengliu.web.action;
import java.io.file;
import java.io.ioexception;
import java.io.inputstream;
import java.util.list;
import javax.servlet.servletexception;
import javax.servlet.http.httpservlet;
import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;
import org.apache.commons.fileupload.fileitem;
import org.apache.commons.fileupload.disk.diskfileitemfactory;
import org.apache.commons.fileupload.servlet.servletfileupload;
import org.apache.commons.io.fileutils;
/**
 * servlet user to accept file upload
 */
public class fileuploadservlet extends httpservlet {
 private static final long serialversionuid = 1l;
 private string serverpath = "e:/";
 protected void doget(httpservletrequest request, httpservletresponse response)
   throws servletexception, ioexception {
  response.getwriter().append("served at: ").append(request.getcontextpath());
  system.out.println("进入后台...");
  // 1.创建diskfileitemfactory对象,配置缓存用
  diskfileitemfactory diskfileitemfactory = new diskfileitemfactory();
  // 2. 创建 servletfileupload对象
  servletfileupload servletfileupload = new servletfileupload(diskfileitemfactory);
  // 3. 设置文件名称编码
  servletfileupload.setheaderencoding("utf-8");
  // 4. 开始解析文件
  try {
   list<fileitem> items = servletfileupload.parserequest(request);
   for (fileitem fileitem : items) {
    if (fileitem.isformfield()) { // >> 普通数据
     string info = fileitem.getstring("utf-8");
     system.out.println("info:" + info);
    } else { // >> 文件
     // 1. 获取文件名称
     string name = fileitem.getname();
     // 2. 获取文件的实际内容
     inputstream is = fileitem.getinputstream();
     // 3. 保存文件
     fileutils.copyinputstreamtofile(is, new file(serverpath + "/" + name));
    }
   }
  } catch (exception e) {
   e.printstacktrace();
  }
 }
 protected void dopost(httpservletrequest request, httpservletresponse response)
   throws servletexception, ioexception {
  doget(request, response);
 }
}

使用webuploader组件上传

分片、并发,预览、压缩,多途径添加文件夹(文件多选,拖拽等),妙传

页面样式使用

<html>
<title>使用webuploader上传</title>
<!-- 1.引入文件 -->
<link rel="stylesheet" type="text/css" href="${pagecontext.request.contextpath }/js/webuploader.css" rel="external nofollow" >
<script type="text/javascript" src="${pagecontext.request.contextpath }/js/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="${pagecontext.request.contextpath }/js/webuploader.js"></script>
</head>
<body>
 <!-- 2.创建页面元素 -->
 <div id="upload">
  <div id="filepicker">文件上传</div>
 </div>
 <!-- 3.添加js代码 -->
 <script type="text/javascript">
  var uploader = webuploader.create(
   {
    swf:"${pagecontext.request.contextpath }/js/uploader.swf",
    server:"${pagecontext.request.contextpath }/fileuploadservlet",
    pick:"#filepicker",
    auto:true
   }  
  );
 </script>
</body>
</html>
  • 生成文件名列表、实时显示上传进度、显示缩略图
  • 增加文件列表div, <div id="filelist"></div>
  • 生成缩略图和显示上传进度
// 生成缩略图和上传进度
uploader.on("filequeued", function(file) {
  // 把文件信息追加到filelist的div中
  $("#filelist").append("<div id='" + file.id + "'><img/><span>" + file.name + "</span><div><span class='percentage'><span></div></div>")
  // 制作缩略图
  // error:不是图片,则有error
  // src:代表生成缩略图的地址
  uploader.makethumb(file, function(error, src) {
   if (error) {
    $("#" + file.id).find("img").replacewith("<span>无法预览 </span>");
   } else {
    $("#" + file.id).find("img").attr("src", src);
   }
  });
 }
);
// 监控上传进度
// percentage:代表上传文件的百分比
uploader.on("uploadprogress", function(file, percentage) {
 $("#" + file.id).find("span.percentage").text(math.round(percentage * 100) + "%");
});
  • 拖拽上传、粘贴上传
  • 创建拖拽区域并设置样式:
<style type="text/css">
 #dndarea {
  width: 200px;
  height: 100px;
  border-color: red;
  border-style: dashed;
 }
</style>  
<!-- 创建用于拖拽的区域 -->
<div id="dndarea"></div>
  • 基本配置中增加dnd区域配置(开启拖拽)

屏蔽拖拽区域外的响应

开启粘贴功能

var uploader = webuploader.create(
 {  swf:"${pagecontext.request.contextpath }/js/uploader.swf",
server:"${pagecontext.request.contextpath }/fileuploadservlet",
  pick:"#filepicker",
  auto:true,
  // 开启拖拽
  dnd:"#dndarea",
  // 屏蔽拖拽区域外的响应
  disableglobaldnd:true,
  // 
 }  
);
  • 文件的分块上传

前端根据需要发送的文件生成一个md5字符串发送给后台,后台创建以该md5字符串命名的文件夹。前端分块发送文件并发送文件块序号给后台,后台接收到文件后按序号名称保存。前端发送完成后通知后台合并文件。

  • 前端配置,开启是否分块、分块大小、线程个数等
// 上传基本配置
var uploader = webuploader.create(
{
 swf:"${pagecontext.request.contextpath }/js/uploader.swf",
 server:"${pagecontext.request.contextpath }/fileuploadservlet",
 pick:"#filepicker",
 auto:true,
 dnd:"#dndarea",
 disableglobaldnd:true,
 paste:"#uploader",

 // 分块上传设置
 // 是否分块
 chunked:true,
 // 每块文件大小(默认5m)
 chunksize:5*1024*1024,
 // 开启几个并非线程(默认3个)
 threads:3,
 // 在上传当前文件时,准备好下一个文件
 preparenextfile:true
}  
);
  • 前端监听分块

可以分为三个时间点:

  • before-send-file: 该方法在文件上传前调用(只会在一个文件上传前调用)。

可以在该方法中获取文件的md5字符串作为后台保存分块文件的目录名

  • before-send: 该方法在每个分块文件上传前调用(每个分块上传前都会调用)。

可以在该方法中发送md5字符串到后台,后台判断是否已经存在分块决定是否发送以达到断点续传的功能

  • after-send-file: 该方法在所有文件上传完成没有错误之后调用(所有分块上传完成后调用)。

可以在该方法中通知后台合并所有分块

  • 前端获取文件md5字符串,发送每个分块时发送到后台,后台接收如果不存在文件夹创建文件夹,保存分块发送的文件
 // 监听分块上传的时间点,断点续传
var filemd5;
webuploader.uploader.register({
 "before-send-file":"beforesendfile",
 "before-send":"beforesend",
 "after-send-file":"aftersendfile"
 },{
  beforesendfile:function(file) {
   // 创建一个deffered,用于通知是否完成操作
   var deferred = webuploader.deferred();
   // 计算文件的唯一标识,用于断点续传和妙传
   (new webuploader.uploader()).md5file(file, 0, 5*1024*1024)
    .progress(function(percentage){
     $("#"+file.id).find("span.state").text("正在获取文件信息...");
    })
    .then(function(val) {
     filemd5 = val;
     $("#" + file.id).find("span.state").text("成功获取文件信息");
     // 放行
     deferred.resolve();
    });
   // 通知完成操作
   return deferred.promise();
  },
  beforesend:function() {
   var deferred = webuploader.deferred();
   // 发送文件md5字符串到后台
   this.owner.options.formdata.filemd5 = filemd5;
   deferred.resolve();
   return deferred.promise();
  },
  aftersendfile:function() {
  }
 }
);

添加state标签

$("#filelist").append("<div id='" + file.id + "'><img/><span>" + file.name + "</span><div><span class='state'></span></div><div><span class='percentage'></span></div></div>");

保存文件

// 4. 开始解析文件
// 文件md5获取的字符串
string filemd5 = null;
// 文件的索引
string chunk = null;
try {
  list<fileitem> items = servletfileupload.parserequest(request);
  for (fileitem fileitem : items) {
    if (fileitem.isformfield()) { // >> 普通数据
      string fieldname = fileitem.getfieldname();
      if ("info".equals(fieldname)) {
        string info = fileitem.getstring("utf-8");
        system.out.println("info:" + info);
      }
      if ("filemd5".equals(fieldname)) {
        filemd5 = fileitem.getstring("utf-8");
        system.out.println("filemd5:" + filemd5);
      }
      if ("chunk".equals(fieldname)) {
        chunk = fileitem.getstring("utf-8");
        system.out.println("chunk:" + chunk);
      }
    } else { // >> 文件
      /*// 1. 获取文件名称
      string name = fileitem.getname();
      // 2. 获取文件的实际内容
      inputstream is = fileitem.getinputstream();
      // 3. 保存文件
      fileutils.copyinputstreamtofile(is, new file(serverpath + "/" + name));*/
      // 如果文件夹没有创建文件夹
      file file = new file(serverpath + "/" + filemd5);
      if (!file.exists()) {
        file.mkdirs();
      }
      // 保存文件
      file chunkfile = new file(serverpath + "/" + filemd5 + "/" + chunk);
      fileutils.copyinputstreamtofile(fileitem.getinputstream(), chunkfile);
    }
  }
  • 前端通知action进行合并文件

前端增加:

// 通知合并分块
$.ajax(
  {
    type:"post",
    url:"${pagecontext.request.contextpath}/uploadactionservlet?action=mergechunks",
    data:{
      filemd5:filemd5
    },
    success:function(response){
    }
  }
);

新增合并action:

package com.yihengliu.web.action;
import java.io.file;
import java.io.filefilter;
import java.io.fileinputstream;
import java.io.fileoutputstream;
import java.io.ioexception;
import java.nio.channels.filechannel;
import java.util.arraylist;
import java.util.arrays;
import java.util.collections;
import java.util.comparator;
import java.util.list;
import java.util.uuid;
import javax.servlet.servletexception;
import javax.servlet.http.httpservlet;
import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;
/**
 * 合并上传文件
 */
public class uploadactionservlet extends httpservlet {
  private static final long serialversionuid = 1l;
  private string serverpath = "e:/";
  protected void doget(httpservletrequest request, httpservletresponse response)
      throws servletexception, ioexception {
    system.out.println("进入合并后台...");
    string action = request.getparameter("action");
    if ("mergechunks".equals(action)) {
      // 获得需要合并的目录
      string filemd5 = request.getparameter("filemd5");
      // 读取目录所有文件
      file f = new file(serverpath + "/" + filemd5);
      file[] filearray = f.listfiles(new filefilter() {
        // 排除目录,只要文件
        @override
        public boolean accept(file pathname) {
          if (pathname.isdirectory()) {
            return false;
          }
          return true;
        }
      });
      // 转成集合,便于排序
      list<file> filelist = new arraylist<file>(arrays.aslist(filearray));
      // 从小到大排序
      collections.sort(filelist, new comparator<file>() {
        @override
        public int compare(file o1, file o2) {
          if (integer.parseint(o1.getname()) < integer.parseint(o2.getname())) {
            return -1;
          }
          return 1;
        }
      });
      // 新建保存文件
      file outputfile = new file(serverpath + "/" + uuid.randomuuid().tostring() + ".zip");
      // 创建文件
      outputfile.createnewfile();
      // 输出流
      fileoutputstream fileoutputstream = new fileoutputstream(outputfile);
      filechannel outchannel = fileoutputstream.getchannel();
      // 合并
      filechannel inchannel;
      for (file file : filelist) {
        inchannel = new fileinputstream(file).getchannel();
        inchannel.transferto(0, inchannel.size(), outchannel);
        inchannel.close();
        // 删除分片
        file.delete();
      }
      // 关闭流
      fileoutputstream.close();
      outchannel.close();
      // 清除文件加
      file tempfile = new file(serverpath + "/" + filemd5);
      if (tempfile.isdirectory() && tempfile.exists()) {
        tempfile.delete();
      }
      system.out.println("合并文件成功");
    }
  }
  protected void dopost(httpservletrequest request, httpservletresponse response)
      throws servletexception, ioexception {
    doget(request, response);
  }
}
  • 断点续传

前端页面发送前添加校验,校验是否已经上传分块

beforesend:function(block) {
        var deferred = webuploader.deferred();
        // 支持断点续传,发送到后台判断是否已经上传过
        $.ajax(
          {
            type:"post",
            url:"${pagecontext.request.contextpath}/uploadactionservlet?action=checkchunk",
            data:{
              // 文件唯一表示                
              filemd5:filemd5,
              // 当前分块下标
              chunk:block.chunk,
              // 当前分块大小
              chunksize:block.end-block.start
            },
            datatype:"json",
            success:function(response) {
              if(response.ifexist) {
                // 分块存在,跳过该分块
                deferred.reject();
              } else {
                // 分块不存在或不完整,重新发送
                deferred.resolve();
              }
            }
          }
        );
        // 发送文件md5字符串到后台
        this.owner.options.formdata.filemd5 = filemd5;
        return deferred.promise();
      }
  • action中添加校验
else if ("checkchunk".equals(action)) {
    // 校验文件是否已经上传并返回结果给前端
    // 文件唯一表示                
    string filemd5 = request.getparameter("filemd5");
    // 当前分块下标
    string chunk = request.getparameter("chunk");
    // 当前分块大小
    string chunksize = request.getparameter("chunksize");
    // 找到分块文件
    file checkfile = new file(serverpath + "/" + filemd5 + "/" + chunk);
    // 检查文件是否存在,且大小一致
    response.setcontenttype("text/html;charset=utf-8");
    if (checkfile.exists() && checkfile.length() == integer.parseint((chunksize))) {
      response.getwriter().write("{\"ifexist\":1}");
    } else {
      response.getwriter().write("{\"ifexist\":0}");
    }
  }

以上所述是小编给大家介绍的java与webuploader相结合实现文件上传功能(实例代码),希望对大家有所帮助

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网