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

因为有很多人问我要源码,特附上源码下载链接在文章的末尾,供有需要时参考 -- 20171212 更新

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

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>无法预览&nbsp;</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: 该方法在所有文件上传完成没有错误之后调用(所有分块上传完成后调用)。

      可以在该方法中通知后台合并所有分块
  1. 前端获取文件md5字符串,发送每个分块时发送到后台,后台接收如果不存在文件夹创建文件夹,保存分块发送的文件
```javascript
// 监听分块上传的时间点,断点续传
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() { }
}
);
```
  1. 添加state标签
```javascript
$("#fileList").append("<div id='" + file.id + "'><img/><span>" + file.name + "</span><div><span class='state'></span></div><div><span class='percentage'></span></div></div>");
```
  1. 保存文件
```java
// 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 { // >> 文件
// 如果文件夹没有创建文件夹
File file = new File(serverPath + "/" + fileMd5);
if (!file.exists()) {
file.mkdirs();
}
// 保存文件
File chunkFile = new File(serverPath + "/" + fileMd5 + "/" + chunk);
FileUtils.copyInputStreamToFile(fileItem.getInputStream(), chunkFile);
}
}
```
  1. 前端通知action进行合并文件

    前端增加:
```javascript
// 通知合并分块
$.ajax(
{
type:"POST",
url:"${pageContext.request.contextPath}/UploadActionServlet?action=mergeChunks",
data:{
fileMd5:fileMd5
},
success:function(response){ }
}
);
```
  1. 新增合并action:
```java
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文件上传的更多相关文章

  1. Java FtpClient 实现文件上传服务

    一.Ubuntu 安装 Vsftpd 服务 1.安装 sudo apt-get install vsftpd 2.添加用户(uftp) sudo useradd -d /home/uftp -s /b ...

  2. Java中实现文件上传下载的三种解决方案

    第一点:Java代码实现文件上传 FormFile file=manform.getFile(); String newfileName = null; String newpathname=null ...

  3. 【原创】用JAVA实现大文件上传及显示进度信息

    用JAVA实现大文件上传及显示进度信息 ---解析HTTP MultiPart协议 (本文提供全部源码下载,请访问 https://github.com/grayprince/UploadBigFil ...

  4. jquery组件WebUploader文件上传用法详解

    这篇文章主要为大家详细介绍了jquery组件WebUploader文件上传用法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 WebUploader是由Baidu WebFE(FEX)团队开发的一 ...

  5. Java下载https文件上传到阿里云oss服务器

    Java下载https文件上传到阿里云oss服务器 今天做了一个从Https链接中下载音频并且上传到OSS服务器,记录一下希望大家也少走弯路. 一共两个类: 1 .实现自己的证书信任管理器类 /** ...

  6. 【Java】JavaWeb文件上传和下载

    文件上传和下载在web应用中非常普遍,要在jsp环境中实现文件上传功能是非常容易的,因为网上有许多用java开发的文件上传组件,本文以commons-fileupload组件为例,为jsp应用添加文件 ...

  7. java+web+大文件上传下载

    文件上传是最古老的互联网操作之一,20多年来几乎没有怎么变化,还是操作麻烦.缺乏交互.用户体验差. 一.前端代码 英国程序员Remy Sharp总结了这些新的接口 ,本文在他的基础之上,讨论在前端采用 ...

  8. Java开发系列-文件上传

    概述 Java开发中文件上传的方式有很多,常见的有servlet3.0.common-fileUpload.框架.不管哪种方式,对于文件上传的本质是不变的. 文件上传的准备 文件上传需要客户端跟服务都 ...

  9. java+web+多级文件上传

    文件夹数据库处理逻辑 publicclass DbFolder { JSONObject root; public DbFolder() { this.root = new JSONObject(); ...

随机推荐

  1. LVS的十种调度算法

    LVS十种调度算法 1.静态调度: ①rr(Round Robin):轮询调度,轮叫调度 轮询调度算法的原理是每一次把来自用户的请求轮流分配给内部中的服务器,从1开始,直到N(内部服务器个数),然后重 ...

  2. 20130620—ant和java杂学随笔

    ant知识点: 1.使用属性定义相对路径的时候,一定要使用location,而不要去使用value  对于<property></property>中location和valu ...

  3. phpcms代码读取文章的内容 实用可行的方法

    在使用phpcms做网站的时候经常遇到读取网站的内容作为推荐,而不是描述.这里使用可行的方法交你如何读取内容推荐.方法有两个,第一种执行的效率低,第二个效率高些. 1. {pc:get sql=&qu ...

  4. WP8.1开发中对于XAML中一些语言的学习(1);

    以前在学习WP开发的时候,看到视频中说到程序在创建之初,MainPaige.xaml页面上有一些代码: <Page x:Class="草案.MainPage" xmlns=& ...

  5. c++ TCP keepalive 使用

    来源:http://blog.csdn.net/weiwangchao_/article/details/7225338 http://www.cnitblog.com/zouzheng/archiv ...

  6. 【排序算法】冒泡排序算法 Java实现

    基本思想 设数组长度为N. 比较前后两个数据,如果前面的数据大于后面的数据,就将两个数据交换. 这样对数组的第0个数据到N - 1个数据进行遍历后,最大的一个数据就沉到了数组的第N - 1个位置. N ...

  7. ZOJ 1492 Maximum Clique 搜索最大团

    ZOJ1492 题意:给一个无向图 求最大团的大小.节点数小于50 数据有限,考虑记忆化搜索,方程很好给出. 令 Si={vi,vi+1.....vn} mc[i]表示Si最大团的大小,倒着推算. 必 ...

  8. iOS 用Swipe手势和动画实现循环播放图片

    主要想法 添加3个ImageView展示图片,实现图片的无限循环. 使用Swipe手势识别用户向右或向左滑动图片. 使用CATransition给ImageView.layer添加动画,展示图片更换的 ...

  9. Web前端与移动开发学习路线图

    文章转载自「开发者圆桌」一个关于开发者入门.进阶.踩坑的微信公众号 这里整理的Web前端与移动开发学习路线图包含初中级两个部分,你可以通过百度云盘下载观看对应的视频 链接: http://pan.ba ...

  10. selenium7种元素识别

    我们以百度主页搜索框为例:= <input autocomplete="off" maxlength="255" value="" c ...