servlet 實現文件上傳
所謂文件上傳就是將本地的文件發送到服務器中保存。例如我們向百度網盤中上傳本地的資源或者我們將寫好的博客上傳到服務器等等就是典型的文件上傳。
servlet 3.0
上次完成文件下載功能使用的是 servlet 2.5,但是想要完成文件上傳,那么繼續使用 servlet 2.5
肯定不是一個好的選擇,因此我們使用 servlet 3.0
來完成文件上傳。下面我來簡單介紹一下 servlet 3.0 的新特性:
1、新增的注解支持
該版本新增了若干注解,用于簡化 servlet、過濾器(filter)和監聽器(listener)的聲明,這使得 web.xml 部署描述文件從該版本開始不再是必選的了。
2、httpservletrequest 對文件上傳的支持
此前,對于處理上傳文件的操作一直是讓開發者頭疼的問題,因為 servlet 本身沒有對此提供直接的支持,需要使用第三方框架來實現,而且使用起來也不夠簡單。如今這都成為了歷史,servlet 3.0 已經提供了這個功能,而且使用也非常簡單。
servlet 3.0 的新特性當然肯定不止這些,但是其他的新特性在這里我們暫時還用不到,也就不做過多了解了。
必要條件
想要完成文件上傳,肯定不是這么簡單,它對瀏覽器端和服務器端都有許多的要求。
對瀏覽器的要求:
-
一個文件的大小一般肯定不止 1 kb,既然這樣,那么要上傳一個文件肯定不能使用
get
方式了,所以上傳文件時必須采用post
方式。 -
2.表單中必須有一個文件上傳項
<input type="file">
,而且必須有 name 屬性。 -
必須設置表單的
enctype
屬性值為multipart/form-data
。
對服務器的要求:
- 當然,我們肯定得使用 servlet 3.0。
-
servlet 3.0 中接收普通上傳組件(除了文件上傳組件)通過
request.getparameter(string)
接收,而文件上傳組件通過request.getpart(string)
接收。 -
servlet 3.0 要求服務器必須是
tomcat7
及其以上。
準備工作
工欲善其事,必先利其器。
1、首先,打開 eclipse
,新建一個 dynamic web project
。
2、鍵入項目名,選擇運行時環境為 apache tomcat v7.0
,選擇 servlet 版本為 3.0
,然后點擊 finished
。
3、在項目的 webcontent
目錄下,新建一個文件夾 upload
,用來存放上傳過來的文件。
4、在 webcontent
目錄下新建一個 index.jsp
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<%@ page language= "java" contenttype= "text/html; charset=utf-8" pageencoding= "utf-8" %> <!doctype html> <html> <head> <meta charset= "utf-8" > <title>上傳</title> </head> <body> <form action= "${pagecontext.request.contextpath}/uploadservlet" method= "post" enctype= "multipart/form-data" > <label>選擇一個文件:</label> <input type= "file" name= "file" ><br> <input type= "submit" value= "上傳" ><br> </form> </body> </html> |
5、使用 tomcat
將次項目發布,并在瀏覽器中預覽。
將服務器啟動,然后在瀏覽器中輸入:http://localhost:8080/upload
。
好吧!樣子有點丑,希望不要介意!如果出現以上界面,那么,準備工作就完成了!
完成案例
首先,新建一個 servlet,在 servlet 3.0 我們不必再為配置 web.xml 而煩惱了,只要要在 servlet 的類名上面一行添加一個注解:
1
|
@webservlet ( "/uploadservlet" ) |
這個注解就相當與 servlet 2.5 中的:
1
2
3
4
5
6
7
8
|
<servlet> <servlet-name>uploadservlet</servlet-name> <servlet- class >club.luckylight.upload.uploadservlet</servlet- class > </servlet> <servlet-mapping> <servlet-name>uploadservlet</servlet-name> <url-pattern>/uploadservlet</url-pattern> </servlet-mapping> |
這樣比較,使用注解不是簡便了很多。
然后,我們還需要添加另一個注解:
1
|
@multipartconfig |
該注解主要是為了輔助 servlet 3.0 中 httpservletrequest 提供的對上傳文件的支持。該注解標注在 servlet 上面,以表示該 servlet 希望處理的請求的 mime類型 是 multipart/form-data
。
接下來,我們就需要根據上傳組件的 name
屬性獲取它了。這里我們使用 path request.getpart(string)
方法。
1
|
part part = request.getpart( "file" ); |
然后,我們就需要根據 part 獲取頭信息,然后根據頭信息獲取文件的路徑。
在瀏覽器抓包,獲取頭信息為:
據此,我們可以獲取文件名或者文件路徑。
1
2
|
string header = part.getheader( "content-disposition" ); string path = header.substring(header.indexof( "filename=" ) + 10 , header.length() - 1 ); |
由于獲取的有可能是文件名,也有可能是文件路徑,為此,有必要編寫一個工具類,用來獲取文件的真實名稱。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/** * 根據文件的路徑獲取文件真實名稱 * * @param path * 文件的路徑 * @return 文件名稱 */ public static string getrealname(string path) { int index = path.lastindexof( "\\" ); if (index == - 1 ) { index = path.lastindexof( "/" ); } return path.substring(index + 1 ); } |
然后,調用這個方法,獲得文件名。
1
|
string name = uploadutils.getrealname(path); |
接下來,我們有必要,給每個文件分配一個存放目錄,因此我又編寫了一個方法,用來生成一個目錄。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/** * 根據文件名返回一個目錄 * * @param name * 文件名稱 * @return 目錄 */ public static string getdir(string name) { int i = name.hashcode(); string hex = integer.tohexstring(i); int j = hex.length(); for ( int k = 0 ; k < 8 - j; k++) { hex = "0" + hex; } return "/" + hex.charat( 0 ) + "/" + hex.charat( 1 ); } |
到此,萬事俱備,只欠東風。我們只需要將文件拷貝到服務器。
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
|
// 獲取文件的真實路徑 string realpath = this .getservletcontext().getrealpath( "/upload" + dir); file file = new file(realpath); if (!file.exists()) { file.mkdirs(); } // 獲取輸入流 inputstream inputstream = part.getinputstream(); // 定義輸出流 fileoutputstream outputstream = new fileoutputstream( new file(file, name)); // 從輸入流中讀入數據并寫到輸出字節流中 int len = - 1 ; byte [] bytes = new byte [ 1024 ]; while ((len = inputstream.read(bytes)) != - 1 ) { outputstream.write(bytes, 0 , len); } // 關閉資源 outputstream.close(); inputstream.close(); // 刪除臨時文件 part.delete(); |
下面來測試一下:
然后,在 tomcat
的 webapps
-> 項目名
-> upload
中就可以找到上傳成功的文件了!
最后,我們打開音樂來試驗下是否真的上傳成功了?
嗯!薛之謙低沉的聲音從耳機中傳來,看來確實是上傳成功了!
完整代碼
uploadservlet.java
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
package club.luckylight.upload; import java.io.file; import java.io.fileoutputstream; import java.io.ioexception; import java.io.inputstream; import javax.servlet.servletexception; import javax.servlet.annotation.multipartconfig; import javax.servlet.annotation.webservlet; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import javax.servlet.http.part; import club.luckylight.util.uploadutils; @webservlet ( "/uploadservlet" ) @multipartconfig public class uploadservlet extends httpservlet { private static final long serialversionuid = 5661013723204858883l; protected void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { // 獲取文件上傳組件 part part = request.getpart( "file" ); // 獲取文件的路徑 string header = part.getheader( "content-disposition" ); string path = header.substring(header.indexof( "filename=" ) + 10 , header.length() - 1 ); // 獲取文件名 string name = uploadutils.getrealname(path); // 獲取文件的存放目錄 string dir = uploadutils.getdir(name); string realpath = this .getservletcontext().getrealpath( "/upload" + dir); file file = new file(realpath); if (!file.exists()) { file.mkdirs(); } // 對拷流 inputstream inputstream = part.getinputstream(); fileoutputstream outputstream = new fileoutputstream( new file(file, name)); int len = - 1 ; byte [] bytes = new byte [ 1024 ]; while ((len = inputstream.read(bytes)) != - 1 ) { outputstream.write(bytes, 0 , len); } // 關閉資源 outputstream.close(); inputstream.close(); // 刪除臨時文件 part.delete(); response.setcontenttype( "text/html;charset=utf-8" ); response.getwriter().print( "文件" + name + "上傳成功!" ); } protected void dopost(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { doget(request, response); } } |
uploadutils.java
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
|
package club.luckylight.util; public class uploadutils { /** * 根據文件的路徑獲取文件真實名稱 * * @param path * 文件的路徑 * @return 文件名稱 */ public static string getrealname(string path) { int index = path.lastindexof( "\\" ); if (index == - 1 ) { index = path.lastindexof( "/" ); } return path.substring(index + 1 ); } /** * 根據文件名返回一個目錄 * * @param name * 文件名稱 * @return 目錄 */ public static string getdir(string name) { int i = name.hashcode(); string hex = integer.tohexstring(i); int j = hex.length(); for ( int k = 0 ; k < 8 - j; k++) { hex = "0" + hex; } return "/" + hex.charat( 0 ) + "/" + hex.charat( 1 ); } } |
總結
這樣,文件上傳案例就完成了,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://www.jianshu.com/p/1968019b6927#