日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

酷炫的文件上传技术

發(fā)布時(shí)間:2025/4/16 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 酷炫的文件上传技术 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1. JavaWeb:上傳下載文件

http://blog.csdn.net/axi295309066/article/details/52984462

2. 課程概述

在Web應(yīng)用系統(tǒng)開(kāi)發(fā)中,文件上傳功能是非常常用的功能,今天來(lái)主要講講JavaWeb中的文件上傳功能的相關(guān)技術(shù)實(shí)現(xiàn),并且隨著互聯(lián)網(wǎng)技術(shù)的飛速發(fā)展,用戶對(duì)網(wǎng)站的體驗(yàn)要求越來(lái)越高,在文件上傳功能的技術(shù)上也出現(xiàn)許多創(chuàng)新點(diǎn),例如異步上傳文件,拖拽式上傳,黏貼上傳,上傳進(jìn)度監(jiān)控,文件縮略圖,大文件斷點(diǎn)續(xù)傳,大文件秒傳等等。

本課程需要的基礎(chǔ)知識(shí):

  • 了解基本的Http協(xié)議內(nèi)容
  • 基本IO流操作技術(shù)
  • Servlet基礎(chǔ)知識(shí)
    • javascript/jQuery技術(shù)基礎(chǔ)知識(shí)

3. 文件上傳的基礎(chǔ)

對(duì)于文件上傳,瀏覽器在上傳的過(guò)程中是將文件以流的形式提交到服務(wù)器端的,并且所有流數(shù)據(jù)都會(huì)隨著Http請(qǐng)求攜帶到服務(wù)器端。所以,文件上傳時(shí)的請(qǐng)求內(nèi)容格式要能夠基本看懂。

文件上傳頁(yè)面:

<form action="/itheimaUpload/UploadServlet" method="post" enctype="multipart/form-data">請(qǐng)選擇上傳的文件:<input type="file" name="attach"/><br/><input type="submit" value="提交"/></form>

Http請(qǐng)求內(nèi)容:

4. Java后臺(tái)使用Servlet接收文件

如果使用Servlet獲取上傳文件的輸入流然后再解析里面的請(qǐng)求參數(shù)是比較麻煩,所以一般后臺(tái)選擇采用Apache的開(kāi)源工具common-fileupload這個(gè)文件上傳組件。

//Java后臺(tái)代碼:Commons-fileUpload組件上傳文件 public class UploadServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//1.配置緩存DiskFileItemFactory factory = new DiskFileItemFactory(1*1024*1024,new File("c:/tempFiles/"));//2.創(chuàng)建ServleFileUpload對(duì)象ServletFileUpload sfu = new ServletFileUpload(factory);//解決文件名稱中文問(wèn)題sfu.setHeaderEncoding("utf-8");//3.解析try {List<FileItem> list = sfu.parseRequest(request);//解析所有內(nèi)容if(list!=null){for(FileItem item:list){//判斷是否為普通表單參數(shù)if(item.isFormField()){//普通表單參數(shù)//獲取表單的name屬性名稱String fieldName = item.getFieldName();//獲取表單參數(shù)值String value = item.getString("utf-8");}else{//文件if(item.getName()!=null && !item.getName().equals("")) {//保存到服務(wù)器硬盤(pán) FileUtils.copyInputStreamToFile(item.getInputStream(), new File("c:/targetFiles/"+item.getName()));item.delete();}}}}} catch (FileUploadException e) {e.printStackTrace();}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);} }

5. 使用WebUploader上傳組件

文件上傳頁(yè)面的前端我們可以選擇使用一些比較好用的上傳組件,例如百度的開(kāi)源組件WebUploader,這個(gè)組件基本能滿足文件上傳的一些日常所需功能,如異步上傳文件,拖拽式上傳,黏貼上傳,上傳進(jìn)度監(jiān)控,文件縮略圖,甚至是大文件斷點(diǎn)續(xù)傳,大文件秒傳。

5.1 下載WebUpload組件

http://fex.baidu.com/webuploader/ 到WebUpload官網(wǎng)下載WebUpload包

WebUpload目錄結(jié)構(gòu):

5.2 基本文件上傳Demo(包含上傳進(jìn)度)

前端

1.1 在頁(yè)面導(dǎo)入所需css,js

<link rel="stylesheet" type="text/css"href="${pageContext.request.contextPath}/css/webuploader.css"> <script type="text/javascript"src="${pageContext.request.contextPath }/js/jquery-1.10.2.min.js"></script> <script type="text/javascript"src="${pageContext.request.contextPath }/js/webuploader.js"></script>

1.2 編寫(xiě)上傳頁(yè)面標(biāo)簽

<!-- 上傳div --><div id="uploader"><!-- 顯示文件列表信息 --><ul id="fileList"></ul><!-- 選擇文件區(qū)域 --><div id="filePicker">點(diǎn)擊選擇文件</div></div>

1.3 編寫(xiě)webupload代碼

<script type="text/javascript">//1.初始化WebUpload,以及配置全局的參數(shù)var uploader = WebUploader.create({//flashk控件的地址swf: "${pageContext.request.contextPath}/js/Uploader.swf",//后臺(tái)提交地址server:"${pageContext.request.contextPath}/UploadServlet",//選擇文件控件的標(biāo)簽pick:"#filePicker",//自動(dòng)上傳文件auto:true,});//2.選擇文件后,文件信息隊(duì)列展示// 注冊(cè)fileQueued事件:當(dāng)文件加入隊(duì)列后觸發(fā)// file: 代表當(dāng)前選擇的文件uploader.on("fileQueued",function(file){//追加文件信息div$("#fileList").append("<div id='"+file.id+"' class='fileInfo'><span>"+file.name+"</span><div class='state'>等待上傳...</div><span class='text'></span></div>");});//3.注冊(cè)上傳進(jìn)度監(jiān)聽(tīng)//file: 正在上傳的文件//percentage: 當(dāng)前進(jìn)度的比例。最大為1.例如:0.2uploader.on("uploadProgress",function(file,percentage){var id = $("#"+file.id);//更新?tīng)顟B(tài)信息id.find("div.state").text("上傳中...");//更新上傳百分比id.find("span.text").text(Math.round(percentage*100)+"%");});//4.注冊(cè)上傳完畢監(jiān)聽(tīng)//file:上傳完畢的文件//response:后臺(tái)回送的數(shù)據(jù),以json格式返回uploader.on("uploadSuccess",function(file,response){//更新?tīng)顟B(tài)信息$("#"+file.id).find("div.state").text("上傳完畢");});

2)后端Servlet代碼

DiskFileItemFactory factory = new DiskFileItemFactory();ServletFileUpload sfu = new ServletFileUpload(factory);sfu.setHeaderEncoding("utf-8");try {List<FileItem> items = sfu.parseRequest(request);for(FileItem item:items){if(item.isFormField()){//普通信息}else{//文件信息//判斷只有文件才需要進(jìn)行保存處理System.out.println("接收的文件名稱:"+item.getName());//拷貝文件到后臺(tái)的硬盤(pán)FileUtils.copyInputStreamToFile(item.getInputStream(), new File(serverPath+"/"+item.getName()));System.out.println("文件保存成功");}}} catch (FileUploadException e) {e.printStackTrace();}

5.3 生成圖片縮略圖

關(guān)鍵點(diǎn):調(diào)用uploader.makeThumb()方法生成縮略圖

uploader.on("fileQueued",function(file){//追加文件信息div$("#fileList").append("<div id='"+file.id+"' class='fileInfo'><img/><span>"+file.name+"</span><div class='state'>等待上傳...</div><span class='text'></span></div>");//制造圖片縮略圖:調(diào)用makeThumb()方法//error: 制造縮略圖失敗//src: 縮略圖的路徑uploader.makeThumb(file,function(error,src){var id = $("#"+file.id);//如果失敗,則顯示“不能預(yù)覽”if(error){id.find("img").replaceWith("不能預(yù)覽");}//成功,則顯示縮略圖到指定位置id.find("img").attr("src",src); });});

5.4 拖拽,黏貼上傳

1)頁(yè)面添加拖拽區(qū)域的div

<!-- 上傳div --><div id="uploader"><!-- 文件拖拽區(qū)域 --><div id="dndArea"><p>將文件直接拖拽到這里即可自動(dòng)上傳</p></div><!-- 顯示文件列表信息 --><ul id="fileList"></ul><!-- 選擇文件區(qū)域 --><div id="filePicker">點(diǎn)擊選擇文件</div></div>

2)在webuploader的全局配置參數(shù)添加拖拽功能的參數(shù)

//1.初始化WebUpload,以及配置全局的參數(shù)var uploader = WebUploader.create({//flashk控件的地址swf: "${pageContext.request.contextPath}/js/Uploader.swf",//后臺(tái)提交地址server:"${pageContext.request.contextPath}/UploadServlet",//選擇文件控件的標(biāo)簽pick:"#filePicker",//自動(dòng)上傳文件auto:true,//開(kāi)啟拖拽功能,指定拖拽區(qū)域dnd:"#dndArea",//禁用頁(yè)面其他地方的拖拽功能,防止頁(yè)面直接打開(kāi)文件disableGlobalDnd:true//開(kāi)啟黏貼功能paste:"#uploader"});

5.5 大文件分塊上傳

1)在webuploader全局參數(shù)中添加分塊上傳參數(shù)

//1.初始化WebUpload,以及配置全局的參數(shù)var uploader = WebUploader.create({//flashk控件的地址swf: "${pageContext.request.contextPath}/js/Uploader.swf",//后臺(tái)提交地址server:"${pageContext.request.contextPath}/UploadServlet",//選擇文件控件的標(biāo)簽pick:"#filePicker",//自動(dòng)上傳文件auto:true,//開(kāi)啟拖拽功能,指定拖拽區(qū)域dnd:"#dndArea",//禁用頁(yè)面其他地方的拖拽功能,防止頁(yè)面直接打開(kāi)文件disableGlobalDnd:true,//開(kāi)啟黏貼功能paste:"#uploader",//分塊上傳設(shè)置//是否分塊上傳chunked:true,//每塊文件大小(默認(rèn)5M)chunkSize:5*1024*1024,//開(kāi)啟幾個(gè)并發(fā)線程(默認(rèn)3個(gè))threads:3,//在上傳當(dāng)前文件時(shí),準(zhǔn)備好下一個(gè)文件prepareNextFile:true});

2)監(jiān)控上傳文件的三個(gè)時(shí)間點(diǎn)

添加以上三個(gè)配置后,會(huì)發(fā)現(xiàn)當(dāng)文件超過(guò)5M時(shí),webuploader自動(dòng)把文件會(huì)分幾個(gè)請(qǐng)求發(fā)送給后臺(tái)

每個(gè)分塊請(qǐng)求,包含的信息:

可以監(jiān)聽(tīng)文件分塊上傳的三個(gè)重要的時(shí)間點(diǎn)。

before-send-file : 在所有分塊發(fā)送之前調(diào)用
before-send: 如果有分塊,在每個(gè)分塊發(fā)送之前調(diào)用
after-send-file: 在所有分塊發(fā)送完成之后調(diào)用

//5.監(jiān)控文件上傳的三個(gè)時(shí)間點(diǎn)(注意:該段代碼必須放在WebUploader.create之前)//時(shí)間點(diǎn)1::所有分塊進(jìn)行上傳之前(1.可以計(jì)算文件的唯一標(biāo)記;2.可以判斷是否秒傳) //時(shí)間點(diǎn)2: 如果分塊上傳,每個(gè)分塊上傳之前(1.詢問(wèn)后臺(tái)該分塊是否已經(jīng)保存成功,用于斷點(diǎn)續(xù)傳)//時(shí)間點(diǎn)3:所有分塊上傳成功之后(1.通知后臺(tái)進(jìn)行分塊文件的合并工作)WebUploader.Uploader.register({"before-send-file":"beforeSendFile","before-send":"beforeSend","after-send-file":"afterSendFile"},{//時(shí)間點(diǎn)1::所有分塊進(jìn)行上傳之前調(diào)用此函數(shù)beforeSendFile:function(){//1.計(jì)算文件的唯一標(biāo)記,用于斷點(diǎn)續(xù)傳和秒傳//2.請(qǐng)求后臺(tái)是否保存過(guò)該文件,如果存在,則跳過(guò)該文件,實(shí)現(xiàn)秒傳功能},//時(shí)間點(diǎn)2:如果有分塊上傳,則 每個(gè)分塊上傳之前調(diào)用此函數(shù)beforeSend:function(){//1.請(qǐng)求后臺(tái)是否保存過(guò)當(dāng)前分塊,如果存在,則跳過(guò)該分塊文件,實(shí)現(xiàn)斷點(diǎn)續(xù)傳功能},//時(shí)間點(diǎn)3:所有分塊上傳成功之后調(diào)用此函數(shù)afterSendFile:function(){//1.如果分塊上傳,則通過(guò)后臺(tái)合并所有分塊文件}});

before-send-file邏輯:

//利用md5File()方法計(jì)算文件的唯一標(biāo)記符//該函數(shù)接收一個(gè)deferredbeforeSendFile:function(file){//創(chuàng)建一個(gè)defferedvar deferred = WebUploader.Deferred();//1.計(jì)算文件的唯一標(biāo)記,用于斷點(diǎn)續(xù)傳和秒傳(new WebUploader.Uploader()).md5File(file,0,5*1024*1024).progress(function(percentage){$("#"+file.id).find("div.state").text("正在獲取文件信息...");}).then(function(val){uniqueFileTag = val;$("#"+file.id).find("div.state").text("成功獲取文件信息");//只有文件信息獲取成功,才進(jìn)行下一步操作deferred.resolve();});//alert(uniqueFileTag);//2.請(qǐng)求后臺(tái)是否保存過(guò)該文件,如果存在,則跳過(guò)該文件,實(shí)現(xiàn)秒傳功能//返回defferedreturn deferred.promise();}

before-send邏輯:

//向后臺(tái)發(fā)送當(dāng)前文件的唯一標(biāo)記,用于后臺(tái)創(chuàng)建保存分塊文件的目錄beforeSend:function(){//攜帶當(dāng)前文件的唯一標(biāo)記到后臺(tái),用于讓后臺(tái)創(chuàng)建保存該文件分塊的目錄this.owner.options.formData.fileMd5 = fileMd5; }

3)后臺(tái)需要保存所有分塊文件

//為每個(gè)文件創(chuàng)建一個(gè)目錄,并保存這個(gè)文件的所有分塊文件//判斷是否已經(jīng)分塊上傳if(chunks!=null){System.out.println("分塊處理...");//進(jìn)行分塊上傳了//建立一個(gè)臨時(shí)目錄,用于保存所有分塊文件File chunksDir = new File(serverPath+"/"+fileMd5);if(!chunksDir.exists()){chunksDir.mkdir();}if(chunk!=null){//保存分塊文件File chunkFile = new File(chunksDir.getPath()+"/"+chunk);FileUtils.copyInputStreamToFile(item.getInputStream(), chunkFile);}

4)前臺(tái)通知后臺(tái)合并所有分塊文件

//前臺(tái)通知后臺(tái)合并文件 after-send-file邏輯:afterSendFile:function(file){//1.如果分塊上傳,則通過(guò)后臺(tái)合并所有分塊文件//請(qǐng)求后臺(tái)合并文件$.ajax({type:"POST",url:"${pageContext.request.contextPath}/UploadCheckServlet?action=mergeChunks",data:{//文件唯一標(biāo)記fileMd5:fileMd5,//文件名稱fileName:file.name},dataType:"json",success:function(response){alert(response.msg);}});}//后臺(tái)合并所有分塊文件if("mergeChunks".equals(action)){System.out.println("開(kāi)始合并文件...");//合并文件String fileMd5 = request.getParameter("fileMd5");String fileName = request.getParameter("fileName");//讀取目錄里面的所有文件File f = new File(serverPath+"/"+fileMd5);File[] fileArray = f.listFiles(new FileFilter(){//排除目錄,只要文件public boolean accept(File pathname) {if(pathname.isDirectory()){return false;}return true;}});//轉(zhuǎn)成集合,便于排序List<File> fileList = new ArrayList<File>(Arrays.asList(fileArray));//從小到大排序Collections.sort(fileList, new Comparator<File>() {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+"/"+fileName);//創(chuàng)建文件outputFile.createNewFile();//輸出流FileChannel outChannel = new FileOutputStream(outputFile).getChannel();//合并FileChannel inChannel;for(File file : fileList){inChannel = new FileInputStream(file).getChannel();inChannel.transferTo(0, inChannel.size(), outChannel);inChannel.close();//刪除分片file.delete();}//清除文件夾File tempFile = new File(serverPath+"/"+fileMd5);if(tempFile.isDirectory() && tempFile.exists()){tempFile.delete();}//關(guān)閉流outChannel.close();response.setContentType("text/html;charset=utf-8");response.getWriter().write("{\"msg\":\"合并成功\"}");}

5.6 大文件斷點(diǎn)續(xù)傳

在實(shí)現(xiàn)了分塊上傳的基礎(chǔ)上,實(shí)現(xiàn)斷點(diǎn)續(xù)傳就非常簡(jiǎn)單了!!!

前端:

//時(shí)間點(diǎn)2:如果有分塊上傳,則 每個(gè)分塊上傳之前調(diào)用此函數(shù)//block:代表當(dāng)前分塊對(duì)象beforeSend:function(block){//1.請(qǐng)求后臺(tái)是否保存過(guò)當(dāng)前分塊,如果存在,則跳過(guò)該分塊文件,實(shí)現(xiàn)斷點(diǎn)續(xù)傳功能var deferred = WebUploader.Deferred();//請(qǐng)求后臺(tái)是否保存完成該文件信息,如果保存過(guò),則跳過(guò),如果沒(méi)有,則發(fā)送該分塊內(nèi)容$.ajax({type:"POST",url:"${pageContext.request.contextPath}/UploadCheckServlet?action=checkChunk",data:{//文件唯一標(biāo)記fileMd5:fileMd5,//當(dāng)前分塊下標(biāo)chunk:block.chunk,//當(dāng)前分塊大小chunkSize:block.end-block.start},dataType:"json",success:function(response){if(response.ifExist){//分塊存在,跳過(guò)該分塊deferred.reject();}else{//分塊不存在或者不完整,重新發(fā)送該分塊內(nèi)容deferred.resolve();}}});//攜帶當(dāng)前文件的唯一標(biāo)記到后臺(tái),用于讓后臺(tái)創(chuàng)建保存該文件分塊的目錄this.owner.options.formData.fileMd5 = fileMd5;return deferred.promise(); },

后臺(tái):

//檢查該分塊是否存在或者完整保存private void checkChunk(HttpServletRequest request,HttpServletResponse response) throws IOException,FileNotFoundException {System.out.println("checkChunk...");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}");}}

5.7 文件秒傳

在所有分塊請(qǐng)求之前,就已經(jīng)可以進(jìn)行實(shí)現(xiàn)秒傳功能!!!

前端:

beforeSendFile:function(file){//創(chuàng)建一個(gè)defferedvar deferred = WebUploader.Deferred();//1.計(jì)算文件的唯一標(biāo)記,用于斷點(diǎn)續(xù)傳和秒傳(new WebUploader.Uploader()).md5File(file,0,5*1024*1024).progress(function(percentage){$("#"+file.id).find("div.state").text("正在獲取文件信息...");}).then(function(val){fileMd5 = val;$("#"+file.id).find("div.state").text("成功獲取文件信息");//2.請(qǐng)求后臺(tái)是否保存過(guò)該文件,如果存在,則跳過(guò)該文件,實(shí)現(xiàn)秒傳功能$.ajax({type:"POST",url:"${pageContext.request.contextPath}/UploadCheckServlet?action=fileCheck",data:{//文件唯一標(biāo)記fileMd5:fileMd5},dataType:"json",success:function(response){if(response.ifExist){$("#"+file.id).find("div.state").text("秒傳成功");//如果存在,則跳過(guò)該文件,秒傳成功deferred.reject();}else{//繼續(xù)上傳deferred.resolve();}}});});//返回defferedreturn deferred.promise();},

后臺(tái):

//檢查文件的md5數(shù)據(jù)是否跟在數(shù)據(jù)庫(kù)存在private void fileCheck(HttpServletRequest request,HttpServletResponse response) throws IOException,FileNotFoundException {String fileMd5 = request.getParameter("fileMd5");//模擬數(shù)據(jù)庫(kù)Map<String,String> database = new HashMap<String,String>();database.put("576018603f4091782b68b78af85704a1", "01.課程回顧.itcast");response.setContentType("text/html;charset=utf-8");if(database.containsKey(fileMd5)){response.getWriter().write("{\"ifExist\":1}");}else{response.getWriter().write("{\"ifExist\":0}");}}

總結(jié)

以上是生活随笔為你收集整理的酷炫的文件上传技术的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。