轉載請注明原文地址:http://www.cnblogs.com/ygj0930/p/6073505.html
一個功能完善的JavaWeb應用,必不可少的一個功能就是文件的上傳。無論是用戶的頭像等,還是用戶需要上傳的一系列資料,都是通過文件的上傳功能實現的。
目前我們實現網站中關於文件的上傳功能時,常用的是apache的開源工具common-fileupload以及common-fileupload的依賴包common-io。
下面以一個注冊頁面的后台程序為例,大致講解這兩個包的使用:
首先,前往apache官網上面下載common-fileupload、common-io這兩個包,並放入工程的WEB-INF文件夾的lib目錄下。
然后,在網站頁面的表單那里設置:
文件選擇按鈕為:<input type="file"/>
表單數據屬性設置為:enctype="multipart/form-data"。因為只有使用enctype="multipart/form-data"
,表單才會把文件的內容編碼到HTML請求中。
原理請移步:http://blog.csdn.net/mazhibinit/article/details/49667511 進行了解。
<form action="upload_do.jsp" method="post" enctype="multipart/form-data"> 文件上傳欄: <input type="file" size="30" name="upload" /> <input type="submit" value="提交上傳" /> </form>
最后,在表單提交的目的jsp文件中使用兩個包中的工具類進行文件的提取與保存,一般步驟如下:
1、實例化一個硬盤文件工廠,用來配置上傳組件ServletFileUpload的一些基本設定。比如
DiskFileItemFactory dfif = new DiskFileItemFactory(); // 定義文件上傳時的“運輸船”大小。文件是一部分一部分上傳的,這里設置為4K。當數據讀取到4K則寫入硬盤的臨時文件夾中,清空運輸船繼續讀取。
//文件傳輸完后,再從臨時文件夾轉存到實際的保存路徑下
dfif.setSizeThreshold(4096);
// 設置存放臨時文件的目錄如下:獲取完整路徑——修改路徑新建臨時文件夾——把臨時文件夾設為工廠的默認目錄(則工廠獲取的內容會默認存放在這里) String realwebbase = request.getSession().getServletContext().getRealPath("/"); File temp_file = new File(realwebbase+"upload/UploadTemp"); if (!temp_file.exists()) { temp_file.mkdirs(); }
dfif.setRepository(temp_file);
2、用工廠實例化上傳組件,則該組件會使用該工廠實例的一系列配置(如:以多大容量為一次上傳文件、臨時文件存放處等)
ServletFileUpload sfu = new ServletFileUpload(dfif); sfu.setHeaderEncoding("UTF-8"); // 設置上傳文件的最大容量 sfu.setSizeMax(MAX_SIZE);
3、從request對象中把上傳內容提取到一個list中。從上面引用的博文處可以看到,POST+multipart/form-data的效果是form表單內的內容以鍵值對的形式提交上去。
List fileList = null; try { fileList = sfu.parseRequest(request); } catch (FileUploadException e) { }
4、用迭代器遍歷list對象,提取上傳內容。上傳內容主要分兩種:文本與非文本內容(圖片、多媒體文件等)
Iterator fileItr = fileList.iterator(); while (fileItr.hasNext()) { FileItem fileItem = (FileItem) fileItr.next(); if(fileItem.isFormField()){ //第一種上傳內容:普通文本,分別獲取鍵名、值內容即可 String name = fileItem.getFieldName(); //獲取鍵值對的鍵名 String value = fileItem.getString("UTF-8"); //此處的getString()是指對list的當前元素(鍵值對)的值,按照參數所指定的解碼方式進行解析、獲取內容 }else{ //第二種上傳內容:非文本,則需要用到流傳輸來把內容讀取、保存到具體的路徑下 String path = fileItem.getName(); //獲取文件的路徑名,用於截取擴展名進行文件類型的判斷// 得到文件的大小,用於判斷文件大小是否合法 long size = fileItem.getSize(); if ("".equals(path) || size == 0) { out.println("上傳的文件無效!"); out.close(); return; } // 得到去除路徑的文件名 String t_name = path.substring(path.lastIndexOf("/") + 1); // 得到文件的擴展名(無擴展名時將得到全名) String t_ext = t_name.substring(t_name.lastIndexOf(".") + 1);
//遍歷允許的擴展名數組,看看上傳文件的擴展名是否合法。 int i = 0;
boolean errorflag=true; while (i < allowedExt.length) { if (allowedExt[i].equals(t_ext)){
errorflag=false; break; } i=i+1; } if (errorflag) { out.println("請上傳合法文件!"); out.close(); return; }
// 用uuid+日期作為文件名的一部分來唯一標識文件 String uuid = UUID.randomUUID().toString(); String today = new SimpleDateFormat("yyyyMMdd").format(new Date()); //生成最終的文件保存完整路徑:目錄路徑+日期+UUID+ . +擴展名 String u_name = realwebbase + "upload/" + today + "/" + uuid + "." + t_ext;
try { File _today_file = new File(realwebbase + "upload/Uploaded/" + _today); //構建文件目錄 if (!_today_file.exists()) { _today_file.mkdirs(); } fileItem.write(new File(u_name)); //把當前list元素的值用write流寫到創建好的路徑下,即實現文件內容的保存了return; } catch (Exception e) { e.printStackTrace(); } }
5、最后,就是把文件的相對路徑信息保存到數據庫中去,使文件得以在其他文件中通過相對路徑進行引用了。