天天看點

javaweb檔案上傳下載下傳

檔案上傳概述

1 檔案上傳的作用

例如網絡硬碟!就是用來上傳下載下傳檔案的。

在智聯招聘上填寫一個完整的履歷還需要上傳照片呢。

2 檔案上傳對頁面的要求

上傳檔案的要求比較多,需要記一下:

必須使用表單,而不能是超連結;

表單的method必須是POST,而不能是GET;

表單的enctype必須是multipart/form-data;

在表單中添加file表單字段,即

<form action="${pageContext.request.contextPath }/FileUploadServlet" method="post" enctype="multipart/form-data">
    	使用者名:<input type="text" name="username"/><br/>
    	檔案1:<input type="file" name="file1"/><br/>
    	檔案2:<input type="file" name="file2"/><br/>
    	<input type="submit" value="送出"/>
    </form>
           

3 比對檔案上傳表單和普通文本表單的差別

通過httpWatch檢視“檔案上傳表單”和“普通文本表單”的差別。

檔案上傳表單的enctype=”multipart/form-data”,表示多部件表單資料;

普通文本表單可以不設定enctype屬性:

當method=”post”時,enctype的預設值為application/x-www-form-urlencoded,表示使用url編碼正文;

當method=”get”時,enctype的預設值為null,沒有正文,是以就不需要enctype了。

對普通文本表單的測試:

<form action="${pageContext.request.contextPath }/FileUploadServlet" method="post">
    	使用者名:<input type="text" name="username"/><br/>
    	檔案1:<input type="file" name="file1"/><br/>
    	檔案2:<input type="file" name="file2"/><br/>
    	<input type="submit" value="送出"/>
</form>
           
javaweb檔案上傳下載下傳

  通過httpWatch測試,檢視表單的請求資料正文,我們發現請求中隻有檔案名稱,而沒有檔案内容。也就是說,當表單的enctype不是multipart/form-data時,請求中不包含檔案内容,而隻有檔案的名稱,這說明普通文本表單中input:file與input:text沒什麼差別了。

對檔案上傳表單的測試:

<form action="${pageContext.request.contextPath }/FileUploadServlet" method="post" enctype="multipart/form-data">
    	使用者名:<input type="text" name="username"/><br/>
    	檔案1:<input type="file" name="file1"/><br/>
    	檔案2:<input type="file" name="file2"/><br/>
    	<input type="submit" value="送出"/>
    </form>
           
javaweb檔案上傳下載下傳
javaweb檔案上傳下載下傳

通過httpWatch測試,檢視表單的請求資料正文部分,發現正文部分是由多個部件組成,每個部件對應一個表單字段,每個部件都有自己的頭資訊。頭資訊下面是空行,空行下面是字段的正文部分。多個部件之間使用随機生成的分隔線隔開。

文本字段的頭資訊中隻包含一條頭資訊,即Content-Disposition,這個頭資訊的值有兩個部分,第一部分是固定的,即form-data,第二部分為字段的名稱。在空行後面就是正文部分了,正文部分就是在文本框中填寫的内容。

  檔案字段的頭資訊中包含兩條頭資訊,Content-Disposition和Content-Type。Content-Disposition中多出一個filename,它指定的是上傳的檔案名稱。而Content-Type指定的是上傳檔案的類型。檔案字段的正文部分就是檔案的内容。

請注意,因為我們上傳的檔案都是普通文本檔案,即txt檔案,是以在httpWatch中是可以正常顯示的,如果上傳的是exe、mp3等檔案,那麼在httpWatch看到的就是亂碼了。

4 檔案上傳對Servlet的要求

當送出的表單是檔案上傳表單時,那麼對Servlet也是有要求的。

首先我們要肯定一點,檔案上傳表單的資料也是被封裝到request對象中的。

request.getParameter(String)方法擷取指定的表單字段字元内容,但檔案上傳表單已經不在是字元内容,而是位元組内容,是以失效。

這時可以使用request的getInputStream()方法擷取ServletInputStream對象,它是InputStream的子類,這個ServletInputStream對象對應整個表單的正文部分(從第一個分隔線開始,到最後),這說明我們需要的解析流中的資料。當然解析它是很麻煩的一件事情,而Apache已經幫我們提供了解析它的工具:commons-fileupload。

可以嘗試把request.getInputStream()這個流中的内容列印出來,再對比httpWatch中的請求資料。

public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		InputStream in = request.getInputStream();
		String s = IOUtils.toString(in);
		System.out.println(s);
	}
           
-----------------------------7ddd3370ab2
Content-Disposition: form-data; name="username"

hello
-----------------------------7ddd3370ab2
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain

aaa
-----------------------------7ddd3370ab2
Content-Disposition: form-data; name="file2"; filename="b.txt"
Content-Type: text/plain

bbb
-----------------------------7ddd3370ab2--
           

commons-fileupload

為什麼使用fileupload:

上傳檔案的要求比較多,需要記一下:

必須是POST表單;

表單的enctype必須是multipart/form-data;

在表單中添加file表單字段,即

Servlet的要求:

不能再使用request.getParameter()來擷取表單資料;

可以使用request.getInputStream()得到所有的表單資料,而不是一個表單項的資料;

這說明不使用fileupload,我們需要自己來對request.getInputStream()的内容進行解析!!!

1 fileupload概述

fileupload是由apache的commons元件提供的上傳元件。它最主要的工作就是幫我們解析request.getInputStream()。

fileupload元件需要的JAR包有:

commons-fileupload.jar,核心包;

commons-io.jar,依賴包。

2 fileupload簡單應用

  fileupload的核心類有:DiskFileItemFactory、ServletFileUpload、FileItem。

使用fileupload元件的步驟如下:

建立工廠類DiskFileItemFactory對象:DiskFileItemFactory factory = new DiskFileItemFactory()

使用工廠建立解析器對象:ServletFileUpload fileUpload = new ServletFileUpload(factory)

使用解析器來解析request對象:List list = fileUpload.parseRequest(request)

隆重介紹FileItem類,它才是我們最終要的結果。一個FileItem對象對應一個表單項(表單字段)。一個表單中存在檔案字段和普通字段,可以使用FileItem類的isFormField()方法來判斷表單字段是否為普通字段,如果不是普通字段,那麼就是檔案字段了。

String getName():擷取檔案字段的檔案名稱;

String getString():擷取字段的内容,如果是檔案字段,那麼擷取的是檔案内容,當然上傳的檔案必須是文本檔案;

String getFieldName():擷取字段名稱,例如:,傳回的是username;

String getContentType():擷取上傳的檔案的類型,例如:text/plain。

int getSize():擷取上傳檔案的大小;

boolean isFormField():判斷目前表單字段是否為普通文本字段,如果傳回false,說明是檔案字段;

InputStream getInputStream():擷取上傳檔案對應的輸入流;

void write(File):把上傳的檔案儲存到指定檔案中。

3 簡單上傳示例

寫一個簡單的上傳示例:

表單包含一個使用者名字段,以及一個檔案字段;

Servlet儲存上傳的檔案到uploads目錄,顯示使用者名,檔案名,檔案大小,檔案類型。

第一步:

完成index.jsp,隻需要一個表單。注意表單必須是post的,而且enctype必須是mulitpart/form-data的。

<form action="${pageContext.request.contextPath }/FileUploadServlet" method="post" enctype="multipart/form-data">
    	使用者名:<input type="text" name="username"/><br/>
    	檔案1:<input type="file" name="file1"/><br/>
    	<input type="submit" value="送出"/>
    </form>
           

第二步:

完成FileUploadServlet

public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 因為要使用response列印,是以設定其編碼
		response.setContentType("text/html;charset=utf-8");
		
		// 建立工廠
		DiskFileItemFactory dfif = new DiskFileItemFactory();
		// 使用工廠建立解析器對象
		ServletFileUpload fileUpload = new ServletFileUpload(dfif);
		try {
			// 使用解析器對象解析request,得到FileItem清單
			List<FileItem> list = fileUpload.parseRequest(request);
			// 周遊所有表單項
			for(FileItem fileItem : list) {
				// 如果目前表單項為普通表單項
				if(fileItem.isFormField()) {
					// 擷取目前表單項的字段名稱
					String fieldName = fileItem.getFieldName();
					// 如果目前表單項的字段名為username
					if(fieldName.equals("username")) {
						// 列印目前表單項的内容,即使用者在username表單項中輸入的内容
						response.getWriter().print("使用者名:" + fileItem.getString() + "<br/>");
					}
				} else {//如果目前表單項不是普通表單項,說明就是檔案字段
					String name = fileItem.getName();//擷取上傳檔案的名稱
					// 如果上傳的檔案名稱為空,即沒有指定上傳檔案
					if(name == null || name.isEmpty()) {
						continue;
					}
					// 擷取真實路徑,對應${項目目錄}/uploads,當然,這個目錄必須存在
					String savepath = this.getServletContext().getRealPath("/uploads");
					// 通過uploads目錄和檔案名稱來建立File對象
					File file = new File(savepath, name);
					// 把上傳檔案儲存到指定位置
					fileItem.write(file);
					// 列印上傳檔案的名稱
					response.getWriter().print("上傳檔案名:" + name + "<br/>");
					// 列印上傳檔案的大小
					response.getWriter().print("上傳檔案大小:" + fileItem.getSize() + "<br/>");
					// 列印上傳檔案的類型
					response.getWriter().print("上傳檔案類型:" + fileItem.getContentType() + "<br/>");
				}
			}
		} catch (Exception e) {
			throw new ServletException(e);
		} 
	}
           

檔案上傳之細節

1 把上傳的檔案放到WEB-INF目錄下

如果沒有把使用者上傳的檔案存放到WEB-INF目錄下,那麼使用者就可以通過浏覽器直接通路上傳的檔案,這是非常危險的。

假如說使用者上傳了一個a.jsp檔案,然後使用者在通過浏覽器去通路這個a.jsp檔案,那麼就會執行a.jsp中的内容,如果在a.jsp中有如下語句:Runtime.getRuntime().exec(“shutdown –s –t 1”);,那麼你就會…

通常我們會在WEB-INF目錄下建立一個uploads目錄來存放上傳的檔案,而在Servlet中找到這個目錄需要使用ServletContext的getRealPath(String)方法,例如在我的upload1項目中有如下語句:

ServletContext servletContext = this.getServletContext();

String savepath = servletContext.getRealPath(“/WEB-INF/uploads”);

其中savepath為:F:\tomcat6_1\webapps\upload1\WEB-INF\uploads。

2 檔案名稱(完整路徑、檔案名稱)

上傳檔案名稱可能是完整路徑:

IE6擷取的上傳檔案名稱是完整路徑,而其他浏覽器擷取的上傳檔案名稱隻是檔案名稱而已。浏覽器差異的問題我們還是需要處理一下的。

String name = file1FileItem.getName();
			response.getWriter().print(name);
           

使用不同浏覽器測試,其中IE6就會傳回上傳檔案的完整路徑,不知道IE6在搞什麼,這給我們帶來了很大的麻煩,就是需要處理這一問題。

處理這一問題也很簡單,無論是否為完整路徑,我們都去截取最後一個“\”後面的内容就可以了。

String name = file1FileItem.getName();
			int lastIndex = name.lastIndexOf("\\");//擷取最後一個“\”的位置
			if(lastIndex != -1) {//注意,如果不是完整路徑,那麼就不會有“\”的存在。
				name = name.substring(lastIndex + 1);//擷取檔案名稱
			}
			response.getWriter().print(name);
           

3 中文亂碼問題

上傳檔案名稱中包含中文:

當上傳的誰的名稱中包含中文時,需要設定編碼,commons-fileupload元件為我們提供了兩種設定編碼的方式:

request.setCharacterEncoding(String):這種方式是我們最為熟悉的方式了;

fileUpload.setHeaderEncdoing(String):這種方式的優先級高與前一種。

上傳檔案的檔案内容包含中文:

通常我們不需關心上傳檔案的内容,因為我們會把上傳檔案儲存到硬碟上!也就是說,檔案原來是什麼樣子,到伺服器這邊還是什麼樣子!

但是如果你有這樣的需求,非要在控制台顯示上傳的檔案内容,那麼你可以使用fileItem.getString(“utf-8”)來處理編碼。

文本檔案内容和普通表單項内容使用FileItem類的getString(“utf-8”)來處理編碼。

4 上傳檔案同名問題(檔案重命名)

通常我們會把使用者上傳的檔案儲存到uploads目錄下,但如果使用者上傳了同名檔案呢?這會出現覆寫的現象。處理這一問題的手段是使用UUID生成唯一名稱,然後再使用“_”連接配接檔案上傳的原始名稱。

例如使用者上傳的檔案是“我的一寸照片.jpg”,在通過處理後,檔案名稱為:“891b3881395f4175b969256a3f7b6e10_我的一寸照片.jpg”,這種手段不會使檔案丢失擴充名,并且因為UUID的唯一性,上傳的檔案同名,但在伺服器端是不會出現同名問題的。

public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		DiskFileItemFactory dfif = new DiskFileItemFactory();
		ServletFileUpload fileUpload = new ServletFileUpload(dfif);
		try {
			List<FileItem> list = fileUpload.parseRequest(request);
			//擷取第二個表單項,因為第一個表單項是username,第二個才是file表單項
			FileItem fileItem = list.get(1);
			String name = fileItem.getName();//擷取檔案名稱
			
			// 如果用戶端使用的是IE6,那麼需要從完整路徑中擷取檔案名稱
			int lastIndex = name.lastIndexOf("\\");
			if(lastIndex != -1) {
				name = name.substring(lastIndex + 1);
			}
			
			// 擷取上傳檔案的儲存目錄
			String savepath = this.getServletContext().getRealPath("/WEB-INF/uploads");
			String uuid = CommonUtils.uuid();//生成uuid
			String filename = uuid + "_" + name;//新的檔案名稱為uuid + 下劃線 + 原始名稱
			
			//建立file對象,下面會把上傳檔案儲存到這個file指定的路徑
			//savepath,即上傳檔案的儲存目錄
			//filename,檔案名稱
			File file = new File(savepath, filename);
			
			// 儲存檔案
			fileItem.write(file);
		} catch (Exception e) {
			throw new ServletException(e);
		} 
	}
           

5 一個目錄不能存放過多的檔案(存放目錄打散)

一個目錄下不應該存放過多的檔案,一般一個目錄存放1000個檔案就是上限了,如果在多,那麼打開目錄時就會很“卡”。你可以嘗試列印C:\WINDOWS\system32目錄,你會感覺到的。

也就是說,我們需要把上傳的檔案放到不同的目錄中。但是也不能為每個上傳的檔案一個目錄,這種方式會導緻目錄過多。是以我們應該采用某種算法來“打散”!

打散的方法有很多,例如使用日期來打散,每天生成一個目錄。也可以使用檔案名的首字母來生成目錄,相同首字母的檔案放到同一目錄下。

日期打散算法:如果某一天上傳的檔案過多,那麼也會出現一個目錄檔案過多的情況;

首字母打散算法:如果檔案名是中文的,因為中文過多,是以會導緻目錄過多的現象。

我們這裡使用hash算法來打散:

擷取檔案名稱的hashCode:int hCode = name.hashCode();;

擷取hCode的低4位,然後轉換成16進制字元;

擷取hCode的5~8位,然後轉換成16進制字元;

使用這兩個16進制的字元生成目錄鍊。例如低4位字元為“5”

這種算法的好處是,在uploads目錄下最多生成16個目錄,而每個目錄下最多再生成16個目錄,即256個目錄,所有上傳的檔案都放到這256個目錄下。如果每個目錄上限為1000個檔案,那麼一共可以儲存256000個檔案。

例如上傳檔案名稱為:建立 文本文檔.txt,那麼把“建立 文本文檔.txt”的哈希碼擷取到,再擷取哈希碼的低4位,和58位。假如低4位為:9,58位為1,那麼檔案的儲存路徑為uploads/9/1/。

int hCode = name.hashCode();//擷取檔案名的hashCode
	//擷取hCode的低4位,并轉換成16進制字元串
	String dir1 = Integer.toHexString(hCode & 0xF);
	//擷取hCode的低5~8位,并轉換成16進制字元串
	String dir2 = Integer.toHexString(hCode >>> 4 & 0xF);
	//與檔案儲存目錄連接配接成完整路徑
	savepath = savepath + "/" + dir1 + "/" + dir2;
	//因為這個路徑可能不存在,是以建立成File對象,再建立目錄鍊,確定目錄在儲存檔案之前已經存在
	new File(savepath).mkdirs();
           

6 上傳的單個檔案的大小限制

限制上傳檔案的大小很簡單,ServletFileUpload類的setFileSizeMax(long)就可以了。參數就是上傳檔案的上限位元組數,例如servletFileUpload.setFileSizeMax(1024*10)表示上限為10KB。

一旦上傳的檔案超出了上限,那麼就會抛出FileUploadBase.FileSizeLimitExceededException異常。我們可以在Servlet中擷取這個異常,然後向頁面輸出“上傳的檔案超出限制”。

public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		DiskFileItemFactory dfif = new DiskFileItemFactory();
		ServletFileUpload fileUpload = new ServletFileUpload(dfif);
		// 設定上傳的單個檔案的上限為10KB
		fileUpload.setFileSizeMax(1024 * 10);
		try {
			List<FileItem> list = fileUpload.parseRequest(request);
			//擷取第二個表單項,因為第一個表單項是username,第二個才是file表單項
			FileItem fileItem = list.get(1);
			String name = fileItem.getName();//擷取檔案名稱
			
			// 如果用戶端使用的是IE6,那麼需要從完整路徑中擷取檔案名稱
			int lastIndex = name.lastIndexOf("\\");
			if(lastIndex != -1) {
				name = name.substring(lastIndex + 1);
			}
			
			// 擷取上傳檔案的儲存目錄
			String savepath = this.getServletContext().getRealPath("/WEB-INF/uploads");
			String uuid = CommonUtils.uuid();//生成uuid
			String filename = uuid + "_" + name;//新的檔案名稱為uuid + 下劃線 + 原始名稱
			
			int hCode = name.hashCode();//擷取檔案名的hashCode
			//擷取hCode的低4位,并轉換成16進制字元串
			String dir1 = Integer.toHexString(hCode & 0xF);
			//擷取hCode的低5~8位,并轉換成16進制字元串
			String dir2 = Integer.toHexString(hCode >>> 4 & 0xF);
			//與檔案儲存目錄連接配接成完整路徑
			savepath = savepath + "/" + dir1 + "/" + dir2;
			//因為這個路徑可能不存在,是以建立成File對象,再建立目錄鍊,確定目錄在儲存檔案之前已經存在
			new File(savepath).mkdirs();
			
			//建立file對象,下面會把上傳檔案儲存到這個file指定的路徑
			//savepath,即上傳檔案的儲存目錄
			//filename,檔案名稱
			File file = new File(savepath, filename);
			
			// 儲存檔案
			fileItem.write(file);
		} catch (Exception e) {
			// 判斷抛出的異常的類型是否為FileUploadBase.FileSizeLimitExceededException
			// 如果是,說明上傳檔案時超出了限制。
			if(e instanceof FileUploadBase.FileSizeLimitExceededException) {
				// 在request中儲存錯誤資訊
				request.setAttribute("msg", "上傳失敗!上傳的檔案超出了10KB!");
				// 轉發到index.jsp頁面中!在index.jsp頁面中需要使用${msg}來顯示錯誤資訊
				}
           

7 上傳檔案的總大小限制

上傳檔案的表單中可能允許上傳多個檔案,例如:

javaweb檔案上傳下載下傳

有時我們需要限制一個請求的大小。也就是說這個請求的最大位元組數(所有表單項之和)!實作這一功能也很簡單,隻需要調用ServletFileUpload類的setSizeMax(long)方法即可。

例如fileUpload.setSizeMax(1024 * 10);,顯示整個請求的上限為10KB。當請求大小超出10KB時,ServletFileUpload類的parseRequest()方法會抛出FileUploadBase.SizeLimitExceededException異常。

8 緩存大小與臨時目錄

大家想一想,如果我上傳一個藍光電影,先把電影儲存到記憶體中,然後再通過記憶體copy到伺服器硬碟上,那麼你的記憶體能吃的消麼?

是以fileupload元件不可能把檔案都儲存在記憶體中,fileupload會判斷檔案大小是否超出10KB,如果是那麼就把檔案儲存到硬碟上,如果沒有超出,那麼就儲存在記憶體中。

  10KB是fileupload預設的值,我們可以來設定它。

  當檔案儲存到硬碟時,fileupload是把檔案儲存到系統臨時目錄,當然你也可以去設定臨時目錄。

public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		DiskFileItemFactory dfif = new DiskFileItemFactory(1024*20, new File("F:\\temp"));
		ServletFileUpload fileUpload = new ServletFileUpload(dfif);
		
		try {
			List<FileItem> list = fileUpload.parseRequest(request);
			FileItem fileItem = list.get(1);
			String name = fileItem.getName();
			String savepath = this.getServletContext().getRealPath("/WEB-INF/uploads");
			
			// 儲存檔案
			fileItem.write(path(savepath, name));
		} catch (Exception e) {
			throw new ServletException(e);
		} 
	}
	
	private File path(String savepath, String filename) {
		// 從完整路徑中擷取檔案名稱
		int lastIndex = filename.lastIndexOf("\\");
		if(lastIndex != -1) {
			filename = filename.substring(lastIndex + 1);
		}
		
		// 通過檔案名稱生成一級、二級目錄
		int hCode = filename.hashCode();
		String dir1 = Integer.toHexString(hCode & 0xF);
		String dir2 = Integer.toHexString(hCode >>> 4 & 0xF);
		savepath = savepath + "/" + dir1 + "/" + dir2;
		// 建立目錄
		new File(savepath).mkdirs();
		
		// 給檔案名稱添加uuid字首
		String uuid = CommonUtils.uuid();
		filename = uuid + "_" + filename;
		
		// 建立檔案完成路徑
		return new File(savepath, filename);
	}
           

檔案下載下傳

2 通過Servlet下載下傳1

被下載下傳的資源必須放到WEB-INF目錄下(隻要使用者不能通過浏覽器直接通路就OK),然後通過Servlet完成下載下傳。

在jsp頁面中給出超連結,連結到DownloadServlet,并提供要下載下傳的檔案名稱。然後DownloadServlet擷取檔案的真實路徑,然後把檔案寫入到response.getOutputStream()流中。

download.jsp

<body>
    This is my JSP page. <br>
    <a href="<c:url value='/DownloadServlet?path=a.avi'/>">a.avi</a><br/>
    <a href="<c:url value='/DownloadServlet?path=a.jpg'/>">a.jpg</a><br/>
    <a href="<c:url value='/DownloadServlet?path=a.txt'/>">a.txt</a><br/>
  </body>
           

DownloadServlet.java

public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String filename = request.getParameter("path");
		String filepath = this.getServletContext().getRealPath("/WEB-INF/uploads/" + filename);
		File file = new File(filepath);
		if(!file.exists()) {
			response.getWriter().print("您要下載下傳的檔案不存在!");
			return;
		}
		IOUtils.copy(new FileInputStream(file), response.getOutputStream());
	}
           

上面代碼有如下問題:

可以下載下傳a.avi,但在下載下傳框中的檔案名稱是DownloadServlet;

不能下載下傳a.jpg和a.txt,而是在頁面中顯示它們。

javaweb檔案上傳下載下傳

3 通過Servlet下載下傳2

下面來處理上一例中的問題,讓下載下傳框中可以顯示正确的檔案名稱,以及可以下載下傳a.jpg和a.txt檔案。

通過添加content-disposition頭來處理上面問題。當設定了content-disposition頭後,浏覽器就會彈出下載下傳框。

而且還可以通過content-disposition頭來指定下載下傳檔案的名稱!

String filename = request.getParameter("path");
		String filepath = this.getServletContext().getRealPath("/WEB-INF/uploads/" + filename);
		File file = new File(filepath);
		if(!file.exists()) {
			response.getWriter().print("您要下載下傳的檔案不存在!");
			return;
		}
		response.addHeader("content-disposition", "attachment;filename=" + filename);
		IOUtils.copy(new FileInputStream(file), response.getOutputStream());
           
javaweb檔案上傳下載下傳
javaweb檔案上傳下載下傳
javaweb檔案上傳下載下傳

雖然上面的代碼已經可以處理txt和jpg等檔案的下載下傳問題,并且也處理了在下載下傳框中顯示檔案名稱的問題,但是如果下載下傳的檔案名稱是中文的,那麼還是不行的。

3 通過Servlet下載下傳3

下面是處理在下載下傳框中顯示中文的問題!

其實這一問題很簡單,隻需要通過URL來編碼中文即可!

download.jsp

<a href="<c:url value='/DownloadServlet?path=這個殺手不太冷.avi'/>">這個殺手不太冷.avi</a><br/>
    <a href="<c:url value='/DownloadServlet?path=白冰.jpg'/>">白冰.jpg</a><br/>
    <a href="<c:url value='/DownloadServlet?path=說明文檔.txt'/>">說明文檔.txt</a><br/>
           

DownloadServlet.java

String filename = request.getParameter("path");
		// GET請求中,參數中包含中文需要自己動手來轉換。
		// 當然如果你使用了“全局編碼過濾器”,那麼這裡就不用處理了
		filename = new String(filename.getBytes("ISO-8859-1"), "UTF-8");
		
		String filepath = this.getServletContext().getRealPath("/WEB-INF/uploads/" + filename);
		File file = new File(filepath);
		if(!file.exists()) {
			response.getWriter().print("您要下載下傳的檔案不存在!");
			return;
		}
		// 所有浏覽器都會使用本地編碼,即中文作業系統使用GBK
		// 浏覽器收到這個檔案名後,會使用iso-8859-1來解碼
		filename = new String(filename.getBytes("GBK"), "ISO-8859-1");
		response.addHeader("content-disposition", "attachment;filename=" + filename);
		IOUtils.copy(new FileInputStream(file), response.getOutputStream());