一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術|

服務器之家 - 編程語言 - JAVA教程 - JavaWeb實現文件上傳下載功能實例詳解

JavaWeb實現文件上傳下載功能實例詳解

2020-07-02 11:12Android-Dev JAVA教程

這篇文章主要介紹了JavaWeb中的文件上傳和下載功能的實現,在開發中,文件上傳和下載功能是非常常用的功能,需要的朋友可以參考下

在Web應用系統開發中,文件上傳和下載功能是非常常用的功能,今天來講一下JavaWeb中的文件上傳和下載功能的實現。

JavaWeb實現文件上傳下載功能實例詳解

文件上傳概述

1、文件上傳的作用

例如網絡硬盤!就是用來上傳下載文件的。
在智聯招聘上填寫一個完整的簡歷還需要上傳照片呢。

2、文件上傳對頁面的要求

上傳文件的要求比較多,需要記一下:

必須使用表單,而不能是超鏈接
表單的method必須是POST,而不能是GET
表單的enctype必須是multipart/form-data
在表單中添加file表單字段,即<input type=”file” name=”xxx”/>

?
1
2
3
4
5
6
7
8
<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了
對普通文本表單的測試:

?
1
2
3
4
5
6
<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沒什么區別了。

對文件上傳表單的測試:

?
1
2
3
4
5
6
7
8
<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實現文件上傳下載功能實例詳解

通過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中的請求數據

?
1
2
3
4
5
6
public void doPost(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
 InputStream in = request.getInputStream();
 String s = IOUtils.toString(in);
 System.out.println(s);
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-----------------------------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組件的步驟如下:

?
1
2
3
4
5
6
7
8
//1.創建工廠類DiskFileItemFactory對象
DiskFileItemFactory factory = new DiskFileItemFactory();
 
//2.使用工廠創建解析器對象
ServletFileUpload fileUpload = new ServletFileUpload(factory);
 
//3.使用解析器來解析request對象
List<FileItem> list = fileUpload.parseRequest(request);

DiskFileItemFactory 磁盤文件項工廠類

public DiskFileItemFactory(int sizeThreshold, File repository)
構造工廠時,指定內存緩沖區大小和臨時文件存放位置

public void setSizeThreshold(int sizeThreshold)
設置內存緩沖區大小,默認10K

public void setRepository(File repository)
設置臨時文件存放位置,默認System.getProperty(“java.io.tmpdir”).

內存緩沖區: 上傳文件時,上傳文件的內容優先保存在內存緩沖區中,當上傳文件大小超過緩沖區大小,就會在服務器端產生臨時文件

臨時文件存放位置: 保存超過了內存緩沖區大小上傳文件而產生臨時文件 ,產生臨時文件可以通過 FileItem的delete()方法刪除

FileItem 表示文件上傳表單中 每個數據部分

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

JavaWeb實現文件上傳下載功能實例詳解

注意事項:因為文件上傳表單采用編碼方式multipart/form-data 與傳統url編碼不同,所有getParameter ()方法不能使用 setCharacterEncoding()無法解決輸入項亂碼問題

ServletFileUpload 文件上傳核心類

JavaWeb實現文件上傳下載功能實例詳解

3、簡單上傳示例

寫一個簡單的上傳示例:

       表單包含一個用戶名字段,以及一個文件字段;
      Servlet保存上傳的文件到uploads目錄,顯示用戶名,文件名,文件大小,文件類型。

第一步:

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

?
1
2
3
4
5
6
7
<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

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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("上傳文件大?。?quot; + 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項目中有如下語句:

?
1
2
ServletContext servletContext = this.getServletContext();
String savepath = servletContext.getRealPath(“/WEB-INF/uploads”);

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

2、文件名稱(完整路徑、文件名稱)

上傳文件名稱可能是完整路徑:

IE6獲取的上傳文件名稱是完整路徑,而其他瀏覽器獲取的上傳文件名稱只是文件名稱而已。瀏覽器差異的問題我們還是需要處理一下的

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

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

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

?
1
2
3
4
5
6
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的唯一性,上傳的文件同名,但在服務器端是不會出現同名問題的

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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位,和5~8位。假如低4位為:9,5~8位為1,那么文件的保存路徑為uploads/9/1/

?
1
2
3
4
5
6
7
8
9
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中獲取這個異常,然后向頁面輸出“上傳的文件超出限制”。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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", "上傳失?。∩蟼鞯奈募隽?0KB!");
 // 轉發到index.jsp頁面中!在index.jsp頁面中需要使用${msg}來顯示錯誤信息
 request.getRequestDispatcher("/index.jsp").forward(request, response);
 return;
 }
 throw new ServletException(e);
 }
}

7、上傳文件的總大小限制

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

JavaWeb實現文件上傳下載功能實例詳解

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

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

8、緩存大小與臨時目錄

大家想一想,如果我上傳一個藍光電影,先把電影保存到內存中,然后再通過內存copy到服務器硬盤上,那么你的內存能吃的消么?
所以fileupload組件不可能把文件都保存在內存中,fileupload會判斷文件大小是否超出10KB,如果是那么就把文件保存到硬盤上,如果沒有超出,那么就保存在內存中。

10KB是fileupload默認的值,我們可以來設置它。

當文件保存到硬盤時,fileupload是把文件保存到系統臨時目錄,當然你也可以去設置臨時目錄

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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);
 }

文件下載

1、通過Servlet下載1

被下載的資源必須放到WEB-INF目錄下(只要用戶不能通過瀏覽器直接訪問就OK),然后通過Servlet完成下載。

在jsp頁面中給出超鏈接,鏈接到DownloadServlet,并提供要下載的文件名稱。然后DownloadServlet獲取文件的真實路徑,然后把文件寫入到response.getOutputStream()流中。

download.jsp

?
1
2
3
4
5
6
<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

?
1
2
3
4
5
6
7
8
9
10
11
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());
}

上面代碼有如下問題:

    1.可以下載a.avi,但在下載框中的文件名稱是DownloadServlet;
    2.不能下載a.jpg和a.txt,而是在頁面中顯示它們。

JavaWeb實現文件上傳下載功能實例詳解

2、通過Servlet下載2

下面來處理上一例中的問題,讓下載框中可以顯示正確的文件名稱,以及可以下載a.jpg和a.txt文件

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

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

?
1
2
3
4
5
6
7
8
9
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實現文件上傳下載功能實例詳解

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

3、通過Servlet下載3

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

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

download.jsp

?
1
2
3
<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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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());

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 91久久99热青草国产 | 岛国不卡| 欧美日韩精品一区二区三区视频 | 日本强不卡在线观看 | 糖心视频在线观看 | 亚洲国产精品嫩草影院久久 | 午夜dj影院在线视频观看完整 | 日本暖暖在线视频 | 国产精品nv在线观看 | 久久视频这有精品63在线国产 | 久久国产精品人妻中文 | 免费看视频高清在线观看 | 精品第一国产综合精品蜜芽 | 日本花季传媒2020旧版安卓 | 无套内谢大学生A片 | 国产美女极品免费视频 | 牧教师在线观看 | 国产精品免费视频一区一 | 久久免费观看视频 | 日本海鸣馆 | 性做久久久久免费观看 | 91视频免费观看网站 | 欧美va在线高清 | 国产一区日韩二区欧美三 | 波多野结衣在线中文 | 日韩精品中文字幕视频一区 | 免费在线观看中文字幕 | 和日本免费不卡在线v | 国产福利一区二区三区四区 | 国产成人免费观看在线视频 | 久久91精品国产91久 | 国产精品香蕉夜间视频免费播放 | 男人狂躁女人下半身 | 无套暴躁白丝秘书 | 91精品久久国产青草 | 国产青草视频在线观看免费影院 | 久见久热 这里只有精品 | 小小水蜜桃免费影院 | 欧美日韩高清不卡一区二区三区 | 国产亚洲自愉自愉 | 玩高中女同桌肉色短丝袜脚文 |