SpringMVC 單檔案上傳與多檔案上傳

GitLqr發表於2017-06-22

一、簡述

一個javaWeb專案中,檔案上傳功能幾乎是必不可少的,本人在專案開發中也時常會遇到,以前也沒怎麼去理它,今天有空學習了一下這方面的知識,於是便將本人學到的SpringMVC中單檔案與多檔案上傳這部分知識做下筆記。

二、單檔案上傳

1、頁面

這裡以一個簡單的表單提交為例子,檔案上傳需要將表單的提交方法設定為post,將enctype的值設定為"multipart/form-data"。

<form action="${pageContext.request.contextPath}/test/upload.do" method="post" enctype="multipart/form-data">
    <input type="file" name="img"><br /> 
    <input type="submit" name="提交">
</form>複製程式碼

2、控制器

在Controller的處理方法中,使用MultipartFile物件作為引數接收前端上傳過來的檔案,具體說明請看程式碼註釋。

@Controller
@RequestMapping("/test")
public class MyController {

    @RequestMapping(value = "/upload.do", method = RequestMethod.POST)
    // 這裡的MultipartFile物件變數名跟表單中的file型別的input標籤的name相同,所以框架會自動用MultipartFile物件來接收上傳過來的檔案,當然也可以使用@RequestParam("img")指定其對應的引數名稱
    public String upload(MultipartFile img, HttpSession session)
            throws Exception {
        // 如果沒有檔案上傳,MultipartFile也不會為null,可以通過呼叫getSize()方法獲取檔案的大小來判斷是否有上傳檔案
        if (img.getSize() > 0) {
            // 得到專案在伺服器的真實根路徑,如:/home/tomcat/webapp/專案名/images
            String path = session.getServletContext().getRealPath("images");
            // 得到檔案的原始名稱,如:美女.png
            String fileName = img.getOriginalFilename();
            // 通過檔案的原始名稱,可以對上傳檔案型別做限制,如:只能上傳jpg和png的圖片檔案
            if (fileName.endsWith("jpg") || fileName.endsWith("png")) {
                File file = new File(path, fileName);
                img.transferTo(file);
                return "/success.jsp";
            }
        }
        return "/error.jsp";
    }
}複製程式碼

3、springmvc.xml配置

使用MultipartFile物件接收前端上傳過來的檔案,還需要在springmvc的配置檔案中進行如下配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    ...

    <!-- 注意:CommonsMultipartResolver的id是固定不變的,一定是multipartResolver,不可修改 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 如果上傳後出現檔名中文亂碼可以使用該屬性解決 -->
        <property name="defaultEncoding" value="utf-8"/>
        <!-- 單位是位元組,不設定預設不限制總的上傳檔案大小,這裡設定總的上傳檔案大小不超過1M(1*1024*1024) -->
        <property name="maxUploadSize" value="1048576"/>
        <!-- 跟maxUploadSize差不多,不過maxUploadSizePerFile是限制每個上傳檔案的大小,而maxUploadSize是限制總的上傳檔案大小 -->
        <property name="maxUploadSizePerFile" value="1048576"/>
    </bean>

    <!-- 設定一個簡單的異常解析器,當檔案上傳超過大小限制時跳轉 -->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="defaultErrorView" value="/error.jsp"/>
    </bean>
</beans>複製程式碼

上面配置檔案中的CommonsMultipartResolver下的屬性值配置不是必須的,你也可以全部不寫。到這裡就可以實現單個檔案上傳了,下面來看看多檔案上傳。

三、多檔案上傳

其實多檔案上傳也很簡單,單檔案上傳是在Controller的處理方法中使用MultipartFile物件作為引數接收前端上傳過來的檔案,而多檔案上傳則使用MultipartFile物件陣列來接收。

1、頁面

該頁面中有幾個name值一樣的file型別的input標籤,其他跟單檔案上傳的頁面沒差。

<form action="${pageContext.request.contextPath}/test/upload.do" method="post" enctype="multipart/form-data">
    file 1 : <input type="file" name="imgs"><br /> 
    file 2 : <input type="file" name="imgs"><br /> 
    file 3 : <input type="file" name="imgs"><br /> 
    <input type="submit" name="提交">
</form>複製程式碼

2、控制器

控制器中的處理方法使用MultipartFile[]陣列作為接收引數,並不能直接使用,需要校正引數,具體說明請看程式碼註釋。

@Controller
@RequestMapping("/test")
public class MyController {

    @RequestMapping(value = "/upload.do", method = RequestMethod.POST)
    // 這裡的MultipartFile[] imgs表示前端頁面上傳過來的多個檔案,imgs對應頁面中多個file型別的input標籤的name,但框架只會將一個檔案封裝進一個MultipartFile物件,
    // 並不會將多個檔案封裝進一個MultipartFile[]陣列,直接使用會報[Lorg.springframework.web.multipart.MultipartFile;.<init>()錯誤,
    // 所以需要用@RequestParam校正引數(引數名與MultipartFile物件名一致),當然也可以這麼寫:@RequestParam("imgs") MultipartFile[] files。
    public String upload(@RequestParam MultipartFile[] imgs, HttpSession session)
            throws Exception {
        for (MultipartFile img : imgs) {
            if (img.getSize() > 0) {
                String path = session.getServletContext().getRealPath("images");
                String fileName = img.getOriginalFilename();
                if (fileName.endsWith("jpg") || fileName.endsWith("png")) {
                    File file = new File(path, fileName);
                    img.transferTo(file);
                }
            }
        }
        return "/success.jsp";
    }
}複製程式碼

同樣的,使用MultipartFile陣列接收前端上傳過來的多個檔案,也需要在springmvc的配置檔案進行配置,具體配置與上述單檔案上傳的springmvc.xml配置沒差,直接拷貝過來就行。這樣,就可以進行多檔案上傳了。

四、多種檔案上傳情景綜合

當然,專案開發中,場景可能並不是這麼簡單,上述的多檔案上傳是一個個檔案選擇後一起上傳(即多個name相同的input標籤),那要是我專案中只要一個input標籤就可以一次性多個檔案呢?又或者一個頁面中既要一個個選擇的多檔案上傳,又要一次性選擇的多檔案上傳,還要有單檔案上傳呢?沒問題,MultipartFile[]通吃,程式碼也很easy,下面直接上程式碼。

1、頁面

這裡的 “一次選擇多個檔案的多檔案上傳” 只是在input標籤中加上了multiple屬性而已。

<form action="${pageContext.request.contextPath}/test/upload.do" method="post" enctype="multipart/form-data">

    一次選擇多個檔案的多檔案上傳 : <br /> 
    <input type="file" name="imgs1" multiple><br /> <br /> 

    一次選擇一個檔案的多檔案上傳 : <br /> 
    <input type="file" name="imgs2"><br /> 
    <input type="file" name="imgs2"><br /><br /> 

    單檔案上傳 : <br /> 
    <input type="file" name="imgs3"><br /><br /> 
    <input type="submit" name="提交">
</form>複製程式碼

2、控制器

@Controller
@RequestMapping("/test")
public class MyController {

    @RequestMapping(value = "/upload.do", method = RequestMethod.POST)
    public String upload(@RequestParam MultipartFile[] imgs1,@RequestParam MultipartFile[] imgs2,@RequestParam MultipartFile[] imgs3, HttpSession session)
            throws Exception {
        String path = session.getServletContext().getRealPath("images");
        for (MultipartFile img : imgs1) {
            uploadFile(path, img);
        }
        for (MultipartFile img : imgs2) {
            uploadFile(path, img);
        }
        for (MultipartFile img : imgs3) {
            uploadFile(path, img);
        }
        return "/success.jsp";
    }

    private void uploadFile(String path, MultipartFile img) throws IOException {
        if (img.getSize() > 0) {
            String fileName = img.getOriginalFilename();
            if (fileName.endsWith("jpg") || fileName.endsWith("png")) {
                File file = new File(path, fileName);
                img.transferTo(file);
            }
        }
    }
}複製程式碼

MultipartFile[]就是如此強大,不管單個多個,邏輯處理一樣,所以建議在專案開發中使用MultipartFile[]作為檔案的接收引數。

五、擴充

1、MultipartFile類常用的一些方法:

String getContentType()//獲取檔案MIME型別
InputStream getInputStream()//獲取檔案流
String getName() //獲取表單中檔案元件的名字
String getOriginalFilename() //獲取上傳檔案的原名
long getSize()  //獲取檔案的位元組大小,單位byte
boolean isEmpty() //是否為空
void transferTo(File dest) 複製程式碼

2、CommonsMultipartResolver的屬性解析

defaultEncoding:表示用來解析request請求的預設編碼格式,當沒有指定的時候根據Servlet規範會使用預設值ISO-8859-1。當request自己指明瞭它的編碼格式的時候就會忽略這裡指定的defaultEncoding。
uploadTempDir:設定上傳檔案時的臨時目錄,預設是Servlet容器的臨時目錄。
maxUploadSize:設定允許上傳的總的最大檔案大小,以位元組為單位計算。當設為-1時表示無限制,預設是-1。
maxUploadSizePerFile:跟maxUploadSize差不多,不過maxUploadSizePerFile是限制每個上傳檔案的大小,而maxUploadSize是限制總的上傳檔案大小。
maxInMemorySize:設定在檔案上傳時允許寫到記憶體中的最大值,以位元組為單位計算,預設是10240。
resolveLazily:為true時,啟用推遲檔案解析,以便在UploadAction中捕獲檔案大小異常。複製程式碼

六、注意

  1. 在開發過程中,建議把配置檔案中的異常解析器(SimpleMappingExceptionResolver)先註釋掉,方便我們檢視錯誤。
  2. 有時候上傳出錯,是因為我們在配置檔案中限制了上傳檔案的大小,你可以不加這個限制,但個人建議這個限制最好還是加上,具體檔案大小限制請根據公司專案情況而定。
  3. SpringMVC中使用MultipartFile接收上傳檔案需要依賴兩個jar包,分別是:commons-fileupload-1.3.3.jar、commons-io-2.5.jar。

相關文章