https://blog.csdn.net/luckyboyguo/article/details/12513079
一般情況下提交表單元素form
,默認的傳輸類型為application/x-www-form-urlencoded,后臺可以通過request.getParameter()
獲取String類型的表單值。但是當iuput元素中有文件時,就不能通過這種方式傳遞。
1. 文件上傳的條件
- 表單必須是post提交方式
- 表單中必須有文件上傳項,文件上傳必須有name屬性和值
- 表單中的enctype屬性必須設置為multipart/form-data
<form method="POST" enctype="multipart/form-data" action="fup.cgi">
File to upload: <input type="file" name="upfile"><br/>
Notes about the file: <input type="text" name="note"><br/>
<br/>
<input type="submit" value="Press"> to upload the file!
</form>
- enctype=application/x-www-form-urlencoded 傳遞時,可以使用
request.getParameter()
獲取 - enctype=multipart/form-data傳遞時,不可以使用
request.getParameter()
獲取
2. Servlet獲取上傳文件
以form/data
方式傳遞的請求報文的body為:
------WebKitFormBoundaryJAjpF3viDTBKnfAy
Content-Disposition: form-data; name="username"
loserwang
------WebKitFormBoundaryJAjpF3viDTBKnfAy
Content-Disposition: form-data; name="password"
ddd
------WebKitFormBoundaryJAjpF3viDTBKnfAy
Content-Disposition: form-data; name="nickname"
ddd
------WebKitFormBoundaryJAjpF3viDTBKnfAy
Content-Disposition: form-data; name="sex"
male
------WebKitFormBoundaryJAjpF3viDTBKnfAy
Content-Disposition: form-data; name="picture"; filename="loserwang.jpg"
Content-Type: image/jpeg
??????JFIF?????,?,?????C???
??
?
???????!????'#))'#&%,1?5,.;/%&6J7;ACFGF*4MRLDR?EFC???C???? ?? C-&-CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC???v???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
理論上在Servlet處可以獲取request的body,分析結果,將上傳文件的二進制寫入本地,但是這樣過于繁瑣。最好的方式是使用第三方的jar包獲取數據,這方面有很多現成的成熟優秀的jar包,比如commons-fileupload.jar。
3. commons-fileupload
Commons是Apache開發源代碼組織的一個Java子項目,該項目主要涉及一些開發中常用的模塊,如文件上傳、命令行處理、數據庫連接池等等
The Commons FileUpload package makes it easy to add robust, high-performance, file upload capability to your servlets and web applications.
3.1 步驟
- (1).下載commons-fileupload.jar和commons-io.jar并放到/Web/WEB-INF/lib。
(/Web/WEB-INF/lib 通常使用的jar文件)
- (2).讀取文件
// 1.創建一個磁盤文件項工廠對象
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
//2.創建一個核心解析類
ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
//3. 解析request請求,返回的是List集合,List集合中存放的是FileItem對象
try {
List<FileItem> list = servletFileUpload.parseRequest(request);
// 4.遍歷集合,獲得每個FileItem,判斷是表單項還是文件上傳項
for(FileItem fileItem:list){
//判斷是表單項還是文件上傳項
if(fileItem.isFormField()){
//點單項處理
}else
//文件上傳項處理
}
}
3.2 表單項處理
假設存在一個多選項name = hobby
//遍歷前的步驟
Map<String, String> map = new HashMap<String, String>();
List<String> hobbyList = new ArrayList<String>();
......
//讀取表單數據
String name = fileItem.getFieldName();
String value = fileItem.getString("UTF-8");
//處理多選項。復選框為list
if("hobby" == name){
hobbyList.add(value);
String hobbyValue = hobbyList.toString().substring(1,hobbyList.size()-1);
map.put("hobby", hobbyValue);
}else{
//將結果存入map
map.put(name, value);
}
3.2 文件項處理
把上傳文件放到 /web/upload:
//獲取文件名
String fileName = fileItem.getFieldName();
//獲取文件上傳的數據
InputStream is = fileItem.getInputStream();
//獲得文件路徑
String path = this.getServletContext().getRealPath("/upload");
String url = path + "\\" + fileName ;
//將輸入流對接到輸出流
OutputStream os = new FileOutputStream(url);
int len = 0;
byte[] b = new byte[1024];
while ((len = is.read(b)) != -1){
os.write(b, 0, len);
}
is.close();
os.close();
這種情況雖然可以滿足基本要求,但是如果上傳的文件名相同,新文件會覆蓋舊文件。為了每個文件不被覆蓋,給每一個文件一個唯一的文件名。可以通過UUID來實現
public class UploadUtils {
/**
* 產生隨機的文件名
*/
public static String getUUIDFileName(String fileName){
// 將文件名的前面部分進行截取: xx.jpg -> .jpg
int idx = fileName.lastIndexOf(".");
String extention = fileName.substring(0, idx);
//JAVA的UUID能產生隨機的id
String uuidFileName = UUID.randomUUID().toString().replace("-","_") + extention;
return uuidFileName;
}
}
(IDEA踩坑:IDEA不編譯空文件夾。/web/upload
一開始沒有圖片,所以不會在out
中產生upload文件夾,就會報錯找不到路徑
。我們直接移動一個圖片到文件夾,選中Build-Rebuild Project
重新加載項目后,重啟服務器 或者update resources即可)。