Spring MVC-------文件上傳,單文件,多文件,文件下載

Spring MVC 框架的文件上傳是基於 commons-fileupload 組件的文件上傳,只不過 Spring MVC 框架在原有文件上傳組件上作了進一步封裝,簡化了文件上傳的代碼實現,取消了不一樣上傳組件上的編程差別。
html

commons-fileupload組件

因爲 Spring MVC 框架的文件上傳是基於 commons-fileupload 組件的文件上傳,所以須要將 commons-fileupload 組件相關的 JAR(commons-fileupload-1.3.1.jar 和 commons-io-2.4.jar)複製到 Spring MVC 應用的 WEB-INF/lib 目錄下。下面講解如何下載相關 JAR 包。

Commons 是 Apache 開放源代碼組織中的一個 Java 子項目,該項目包括文件上傳、命令行處理、數據庫鏈接池、XML 配置文件處理等模塊。fileupload 就是其中用來處理基於表單的文件上傳的子項目,commons-fileupload 組件性能優良,並支持任意大小文件的上傳。

commons-fileupload 組件能夠從「http://commons.apache.org/proper/commons-fileupload/」下載,本教程採用的版本是 1.2.2。下載它的 Binares 壓縮包(commons-fileupload-1.3.1-bin.zip),解壓縮後的目錄中有兩個子目錄,分別是 lib 和 site。

在 lib 目錄下有一個 JAR 文件——commons-fileupload-1.3.1.jar,該文件是 commons-fileupload 組件的類庫。在 site 目錄中是 commons-fileupload 組件的文檔,也包括 API 文檔。

commons-fileupload 組件依賴於 Apache 的另一個項目——commons-io,該組件能夠從「http://commons.apache.org/proper/commons-io/」下載,本教程採用的版本是 2.4。下載它的 Binaries 壓縮包(commons-io-2.4-bin.zip),解壓縮後的目錄中有 4 個 JAR 文件,其中有一個 commons-io-2.4.jar 文件,該文件是 commons-io 的類庫。
java

基於表單的文件上傳

標籤 <input type="file"/> 會在瀏覽器中顯示一個輸入框和一個按鈕,輸入框可供用戶填寫本地文件的文件名和路徑名,按鈕可讓瀏覽器打開一個文件選擇框供用戶選擇文件。

文件上傳的表單例子以下:
web

<form method="post" action="upload" enctype="multipart/form-data">
    <input type="file" name="myfile"/>
</form>spring

對於基於表單的文件上傳,不要忘記使用 enctype 屬性,並將它的值設置爲 multipart/form-data,同時將表單的提交方式設置爲 post。爲何要這樣呢?下面從 enctype 屬性提及。

表單的 enctype 屬性指定的是表單數據的編碼方式,該屬性有如下 3 個值。
數據庫

  • application/x-www-form-urlencoded:這是默認的編碼方式,它只處理表單域裏的 value 屬性值。
  • multipart/form-data:該編碼方式以二進制流的方式來處理表單數據,並將文件域指定文件的內容封裝到請求參數裏。
  • text/plain:該編碼方式只有當表單的 action 屬性爲「mailto:」URL 的形式時才使用,主要適用於直接經過表單發送郵件的方式。


由上面 3 個屬性的解釋可知,在基於表單上傳文件時 enctype 的屬性值應爲 multipart/form-data。
apache

MultipartFile接口

在 Spring MVC 框架中上傳文件時將文件相關信息及操做封裝到 MultipartFile 對象中,所以開發者只須要使用 MultipartFile 類型聲明模型類的一個屬性便可對被上傳文件進行操做。該接口具備以下方法。

編程

名稱 做用
byte[] getBytes() 以字節數組的形式返回文件的內容
String getContentType() 返回文件的內容類型
InputStream getInputStream() 返回一個InputStream,從中讀取文件的內容
String getName() 返回請求參數的名稱
String getOriginalFillename() 返回客戶端提交的原始文件名稱
long getSize() 返回文件的大小,單位爲字節
boolean isEmpty() 判斷被上傳文件是否爲空
void transferTo(File destination) 將上傳文件保存到目標目錄下


在上傳文件時須要在配置文件中使用 Spring 的 org.springframework.web.multipart.commons.CommonsMultipartResolver 類配置 MultipartResolver 用於文件上傳。
數組

Spring MVC單文件上傳

1)建立應用並導入 JAR 包

建立應用 springMVCDemo11,將 Spring MVC 相關的 JAR 包、commons-fileupload 組件相關的 JAR 包以及 JSTL 相關的 JAR 包導入應用的 lib 目錄中,如圖 1 所示。

瀏覽器

springMVCDemo11應用的JAR包
圖 1  springMVCDemo11


2)建立 web.xml 文件

在 WEB-INF 目錄下建立 web.xml 文件。爲防止中文亂碼,須要在 web.xml 文件中添加字符編碼過濾器,這裏再也不贅述。
spring-mvc

3)建立文件選擇頁面

在 WebContent 目錄下建立 JSP 頁面 oneFile.jsp,在該頁面中使用表單上傳單個文件,具體代碼以下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>Insert title here</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/onefile"
method="post" enctype="multipart/form-data">
選擇文件:<input type="file" name="myfile"><br>
文件描述:<input type="text" name="description"><br>
<input type="submit" value="提交">
</form>
</body>
</html>

 

4)建立 POJO 類

在 src 目錄下建立 pojo 包,在該包中建立 POJO 類 FileDomain。而後在該 POJO 類中聲明一個 MultipartFile 類型的屬性封裝被上傳的文件信息,屬性名與文件選擇頁面 oneFile.jsp 中的 file 類型的表單參數名 myfile 相同。具體代碼以下:

package pojo;
import org.springframework.web.multipart.MultipartFile;
public class FileDomain {
private String description;
private MultipartFile myfile;

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public MultipartFile getMyfile() {
return myfile;
}

public void setMyfile(MultipartFile myfile) {
this.myfile = myfile;
}
}

 

5)建立控制器類

在 src 目錄下建立 controller 包,並在該包中建立 FileUploadController 控制器類。具體代碼以下:

package controller;

import java.io.File;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

import pojo.FileDomain;

@Controller
public class FileUploadController {
// 獲得一個用來記錄日誌的對象,這樣在打印信息時可以標記打印的是哪一個類的信息
private static final Log logger = LogFactory.getLog(FileUploadController.class);
/**
* 單文件上傳
*/
@RequestMapping("/onefile")
public String oneFileUpload(@ModelAttribute FileDomain fileDomain,
HttpServletRequest request) {
/*
* 文件上傳到服務器的位置「/uploadfiles」,該位置是指
* workspace\.metadata\.plugins\org.eclipse
* .wst.server.core\tmp0\wtpwebapps, 發佈後使用
*/
String realpath = request.getServletContext()
.getRealPath("uploadfiles");
String fileName = fileDomain.getMyfile().getOriginalFilename();
File targetFile = new File(realpath, fileName);
if (!targetFile.exists()) {
targetFile.mkdirs();
}
// 上傳
try {
fileDomain.getMyfile().transferTo(targetFile);
logger.info("成功");
} catch (Exception e) {
e.printStackTrace();
}
return "showOne";
}
}

 

6)建立 Spring MVC 的配置文件

在上傳文件時須要在配置文件中使用 Spring 的 CommonsMultipartResolver 類配置 MultipartResolver 用於文件上傳,應用的配置文件 springmvc-servlet.xml 的代碼以下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 使用掃描機制掃描包 -->
<context:component-scan base-package="controller" />
<!-- 完成視圖的對應 -->
<!-- 對轉向頁面的路徑解析。prefix:前綴, suffix:後綴 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>

<!-- 配置MultipartResolver,用於上傳文件,使用spring的CommonsMultipartResolver -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="5000000" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
</beans>

 

7)建立成功顯示頁面

在 WEB-INF 目錄下建立 JSP 文件夾,並在該文件夾中建立單文件上傳成功顯示頁面 showOne.jsp。具體代碼以下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>Insert title here</title>
</head>
<body>
${fileDomain.description }
<br>
<!-- fileDomain.getMyFile().getOriginalFilename()-->
${fileDomain.myfile.originalFilename }
</body>
</html>

  

8)測試文件上傳

發佈 springMVCDemo11 應用到 Tomcat 服務器並啓動 Tomcat 服務器,而後經過地址「http://localhost:8080/springMVCDemo11/oneFile.jsp」運行文件選擇頁面,運行結果如圖 2 所示。

單文件選擇頁面
                圖 2  單文件選擇頁面


在圖 2 中選擇文件並輸入文件描述,而後單擊「提交」按鈕上傳文件,若成功則顯示如圖 3 所示的結果。

單文件成功上傳結果
                圖 3  單文件成功上傳結果
 

Spring MVC多文件上傳

1)建立多文件選擇頁面

在 WebContent 目錄下建立 JSP 頁面 multiFiles.jsp,在該頁面中使用表單上傳多個文件,具體代碼以下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>Insert title here</title>
</head>
<body>
    <form action="${pageContext.request.contextPath }/multifile"
        method="post" enctype="multipart/form-data">
        選擇文件1:<input type="file" name="myfile"><br>
        文件描述1:<input type="text" name="description"><br />
        選擇文件2:<input type="file" name="myfile"><br>
        文件描述2:<input type="text" name="description"><br />
        選擇文件3:<input type="file" name="myfile"><br>
        文件描述3:<input type="text" name="description"><br />
        <input type="submit" value="提交">
    </form>
</body>
</html>

 

2)建立 POJO 類

在上傳多文件時須要 POJO 類 MultiFileDomain 封裝文件信息,MultiFileDomain 類的具體代碼以下:

 

 

package pojo;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
public class MultiFileDomain {
    private List<String> description;
    private List<MultipartFile> myFile;
    // 省略setter和getter方法
}

3)添加多文件上傳處理方法

在控制器類 FileUploadController 中添加多文件上傳的處理方法 multiFileUpload,具體代碼以下:

/**
* 多文件上傳
*/
@RequestMapping("/multifile")
public String multiFileUpload(@ModelAttribute MultiFileDomain multiFileDomain,HttpServletRequest request) {
    String realpath = request.getServletContext().getRealPath("uploadfiles");
    File targetDir = new File(realpath);
    if (!targetDir.exists()) {
        targetDir.mkdirs();
    }
    List<MultipartFile> files = multiFileDomain.getMyFile();
    for (int i = 0; i < files.size(); i++) {
        MultipartFile file = files.get(i);
        String fileName = file.getOriginalFilename();
        File targetFile = new File(realpath, fileName);
        // 上傳
        try {
            file.transferTo(targetFile);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    logger.info("成功");
    return "showMulti";
}

 

 

4)建立成功顯示頁面

在 JSP 文件夾中建立多文件上傳成功顯示頁面 showMulti.jsp,具體代碼以下:
 
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!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>Insert title here</title>
</head>
<body>
    <table>
        <tr>
            <td>詳情</td>
            <td>文件名</td>
        </tr>
        <!-- 同時取兩個數組的元素 -->
        <c:forEach items="${multiFileDomain.description}" var="description"
            varStatus="loop">
            <tr>
                <td>${description}</td>
                <td>${multiFileDomain.myfile[loop.count-1].originalFilename}</td>
            </tr>
        </c:forEach>
        <!-- fileDomain.getMyfile().getOriginalFilename() -->
    </table>
</body>
</html>

5)測試文件上傳

發佈 springMVCDemo11 應用到 Tomcat 服務器並啓動 Tomcat 服務器,而後經過地址「http://localhost:8080/springMVCDemo11/multiFiles.jsp」運行多文件選擇頁面,運行結果如圖 1 所示。

多文件選擇頁面
                圖 1  多文件選擇頁面


在圖 1 中選擇文件並輸入文件描述,而後單擊「提交」按鈕上傳多個文件,若成功則顯示如圖 2 所示的結果。

多文件成功上傳結果
                圖 2  多文件成功上傳結果  
 
 

Spring MVC文件下載

 

文件下載的實現方法

實現文件下載有如下兩種方法:

  • 經過超連接實現下載。
  • 利用程序編碼實現下載。


經過超連接實現下載當然簡單,但暴露了下載文件的真實位置,而且只能下載存放在 Web 應用程序所在的目錄下的文件。

利用程序編碼實現下載能夠增長安全訪問控制,還能夠從任意位置提供下載的數據,能夠將文件存放到 Web 應用程序之外的目錄中,也能夠將文件保存到數據庫中。

利用程序實現下載須要設置兩個報頭:

1)Web 服務器須要告訴瀏覽器其所輸出內容的類型不是普通文本文件或 HTML 文件,而是一個要保存到本地的下載文件,這須要設置 Content-Type 的值爲 application/x-msdownload。

2)Web 服務器但願瀏覽器不直接處理相應的實體內容,而是由用戶選擇將相應的實體內容保存到一個文件中,這須要設置 Content-Disposition 報頭。

該報頭指定了接收程序處理數據內容的方式,在 HTTP 應用中只有 attachment 是標準方式,attachment 表示要求用戶干預。在 attachment 後面還能夠指定 filename 參數,該參數是服務器建議瀏覽器將實體內容保存到文件中的文件名稱。

設置報頭的示例以下:

response.setHeader("Content-Type", "application/x-msdownload");
response.setHeader("Content-Disposition", "attachment;filename="+filename);

文件下載的過程

下面繼續經過 springMVCDemo11 應用講述利用程序實現下載的過程,要求從《Spring MVC單文件上傳》上傳文件的目錄(workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\springMVCDemo11\uploadfiles)中下載文件,具體開發步驟以下:

1)編寫控制器類

首先編寫控制器類 FileDownController,在該類中有 3 個方法,即 show、down 和 toUTF8String。其中,show 方法獲取被下載的文件名稱;down 方法執行下載功能;toUTF8String 方法是下載保存時中文文件名的字符編碼轉換方法。

FileDownController 類的代碼以下:

package controller;
import java.io.File;
import java.io.FileInputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class FileDownController {
    // 獲得一個用來記錄日誌的對象,在打印時標記打印的是哪一個類的信息
    private static final Log logger = LogFactory
            .getLog(FileDownController.class);
    /**
     * 顯示要下載的文件
     */
    @RequestMapping("showDownFiles")
    public String show(HttpServletRequest request, Model model) {
        // 從 workspace\.metadata\.plugins\org.eclipse.wst.server.core\
        // tmp0\wtpwebapps\springMVCDemo11\下載
        String realpath = request.getServletContext()
                .getRealPath("uploadfiles");
        File dir = new File(realpath);
        File files[] = dir.listFiles();
        // 獲取該目錄下的全部文件名
        ArrayList<String> fileName = new ArrayList<String>();
        for (int i = 0; i < files.length; i++) {
            fileName.add(files[i].getName());
        }
        model.addAttribute("files", fileName);
        return "showDownFiles";
    }
    /**
     * 執行下載
     */
    @RequestMapping("down")
    public String down(@RequestParam String filename,
            HttpServletRequest request, HttpServletResponse response) {
        String aFilePath = null; // 要下載的文件路徑
        FileInputStream in = null; // 輸入流
        ServletOutputStream out = null; // 輸出流
        try {
            // 從workspace\.metadata\.plugins\org.eclipse.wst.server.core\
            // tmp0\wtpwebapps下載
            aFilePath = request.getServletContext().getRealPath("uploadfiles");
            // 設置下載文件使用的報頭
            response.setHeader("Content-Type", "application/x-msdownload");
            response.setHeader("Content-Disposition", "attachment; filename="
                    + toUTF8String(filename));
            // 讀入文件
            in = new FileInputStream(aFilePath + "\\" + filename);
            // 獲得響應對象的輸出流,用於向客戶端輸出二進制數據
            out = response.getOutputStream();
            out.flush();
            int aRead = 0;
            byte b[] = new byte[1024];
            while ((aRead = in.read(b)) != -1 & in != null) {
                out.write(b, 0, aRead);
            }
            out.flush();
            in.close();
            out.close();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        logger.info("下載成功");
        return null;
    }
    /**
     * 下載保存時中文文件名的字符編碼轉換方法
     */
    public String toUTF8String(String str) {
        StringBuffer sb = new StringBuffer();
        int len = str.length();
        for (int i = 0; i < len; i++) {
            // 取出字符中的每一個字符
            char c = str.charAt(i);
            // Unicode碼值爲0~255時,不作處理
            if (c >= 0 && c <= 255) {
                sb.append(c);
            } else { // 轉換 UTF-8 編碼
                byte b[];
                try {
                    b = Character.toString(c).getBytes("UTF-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                    b = null;
                }
                // 轉換爲%HH的字符串形式
                for (int j = 0; j < b.length; j++) {
                    int k = b[j];
                    if (k < 0) {
                        k &= 255;
                    }
                    sb.append("%" + Integer.toHexString(k).toUpperCase());
                }
            }
        }
        return sb.toString();
    }
}

 

2)建立文件列表頁面

下載文件示例須要一個顯示被下載文件的 JSP 頁面 showDownFiles.jsp,代碼以下:

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <table>
        <tr>
            <td>被下載的文件名</td>
        </tr>
        <!--遍歷 model中的 files-->
        <c:forEach items="${files}" var="filename">
            <tr>
                <td>
                    <a href="${pageContext.request.contextPath }/down?filename=${filename}">${filename}</a>
                </td>
            </tr>
        </c:forEach>
    </table>
</body>
</html>

 

3)測試下載功能

發佈 springMVCDemo11 應用到 Tomcat 服務器並啓動 Tomcat 服務器,而後經過地址「http://localhost:8080/springMVCDemo11/showDownFiles」測試下載示例,運行結果如圖 1 所示。

被下載文件列表頁面                   圖 1  被下載文件列表頁面
相關文章
相關標籤/搜索