寫在前面:
這幾天,有去研究一下WebUploader上傳文件,前面的博客有記錄下使用WebUploader簡單上傳文件的例子,今天就把分片斷點上傳的例子也記錄下吧,在博客園中,也查看了一些資料,基本上後台處理數據都是用的Servlet,或者是SpringMVC,由於最近的項目一直都是Struts2,所以這裡就用Struts2中的action來對數據進行處理,達到分片上傳文件的效果。
1.什麼是分片上傳?
顧名思義,就是把文件分成一片片,即讓一個文件,分割成好幾個小文件,然後再上傳。這樣做的好處是便於上傳大文件。
2.分片上傳大致思路:
1.前台頁面,選擇文件,點擊按鈕進行上傳。
2.WebUploader將上傳的文件,分割成指定的個數,挨個發送到服務端后台。
3.服務器接收分割後的小文件,並存儲到臨時文件夾下
4.服務器接收分割後的小文件完畢後,前台頁面執行上傳成功函數。
5.在上傳成功函數中,發送請求到服務器,請求合併小文件為一個整體的文件。
6.服務器後台對文件進行合併操作,合併完成後刪除存儲小文件的臨時文件。
了解了分片上傳的大致過程,下面直接上demo吧。
前台頁面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %><% String scheme = request.getScheme(); String serverName = request.getServerName(); String contextPath = request.getContextPath(); int port = request.getServerPort(); //網站的訪問跟路徑String baseURL = scheme + "://" + serverName + ":" + port + contextPath; request.setAttribute("baseURL", baseURL);%><html><head> <title>WebUploader文件分片上傳簡單示例</title> <%--引入css樣式--%> <link href="${baseURL}/webuploader0.1.5/webuploader.css" rel="external nofollow" rel="stylesheet" type="text/css"/> <script src="${baseURL}/ligerui2/jquery/jquery-1.9.0.min.js" type="text/javascript"></script> <%--引入文件上傳插件--%> <script type="text/javascript" src="${baseURL}/webuploader0.1.5/webuploader.min.js"></script> <script type="text/javascript"> $(function(){ /* 對於uploader的創建,最好等dom元素也就是下面的div創建好之後再創建,因為裡面有用到選擇文件按鈕, 不然會創建報錯,這是很容易忽視的地方,故這裡放到$(function(){}來進行創建*/ var uploader = WebUploader.create({ // swf文件路徑swf: '${baseURL}/webuploader0.1.5/Uploader.swf', // 文件接收服務端地址。 server: '${baseURL}/uploadFile2', // [默認值:'file'] 設置文件上傳域的name。 fileVal:'upload', // 選擇文件的按鈕。可選。 // 內部根據當前運行是創建,可能是input元素,也可能是flash. pick: { multiple: false, id: '#filePicker' }, // 上傳並發數。允許同時最大上傳進程數[默認值:3] 即上傳文件數/*這個是關鍵如果開啟了分片上傳並不限制同時上傳的數目會導致後台接受的分片錯亂比如按正常的分片第一片應該是開頭但接收的可能就變成第三片從而順序錯亂這是由於百度webuploader默認允許同時最大上傳進程數為3個所以會導致接受順序錯亂從而重組發生錯誤,故這裡設置為1*/ threads: 1, // 自動上傳修改為手動上傳auto: false, //是否要分片處理大文件上傳。 chunked: true, // 如果要分片,分多大一片? 默認大小為5M. chunkSize: 5 * 1024 * 1024, // 不壓縮image, 默認如果是jpeg,文件上傳前會壓縮一把再上傳! resize: false, formData: { guid: Math.random() //這裡主要用於命名存儲小文件的臨時文件夾} }); //當有文件添加進來的時候uploader.on('fileQueued', function (file) { //重新選擇文件進行清空$("#fileList").html(""); //具體邏輯根據項目需求來寫這裡知識簡單的舉個例子寫下$one = $("<div id='"+file.id+"'>"+file.name+"</div>"); $two = $("<div id='state'>等待上傳......</div>"); $("#fileList").append($one); $("#fileList").append($two); }); // 文件上傳過程中創建進度條實時顯示。 uploader.on('uploadProgress', function (file, percentage) { // 具體邏輯... console.log("uploadProgress===="+percentage); $("#state").text("正在上傳中..."); }); // 文件上傳成功處理。 uploader.on('uploadSuccess', function (file, response) { // 具體邏輯... console.log('upload success.../n'); console.log(uploader.options.formData.guid); console.log(file.name); //合併文件$.post( "${baseURL}/mergeFile", //發送到後台的參數{ guid: uploader.options.formData.guid, chunks: Math.ceil(file.size / (5 * 1024 * 1024)), fileName: file.name }, function(data){ }); $("#state").text("文件上傳成功啦~~~"); }); // 文件上傳失敗處理。 uploader.on('uploadError', function (file) { // 具體邏輯... }); // 上傳傳完畢,不管成功失敗都會調用該事件,主要用於關閉進度條uploader.on('uploadComplete', function (file) { // 具體邏輯... }); //點擊上傳按鈕觸發事件$("#btnClick").click(function(){ uploader.upload(); }); //取消上傳$("#btnCancel").click(function(){ //邏輯處理.. }); }); </script></head><body style="padding:10px"><div id="layout1"> <div id="uploader-demo"> <div id="fileList" ></div> <div id="filePicker" >選擇文件</div> <button id="btnClick">開始上傳</button> <button id="btnCancel">取消上傳</button> </div></div></body></html>後台action:
/** * Description:com.ims.action * Author: Eleven * Date: 2017/12/26 10:50 */@Controller("FileAction")public class FileAction { /*用於接收分割請求的每個小文件的相關參數*/ //記得提供對應的get set方法//上傳文件對象(和表單type=file的name值一致) private File upload; //文件名private String uploadFileName; //上傳類型private String uploadContentType; /** * 以下變量都是public,參數太多,不想設為private再去寫get,set方法了, * 就偷個懶直接用了public了*/ //文件分片序號public String chunk; public String guid;//合併與分割都有用到//用於接收發送合併請求的相關參數public String fileName; //文件名public String chunks; //分割數量//當進行分片上傳文件的時候,每上傳一個小文件就會調用這個方法,這個就跟普通的保存文件沒啥區別的public void uploadFile2() throws Exception{ String str = "D:/upload44/divide/"; //文件保存路徑//保存每個小文件的路徑String realPath = str + guid +"/" + chunk; File tmp =new File(realPath); FileUtils.copyFile(upload, tmp); System.out.println("上傳文件"+uploadFileName+",第幾塊:"+chunk+",大小:"+(upload.length()/1024/1024)+"M"); } //文件合併public void mergeFile() throws Exception{ String path = "D:/upload44/merge/" ; //創建合併文件夾new File(path).mkdir(); //創建合併後的文件File newFile = new File(path + fileName); if(!newFile.exists()){ newFile.createNewFile(); } FileOutputStream outputStream = new FileOutputStream(newFile, true);//文件追加寫入byte[] byt = new byte[10 * 1024 * 1024]; int len; FileInputStream temp = null;//分片文件for (int i = 0; i < Integer.parseInt(chunks); i++) { //"D:/upload44/divide/" + guid + "/" + i 為保存分割後的小文件的路徑temp = new FileInputStream(new File("D:/upload44/divide/" + guid + "/" + i)); while ((len = temp.read(byt)) != -1) { System.out.println(len); outputStream.write(byt, 0, len); } temp.close(); } //當所有追加寫入都寫完才可以關閉流outputStream.close(); //刪除分片文件String path2 = "D:/upload44/divide/" + guid; FileUtils.deleteDirectory(new File(path2));//刪除目錄下所有的內容System.out.println("success!guid=" + guid + ";chunks=" + chunks + ";fileName=" + fileName); } public File getUpload() { return upload; } public void setUpload(File upload) { this.upload = upload; } public String getUploadFileName() { return uploadFileName; } public void setUploadFileName(String uploadFileName) { this.uploadFileName = uploadFileName; } public String getUploadContentType() { return uploadContentType; } public void setUploadContentType(String uploadContentType) { this.uploadContentType = uploadContentType; }}struts.xml配置:
<action name="uploadFile2" method="uploadFile2"></action><action name="mergeFile" method="mergeFile"></action>
好啦,到這裡,一個簡單的文件分片斷點上傳就完成了。
對了補充說明下,後台只是接收了一些簡單的參數而已,而從前台WebUploader傳遞過來的參數當然不止上面那幾個了,所以,可以學會用F12調試模式,進行查看發送的請求,以及相關的請求參數,這裡就不多說了
運行截圖:
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。