Servlet實現檔案上傳詳解與實戰
檔案上傳
1.客戶端程式設計
要上傳檔案,必須利用mutipart/form-data 設定HTML表單的enctype 屬性值
<form action="action" enctype="mutipart/form-data" method="post">
Select a file <input type="file" name="fileName"/>
<input type="submit" value="Upload">
</form>
如果想上傳多個檔案,則不得不使用檔案input元素,在input元素加入multipel屬性 ,以便生成一個按鈕供選擇多個檔案
<input type="file" name="fileName" mutipel/>
<input type="file" name="fileName" mutipel="multipel"/>
<input type="file" name="fileName" mutipel=""/> 同樣效果
2. 伺服器端程式設計
Sevlet中的伺服器處理上傳檔案的Servlet必須用 @MutipartConfig 進行標註。
MutipartConfig帶有下面幾個屬性:
maxFileSize: 表示可上傳檔案的容量。預設為-1,表示不受限制
maxRequestSize:表示允許多部分HTTP請求的最大容量。預設為-1,表示不受限制
location:將上傳的檔案儲存到磁碟中的指點位置,呼叫Part的write方法將用到它
fileSizeThreshold:設定一個溢位尺寸,超過這個值之後,上傳的檔案將被寫入磁碟
在一個有多部分組成的請求中,標一個表單域,包括非檔案域,都會被轉換成一個Part
HttpServletRequest 介面定義了以下方法來處理多部分的請求:
Part getPart (String name) :返回指點名稱的Part
Collection getParts() :返回這個請求的所有PART
Part介面還有以下的方法
String getName() 返回與指定部分有關的域名稱,非檔名稱(要想獲取檔名稱,需要解析content-disposition標頭)
Collection getHeaderNames() 返回這個part中所有標頭名稱
String getContentType() 如果part是檔案,則返回檔案的名稱,否則返回null (用於檢驗一個Part是否為檔案域)
String getHeader(String name) 返回指點name的標頭名稱
Collection getHeaders(String name) 返回這個part中所有標頭名稱
void write(String path) 將上傳的檔案寫入磁碟中。如果path是個絕對路徑,則寫入,如果path是相對路徑,那麼將被寫入相對MultiConfig註解的location屬性指定的路徑
void delete() 刪除該檔案對應的儲存
java.io.InputStream getInputStream() 以InputStream的形式返回上傳檔案的內容
如果上傳一個名為document的note.txt檔案時,其具有標頭:
content-type:text/plain
content-disposition:form-data;name="document" ;filename="note.txt"
如果沒有選擇檔案,還是會為該檔案域建立一個Part,相關標頭:
content-type:application/octet-stream
content-disposition:form-data;name="document" ;filename=""
對於非檔案的域,Part只有content-disposition標頭
3.例項:上傳Servlet範例
下面例子示範如何編寫一個多部分的Servlet。它可以處理單個檔案上傳
SingleUploadServlet類,實現MutipartConfig
import java.io.IOException;
import java.io.PrintWriter;
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;
@WebServlet(urlPatterns={"/singleUpload"})
@MultipartConfig
public class SingleUploadServlet extends HttpServlet {
private static final long serialVersionUID=8593038L;
private String getFilename(Part part){
String contentDispositoinHeader=part.getHeader("content-disposition");
String [] elements=contentDispositoinHeader.split(";");
for(String element:elements){
if(element.trim().startsWith("filename")){
return element.substring(
element.indexOf('=')+1).trim().replace("\"", "");
}
}
return null;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO Auto-generated method stub
Part part=req.getPart("filename");
String fileName=getFilename(part);
if(fileName!=null&&!fileName.isEmpty()){
part.write(getServletContext().getRealPath("/WEB-INF")+"/"+fileName);
}
resp.setContentType("text/html");
PrintWriter writer=resp.getWriter();
writer.print("<br/>Uploaded file name:"+fileName);
writer.print("<br/>Size:"+part.getSize());
String author=req.getParameter("author");
writer.print("<br/>Author:"+author);
}
singleUpload.jsp頁面
<body>
<h1>Select a file to upload</h1>
<form action="singleUpload" enctype="multipart/form-data"
method="post">
Author:<input type="text" name="author"><br>
Select a file to upload <input type="file" name="filename " ><br>
<input type="submit" value="Upload" ></form>
</body>
與前一個例子相似,只不過它是遍歷Part集合,努力核實Part是包含一個檔案還是一個域值
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
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;
@WebServlet(urlPatterns={"/multipleUploads"})
@MultipartConfig
public class MultipleUploadsServlet extends HttpServlet {
private static final long serialVersionUID=9991L;
private String getFilename(Part part){
String contentDispositoinHeader=part.getHeader("content-disposition");
String [] elements=contentDispositoinHeader.split(";");
for(String element:elements){
if(element.trim().startsWith("filename")){
return element.substring(
element.indexOf('=')+1).trim().replace("\"", "");
}
}
return null;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO Auto-generated method stub
resp.setContentType("text/html");
PrintWriter writer=resp.getWriter();
Collection<Part> parts=req.getParts();
for(Part part:parts){
if(part.getContentType()!=null){
String fileName=getFilename(part);
if(fileName!=null&&!fileName.isEmpty()){
part.write(getServletContext().getRealPath("/WEB-INF")+"/"+fileName);
writer.print("<br/>Uploader file name:"+fileName);
writer.print("<br/>Size:"+part.getSize());
}
}else{
//假如不存在內容型別,則意味著Part表示的是一個非檔案域
String partName=part.getName();
String filedValue=req.getParameter(partName);
writer.print("<br/>"+partName+":"+filedValue);
}
}
}
}
multipelUploads.jsp<body>
<h1>Select a file to upload</h1>
<form action="multipleUploads" enctype="multipart/form-data" method="post">
Author:<input name="author"><br>
First file to upload <input type="file" name="filename"><br>
Second file to upload<input type="file" name="filename"><br>
<input type="submit" value="Upload"></form>
</body>