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.限定上傳文件類型
判斷上傳文件後綴名