jsp教程 使用者上傳頭像、上傳圖片、郵件上傳附件代碼
2. 頁面表單的實現
檔案上傳表單和普通表單有兩個區別
1) 需要檔案上傳欄位 <input type=”file” />
2) form 表單的 enctype 屬性需要指定為 multipart/form-data
3. 伺服器端解析request
在 Servlet 中通過 request.getInputStream 獲得表單上傳資料,會探索資料是分段發送的
由於自己寫程式解析有難度,我們可以使用Apache 開發的開源組件Commons-fileupload
需要匯入 jar 包Commons-fileupload 和Commons-io
4 . UploadServlet 中處理檔案上傳程式
// 1. 建立工廠類
DiskFileItemFactory factory = new DiskFileItemFactory();
// 2. 建立FileUpload對象
ServletFileUpload upload = new ServletFileUpload(factory);
// 3. 判斷是否是上傳表單
boolean b = upload.isMultipartContent(request);
if(!b) {
// 不是檔案上傳
request.setAttribute("message", "對不起,不是檔案上傳表單!");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
// 是檔案上傳表單
// 4. 解析request,獲得FileItem項
List<FileItem> fileitems = upload.parseRequest(request);
// 5. 遍曆集合
for(FileItem item : fileitems) {
// 判斷是不是普通欄位
if(item.isFormField()) {
String name = item.getFieldName();
String value = item.getString();
// 手工的轉換了
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);
// 建立檔案
ServletContext context = getServletContext();
String dir = context.getRealPath("WEN-INF/upload");
File file = new File(dir, filename);
file.createNewFile();
// 獲得流,讀取資料寫入檔案
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(); // 刪除臨時檔案
}
二、 檔案上傳處理細節
1. 中文亂碼問題
1) 檔案名稱中文亂碼問題,解決辦法: 告訴檔案上傳組件以什麼編碼方式來解碼檔案名稱
ServletUpload.setCharacterEncoding(“utf-8”);
request. setCharacterEncoding(“utf-8”);
2) 普通欄位中文亂碼問題
fileitem.getString(“utf-8”);
2. 臨時檔案
對於大檔案不能緩衝在記憶體,需要緩衝到硬碟,為了方便管理,我們需要設定臨時檔案存放目錄
// 設定臨時檔案的存放位置
factory.setRepository(new File("d:/temp"));
檔案上傳完畢需要刪除臨時檔案,否則會導致伺服器存在兩份上傳檔案
// 注意,需要先將流進行關閉,否則會導致臨時檔案無法刪除
out.close();
in.close();
// 刪除臨時檔案
fileitem.delete();
3. 檔案存放目錄
1) 目錄需要隱藏,禁止外界直接存取
2) 檔案名稱需要保證不重複
3) 檔案應該分目錄存放
三、上傳進度條
1. 實現進度監聽
需要實現對檔案上傳進度的監聽,需要給FileUpload 對象添加 ProgressListener
在upload方法中對與進度相關的資料進行處理
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("上傳進度:" + progress + "%");
// request.getSession().setAttribute("progress", progress);
}
});
2. 在 jsp 頁面顯示進度
實驗:
1) 使用 iframe 發送請求, 請求一個Servlet, 在Servlet 中返迴響應,發送自增的num
此時會發現 iframe 會不停第想Servlet發送請求
2) 點擊檔案上傳按鈕後,iframe立刻停止重新整理,直至上傳完畢頁面跳轉至新頁面
3)為了觀察實驗結果,將form 的 target 指定為 iframe, UploadServlet回送上傳完畢的結果
4) 出現上述問題的原因,瀏覽器不支援多線程同時訪問伺服器只能同時發送一個請求,
這樣的訪問方式為同步訪問
5) 要在檔案上傳的同時在iframe中實現進度訪問,就需要ie瀏覽器與伺服器進行非同步互動
此時就需要 XMLHttpRequest 對象
在網頁特效中可以直接使用XMLHttpRequest 對象與伺服器進行非同步通訊
獲得XmlHttpRequest 對象的方式有兩種
ie7以上版本
var xhr = null;
if(window.XMLHttpRequest)
xhr = new XMLHttpRequest();
ie7以下版本
if(window.ActiveXObject)
xhr = new ActiveXObject(“Microsoft.XMLHTTP”);
獲得對象後需要調用open方法輸入請求地址
注意請求方式, 地址的輸入, 並且需要設定為true 指定非同步訪問該地址
xhr.open(“get”,”/upload/servlet/UploadServlet”, false)
// 調用send 方法發送請求,post方式需要發送訊息體,get方式則不用直接傳入null值
xhr.send(null);
// 訪問 responseText 屬性獲得 Servlet 回送的資料
document.write(xhr.responseText);
四、 api方法
1. DiskFileItemFactory 對象
設定緩衝區大小,位元組為單位,預設為10K,一般不用修改
factory.setSizeThreshold(1000);
設定臨時檔案存放目錄
factory.setRepository(file);
2. ServletFileUpload 對象
判斷是否為檔案上傳表單
boolean b = upload.isMultipartContent(request);
解析request對象
List<FileItem> list = upload.parseRequest(request);
設定上傳檔案的最大值
setFileSizeMax(long fileSizeMax)
設定上傳檔案總量的最大值
setSizeMax(long sizeMax)
設定編碼格式
setHeaderEncoding(java.lang.String encoding)
註冊進度監聽器
setProgressListener(ProgressListener pListener)
3. FileItem 對象
獲得表單欄位的屬性名稱
item.getFieldName();
獲得普通欄位的值
item.getString(charsetName)
獲得檔案上傳欄位的檔案名稱
item.getName()
獲得檔案上傳的流
item.getInputStream()
檔案上傳時需要注意的問題:
1.如何設定上傳檔案最大值,並實現超出最大值時給使用者一個友好提示
upload.setFileSizeMax(1024*10); //設定最大值
實現超出最大值時給使用者一個友好提示:在程式中捕獲FileUploadBase.FileSizeLimitExceededException
只要程式拋出這個異常,代表使用者上傳的檔案超出最大值
2.上傳過程中的亂碼問題
2.1 普通輸入項的亂碼
item.getString("碼錶 ")
2.2 上傳檔案名稱的亂碼
ServletFileUpload.setHeaderEncoding("碼錶")
3.上傳檔案的安全性問題
為防止使用者直接上傳檔案,危害伺服器安全,程式應禁止使用者直接存取上傳檔案(即把上傳檔案儲存在使用者無法直接存取的目錄)
4.防止檔案覆蓋(UUID)
5.檔案打散儲存(一個目錄下面不能存超出1000個檔案)
用hash演算法組建目錄儲存
6.設定監聽器,監聽檔案上傳進度
upload.setProgressListener(new ProgressListener(){
public void update(long arg0, long arg1, int arg2) {
System.out.println("當前已上傳" + arg0 + ",當前處理的檔案總大小" + arg1);
}
});
7.臨時檔案的刪除問題
處理完每一個檔案上傳後,一定要記得調用Fileitem.delete方法,刪除臨時檔案
8.限定上傳檔案類型
判斷上傳檔案尾碼名