Servlet文件上傳
Servlet 可以與 HTML form 標籤一起使用,來允許用戶上傳文件到服務器。上傳的文件可以是文本文件或圖像文件或任何文檔。
本文使用到的文件有:
- upload.jsp : 文件上傳表單。
- message.jsp : 上傳成功後跳轉頁面。
- UploadServlet.java : 上傳處理 Servlet。
需要引入的 jar 文件:commons-fileupload-1.3.2、commons-io-2.5.jar。
下面的 HTML 代碼創建了一個文件上傳表單。以下幾點需要注意:
- 表單 method 屬性應該設置爲 POST 方法,不能使用 GET 方法。
- 表單 enctype 屬性應該設置爲 multipart/form-data.
- 表單 action 屬性應該設置爲在後端服務器上處理文件上傳的 Servlet 文件。下面的實例使用了 UploadServlet Servlet 來上傳文件。
- 上傳單個文件,您應該使用單個帶有屬性 type=”file” 的
實現步驟
- 1、創建DiskFileItemFactory對象,設置緩衝區大小和臨時文件目錄
- 2、使用DiskFileItemFactory 對象創建ServletFileUpload對象,並設置上傳文件的大小限制。
- 3、調用ServletFileUpload.parseRequest方法解析request對象,得到一個保存了所有上傳內容的List對象。
- 4、對list進行迭代,每迭代一個FileItem對象,調用其isFormField方法判斷是否是上傳文件
- 爲普通表單字段,則調用getFieldName、getString方法得到字段名和字段值
- 爲上傳文件,則調用getInputStream方法得到數據輸入流,從而讀取上傳數據。
ServletContext類
WEB容器在啓動時,它會爲每個WEB應用程序都創建一個對應的ServletContext對象,它代表當前web應用。
ServletConfig對象中維護了ServletContext對象的引用,開發人員在編寫servlet時,可以通過ServletConfig.getServletContext方法獲得ServletContext對象。
由於一個WEB應用中的所有Servlet共享同一個ServletContext對象,因此Servlet對象之間可以通過ServletContext對象來實現通訊。ServletContext對象通常也被稱之爲context域對象。
1.多個Servlet通過ServletContext對象實現數據共享。
在InitServlet的Service方法中利用ServletContext對象存入需要共享的數據
/*獲取ServletContext對象*/
ServletContext context = this.getServletContext();
//存入共享的數據
context.setAttribute("name", "haha");
在其它的Servlet中利用ServletContext對象獲取共享的數據
/*獲取ServletContext對象*/
ServletContext context = this.getServletContext();
//獲取共享的數據
String name = context.getAttribute("name");
System.out.println("共享的內容值是:"+name);
2.獲取WEB應用的初始化參數。
在web.xml文件中配置需要初始化的參數信息。
<web-app>
<context-param>
<param-name>url</param-name>
<param-value>jdbc:MySQL://localhost:3306/4g</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>1314qr</param-value>
</context-param>
<context-param>
<param-name>user</param-name>
<param-value>root</param-value>
</context-param>
</web-app>
在DemoServlet的doPost方法中測試獲取初始化參數的步驟如下:
/*獲取ServletContext對象*/
ServletContext context = this.getServletContext();
/*獲取初始化參數*/
//獲取指定名稱的初始化參數
String url = context.getInitParameter("url");
//獲取web.xml文件中所有的初始化應用參數
Enumeration<String> enumer = context.getInitParameterNames();
while(enumer.hasMoreElements()){
String name = enumer.nextElement();
String value = context.getInitParameter(name);
System.out.println(name+"=========="+value);
}
2.實現Servlet的轉發:
在測試的Servlet中實現轉發的步驟如下:
/*要利用ServletContext對象實現轉發獲取對象*/
ServletContext context = this.getServletContext();
//在request對象中存入name屬性
request.setAttribute("name", "haha");
/*根據轉發的地址獲取 RequestDispatcher對象*/
RequestDispatcher rd = context.getRequestDispatcher("/index.jsp");
//調用轉發方法 以下采用任意方法即可
rd.forward(request, response);
//rd.include(request, response);
注意:forward與include的區別
forward方法是把請求的內容轉發到另外的一個servlet.而include是把另一個servlet處理過後的內容拿過來.
(forward方法調用後在響應中的沒有提交的內容被自動消除。將請求轉發給其他的Servlet後,由
被調用的Servlet負責對請求做出響應,而原先Servlet的執行則終止。
include方法使原先的Servlet和轉發到的Servlet都可以輸出響應信息,即原先的Servlet還可以繼續輸出響應信息)
3.利用ServletContext對象讀取資源文件。
讀取資源文件(properties文件(屬性文件))的三種方式
配置的properties的內容如下:
url=jdbc:mysql://localhost:3306/3g ;
user=root;
password=root;
獲取實現的代碼如下:
/*獲取ServletContext對象*/
ServletContext context = this.getServletContext();
//第一種方式
URL url = context.getResource("WEB-INF/classes/db.properties");
InputStream is = url.openStream();
//第二種方式
/*讀取db.properties文件*/
String path =context.getRealPath("WEB-INF/classes/db.properties");
/*根據文件的路徑 構建文件對象*/
File file = new File(path);
/*根據file文件對象 創建輸入流*/
InputStream is = new FileInputStream(file);
//第三種方式
InputStream is = context.getResourceAsStream("WEB-INF/classes/db.properties ");
以三種方式任意一種可以:
/解析properties的文件/
Properties prop = new Properties();
//從輸入流中讀取屬性列表(鍵和元素對)。
prop.load(is);
Set<String> set = prop.stringPropertyNames();
//遍歷set集合
Iterator<String> it = set.iterator();
while(it.hasNext()){
String key = it.next();
String value = prop.getProperty(key);
System.out.println(key+"-----"+value);
}
DiskFileItemFactory類
DiskFIleItemFactory是FileItem對象的工廠,常用方法如下:
- public void setSize Threshold(int sizeThresshold):設置內存緩衝區的大小,默認值爲10k。當上傳文件大於緩衝區大小,fileupload組件使用臨時文件緩存上傳文件。由於Java虛擬機默認可以使用的內存空間是有限的,超出限制會拋出“java.lang.OutOfMemory”錯誤。如果上傳文件很大,在內存中將無法臨時保存該文件內容,Apache文件上傳組件轉而採用臨時文件來保存這些數據;如果上傳的文件很小,保存在內存中將會達到更快的效應。
- public void setRepository(Java.io.File repository) :指定臨時文件目錄,默認值爲System.getProperty(“Java.io.tmpdir”).
- public DiskFileItemFactory(int sizeThreshold,java.io.File repository) :構造函數採用參數指定臨界值和系統臨時文件夾構造文件項工廠對象。
- boolean isMultipartContent(HttpServletRequest request) :判斷上傳表單是否爲multipart/form-data類型
- List parseRequest(HttpServletRequest request):解析request對象,並把表單中的每一個輸入項包裝成一個fileItem 對象,並返回一個保存了所有FileItem的list集合。
- setFileSizeMax(long fileSizeMax) :設置上傳文件的最大值
- setSizeMax(long sizeMax) :設置上傳文件總量的最大值
- setHeaderEncoding(java.lang.String encoding) :設置編碼格式
- setProgressListener(ProgressListener pListener)
ServletFileUpload類
該類是文件上傳的核心類,在使用ServletFileUpload對象解析請求時要設置DiskFileItemFactory對象屬性sizeThreshold(臨界值)和repository(臨時目錄),所以實現文件上傳之前,先構造好DiskFileItemFactory的實例對象,通過ServletFileUpload對象的構造方法或者FileItemFactory()方法設置ServletFileUpload對象的FileItemFactory對象。
構造方法:
public ServletFileUpload()
構造一個未初始化的實例,需要在解析請求之前先調用setFileItemFactory()方法設置 fileItemFactory屬性。
public ServletFileUpload(FileItemFactory fileItemFactory)
構造一個實例,並根據參數指定的FileItemFactory 對象,設置 fileItemFactory屬性。
ServletFileUpload類常用方法:
1) public void setSizeMax(long sizeMax)
setSizeMax方法繼承自FileUploadBase類,用於設置請求消息實體內容(即所有上傳數據)的最大尺寸限制,以防止客戶端惡意上傳超大文件來浪費服務器端的存儲空間。其參數是以字節爲單位的long型數字。
在請求解析的過程中,如果請求消息體內容的大小超過了setSizeMax方法的設置值,將會拋出FileUploadBase內部定義的SizeLimitExceededException異常(FileUploadException的子類)。該方法有一個對應的讀方法:public long getSizeMax()方法。2) public void setFileSizeMax(long fileSizeMax)
setFileSizeMax方法繼承自FileUploadBase類,用於設置單個上傳文件的最大尺寸限制,以防止客戶端惡意上傳超大文件來浪費服務器端的存儲空間。其參數是以字節爲單位的long型數字。該方法有一個對應的讀方法:public long geFileSizeMax()方法。
在請求解析的過程中,如果單個上傳文件的大小超過了setFileSizeMax方法的設置值,將會拋出FileUploadBase內部定義的FileSizeLimitExceededException異常(FileUploadException的子類)。3) public List parseRequest(javax.servlet.http.HttpServletRequest req)
parseRequest 方法是ServletFileUpload類的重要方法,它是對HTTP請求消息體內容進行解析的入口方法。它解析出FORM表單中的每個的數據,並將它們分別包裝成獨立的FileItem對象,然後將這些FileItem對象加入進一個List類型的集合對象中返回。
該方法拋出FileUploadException異常來處理諸如文件尺寸過大、請求消息中的實體內容的類型不是“multipart/form-data”、IO異常、請求消息體長度信息丟失等各種異常。每一種異常都是FileUploadException的一個子類型。4) public FileItemIterator getItemIterator(HttpServletRequest request)
getItemIterator方法和parseRequest 方法基本相同。但是getItemIterator方法返回的是一個迭代器,該迭代器中保存的不是FileItem對象,而是FileItemStream 對象,如果你希望進一步提高新能,你可以採用getItemIterator方法,直接獲得每一個文件項的數據輸入流,做底層處理;如果性能不是問題,你希望代碼簡單,則採用parseRequest方法即可。
5) public stiatc boolean isMultipartContent(HttpServletRequest req)
isMultipartContent方法方法用於判斷請求消息中的內容是否是“multipart/form-data”類型,是則返回true,否則返回false。isMultipartContent方法是一個靜態方法,不用創建ServletFileUpload類的實例對象即可被調用。
6) getFileItemFactory()和setFileItemFactory(FileItemFactory)
方法繼承自FileUpload類,用於設置和讀取fileItemFactory屬性。
7) public void setProgressListener(ProgressListener pListener)
設置文件上傳進度監聽器。該方法有一個對應的讀取方法:ProgressListener getProgressListener()。
8) public void setHeaderEncoding()
在文件上傳請求的消息體中,除了普通表單域的值是文本內容以外,文件上傳字段中的文件路徑名也是文本,在內存中保存的是它們的某種字符集編碼的字節數組,Apache文件上傳組件在讀取這些內容時,必須知道它們所採用的字符集編碼,才能將它們轉換成正確的字符文本返回。
setHeaderEncoding方法繼承自FileUploadBase類,用於設置上面提到的字符編碼。如果沒有設置,則對應的讀方法getHeaderEncoding()方法返回null,將採用HttpServletRequest設置的字符編碼,如果HttpServletRequest的字符編碼也爲null,則採用系統默認字符編碼。可以通過一下語句獲得系統默認字符編碼:
System.getProperty(“file.encoding”));
File.separate
爲了跨平臺考慮,文件寫法如下所示:
//windows寫法
File file = new File("C:\tmp\test.txt");
//linux寫法
File file new File("/tmp/test.txt");
//跨平臺寫法
File myFile = new File("C:"+File.separate+"tmp"+File.separate+File.seaprate+"test.txt");
- separatorChar爲系統默認名稱分隔符,此字段被初始化爲包含file.seprate值得第一個字符,在Unix系統爲“/”,在windows系統爲“\”。
- pathsepratorChar爲系統路徑分隔符,此字段被初始化爲包含path.seprate值得第一個字符,在Unix系統爲“:”,在windows系統爲“;”。
具體操作
1、設置文件上傳的MEMORY_THRESHOLD(內存臨界值)、MAX_FILE_SIZE(最大上傳文件值)、MAX_REEQUEST_SIZE(最大請求值)。
private static final int MEMORY_THRESHOLD = 1024*1024*3;
private static final int MAX_FILE_SIZE = 1024*1024*40;
private static final int MAX_REQUEST_SIZE = 1024*1024*50
2、 設置文件上傳服務器的臨時目錄
DiskFileItemFactory factory = new DiskFileItemFatory();
factory.setRepository(MEMRORY_THRESHOLD);
//設置臨時存儲目錄
factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
ServletFileUpload upload = new ServletFileUpload(factory);
//設置最大單文件值
upload.setFileSizeMax(MAX_FILE_SIZE);
//設置最大請求值(文件和表單數據)
upload.setSizeMax(MAX_REQUEST_SIZE);
//設置編碼
upload.setHeaderEncoding("utf-8");
//構建上傳文件臨時存儲目錄路徑
String uploadPath = (this)request.getServletContext().getRealPath("./")+file.separate+UPLOAD_DIRECTORY;
3、解析請求內容提取文件數據
list<FileItem> formItems = upload.parseRequest(request);
//處理不在表單中的數據
for(FileItem item : formItems){
if(!item.isFormField){
String fileName = new File(item.getName()).getName();
String filePath = uploadPath +file.separate+fileName;
File storeFile = new File(filePath);
item.write(storeFile);
}
}
4、跳轉到jsp文件,反饋上傳消息結果
request.getServletContext().getRequestDispatcher("/../jsp").forword(request,response);
servlet文件下載
getParameter和getAttribute區別
- getParameter得到的都是String,用於讀取提交表單的值,或是某個表單提交過去的數據。 getAtrribute獲取可以是對象Object,需進行轉換,可用此設置任意對象,用於獲取對象容器的數據值。(主要爲SESSION值)
- getParameter()獲取POST/GET傳遞的參數值,用於客戶端重定向,用於表單或url重定向傳值接收數據。
- getAttribute()用於服務器重定向,在servlet中使用forword函數。
操作步驟
1、獲得請求文件名
String fileName = request.getParameter("FileName");
2、設置相關屬性
//設置文件MIME類型
response.setContentType(getServletContext().getMimeType(filename));
//設置Content.Disposition
response.setHeader("Content-Disposition","attachment;filename="+filename);
3、獲取目標文件絕對路徑,讀取文件
String FilePath = getServletContent().getRealPath("/upload/"+filename);
//讀取文件
InputStream in = new FileInputStream(FilePath);
OutputStream out response.getOutputStream();
//寫文件
out.write(in.read());