最后发现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对比,效果还不错