一直在寻找一个能够上传4G以上文件,并且支持断点续传的插件,而且可以在多浏览器使用
最后发现plupload可以上传超4G,并且Silverlight,flash,html4,html5模式上传
Silverlight 安装微软的Silverlight
flash只要浏览器支持flash就行,但存在一个bug,文件超过4G时,选择文件后上传列表不响应,只能推拽进上传列表
html5浏览器支持
以上只需要存在一个即可上传
不废话,直接看代码,希望大家指教
找到plupload.dev.js
修改成如下:
onUploadFile function onUploadFile(up, file) { var url = up.settings.url, chunkSize = up.settings.chunk_size, retries = up.settings.max_retries, features = up.features, offset = 0, blob; if (file.name != null) { $.get("ckeck", { filename : file.name, chunk_size:up.settings.chunk_size, }, function(data) { offset = data.off; }); }
断点续传需要数据库的支持,因为是测试使用简单的JDBC操作数据库
package db;
import java.sql.*;
public class Database {
private String dbDriver="com.mysql.jdbc.Driver";
private String sConnStr = "jdbc:mysql://localhost:3306/upload?useUnicode=true&characterEncoding=UTF-8";
public Connection connect = null;
public ResultSet rs=null;
public Database() {
try {
Class.forName(dbDriver).newInstance();
connect = DriverManager.getConnection(sConnStr,"root","");
}
catch (Exception ex) {
System.out.println("");
}
}
public ResultSet executeQuery(String sql) {
System.out.println(sql);
try{
connect=DriverManager.getConnection(sConnStr,"root","");
Statement stmt=connect.createStatement();
rs=stmt.executeQuery(sql);
}catch(SQLException ex){
System.err.println(ex.getMessage());
}
return rs;
}
public void executeUpdate(String sql)
{
System.out.println(sql);
Statement stmt=null;
rs=null;
try
{ connect=DriverManager.getConnection(sConnStr,"root","");
stmt=connect.createStatement();
stmt.executeUpdate(sql);
stmt.close();
connect.close();
}
catch(SQLException ex)
{
System.err.println(ex.getMessage());
}
}
}
plupload是分块上传文件,记录文件上传到哪块,以便断点
package gson.demo;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.ResultSet;
import java.util.List;
import java.util.UUID;
import javax.servlet.ServletConfig;
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.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import db.Database;
public class UploaderServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
String repositoryPath;
String uploadPath;
@SuppressWarnings("unchecked")
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
Integer schunk = null;// 分割块数
Integer schunks = null;// 总分割数
String name = null;// 文件名
BufferedOutputStream outputStream = null;
if (ServletFileUpload.isMultipartContent(request)) {
try {
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(1024);
factory.setRepository(new File(repositoryPath));// 设置临时目录
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("UTF-8");
upload.setSizeMax(5 * 1024 * 1024 * 1024);// 设置附近大小
List<FileItem> items = upload.parseRequest(request);
// 生成新文件名
String newFileName = null;
for (FileItem item : items) {
if (!item.isFormField()) {// 如果是文件类型
name = newFileName;// 获得文件名
if (name != null) {
String nFname = newFileName;
if (schunk != null) {
nFname = schunk + "_" + name;
}
File savedFile = new File(uploadPath, nFname);
item.write(savedFile);
}
} else {
// 判断是否带分割信息
if (item.getFieldName().equals("chunk")) {
schunk = Integer.parseInt(item.getString());
System.out.println(schunk);
}
if (item.getFieldName().equals("chunks")) {
schunks = Integer.parseInt(item.getString());
}
if (item.getFieldName().equals("name")) {
newFileName = item.getString();
}
}
}
Database db = new Database();
if (schunk != null && schunk == 0) {
String ckcksql = "select * from file where filename ='"
+ newFileName + "'";
db.executeQuery(ckcksql);
if (db.rs.first()) {
} else {
String sql = "INSERT INTO file (filename,schunk,schunks) VALUES ('"
+ newFileName
+ "',"
+ schunk
+ ","
+ schunks
+ ")";
db.executeUpdate(sql);
}
} else {
String sql = "update file set schunk=" + schunk
+ " where filename ='" + newFileName + "'";
db.executeUpdate(sql);
}
if (schunk != null && schunk + 1 == schunks) {
outputStream = new BufferedOutputStream(
new FileOutputStream(new File(uploadPath,
newFileName)));
// 遍历文件合并
for (int i = 0; i < schunks; i++) {
File tempFile = new File(uploadPath, i + "_" + name);
byte[] bytes = FileUtils.readFileToByteArray(tempFile);
outputStream.write(bytes);
outputStream.flush();
tempFile.delete();
}
outputStream.flush();
}
response.getWriter()
.write("{\"status\":true,\"newName\":\"" + newFileName
+ "\"}");
} catch (FileUploadException e) {
e.printStackTrace();
response.getWriter().write("{\"status\":false}");
} catch (Exception e) {
e.printStackTrace();
response.getWriter().write("{\"status\":false}");
} finally {
try {
if (outputStream != null)
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Override
public void init(ServletConfig config) throws ServletException {
repositoryPath = FileUtils.getTempDirectoryPath();
System.out.println("临时目录:" + repositoryPath);
uploadPath = config.getServletContext().getRealPath(
config.getInitParameter("uploadPath"));
System.out.println("目录:" + uploadPath);
File up = new File(uploadPath);
if (!up.exists()) {
up.mkdir();
}
}
}
上传之前检测文件是否上传过,注:修改文件后再上传未作处理,可获取文件大小存库,对比,如果大小改变,不再断点续传,重新上传
数据库设计(Mysql)
package gson.demo;
import java.io.File;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import db.Database;
public class CkeckFileServlet extends HttpServlet {
String repositoryPath;
String uploadPath;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO Auto-generated method stub
String fileName=new String(req.getParameter("filename").getBytes("8859_1"),"utf-8");
String chunk_size = req.getParameter("chunk_size");
System.out.println(chunk_size);
System.out.println(fileName);
resp.setContentType("text/json; charset=utf-8");
Database db = new Database();
String sql = "select * from file where filename = '" + fileName+"'";
ResultSet RS_result = db.executeQuery(sql);
try {
if (db.rs.first()) {
int schunk = RS_result.getInt("schunk");
//删除最近一个分块,防止最后一个分块未上传之前被断开上传,一般不会发生
deleteFile(uploadPath+schunk+"_"+fileName);
long off = schunk * Long.parseLong(chunk_size);
resp.getWriter().write("{\"off\":"+off+"}");
} else {
resp.getWriter().write("{\"off\":0}");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(req, resp);
}
@Override
public void init(ServletConfig config) throws ServletException {
repositoryPath = FileUtils.getTempDirectoryPath();
uploadPath = config.getServletContext().getRealPath(
config.getInitParameter("uploadPath"));
File up = new File(uploadPath);
if (!up.exists()) {
up.mkdir();
}
}
public boolean deleteFile(String sPath) {
boolean flag = false;
File file = new File(sPath);
// 路径为文件且不为空则进行删除
if (file.isFile() && file.exists()) {
file.delete();
flag = true;
}
return flag;
}
}
首页
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"+ request.getServerName() + ":" + request.getServerPort()+ path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>GodSon Easyui 结合Pluplaod插件的上传演示</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<link rel="stylesheet" href="bootstrap/easyui.css" type="text/css"></link>
<script type="text/javascript" src="jquery-1.8.0.min.js"></script>
<script type="text/javascript" src="easyui/jquery.easyui.min.js"></script>
<script type="text/javascript">
/**
* 创建上传窗口 公共方法
* @param chunk 是否分割大文件
* @param callBack 上传成功之后的回调
*/
function Uploader(chunk,callBack){
var addWin = $('<div style="overflow: hidden;"/>');
var upladoer = $('<iframe/>');
upladoer.attr({'src':'<%=basePath%>/uploader.jsp?chunk='+chunk,width:'100%',height:'100%',frameborder:'0',scrolling:'no'});
addWin.window({
title:"上传文件",
height:350,
width:550,
minimizable:false,
modal:true,
collapsible:false,
maximizable:false,
resizable:false,
content:upladoer,
onClose:function(){
var fw = GetFrameWindow(upladoer[0]);
var files = fw.files;
$(this).window('destroy');
callBack.call(this,files);
},
onOpen:function(){
var target = $(this);
setTimeout(function(){
var fw = GetFrameWindow(upladoer[0]);
fw.target = target;
},100);
}
});
}
/**
* 根据iframe对象获取iframe的window对象
* @param frame
* @returns {Boolean}
*/
function GetFrameWindow(frame){
return frame && typeof(frame)=='object' && frame.tagName == 'IFRAME' && frame.contentWindow;
}
function makerUpload(chunk){
Uploader(chunk,function(files){
if(files && files.length>0){
$("#res").text("成功上传:"+files.join(","));
}
});
}
</script>
</head>
<body style="width: 100%;height: 100%;overflow:hidden;margin: 0;padding: 0;">
<h1>GodSon Easyui 结合Pluplaod插件的上传演示</h1>
<hr/>
<a class="easyui-linkbutton" href="javascript:makerUpload(false)">不分割文件上传</a> <a class="easyui-linkbutton" href="javascript:makerUpload(true)">分割文件上传</a>
<hr/>
<div id="res"></div>
</body>
</html>
上传页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>文件上传</title>
<link rel="stylesheet" href="plupload/js/jquery.plupload.queue/css/jquery.plupload.queue.css" type="text/css"></link>
<script type="text/javascript" src="jquery-1.8.0.min.js"></script>
<script type="text/javascript" src="plupload/js/plupload.full.min.js"></script>
<script type="text/javascript" src="plupload/js/i18n/Moxie.js"></script>
<script type="text/javascript" src="plupload/js/i18n/zh_CN.js"></script>
<script type="text/javascript" src="plupload/js/jquery.plupload.queue/jquery.plupload.queue.js"></script>
<body style="padding: 0;margin: 0;">
<div id="uploader"> </div>
<script type="text/javascript">
var files = [];
var errors = [];
var type = 'file';
var chunk = eval('${param.chunk}');
var max_file_size = '9000mb';
var filters = {title : "文档", extensions : "zip,doc,docx,xls,xlsx,ppt,pptx"};
$("#uploader").pluploadQueue($.extend({
runtimes : 'flash,html4,html5',
url : 'uploader',
max_file_size : max_file_size,
file_data_name:'file',
filters : [filters],
// Flash settings
flash_swf_url : '/plupload/plupload/js/Moxie.swf',
// Silverlight settings
silverlight_xap_url : '/plupload/plupload/js/Moxie.xap',
init:{
FileUploaded:function(uploader,file,response){
if(response.response){
var rs = $.parseJSON(response.response);
if(rs.status){
files.push(file.name);
}else{
errors.push(file.name);
}
}
},
UploadComplete:function(uploader,fs){
var e= errors.length ? ",失败"+errors.length+"个("+errors.join("、")+")。" : "。";
alert("上传完成!共"+fs.length+"个。成功"+files.length+e);
target.window("close");
}
}
},(chunk ? {chunk_size:'5mb'} : {})));
</script>
</body>
</html>
除了上面说到的,修改文件之后上传未处理,还有一个中文乱码未处理,
if (item.getFieldName().equals("name")) {
newFileName = item.getString();
}
修改编码
newFileName = new String(item.getString().getBytes("8859_1"),"utf-8");
对于修改文件之后,继续上传,在实际应用中我使用的是MD5对比,效果还不错