一、Apache Commons-FileUpload簡介
Apache Commons是一個專注於可重用Java組件的所有方面的 Apache 項目。
Apache Commons項目由三個部分組成:
- Commons Proper - 可重用Java組件的存儲庫。
- The Commons Sandbox - 用於Java組件開發的工作區。
- The Commons Dormant - 當前不活動的組件存儲庫。
Commons-FileUpload是Commons Proper中的一個組件,該組件依賴於Commons-IO ,Commons-IO也是 Commons Proper中的一個組件。
Commons FileUpload的JAR包下載
Commons IO的JAR包下載
<!-- upload file --> <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency>
三.前端界面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<% String path = request.getContextPath(); %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>upload</title>
</head>
<br>
<br>
<form action="<%=path%>/device/uploadFile" method ="post" enctype="multipart/form-data">
<input type ="file" name ="doc1"><br><br>
<input type ="file" name ="doc2"><br><br>
<input type ="text" name = info><br><br>
<input type ="password" name ="password"><br><br>
<input type="submit" value="提交">
</form>
<body>
</body>
</html>
四.后台代碼
@RequestMapping(value="/uploadFile") public String uploadFile(final HttpServletRequest request, final HttpServletResponse response){ request.setAttribute("msg", "Not first time!"); //創建一個“硬盤文件條目工廠”對象 DiskFileItemFactory factory = new DiskFileItemFactory(); //設置閾值,設置JVM一次能夠處理的文件大小(默認吞吐量是10KB) factory.setSizeThreshold(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD); //設置臨時文件的存儲位置(文件大小大於吞吐量的話就必須設置這個值,比如文件大小:1GB ,一次吞吐量:1MB) factory.setRepository(new File("d:\\test")); //創建核心對象 ServletFileUpload fileUpload = new ServletFileUpload(factory); //設置最大可支持的文件大小(10MB) fileUpload.setFileSizeMax(1024*1024*10); //設置轉換時使用的字符集 fileUpload.setHeaderEncoding("UTF-8"); if(ServletFileUpload.isMultipartContent(request)){ try { List<FileItem> fileItems = fileUpload.parseRequest(request); for ( FileItem fileItem : fileItems) { if(fileItem.isFormField()){//判斷該FileItem為一個普通的form元素 //獲取字段名 String fieldName = fileItem.getFieldName(); //獲取字段值,並解決亂碼 String fieldValue = fileItem.getString("UTF-8"); System.out.println(fieldName +" : " + fieldValue); }else{//判斷該FileItem為一個文件 System.out.println("Start to uplaod file!"); //獲取文件名 String fileName = fileItem.getName(); System.out.println("fileName : " + fileName); //獲取文件大小 long fileSize = fileItem.getSize(); System.out.println("fileSize : " + fileSize); fileItem.write(new File("D://test//upload"+File.separator +fileName)); } } } catch (FileUploadException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } return "device/uploadFile"; }
五。異常
catch(FileUploadBase.SizeLimitExceededException ex){ out.print("上傳失敗,文件太大,單個文件的最大限制是:"+upload.getSizeMax()+"bytes!"); }
1.其中需要注意的是流的操作,和File類的操作,mkdirs()和mkdir()的區別是什么?它們都是用來創建文件夾的,區別在mkdirs能創建多級目錄,而mkdir()只能創建當前的文件夾,如果發現上一層目錄並還沒有創建時,它也會無動於衷,什么也不干,也就不能創建當前文件夾,必須先要創建了上一級文件夾才可以。
2.上面還有很多的問題需要解決,比如上傳文件名的亂碼問題,比如單表內容的亂碼問題,比如上傳文件同名問題,如果上傳的文件很大,該如何進行處理,比如,放在同一級目錄下的文件過多如何處理。每次都自己手動寫輸出流,將內容存到指定位置,太過麻煩,等等問題,現在寫一個加強版,在解決上面所有的問題。
3.上傳文件名亂碼問題:使用servletFileUpload.setHeaderEncoding("UTF-8");或者request.setCharacterEncoding("UTF-8")都可以
4.表單內容亂碼問題:使用getString("utf-8")即可,也就是在獲取內容時,就可以設置碼表。
5.上傳文件同名問題:使用UUID.randomUUID().toString().replace("-", "").獲得一個獨一無二的32位數字
6.使用FileUtils.copyInputStreamToFile(is, file);來將內容輸出到指定路徑文件中去,mkdirs() 自動創建目錄
7.同一級目錄下的文件過多問題:創建多級目錄,通過文件名的hashcode的值,hashCode為int型,占4個字節,一個字節占8位,也就是占32位,將其分組,4位4位一組,就能分8組,每一次代表一層目錄,也就能夠分8層目錄,每一層中,有可以創建16種不同的文件夾。這樣算下來,就能有很多很多個文件夾了,每個文件夾下面都可以存很多文件,看我們的業務需求,來決定要創建幾層目錄,就從hashcode中拿幾組數據出來。原理圖如下

public class StringUtils { /** * 生成二級目錄 * @param fileName abc.txt * @return /4/5 */ public static String getDir(String fileName) { //1 hashCode值 int hashCode = fileName.hashCode(); System.out.println(hashCode); //2 第一層 0xf表示15的16進制數。 int dir1 = hashCode & 0xf; //3 第二層目錄 int dir2 = hashCode >>> 4 & 0xf; //4 拼寫 return "/" + dir1 + "/" + dir2; } public static void main(String[] args) { System.out.println(getDir("abc.txt")); } }
總結上傳:
其實理解了也不是很難,就是上傳文件后的處理比較麻煩,各種小問題,存儲過程最為麻煩。
1、創建工廠類
2、使用核心類,
3、解析request請求,
4、遍歷請求體的內容,將上傳內容和普通表單內容都獲取出來
5、獲取到上傳內容時,對其存儲位置進行設置
其中很多細節問題都在上面已經說清楚了,代碼中也有很多注釋。