原始碼剖析CommonsMultipartResolver解釋parseRequest無法獲得FileItem
相信在Javaweb做檔案上傳的時候大家都用到commons-fileupload這個元件,使用這個元件實現檔案上傳時都會用到這句程式碼List<FileItem> list = servletFileUpload.parseRequest(request);
,意思是解析從客戶端傳送到伺服器的request請求(Form表單)得到一個FileItem的List集合,這樣每個FileItem都可以簡單地通過封裝好的方法獲得檔名,檔案資訊等。但是一旦處理不慎就會出現List.size()為0的問題,即解析後得不到FileItem。
琢磨了很久我才知道,之所以之前commons-fileupload能上傳但後來又不能上傳,是因為後來我在配置檔案中注入了一個叫做CommonsMultipartResolver的元件。注入這個元件是因為在專案其他地方要用到MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
這樣說來,沒有引入CommonsMultipartResolver前,commons-fileupload通過servletFileUpload.parseRequest(request)將request解析了,能得到FileItem集合。引入CommonsMultipartResolver之後,進行同樣的解析得不到FileItem集合了。那只有一個原因,就是前後request物件變了。下面就來debug檢視前後request物件的區別:
沒有引入CommonsMultipartResolver前:
引入CommonsMultipartResolver後:
對比前後可見,request物件確實不一樣。那CommonsMultipartResolver究竟做了什麼?
開啟CommonsMultipartResolver原始碼:
protected MultipartParsingResult parseRequest(HttpServletRequest request) throws MultipartException {
String encoding = this.determineEncoding(request);
FileUpload fileUpload = this .prepareFileUpload(encoding);
try {
List ex = ((ServletFileUpload)fileUpload).parseRequest(request);
return this.parseFileItems(ex, encoding);
} catch (SizeLimitExceededException var5) {
throw new MaxUploadSizeExceededException(fileUpload.getSizeMax(), var5);
} catch (FileUploadException var6) {
throw new MultipartException("Could not parse multipart servlet request", var6);
}
}
從原始碼可以看到:CommonsMultipartResolver本身就依賴於commons-fileupload這個包,自己也有一個叫做parseRequest的方法,這個方法呼叫了commons-fileupload包裡FileUpload的parseRequest方法。
現在知道原因了,原來CommonsMultipartResolver這個元件會檢測從客戶端來的request,若是multipart/form-data資料就會自動將其用common-fileupload的parseRequest方法進行解析。因此引入這個元件後,想再通過List<FileItem> list = servletFileUpload.parseRequest(request);
解析得到FileItem是不可能的,此前已經解析過一次了,再解析當然為空。
解決方案:
不要再使用List<FileItem> list = servletFileUpload.parseRequest(request);
這個方法得到FileItem的List(之後遍歷這個List獲取Form表單的資料)。
既然CommonsMultipartResolver已經幫我們解析了,那就直接用:
if(!ServletFileUpload.isMultipartContent(request)){
//如果上傳的資料不是表單原始的資料(經過編碼),則直接返回。因為只有表單原始資料才會被接收
//http://stackoverflow.com/questions/4526273/what-does-enctype-multipart-form-data-mean
return;
}
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
dynamicsText = multipartRequest.getParameter("dynamicsText");//獲取表單文字部分
MultipartFile multipartFile = multipartRequest.getFile("dynamicsFile");//獲取表單
String savePath = request.getSession().getServletContext().getRealPath("/") + "user_space/"+userId;
File file = new File(savePath);
if (!file.exists() && !file.isDirectory()) {
file.mkdirs();//新建資料夾(多重)
}
dynamicsFile = multipartFile.getOriginalFilename();
multipartFile.transferTo(new File(savePath+"/"+dynamicsFile));
如有問題或補充,請大家在評論中儘管提,共同交流^~^。