Java Web下接收檔案常基於fileupload外掛程式實現,其一般代碼如下:
index.html
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"/> <title>Title</title></head><body><form action="/test/file" enctype="multipart/form-data" method="post"> 上傳使用者:<input type="text" name="username"/><br/> 上傳檔案:<input type="file" name="file2"/><br/> <input type="submit" value="提交"/></form></body></html>
對應的後台Controller代碼:
@RequestMapping(value = "/test/file") @ResponseBody public String file (HttpServletRequest request,HttpServletResponse response) throws IOException{ response.setContentType("application/json;charset=utf-8"); try{ //使用Apache檔案上傳組件處理檔案上傳步驟: //1、建立一個DiskFileItemFactory工廠 DiskFileItemFactory factory = new DiskFileItemFactory(); //設定工廠的緩衝區的大小,當上傳的檔案大小超過緩衝區的大小時,就會產生一個臨時檔案存放到指定的臨時目錄當中。 factory.setSizeThreshold(1024*100);//設定緩衝區的大小為100KB,如果不指定,那麼緩衝區的大小預設是10KB /*//設定上傳時產生的臨時檔案的儲存目錄 factory.setRepository(tmpFile);*/ //2、建立一個檔案上傳解析器 ServletFileUpload upload = new ServletFileUpload(factory); //監聽檔案上傳進度 upload.setProgressListener(new ProgressListener(){ public void update(long pBytesRead, long pContentLength, int arg2) { System.out.println("檔案大小為:" + pContentLength + ",當前已處理:" + pBytesRead); } }); //解決上傳檔案名稱的中文亂碼 upload.setHeaderEncoding("UTF-8"); //3、判斷提交上來的資料是否是上傳表單的資料 if(!ServletFileUpload.isMultipartContent(request)){ //按照傳統方式擷取資料 return; } //設定上傳單個檔案的大小的最大值,目前是設定為1024*1024位元組,也就是1MB upload.setFileSizeMax(1024*1024*10); //設定上傳檔案總量的最大值,最大值=同時上傳的多個檔案的大小的最大值的和,目前設定為10MB upload.setSizeMax(1024*1024*30); //4、使用ServletFileUpload解析器解析上傳資料,解析結果返回的是一個List<FileItem>集合,每一個FileItem對應一個Form表單的輸入項 List<FileItem> list = upload.parseRequest(request); for(FileItem item : list){ //如果fileitem中封裝的是普通輸入項的資料 if(item.isFormField()){ String name = item.getFieldName(); //解決普通輸入項的資料的中文亂碼問題 String value = item.getString("UTF-8"); //value = new String(value.getBytes("iso8859-1"),"UTF-8"); System.out.println(name + "=" + value); }else{//如果fileitem中封裝的是上傳檔案 //得到上傳的檔案名稱, String filename = item.getName(); System.out.println(filename); if(filename==null || filename.trim().equals("")){ continue; } //注意:不同的瀏覽器提交的檔案名稱是不一樣的,有些瀏覽器提交上來的檔案名稱是帶有路徑的,如: c:\a\b\1.txt,而有些只是單純的檔案名稱,如:1.txt //處理擷取到的上傳檔案的檔案名稱的路徑部分,只保留檔案名稱部分 filename = filename.substring(filename.lastIndexOf("\\")+1); //得到上傳檔案的副檔名 String fileExtName = filename.substring(filename.lastIndexOf(".")+1); filename = filename.substring(0,filename.lastIndexOf(".")); //如果需要限制上傳的檔案類型,那麼可以通過檔案的副檔名來判斷上傳的檔案類型是否合法 System.out.println("上傳的檔案的副檔名是:"+fileExtName); //儲存檔案 FileManager fileManager = new FileManager(); if(FileManager.ERROR.equals(fileManager.save(filename,fileExtName,"song",item.getInputStream()))){ return JsonUtil.statusResponse(1,"上傳檔案失敗",null); } } } }catch (FileUploadBase.FileSizeLimitExceededException e) { e.printStackTrace(); return JsonUtil.statusResponse(1,"單個檔案超出最大值。。。",null); }catch (FileUploadBase.SizeLimitExceededException e) { e.printStackTrace(); return JsonUtil.statusResponse(1,"上傳檔案的總的大小超出限制的最大值。。。",null); }catch (Exception e) { e.printStackTrace(); return JsonUtil.statusResponse(1,"其他異常,上傳失敗。。。",null); } return JsonUtil.statusResponse(0,"上傳檔案成功",fileManager.getFileURI(filename,fileExtName)); }
我是在SpringBoot下測試時,發現的該問題,即在解析請求時List list = upload.parseRequest(request);得到的list size=0,也就是根本沒有得到檔案資料。我在網上搜尋該問題的解決方案,大致有以下兩種:
(1)原因在於Spring的設定檔中已經配置了MultipartResolver,導致檔案上傳請求已經被預先處理過了,所以此處解析檔案清單為空白,對應的做法是刪除該段配置。
(2)認為是structs的過濾器導致請求已被預先處理,所以也要修改對應過濾器的配置。
然而,在SpringBoot下,上述兩種解決方案不可能做到,因為SpringBoot的相關配置都是自己完成的,根本沒有顯示的設定檔。況且以上兩種解決方案,修改設定檔可能影響整個工程的其他部分,所以得另尋方案。
我通過斷點調試該Controller代碼,發現傳入的參數HttpServletRequest執行個體已經為StandardMultipartHttpServletRequest 對象了,且其結構中包含整個form表單的所有欄位資訊,我就想,區別於網上已有的兩種解決方案,總是想避免這種預先處理,何不就利用這種預先處理,來簡化自己的代碼結構呢。於是就有了下面的解決代碼。其方法很簡單,就是對傳入的request做強制轉型,從而可以根據StandardMultipartHttpServletRequest 執行個體方法得到相關form表單資料,從而大大簡化代碼結構,示意如下:
@RequestMapping(value = "/file") @ResponseBody public String file (HttpServletRequest request, HttpServletResponse response) throws IOException { ... try { StandardMultipartHttpServletRequest req = (StandardMultipartHttpServletRequest) request; Iterator<String> iterator = req.getFileNames(); while (iterator.hasNext()) { MultipartFile file = req.getFile(iterator.next()); String fileNames = file.getOriginalFilename(); int split = fileNames.lastIndexOf("."); //隱藏檔 //檔案名稱 fileNames.substring(0,split) //檔案格式 fileNames.substring(split+1,fileNames.length()) //檔案內容 file.getBytes() ... } }catch (Exception e){ e.printStackTrace(); return "fail"; } return "success"; }