JavaWeb筆記-22-檔案上傳、八大細節問題處理
阿新 • • 發佈:2018-11-03
1、檔案上傳
1)上傳檔案對錶單的限制 1. method="post" 2. enctype="multipart/form-data" //多部件表單資料 3. 表單中需要新增檔案表單選項:<input type="file" name="xxx" /> 2)上傳檔案對Servlet的限制 1.不能使用request.getParameter("xxx");來獲取表單引數 //因為此方法返回值為字串。 2.獲取表單引數方法:ServletInputStream request.getInputStream(); //包含整個請求的體!
eg:
<form action="" method="post" enctype="multipart/form-data">
使用者名稱;<input type="text" name="username"/><br/>
照 片:<input type="file" name="zhaoPian"/><br/>
<input type="submit" value="上傳"/>
</form>
2、不同表單結構介紹:
1)多部件表單的體 分割出多個部件。即一個表單項一個部件。 每個部件包含:請求頭、空行、、請求體。 2)普通表單項: 1個頭: Content-Disposition:包含name="xxxx",即表單項名稱。 體:表單項的值 3)檔案表單項: 2個頭: Content-Disposition:包含name="xxxx",即表單項名稱; filename="xxx",表示上傳檔案的名稱 Content-Type:它是上傳檔案的MIME型別,例如:image/pjpeg,表示上傳的是圖片,圖上中jpg副檔名的圖片。 體:上傳檔案的內容。 解析檔案的jar包: commons-fileupload.jar commons-io.jar //依賴包 此包會幫我們解析request的上傳資料 解析結果:將每個表單項資料單獨封裝到FileItem物件中。使用時呼叫FileItem物件方法即可
3、上傳三步:
前提:匯入jar包: 步驟: 1)建立工廠:DiskFileItemFactory factory = new DiskFileItemFactory(); 2)建立解析器:ServletFileUpload sfu = new ServletFileUpload(factory); 3)使用解析器解析request,得到FileItem集合:List<FileItem> fileItemList = sfu.parseRequest(request); 相關類: 工廠: DiskFileItemFactory 解析器:ServletUpload 表單項:FileItem 相關方法: FileItem 1)boolean isFormField();是否為普通表單項。 true:普通表單項 false:檔案表單項 2)String getFieldName(); 返回當前表單項的名稱。 3)String getString(String charset);返回表單項的值。 4)String getName(); 返回上傳的檔名稱 5)long getSize();返回上傳檔案的位元組數 6)InputStream getInputStream(); 返回檔案對應的輸入流。 7)void write(File destFile); 把上傳的檔案儲存到指定的檔案中。
4、上傳的細節:
1.檔案必須儲存到WEB-INF下
原因:不讓瀏覽器直接訪問到
2.檔名稱相關的三個問題。
1)問題:少部分瀏覽器上傳的檔名是絕對路徑。
解決1:所以需要切割檔名。只保留檔名,不保留路徑
具體實施:判斷是否為絕對路徑程式碼
String filename = xxx.getname(); //得到路徑名
int index = filename.lastIndexOf("\\"); //檢視是否存在"\\"
if(index != -1){ //存在
filename = filename.subString(index+1); //擷取掉"\\"部分路徑
}
2)問題:檔名亂碼或表單項亂碼
解決2: 1)request.setCharacterEncoding("utf-8"); //優先順序低
2)servletFileUpload.setHeaderEncoding("utf-8"); //優先順序
3)問題:檔案同名問題
解決3:為檔案新增字首(藉助UUID)
實施:filename = CommonUtils.uuid() + "_" + filename;
3.目錄打散(分類、分層)
不能在一個檔案下存放過多檔案。
按首字元打散
按時間打散
***hash打散:
1)通過檔名獲得int值。即呼叫hashcode();
2)將int值轉換為16進位制0~9、A~F
3)獲取十六進位制的前兩位生成目錄。目錄為兩層。
eg: 1B2C3D4E5F, 目錄為 /1/B 兩層
知識點:hashCode是jdk根據物件的 地址/字串/數字 算出來的int型別的數值
public int hashCode()返回該物件的雜湊碼值。
4.上傳檔案大小限制
對單個檔案大小限制
// sfu.setFileSizeMax(100 * 1024);//限制單個檔案大小為100K
對整個請求所有資料大小限制
// sfu.setSizeMax(1024 * 1024);//限制整個表單大小為1M
注:限制語句必須在檔案解析之前
5.快取大小與臨時目錄
快取:當上傳檔案超出快取大小設定值後,將不會存入記憶體,而是存入硬碟中的臨時目錄
臨時目錄:當檔案存入記憶體後會被刪除。
伺服器儲存檔案細節:
最終目標:伺服器會儲存檔案到記憶體。
特殊情況:當檔案過大時,檔案會先儲存到硬碟中,然後再寫入記憶體(指定目錄)
JVM預設記憶體為64M
5、上傳程式碼演示
/**
* 1.上傳檔案
* 2.處理細節問題
* @author 一萬年行不行
*
*/
public class Upload3Servlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
/*
* 上傳三步
*/
// 工廠
DiskFileItemFactory factory = new DiskFileItemFactory();
// 設定快取檔案
// DiskFileItemFactory factory = new DiskFileItemFactory(20*1024, new File("F:/temp"));
// 解析器
ServletFileUpload sfu = new ServletFileUpload(factory);
// sfu.setFileSizeMax(10 * 1024);//限制單個檔案大小為10K
// sfu.setSizeMax(1024 * 1024);//限制整個表單大小為1M
// 解析,得到List
try {
List<FileItem> list = sfu.parseRequest(request);
FileItem fi = list.get(1);
//生成檔案儲存目錄:
//////////////////////////////////////////////////////
//1. 得到儲存檔案的根路徑 (由自己設定)
String root = this.getServletContext().getRealPath("/WEB-INF/files/");
System.out.println(root);
/*
* 2. 生成二層目錄
* 1). 得到檔名稱
* 2). 得到hashCode
* 3). 轉發成16進位制
* 4). 獲取前二個字元用來生成目錄
*/
String filename = fi.getName();//獲取上傳的檔名稱
//處理檔名的絕對路徑問題
int index = filename.lastIndexOf("\\");
if(index != -1) {
filename = filename.substring(index+1);
}
//給檔名稱新增uuid字首,處理檔案同名問題
String savename = CommonUtils.uuid() + "_" + filename;
//1. 得到hashCode
int hCode = filename.hashCode();
String hex = Integer.toHexString(hCode);
//2. 獲取hex的前兩個字母,與root連線在一起,生成一個完整的路徑
File dirFile = new File(root, hex.charAt(0) + "/" + hex.charAt(1));
//3. 根據生成路徑 建立目錄鏈
dirFile.mkdirs();
//4. 建立目標檔案 (將檔案地址和檔名繫結)
File destFile = new File(dirFile, savename);
//5. 儲存 (將檔案內容寫入 目標檔案)
fi.write(destFile);
///////////////////////////////////////////////////////
} catch (FileUploadException e) {
if(e instanceof FileUploadBase.FileSizeLimitExceededException) {
request.setAttribute("msg", "您上傳的檔案超出了10KB!");
request.getRequestDispatcher("/index.jsp").forward(request, response);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}