爲方便演示, 全部處理邏輯所有放在Controller完成, 再也不寫Service等各層接口及實現. 如需在Service層處理, 思路及方法也是徹底同樣的.html
先說前臺. 運行之後就是這樣子的. 一個很是簡單的表單頁面, 兩個文件上傳按鈕, 一個提交java
其中單個文件上傳, 即只能選擇一個文件, 沒法同時選擇多個web
相對的, 多個文件就是能夠同時選擇多個文件了spring
文件選擇之後就是這個樣子apache
代碼以下: 一個form, 文件上傳就是一個<input>輸入, 屬性type="file". 此時只能選擇單個文件. 然後面加一個multiple, 便可同時選擇多個文件app
action屬性中的路徑後綴爲.htm, 是由於個人環境中配置了映射, 因此要在Controller中指定的路徑後添加一個.htm後綴, 不然系統會報404. 若是沒有配置該項則無需添加後綴
ide
[html] view plain copy post
<body> 測試
<form action="${pageContext.request.contextPath}/test/upload.htm" enctype="multipart/form-data" method="post"> 編碼
單個文件: <input type="file" name="fileTest"><br/>
多個文件: <input type="file" name="fileList" multiple/></br/>
<input type="submit" value="提交" />
</form>
</body>
另外一點須要注意的是, 要實現文件上傳, form中必須指定屬性enctype="multipart/form-data". method屬性爲"post"
前臺就這些東西了, 沒什麼特殊的. 而後再看後臺
首先Spring配置文件中加這麼一個bean
[html] view plain copy
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 默認編碼 -->
<property name="defaultEncoding" value="utf-8" />
<!-- 文件大小最大值 -->
<property name="maxUploadSize" value="10485760" />
<!-- 內存中的最大值 -->
<property name="maxInMemorySize" value="40960" />
</bean>
也能夠在代碼中直接建立對象
[java] view plain copy
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
可是我的認爲配置之後使用比較方便, 各位根據實際須要來吧
其中maxUploadSize屬性用來設計上傳文件的最大值, 單位是字節. 注意這裏是總的上傳限制, 好比設置爲10M, 上傳了4個3M的文件. 雖然單個文件都在10M之內, 可是總大小已經超過10M限制, 會拋出MaxUploadSizeExceededException異常
[java] view plain copy
package com.test.controller;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
/**
* 文件上傳測試類
*/
@Controller
@RequestMapping("/test")
public class FileUploadController {
@ResponseBody
@RequestMapping(value="upload")
public void testUpload(MultipartHttpServletRequest request) throws IOException {
/*
* MultipartHttpServletRequest: 繼承於HttpServletRequest以及MultipartRequest.
* 其中MultipartRequest中定義了相關的訪問操做. MultipartHttpServletRequest重寫
* 了HttpServletRequest中的方法, 並進行了擴展. 若是以HttpServletRequest來接收參
* 數, 則須要先將其轉爲MultipartHttpServletRequest類型
* MultipartHttpServletRequest request = (MultipartHttpServletRequest) HttpServletRequest;
*/
/*
* 再說回剛纔的form, 假設咱們在單個文件選框中上傳了文件1, 多個文件選框中上傳了文件2, 3, 4.
* 那麼對於後臺接收到的, 能夠這麼理解, 就是一個Map的形式(實際上它後臺真的是以Map來存儲的).
* 這個Map的Key是什麼呢? 就是上面<input>標籤中的name=""屬性. Value則是咱們剛纔上傳的
* 文件, 經過下面的示例能夠看出每個Value就是一個包含對應文件集合的List
*
* 傳到後臺接收到的Map就是這樣:
* fileTest: 文件1
* fileList: 文件2, 文件3, 文件4
*
* 雖然從方法名的表面意義來看是獲得文件名, 但實際上這個文件名跟上傳的文件自己並無什麼關係.
* 剛纔說了這個Map的Key就是<input>標籤中的name=""屬性, 因此獲得的也就是這個屬性的值
*/
Iterator<String> fileNames = request.getFileNames();
while (fileNames.hasNext()) {
//把fileNames集合中的值打出來
String fileName=fileNames.next();
System.out.println("fileName: "+fileName);
/*
* request.getFiles(fileName)方法即經過fileName這個Key, 獲得對應的文件
* 集合列表. 只是在這個Map中, 文件被包裝成MultipartFile類型
*/
List<MultipartFile> fileList=request.getFiles(fileName);
if (fileList.size()>0) {
//遍歷文件列表
Iterator<MultipartFile> fileIte=fileList.iterator();
while (fileIte.hasNext()) {
//得到每個文件
MultipartFile multipartFile=fileIte.next();
//得到原文件名
String originalFilename = multipartFile.getOriginalFilename();
System.out.println("originalFilename: "+originalFilename);
//設置保存路徑.
String path ="G:/testUpload/";
//檢查該路徑對應的目錄是否存在. 若是不存在則建立目錄
File dir=new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
String filePath = path + originalFilename;
System.out.println("filePath: "+filePath);
//保存文件
File dest = new File(filePath);
if (!(dest.exists())) {
/*
* MultipartFile提供了void transferTo(File dest)方法,
* 將獲取到的文件以File形式傳輸至指定路徑.
*/
multipartFile.transferTo(dest);
/*
* 若是需對文件進行其餘操做, MultipartFile也提供了
* InputStream getInputStream()方法獲取文件的輸入流
*
* 例以下面的語句即爲經過
* org.apache.commons.io.FileUtils提供的
* void copyInputStreamToFile(InputStream source, File destination)
* 方法, 獲取輸入流後將其保存至指定路徑
*/
//FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), dest);
}
//MultipartFile也提供了其餘一些方法, 用來獲取文件的部分屬性
//獲取文件contentType
String contentType=multipartFile.getContentType();
System.out.println("contentType: "+contentType);
/*
* 獲取name
* 其實這個name跟上面提到的getFileName值是同樣的,
* 就是Map中Key的值. 即前臺頁面<input>中name=""
* 屬性. 可是上面的getFileName只是獲得這個Map的Key,
* 而Spring在處理上傳文件的時候會把這個值以name屬性
* 記錄到對應的每個文件. 若是須要從文件層面獲取這個
* 值, 則可使用該方法
*/
String name=multipartFile.getName();
System.out.println("name: "+name);
//獲取文件大小, 單位爲字節
long size=multipartFile.getSize();
System.out.println("size: "+size);
System.out.println("---------------------------------------------------");
}
}
}
}
}