基于表單的文件上傳 2010-04-05 21:13:27
- 如果在表單中使用表單元素 <input type=“file” />,瀏覽器在解析表單時,,會自動生成一個輸入框和一個按鈕,輸入框可供用戶填寫本地文件的文件名和路徑名,,按鈕可以讓瀏覽器打開一個文件選擇框供用戶選擇文件:
-
-
-
- 當(dāng)表單需要上傳文件時,,需指定表單 enctype 的值為 multipart/form-data
-
- 在 form 元素的語法中,enctype 屬性指定將數(shù)據(jù)發(fā)送到服務(wù)器時瀏覽器使用的編碼類型,。
-
- enctype 屬性取值:
-
- application/x-www-form-urlencoded:表單 enctype 屬性的默認(rèn)值,。這種編碼方案使用有限的字符集,當(dāng)使用了非字母和數(shù)字時,,必須用”%HH”代替(H 代表十六進(jìn)制數(shù)字),。對于大容量的二進(jìn)制數(shù)據(jù)或包含非 ASCII 字符的文本來說,這種編碼不能滿足要求,。
-
- multipart/form-data:form 設(shè)定了enctype=“multipart/form-data”屬性后,,表示表單以二進(jìn)制傳輸數(shù)據(jù) .
-
-
-
- Commons-fileupload 組件上傳的基本原理
-
- FileUpload組件將頁面提交的所有元素(普通form表單域,,如text和文件域file)都看作一樣的FileItem,這樣上傳頁面提交的 request請求也就是一個FileItem的有序組合,,F(xiàn)ileUpload組件可以解析該request,,并返回一個一個的FileItem。而對每一個FileItem,,F(xiàn)ileUpload組件可以判斷出它是普通form表單域還是文件file域,,從而根據(jù)不同的類型,采取不同的操作--如果是表單域,,就讀出其值,,如果是文件域,就保存文件到服務(wù)器硬盤上或者內(nèi)存中
-
-
-
- Commons-fileupload 組件API
-
- ServletFileUpload 負(fù)責(zé)處理上傳的文件數(shù)據(jù),,并將每部分的數(shù)據(jù)封裝成一到 FileItem 對象中,。
-
- DiskFileItemFactory 是創(chuàng)建 FileItem 對象的工廠,在這個工廠類中可以配置內(nèi)存緩沖區(qū)大小和存放臨時文件的目錄,。
-
- ServletFileUpload 在接收上傳文件數(shù)據(jù)時,,會將內(nèi)容保存到內(nèi)存緩存區(qū)中,如果文件內(nèi)容超過了 DiskFileItemFactory 指定的緩沖區(qū)的大小,,那么文件將被保存到磁盤上,,存儲為 DiskFileItemFactory 指定目錄中的臨時文件。等文件數(shù)據(jù)都接收完畢后,,ServletUpload 在從文件中將數(shù)據(jù)寫入到上傳文件目錄下的文件中
-
-
-
-
-
- 進(jìn)行文件上傳和下載的具體操作:
-
- 首先,,加載必要的jar包:“commons-fileupload-1.2.1.jar”,“commons-io-1.4.jar”
-
- 步驟:
-
- 0. 創(chuàng)建 FileItemFactory 子類 DiskFileItemFactory 的對象
-
- 1.為了得到 ServletFileUpload 對象, 先需要得到 FileItemFactory 的一個對象, 然后調(diào)用 new ServletFileUpload(FileItemFactory fif); 方法得到 ServletFileUpload 對象
-
- 2.為了得到 FileItem 的集合,, 先需要得到 ServletFileUpload 對象,, 然后調(diào)用該對象的 parseRequest() 方法得到 FileItem 的 List
-
- 3.從 HttpServletRequest 對象中得到 FileItem 的集合
-
- 4. 對上述集合進(jìn)行遍歷:判斷是表單域還是文件域
-
-
-
- 下面是對文件上傳相關(guān)操作的代碼示例。
-
-
-
- boolean isMultipart = ServletFileUpload.isMultipartContent(request);
-
-
-
-
-
- if(!isMultipart){
-
- response.getWriter().println("沒有文件域");
-
- return;
-
- }
-
-
-
-
-
-
-
-
-
- DiskFileItemFactory itemFactory = new DiskFileItemFactory();
-
-
-
-
-
- ServletFileUpload fileUpload = new ServletFileUpload();
-
- fileUpload.setFileItemFactory(itemFactory);
-
- 設(shè)置上傳文件的最大大小
-
- fileUpload.setFileSizeMax(1000 * 100);
-
-
-
- String forwardPage = null;
-
-
-
- try {
-
-
-
- List<FileItem> items = fileUpload.parseRequest(request);
-
-
-
- Map<String, String> paramMap = new HashMap<String, String>();
-
- FileItem fileItem = null;
-
-
-
-
-
- Iterator<FileItem> it = items.iterator();
-
- while(it.hasNext()){
-
- FileItem item = it.next();
-
-
-
- if(item.isFormField()){
-
-
-
- 獲得表單中該字段的字段名
-
- String fieldName = item.getFieldName();
-
- 獲得表單中與上面字段名對應(yīng)的字段值
-
- String value = item.getString("UTF-8");
-
-
-
- paramMap.put(fieldName, value);
-
- }
-
-
-
- else{
-
- 這里獲得了與file對應(yīng)的FileItem對象
-
- fileItem = item;
-
- }
-
-
-
- }
-
-
-
-
-
-
-
- String path = null;
-
-
-
- path = this.getServletContext().getRealPath("/photoes");
-
-
-
- File photoesDir = new File(path);
-
- if(!photoesDir.exists()){
-
- photoesDir.mkdir();
-
- }
-
-
-
- path = path + "/" + paramMap.get("username");
-
-
-
- File file = new File(path + ".jpg");
-
-
-
-
-
- fileItem.write(file);
-
-
-
- 上傳文件表單的兩個準(zhǔn)備工作
-
- 1. 提交方式改為 POST
-
- 2. enctype 屬性的取值改為 multipart/form-data
-
-
-
- 在獲取表單值時
-
- 1. 不能使用 request.getParameter() 方法, 因為該方法僅能獲取字符串, 對二進(jìn)制無能為力.
-
- 2. 使用 fileUpload 組件讀取上傳文件及表單域字段.
-
-
-
- fileUpload 組件的核心思想
-
- fileUpload 組件認(rèn)為: 所有的表單域(包含文件域和文本域)都是 FileItem 對象.
-
- 步驟:
-
- 1. 獲取 FileItem 對象組成的 List
-
- 2. 對 List 進(jìn)行遍歷
-
- 3. 判斷每一個 FileItem 對象是表單域 還是 文件域, 以進(jìn)行不同的處理.
-
-
-
- 詳細(xì)步驟:
-
- 1. 檢查表單的 enctype 是否為 multipart/form-data, 以決定是否使用 FileUpload 組件進(jìn)行解析請求
-
- 2. 若表單的 enctype 是否為 multipart/form-data, 則需要獲取 封裝了所有表單域 的對應(yīng)的 FileItem 對象的 List: List<FileItem> list = null;
-
- 3) 獲取 ServletFileUpload 對象, 調(diào)用該對象的 public java.util.List parseRequest(javax.servlet.http.HttpServletRequest request)
-
- 方法獲取封裝 FileItem 的List
-
- 2) 需要使用 ServletFileUpload 的構(gòu)造器來創(chuàng)建 ServletFileUpload 對象:
-
- ^ 使用任意一個構(gòu)造器都可以得到 ServletFileUpload 對象, 但都需要先得到 FileItemFactory 對象
-
- * ServletFileUpload upload = new ServletFileUpload();
-
- upload.setFileItemFactory(factory);
-
- * ServletFileUpload upload = new ServletFileUpload(factory);
-
- 1) 創(chuàng)建 FileItemFactory 接口是想類對象: DiskFileItemFactory, 直接創(chuàng)建該對象.
-
- 3. 可以調(diào)用 DiskFileItemFactory 的相關(guān)方法來對文件上傳進(jìn)行一些優(yōu)化:
-
- 1) setSizeThreshold(int sizeThreshold):設(shè)置使用臨時文件夾的大小.
-
- 2) setRepository(): 設(shè)置臨時文件夾
-
- 4. 可以調(diào)用 ServletUpload 的方法進(jìn)行文件上傳的一些控制
-
- 1) setFileSizeMax: 設(shè)置單個文件的最大上傳值
-
- 2) setSizeMax:設(shè)置總上傳文件的最大值, 以 byte 為單位.
-
- 5. 關(guān)于中文亂碼的問題:
-
- 1) 在解析 request 之前: request.setCharacterEncoding("UTF-8"); 可以解決文件域的亂碼問題
-
- 2) 在解析表單域時需要使用: new String(value.getBytes("iso-8859-1"), "UTF-8"); 解決中文亂碼問題.
-
- 但是有時候,,即使我們按照上面方式設(shè)置了,可以還是中文亂碼,,這個時候問題多半就出在tomcat的配置上了,,打開tomcat的service.xml文件,在那里面注意下面部分
-
- <Connector port="8989" protocol="HTTP/1.1"
-
- connectionTimeout="20000"
-
- redirectPort="8443" useBodyEncodingForURI="true"/>
-
- 只有加上了紅色部分的設(shè)置,,我們在程序中配置EncodingUrl才能起作用,。
-
-
-
- 下面一段代碼是文件下載的相關(guān)操作
-
-
-
-
-
-
-
- response.setContentType("application/x-msdownload");
-
-
-
-
-
-
-
- response.setHeader("Content-Disposition", "attachment; filename=haha.ppt");
-
-
-
-
-
- OutputStream os = response.getOutputStream();
-
- BufferedOutputStream bos = new BufferedOutputStream(os);
-
-
-
-
-
- InputStream is = null;
-
- is = new FileInputStream("E:\\source\\090515\\javaee\\fileupload\\fileUpload.ppt");
-
- BufferedInputStream bis = new BufferedInputStream(is);
-
-
-
- int length = 0;
-
- byte [] temp = new byte[1 * 1024 * 10];
-
- while((length = bis.read(temp)) != -1){
-
- bos.write(temp, 0, length);
-
- System.out.println("循環(huán)操作中...");
-
- }
-
-
-
- bis.close();
-
- bos.close();
-
-
-
- 但是上面的這種方式無法被迅雷之類的下載工具下載,,如果希望被迅雷之類的東西下載,就直接這么寫就可以了
-
- request.getRequestDispatcher("/data/fileUpload.ppt")
-
- .forward(request, response);
|