SpringBoot上傳檔案

初念初戀發表於2022-03-04

上傳檔案應該是最經常遇到的場景,今天就來和大家一起來簡單做一個Spring Boot上傳檔案的功能,廢話不多說,直接開始。

專案結構,如下圖:

image-20220224192854095

pom 依賴

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
       <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

上傳控制類

@Controller
public class UploadController
{
    private static String UPLOADED_FOLDER = "D:\\uploadFile\\";

    @GetMapping("/")
    public String index()
    {
        return "upload";
    }

    @PostMapping("/upload")
    public String singleFileUpload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes)
    {
        if (file.isEmpty())
        {
            redirectAttributes.addFlashAttribute("message", "請選擇檔案上傳");
            return "redirect:uploadStatus";
        }

        try
        {
            byte[] bytes = file.getBytes();
            Path dir = Paths.get(UPLOADED_FOLDER);
            Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
            if (!Files.exists(dir))
            {
                Files.createDirectories(dir);
            }
            Files.write(path, bytes);
            redirectAttributes.addFlashAttribute("message","上傳成功,檔案的名稱:" + file.getOriginalFilename());

        }
        catch (IOException e)
        {
            redirectAttributes.addFlashAttribute("message", "服務異常");
            e.printStackTrace();
        }
        return "redirect:/uploadStatus";
    }

    @GetMapping("/uploadStatus")
    public String uploadStatus()
    {
        return "uploadStatus";
    }
}

通過MultipartFile讀取檔案資訊,如果檔案為空跳轉到結果頁並給出提示;如果不為空讀取檔案流並寫入到指定目錄,最後將結果展示到頁面。

MultipartFile是Spring上傳檔案的封裝類,包含了檔案的二進位制流和檔案屬性等資訊,在配置檔案中也可對相關屬性進行配置。

  • spring.http.multipart.enabled=true #預設支援檔案上傳.
  • spring.http.multipart.file-size-threshold=0 #支援檔案寫入磁碟.
  • spring.http.multipart.location= # 上傳檔案的臨時目錄
  • spring.http.multipart.max-file-size=1Mb # 最大支援檔案大小
  • spring.http.multipart.max-request-size=10Mb # 最大支援請求大小

最常用的是最後兩個配置內容,限制檔案上傳大小,上傳時超過大小會丟擲異常。

配置檔案

application.properties

server.port=8086
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB

異常處理

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MultipartException.class)
    public String handleError1(MultipartException e, RedirectAttributes redirectAttributes) {
        redirectAttributes.addFlashAttribute("message", e.getCause().getMessage());
        return "redirect:/uploadStatus";
    }
}

設定一個@ControllerAdvice用來監控Multipart上傳的檔案大小是否受限,當出現此異常時在前端頁面給出提示。

前端頁面

upload.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>
<h1>上傳檔案</h1>
<form method="POST" action="/upload" enctype="multipart/form-data">
    <input type="file" name="file" /><br/><br/>
    <input type="submit" value="Submit" />
</form>
</body>
</html>

uploadStatus.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>
<h1>上傳狀態</h1>
<div th:if="${message}">
    <h2 th:text="${message}"/>
</div>
</body>
</html>

測試

  • 啟動專案,瀏覽器輸入localhost:8086,顯示如下:

image-20220224194637932

  • 選擇檔案進行上傳,這裡我選擇了一張圖片

image-20220224194917297

  • 點選Submit,顯示上傳成功。

image-20220224195150865

  • 檢視本地資料夾D:\\uploadFile\\中已經有了該圖片,至此該上傳功能已實現。

大檔案上傳

  • 測試一下,超過設定的10M的檔案上傳結果,如下圖,上傳檔案大於10M出現連線重置的問題,此異常內容 GlobalException 也捕獲不到。

image-20220224195712745

Tomcat連線重置

如果部署到Tomcat,請配置maxSwallowSize以避免此Tomcat連線重置問題。 對於嵌入式Tomcat,宣告一個TomcatEmbeddedServletContainerFactory,如下程式碼:

package com.cy;

import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class SpringbootUploadApplication
{

    public static void main(String[] args)
    {
        SpringApplication.run(SpringbootUploadApplication.class, args);
    }

    @Bean
    public TomcatEmbeddedServletContainerFactory tomcatEmbedded() {
        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
        tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {
            if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) {
                //-1 means unlimited
                ((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);
            }
        });
        return tomcat;
    }

}

再次上傳超過大小限制的檔案,頁面丟擲異常如下:

image-20220225092138180

總結

關於springboot上傳檔案簡單的demo完成了,還有多檔案上傳,小夥伴們也可以自己去試試。

相關文章