1. 程式人生 > >JAVA的檔案上傳和下載詳解

JAVA的檔案上傳和下載詳解

1、過濾器案例:通用字符集編碼過濾器
1.1 表單提交中文資料到servlet裡面會有亂碼,之前需要在每個servlet裡面都需要處理

     編寫過濾器,把設定中文的程式碼寫到過濾器裡面,在每個servlet裡面不需要寫處理程式碼

1.2 增強類中的方法有三種方式
(1)繼承
(2)裝飾者模式
(3)動態代理
1.3 實現的過程
(1)無論get提交還是post提交,在servlet都使用request裡面的getParameter方法得到
(2)增強request裡面getParameter方法,把邏輯增強,如果get提交編碼轉換,如果post提交設定編碼
(3)如何增強request裡面方法?
第一種做法:使用裝飾者模式實現,實現HttpServletRequest介面,需要把接口裡面的所有方法都實現
第二種做法:sun公司為HttpServletRequest介面提供了一個類,這個類為了讓增強使用的類,HttpServletRequestWrapper 
繼承類就可以了。
(4)總結
= 增強類中的方法,如果增強request裡面的方法,直接繼承HttpServletRequestWrapper類實現
  如果增強response裡面的方法,直接繼承HttpServletResponseWrapper 類實現
= 過濾器實現的過程
第一部分:檔案上傳
1、什麼是檔案的上傳
1.1 把本地電腦上的檔案存到伺服器上面,這個過程稱為上傳操作,比如網盤
1.2 在servlet裡面2.5版本中不能實現檔案上傳(使用servlet3.0版本可以實現檔案上傳)
1.3 依賴第三方元件實現檔案上傳
(1)首先匯入jar包
1.4 有兩個
(1)fileUpload:使用在模型二,是 Apache組織開源元件,元件FileUpload依賴於Commons IO元件(匯入兩個jar包)
(2)jspsmartupload:使用在模型一,適於嵌入執行上傳下載操作的JSP檔案中
2、程式碼實現檔案上傳
2.1 檔案上傳滿足三個要求(**)
第一個:在表單裡面提交方式 method="post"
第二個:在表單裡面有檔案上傳項,在檔案上傳項裡面必須有name屬性
<input type="file" name="file"/>
第三個:在表單裡面設定提交資料的型別 使用屬性 enctype="multipart/form-data"
2.2 fileUpload程式碼實現的步驟(固定的)
第一步:建立磁碟檔案項工廠
new DiskFileItemFactory();
第二步:建立核心上傳類
new ServletFileUpload(FileItemFactory fileItemFactory)
引數:傳遞第一步new出來的物件就可以了,因為new出來的物件是FileItemFactory實現類
第三步:使用核心上傳類解析request物件
List parseRequest(javax.servlet.http.HttpServletRequest request)
返回list集合 List<FileItem>
第四步:遍歷list集合,判斷是否普通輸入項還是檔案上傳項
遍歷之後每部分都是FileItem
使用FileItem裡面boolean isFormField()判斷是否是普通輸入項,如果返回true是普通輸入項
第五步:如果普通輸入項獲取值,如果是檔案上傳項寫上傳流操作
獲取普通輸入項的值:
getFieldName():獲取普通輸入項name的屬性值
getString():獲取普通輸入項的輸入的值
獲取檔案上傳項內容
getName():獲取到上傳檔案的檔名稱
獲取上傳檔案的輸入流:
getInputStream()
2.3 實現的程式碼
String filename = fileItem.getName();
	//在某些瀏覽器裡面得到的帶路徑:C:\Users\asus\Desktop\1.txt
	int lens = filename.lastIndexOf("\\");
	//判斷是否帶路徑
	if(lens != -1) {
		filename = filename.substring(lens+1);
	}
	//流操作
	//得到表單提交的檔案的輸入流
	InputStream in = fileItem.getInputStream();
	//使用輸出流把寫到伺服器上
	//得到資料夾的完全路徑 servletcontext
	String path = getServletContext().getRealPath("/upload");
	OutputStream out = new FileOutputStream(path+"/"+filename);
	//流對接
	int len = 0;
	byte[] b = new byte[1024];
	while((len=in.read(b))!=-1) {
		out.write(b, 0, len);
	}
	//關閉流
	out.close();
	in.close();
3、核心api的使用
3.1 上傳檔案時候,上傳檔名稱中包含中文,亂碼問題
(1)ServletFileUpload類 setHeaderEncoding(java.lang.String encoding) 
3.2 普通輸入項裡面中文解決
(1)FileItem : getString(java.lang.String encoding)
3.3 其他的方法介紹
ServletFileUpload類其他的方法:
(1)setFileSizeMax(long fileSizeMax):設定單個檔案上傳的大小
(2)setSizeMax(long sizeMax):設定總的檔案的大小
(3)如果超過大小,丟擲異常資訊:The field filename exceeds its maximum permitted  size of 1048576 characters.
FileItem的其他的方法:
(1)getName():獲取上傳檔案的名稱

在某些瀏覽器裡面得到檔名稱包含路徑,擷取得到檔名稱

==============================================================
總結
1、過濾器案例
(1)增強類中的方法(增強request裡面的方法)
2、上傳
(1)上傳三個要求
(2)程式碼實現上傳的步驟
(3)如何使用程式碼實現上傳
(4)核心api的方法
===============================================================
1、檔案上傳的問題
1.1 檔案重名問題
(0)如果上傳多個相同名稱的檔案,最後一次上傳的檔案會把之前的檔案覆蓋
(1)解決方法:保證檔名稱唯一的,不會覆蓋
(2)具體實現:在檔名稱裡面拼接唯一的值(UUID、毫秒數)
(3)程式碼
	//生成uuid值
	String uuid = UUID.randomUUID().toString();
	// uuid_filename
	filename = uuid+"_"+filename;
1.2 在資料夾裡面過多檔案
(0)如果資料夾裡面檔案過多,造成讀寫很慢
(1)解決方法:
第一種:按照日期進行儲存(年、月、日、小時)
第二種:根據使用者進行儲存(張三的檔案存到張三資料夾裡面)
第三種:根據檔案數量進行儲存(比如3000個檔案存到一個資料夾中)
(2)第四種:使用目錄分離演算法(**)
第一步:得到檔案的唯一的名稱,計算唯一的檔名稱 hashcode值,返回int值
第二步:使用第一步得到int值,& 0xf (1111),把結果作為第一級目錄
第三步:使用第一步的int值,把值右移4位,把右移4位的結果再 & 0xf,把結果作為第二級目錄
......以此類推
(3)int是32位,在計算機如何表示的?
 0 1 10 11 100 101 .........
 = 表示方式:每四位表示一段,一共有8段
0001 1000 1010 1001 0010 1001 1010  1010 
(4)程式碼
public static String getPath(String filename) {
		//計算檔名稱hashcode值
		int code1 = filename.hashCode();
		//把得到int值 & 0xf
		int d1 = code1 & 0xf;
		//把int值右移4位
		int code2 = code1 >>> 4;
		//再&0xf
		int d2 = code2 & 0xf;
		return "/"+d1+"/"+d2;
	}
(5)上傳中分離目錄完善
//得到資料夾的完全路徑 servletcontext
	String path = getServletContext().getRealPath("/upload");
	//得到分離的目錄
	String url = UploadUtils.getPath(filename);
	//因為分離的目錄沒有建立,首先建立,在存檔案
	File file = new File(path+url);
	//判斷檔案是否存在
	if(!file.exists()) {
		//建立
		file.mkdirs();
	}
	OutputStream out = new FileOutputStream(path+url+"/"+filename);
2、案例-新增商品(上傳商品圖片)
2.1 最終目的:把圖片上傳到伺服器、把商品資訊存到資料庫
2.2 實現的步驟
(1)建立新增商品的頁面,表單,滿足上傳的三個要求,提交servlet
(2)建立servlet,實現上傳,獲取表單提交過來的商品的資訊,把商品資訊存到資料庫
(3)上傳圖片(在資料庫裡面儲存上傳圖片的路徑)
2.3 總結
(1)在上傳程式碼中如何獲取普通輸入項的值,把多個普通輸入項的值封裝到javabean
(2)上傳程式碼實現
(3)新增資料到資料庫
第二部分:檔案下載
1、什麼是檔案的下載
1.1 把伺服器上面的檔案儲存到本地的硬碟上,這個過程稱為檔案的下載
2、實現檔案下載
2.1 實現的步驟
(1)在伺服器上需要有可以下載的檔案
(2)得到伺服器上面檔案的內容
= 使用位元組流,使用輸入流
(3)使用輸出流把檔案內容寫到瀏覽器中
(4)重要步驟:設定頭資訊 Content-Disposition,無論什麼格式檔案都是以下載方式開啟
= response.setHeader("Content-Disposition", "attachment;filename="+filename);
3、下載中文名稱的檔案
3.1 如果下載檔名稱包含中文,下載顯示時候不能正常顯示
3.2 解決方法:
(1)不同的瀏覽器有不同的編碼  火狐和非火狐
(2)ie採用url編碼,火狐採用base64編碼
(3)實現方式:
區分不同的瀏覽器,(使用請求頭 User-Agent得到不同的瀏覽器資訊)
對不同的瀏覽器進行不同的編碼
(4)程式碼
String agent = request.getHeader("User-Agent");
	//如果是火狐瀏覽器
	if(agent.contains("Firefox")) {
		//base64編碼
		filename = "=?UTF-8?B?"+
			new BASE64Encoder().encode(filename.getBytes("utf-8"))+"?=";
	} else {//ie瀏覽器 url編碼
		filename = URLEncoder.encode(filename, "utf-8");
	}
4、檔案下載有兩種方式
第一種:程式碼實現檔案下載
第二種:使用超連結下載檔案
(1)在超連結裡面直接寫檔案在專案中的路徑
<a href="${pageContext.request.contextPath }/img/2.zip">2.zip</a>
(2)如果檔案格式是圖片格式,直接開啟