遇到了List<FileItem>為空的問題,已經確定表單已經提交到正確的servlet,但是List<FileItem>就是為空,連普通表單都娶不到的原因是:
type=“file”的input標簽沒有name屬性!!!(一定要加name屬性)
文件上傳要注意的細節:(在黑馬程序員視頻筆記借鑒來的):
上傳(上傳不能使用BaseServlet)
1. 上傳對表單限制
* method="post"
* enctype="multipart/form-data"
* 表單中需要添加文件表單項:<input type="file" name="xxx" />
<form action="xxx" method="post" enctype="multipart/form-data">
用戶名;<input type="text" name="username"/><br/>
照 片:<input type="file" name="zhaoPian"/><br/>
<input type="submit" value="上傳"/>
</form>
2. 上傳對Servlet限制
* request.getParametere("xxx");這個方法在表單為enctype="multipart/form-data"時,它作廢了。它永遠都返回null
* ServletInputStream request.getInputStream();包含整個請求的體!
-------------------------------
多部件表單的體
1. 每隔出多個部件,即一個表單項一個部件。
2. 一個部件中自己包含請求頭和空行,以及請求體。
3. 普通表單項:
> 1個頭:Content-Disposition:包含name="xxxx",即表單項名稱。
> 體就是表單項的值
4. 文件表單項:
> 2個頭:
* Content-Disposition:包含name="xxxx",即表單項名稱;還有一個filename="xxx",表示上傳文件的名稱
* Content-Type:它是上傳文件的MIME類型,例如:image/pjpeg,表示上傳的是圖片,圖上中jpg擴展名的圖片。
> 體就是上傳文件的內容。
===========================================
commons-fileupload
* commons-fileupload.jar
* commons-io.jar
這個小組件,它會幫我們解析request中的上傳數據,解析后的結果是一個表單項數據封裝到一個FileItem對象中。我們只需要調用FileItem的方法即可!
---------------
1. 上傳三步
相關類:
* 工廠:DiskFileItemFactory
* 解析器:ServletFileUpload
* 表單項:FileItem
1). 創建工廠:DiskFileItemFactory factory = new DiskFileItemFactory();
2). 創建解析器:ServletFileUpload sfu = new ServletFileUpload(factory);
3). 使用解析器來解析request,得到FileItem集合:List<FileItem> fileItemList = sfu.parseRequest(request);
2. FileItem
* boolean isFormField():是否為普通表單項!返回true為普通表單項,如果為false即文件表單項!
* String getFieldName():返回當前表單項的名稱;
* String getString(String charset):返回表單項的值;
* String getName():返回上傳的文件名稱
* long getSize():返回上傳文件的字節數
* InputStream getInputStream():返回上傳文件對應的輸入流
* void write(File destFile):把上傳的文件內容保存到指定的文件中。
* String getContentType();
---------------
上傳的細節:
1. 文件必須保存到WEB-INF下!
* 目的是不讓瀏覽器直接訪問到!
* 把文件保存到WEB-INF目錄下!
2. 文件名稱相關問題
* 有的瀏覽器上傳的文件名是絕對路徑,這需要切割!C:\files\baibing.jpg
String filename = fi2.getName();
int index = filename.lastIndexOf("\\");
if(index != -1) {
filename = filename.substring(index+1);
}
* 文件名亂碼或者普通表單項亂碼:request.setCharacterEncoding("utf-8");因為fileupload內部會調用request.getCharacterEncoding();
> request.setCharacterEncoding("utf-8");//優先級低
> servletFileUpload.setHeaderEncoding("utf-8");//優先級高
* 文件同名問題;我們需要為每個文件添加名稱前綴,這個前綴要保證不能重復。uuid
> filename = CommonUtils.uuid() + "_" + filename;
3. 目錄打散
* 不能在一個目錄下存放之多文件。
> 首字符打散:使用文件的首字母做為目錄名稱,例如:abc.txt,那么我們把文件保存到a目錄下。如果a目錄這時不存在,那么創建之。
> 時間打散:使用當前日期做為目錄。
> 哈希打散:
* 通過文件名稱得到int值,即調用hashCode()
* 它int值轉換成16進制0~9, A~F
* 獲取16進制的前兩位用來生成目錄,目錄為二層!例如:1B2C3D4E5F,/1/B/保存文件。
4. 上傳文件的大小限制
* 單個文件大小限制
> sfu.setFileSizeMax(100*1024):限制單個文件大小為100KB
> 上面的方法調用,必須在解析開始之前調用!
> 如果上傳的文件超出限制,在parseRequest()方法執行時,會拋出異常!FileUploadBase.FileSizeLimitExceededException
* 整個請求所有數據大小限制
> sfu.setSizeMax(1024 * 1024);//限制整個表單大小為1M
> 這個方法也是必須在parseRequest()方法之前調用
> 如果上傳的文件超出限制,在parseRequest()方法執行時,會拋出異常!FileUploadBase.SizeLimitExceededException
5. 緩存大小與臨時目錄
* 緩存大小:超出多大,才向硬盤保存!默認為10KB
* 臨時目錄:向硬盤的什么目錄保存
設置緩存大小與臨時目錄:new DiskFileItemFactory(20*1024, new File("F:/temp"))