18-文件上传
一、文件上傳入門(mén)
1. 應(yīng)用:
?用戶上傳頭像、上傳圖片、郵件上傳附件等
2. 頁(yè)面表單的實(shí)現(xiàn)
??? 文件上傳表單和普通表單有兩個(gè)區(qū)別
??? 1) 需要文件上傳字段? <input type=”file” />
??? 2) form 表單的 enctype 屬性需要指定為 multipart/form-data
3. 服務(wù)器端解析request
??? 在 Servlet 中通過(guò) request.getInputStream 獲得表單上傳數(shù)據(jù),會(huì)發(fā)現(xiàn)數(shù)據(jù)是分段發(fā)送的
由于自己寫(xiě)程序解析有難度,我們可以使用Apache 開(kāi)發(fā)的開(kāi)源組件Commons-fileupload
需要導(dǎo)入 jar 包Commons-fileupload 和Commons-io
4 . UploadServlet 中處理文件上傳程序
?
// 1. 創(chuàng)建工廠類(lèi)
DiskFileItemFactory factory = new DiskFileItemFactory();
// 2. 創(chuàng)建FileUpload對(duì)象
ServletFileUpload upload = new ServletFileUpload(factory);
// 3. 判斷是否是上傳表單
boolean b = upload.isMultipartContent(request);
if(!b) {
??? // 不是文件上傳
request.setAttribute("message", "對(duì)不起,不是文件上傳表單!");
request.getRequestDispatcher("/message.jsp").forward(request, response);
??? return;
}
// 是文件上傳表單
// 4. 解析request,獲得FileItem項(xiàng)
List<FileItem> fileitems = upload.parseRequest(request);
// 5. 遍歷集合
for(FileItem item : fileitems) {
??? // 判斷是不是普通字段
if(item.isFormField()) {
??? String name = item.getFieldName();
??? String value = item.getString();
??? // 手工的轉(zhuǎn)換了
??? value = new String(value.getBytes("iso-8859-1"),"utf-8");
??? System.out.println(name + "=" + value);
} else {
??? // 文件上傳字段
??? // 獲得文件名
??? String filename = item.getName();
??? System.out.println(filename);
??? filename = filename.substring(filename.lastIndexOf("\\")+1);
???
??? System.out.println(filename);
??? // 創(chuàng)建文件
??? ServletContext context = getServletContext();
??? String dir = context.getRealPath("WEN-INF/upload");
??? File file = new File(dir, filename);
??? file.createNewFile();
???
??? // 獲得流,讀取數(shù)據(jù)寫(xiě)入文件
??? InputStream in = item.getInputStream();
??? FileOutputStream fos = new FileOutputStream(file);
???
??? int len;
??? byte[] buffer = new byte[1024];
??? while((len=in.read(buffer))>0)
?????? fos.write(buffer,0,len);
??? fos.close();
??? in.close();
??? item.delete();??? // 刪除臨時(shí)文件
}
?
?
二、 文件上傳處理細(xì)節(jié)
1. 中文亂碼問(wèn)題
??? 1) 文件名中文亂碼問(wèn)題,解決辦法: 告訴文件上傳組件以什么編碼方式來(lái)解碼文件名
?????? ServletUpload.setCharacterEncoding(“utf-8”);
?????? request. setCharacterEncoding(“utf-8”);
????
??? 2) 普通字段中文亂碼問(wèn)題
?????? fileitem.getString(“utf-8”);??????
?
2. ? 臨時(shí)文件
??? 對(duì)于大文件不能緩存在內(nèi)存,需要緩存到硬盤(pán),為了方便管理,我們需要設(shè)置臨時(shí)文件存放目錄
??? // 設(shè)置臨時(shí)文件的存放位置
factory.setRepository(new File("d:/temp"));
?
??? 文件上傳完畢需要?jiǎng)h除臨時(shí)文件,否則會(huì)導(dǎo)致服務(wù)器存在兩份上傳文件
// 注意,需要先將流進(jìn)行關(guān)閉,否則會(huì)導(dǎo)致臨時(shí)文件無(wú)法刪除
out.close();
in.close();
// 刪除臨時(shí)文件
fileitem.delete();
?
3. 文件存放目錄
??? 1) 目錄需要隱藏,禁止外界直接訪問(wèn)
??? 2) 文件名需要保證不重復(fù)
??? 3) 文件應(yīng)該分目錄存放
?
三、上傳進(jìn)度條
1. 實(shí)現(xiàn)進(jìn)度監(jiān)聽(tīng)
??? 需要實(shí)現(xiàn)對(duì)文件上傳進(jìn)度的監(jiān)聽(tīng),需要給FileUpload 對(duì)象添加 ProgressListener
??? 在upload方法中對(duì)與進(jìn)度相關(guān)的數(shù)據(jù)進(jìn)行處理
??? upload.setProgressListener(new ProgressListener() {
??? long num = 0;
??? public void update(long bytesRead, long contentLength, int items) {
??????
??? ??? ??? long progress = bytesRead*100/contentLength;
?????? ??? if(progress==num)
?????????? ??? return;
?????? ??? num = progress;
?????? ??? System.out.println("上傳進(jìn)度:" + progress + "%");
??????
??? ??? //? request.getSession().setAttribute("progress", progress);
??? ??? }
??? });
?
2. 在 jsp 頁(yè)面顯示進(jìn)度
??? 實(shí)驗(yàn):?
??? 1) 使用 iframe 發(fā)送請(qǐng)求, 請(qǐng)求一個(gè)Servlet, 在Servlet 中返回響應(yīng),發(fā)送自增的num
?????? 此時(shí)會(huì)發(fā)現(xiàn) iframe 會(huì)不停第想Servlet發(fā)送請(qǐng)求
??? 2) 點(diǎn)擊文件上傳按鈕后,iframe立刻停止刷新,直至上傳完畢頁(yè)面跳轉(zhuǎn)至新頁(yè)面
??? 3)為了觀察實(shí)驗(yàn)結(jié)果,將form 的 target 指定為 iframe, UploadServlet回送上傳完畢的結(jié)果
??? 4) 出現(xiàn)上述問(wèn)題的原因,瀏覽器不支持多線程同時(shí)訪問(wèn)服務(wù)器只能同時(shí)發(fā)送一個(gè)請(qǐng)求,
?????? 這樣的訪問(wèn)方式為同步訪問(wèn)
??? 5) 要在文件上傳的同時(shí)在iframe中實(shí)現(xiàn)進(jìn)度訪問(wèn),就需要ie瀏覽器與服務(wù)器進(jìn)行異步交互
?????? 此時(shí)就需要 XMLHttpRequest 對(duì)象
?????? 在javascript中可以直接使用XMLHttpRequest 對(duì)象與服務(wù)器進(jìn)行異步通信
?????? 獲得XmlHttpRequest 對(duì)象的方式有兩種
?????? ie7以上版本
?????? var xhr = null;
?????? if(window.XMLHttpRequest)
?????????? xhr = new XMLHttpRequest();
?????? ie7以下版本
?????? if(window.ActiveXObject)
?????????? xhr = new ActiveXObject(“Microsoft.XMLHTTP”);
??????
?????? 獲得對(duì)象后需要調(diào)用open方法輸入請(qǐng)求地址
?????? 注意請(qǐng)求方式, 地址的輸入, 并且需要設(shè)置為true 指定異步訪問(wèn)該地址
?????? xhr.open(“get”,”/upload/servlet/UploadServlet”, false)
??????
?????? // 調(diào)用send 方法發(fā)送請(qǐng)求,post方式需要發(fā)送消息體,get方式則不用直接傳入null值
?????? xhr.send(null);
??????
?????? // 訪問(wèn) responseText 屬性獲得 Servlet 回送的數(shù)據(jù)
?????? document.write(xhr.responseText);
?
四、 api方法
1. DiskFileItemFactory 對(duì)象
??? 設(shè)置緩沖區(qū)大小,字節(jié)為單位,默認(rèn)為10K,一般不用修改
??? factory.setSizeThreshold(1000);
??? 設(shè)置臨時(shí)文件存放目錄
??? factory.setRepository(file);
?
2. ServletFileUpload 對(duì)象
??? 判斷是否為文件上傳表單
??? boolean b = upload.isMultipartContent(request);
?? 解析request對(duì)象
?? List<FileItem> list = upload.parseRequest(request);
?? 設(shè)置上傳文件的最大值
??? setFileSizeMax(long?fileSizeMax)
??? 設(shè)置上傳文件總量的最大值
??? setSizeMax(long?sizeMax)
??? 設(shè)置編碼格式
??? setHeaderEncoding(java.lang.String?encoding)
??? 注冊(cè)進(jìn)度監(jiān)聽(tīng)器
??? setProgressListener(ProgressListener?pListener)
?
3. FileItem 對(duì)象
??? 獲得表單字段的屬性名
??? item.getFieldName();
??? 獲得普通字段的值
??? item.getString(charsetName)
??? 獲得文件上傳字段的文件名
??? item.getName()
??? 獲得文件上傳的流
??? item.getInputStream()
??
?
總結(jié)
- 上一篇: 单兵数字化装备中武器分系统主要部件包括(
- 下一篇: 19-过滤器