1. 程式人生 > 實用技巧 >【SpringMVC】SpringMVC 實現檔案上傳

【SpringMVC】SpringMVC 實現檔案上傳

SpringMVC 實現檔案上傳

文章原始碼

檔案上傳回顧

檢視 JavaWeb 階段的檔案上傳下載

實現步驟:

  • 客戶端:
    • 傳送 post 請求,告訴伺服器要上傳什麼檔案
  • 伺服器:
    • 要有一個 form 標籤,method=post 請求,form 標籤的 encType 屬性值必須為 multipart/form-data
    • form 標籤中使用 input type=file 新增上傳的檔案接收並處理上傳的檔案

檔案上傳時 HTTP 協議說明:

  • Content-type 表示提交的資料型別
    • multipart/form-data 表示提交的資料,以多段(每一個表單項代表一個數據段)的形式進行拼接,然後以二進位制流的形式傳送給伺服器
    • boundary 表示每段資料的分隔符,它的值是有瀏覽器隨機生成的,它是每段資料的分割符

實現上傳下載功能常用兩個包:

  • commons-fileupload-1.3.1.jar
  • commons-io-2.4.jar

FileUploadController.java

@Controller
@RequestMapping("/file")
public class FileUploadController {

    /**
     * 檔案上傳回顧
     * @return
     */
    @RequestMapping(path = {"/upload1"})
    public String upload1(HttpServletRequest request) throws Exception {
        System.out.println("called upload1...");

        String path = request.getSession().getServletContext().getRealPath("/uploads"); // 獲取到要上傳的檔案目錄
        System.out.println(path);
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }

        DiskFileItemFactory factory = new DiskFileItemFactory();    // 建立磁碟檔案項工廠
        ServletFileUpload fileUpload = new ServletFileUpload(factory);
        List<FileItem> fileItems = fileUpload.parseRequest(request);    // 解析request物件
        for (FileItem fileItem : fileItems) {
            if (fileItem.isFormField()) {   // 判斷檔案項是普通欄位,還是上傳的檔案
                System.out.println(fileItem.getName());
            } else {
                String itemName = fileItem.getName();   // 獲取到上傳檔案的名稱
                itemName = UUID.randomUUID().toString() + "-" + itemName;   // 把檔名唯一化
                fileItem.write(new File(file, itemName));   // 上傳檔案
                fileItem.delete();
            }
        }

        return "success";
    }
}

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>檔案上傳</title>
</head>
<body>
    <h3>檔案上傳回顧</h3>
    <form action="file/upload1" method="post" enctype="multipart/form-data">
        名稱:<input type="text" name="picName"/><br/>
        圖片:<input type="file" name="picFile"/><br>
        <input type="submit" value="上傳檔案"/>
    </form>
</body>
</html>

SpringMVC 傳統方式的檔案上傳

傳統方式的檔案上傳,指的是我們上傳的檔案和訪問的應用存在於同一臺伺服器上。並且上傳完成之後,瀏覽器可能跳轉。

SpringMVC 框架提供了 MultipartFile 物件,該物件表示上傳的檔案,要求變數名稱必須和表單 file 標籤的 name 屬性名稱相同。並且需要配置檔案解析器物件

    <!-- 配置 檔案解析器,要求 id 名稱必須是 multipartResolver -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10485760"/>
    </bean>

FileUploadController.java

@Controller
@RequestMapping("/file")
public class FileUploadController {

    /**
     * SpringMVC 傳統方式的檔案上傳
     * @return
     */
    @RequestMapping(path = {"/upload2"})
    public String upload2(HttpServletRequest request, String picName, MultipartFile picFile) throws Exception {
        System.out.println("called upload2...");
        String path = request.getSession().getServletContext().getRealPath("/uploads"); // 獲取到要上傳的檔案目錄
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }

        String fileName = picName + "-" + picFile.getOriginalFilename();
        fileName = UUID.randomUUID().toString() + "-" + fileName;
        picFile.transferTo(new File(file, fileName));   // 上傳檔案

        return "success";
    }
}

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>檔案上傳</title>
</head>
<body>
    <h3>SpringMVC 傳統方式檔案上傳</h3>
    <form action="file/upload2" method="post" enctype="multipart/form-data">
        名稱:<input type="text" name="picName"/><br/>
        圖片:<input type="file" name="picFile"/><br>
        <input type="submit" value="上傳檔案"/>
    </form>
    <br>
</body>
</html>

SpringMVC 跨伺服器方式的檔案上傳

在實際開發中,可能會有很多處理不同功能的伺服器。例如:

  • 應用伺服器:負責部署應用
  • 資料庫伺服器:執行資料庫
  • 快取和訊息伺服器:負責處理大併發訪問的快取和訊息
  • 檔案伺服器:負責儲存使用者上傳檔案的伺服器

分伺服器處理的目的是讓伺服器各司其職,從而提高專案的執行效率。

準備兩個 Tomcat 伺服器,注意 HTTP Port 和 JMX Port 不能相同。

一個用作檔案伺服器,並建立一個用於存放檔案的 web 工程。檔案伺服器原始碼,並修改檔案伺服器的 web.xml 配置,使其可以支援寫入操作,搜尋 DefaultServlet,新增以下程式碼:

<init-param>
    <param-name>readonly</param-name>
    <param-value>false</param-value>
</init-param>

另一個 Tomcat 伺服器,編寫以下程式碼


FileUploadController.java

@Controller
@RequestMapping("/file")
public class FileUploadController {

    /**
     * SpringMVC 跨伺服器方式的檔案上傳
     * @return
     */
    @RequestMapping(path = {"/upload3"})
    public String upload3( String picName, MultipartFile picFile) throws Exception {
        System.out.println("called upload3...");

        String path = "http://localhost:9090/file-server/uploads/";  // 定義上傳檔案伺服器路徑

        String fileName = picName + "-" + picFile.getOriginalFilename();
        fileName = UUID.randomUUID().toString() + "-" + fileName;

        // 1. 建立客戶端物件
        Client client = Client.create();

        // 2. 和檔案伺服器進行連線
        WebResource resource = client.resource(path + fileName);

        // 3. 上傳檔案,跨伺服器的
        resource.put(picFile.getBytes());

        return "success";
    }
}

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>檔案上傳</title>
</head>
<body>
    <h3>SpringMVC 跨伺服器方式檔案上傳</h3>
    <form action="file/upload3" method="post" enctype="multipart/form-data">
        名稱:<input type="text" name="picName"/><br/>
        圖片:<input type="file" name="picFile"/><br>
        <input type="submit" value="上傳檔案"/>
    </form>
</body>
</html>

練習和總結