1. 程式人生 > 其它 >spring-mvc之檔案上傳與下載

spring-mvc之檔案上傳與下載

配置

spring-boot中,起步依賴自動添加了需要的庫,並自動配置了 MultipartResolver 解析器,所以這步只針對直接使用spring的情況

spring-webmvc基於Apache提供的2個庫實現檔案的上傳與下載

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.8.0</version>
</dependency>

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

配置MultipartResolver元件

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>

檔案上傳

官方文件參考

https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-multipart-forms

Spring中檔案上傳的核心是使用 MultipartFile 型別的引數接收檔案資料。

MultipartFile提供了以下常用方法

  • boolean isEmpty() - 判斷表單檔案是否為空
  • String getOriginalFilename(); - 獲取檔名
  • String getContentType() - 獲取檔案型別
  • long getSize() - 獲取檔案大小
  • byte[] getBytes() - 將檔案轉換為位元組陣列
  • InputStream getInputStream() - 將檔案轉換為輸入流
  • void transferTo(File dest) - 檔案儲存的快捷方式
  • void transferTo(Path dest)

另外,spring-boot檔案上傳預設配置中,單檔案限制大小為1MB,單次請求檔案總大小限制為10MB,可以使用以下方式修改預設值

spring:
  servlet:
    multipart:
      enabled: true
      max-file-size: 2MB # 單檔案大小限制
      max-request-size: 10MB # 檔案總大小限制

單檔案上傳示例

HTML表單

<form action="/file/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file">
    <button type="submit">上傳</button>
</form>

控制器程式碼

@PostMapping("/file/upload")
@ResponseBody
public String uploadFile(@RequestParam("file")MultipartFile file)
{
    if(!file.isEmpty())
    {
        String fileName=file.getOriginalFilename();
        String basePath="/home/lyp/Projects/spring-boot/web/src/main/resources/res";
        try
        {
            File f=new File(basePath,fileName);
            file.transferTo(f);
            return "上傳成功";
        }
        catch(IOException e)
        {
            e.printStackTrace();
        }
    }
    return "上傳失敗";
}

多檔案上傳示例

HTML表單

<form action="/files/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="files" multiple>
    <button type="submit">上傳</button>
</form>

控制器中只需要接收MultipartFile陣列或List即可

@PostMapping("/files/upload")
@ResponseBody
public String uploadFiles(@RequestParam("files") List<MultipartFile> files)
{
    String basePath = "/home/lyp/Projects/spring-boot/web/src/main/resources/res";
    try
    {
        for(MultipartFile file: files)
        {
            if(!file.isEmpty())
            {
                String fileName = file.getOriginalFilename();
                File f = new File(basePath,fileName);
                file.transferTo(f);
            }
        }
        return "上傳成功";
    }
    catch(IOException e)
    {
        e.printStackTrace();
    }

    return "上傳失敗";
}

檔案下載

使用Servlet相關的API即可,唯一需要注意的是設定響應頭資訊

這裡測試圖片在res目錄下,客戶端之所以直接從根路徑訪問而不用加res字首,是因為額外將res目錄配置到spring-boot的靜態資源查詢路徑中了。
配置方法就是使用 static-locations 選項。

HTML程式碼

<img src="/test.png" alt="">
<a href="/file/download?filename=test.png">下載</a>

控制器程式碼

@GetMapping("/file/download")
@ResponseBody
public String download(@RequestParam("filename") String filename,
                        HttpServletResponse resp)
{
    if(filename!=null && !filename.isBlank())
    {
        String basePath = "/home/lyp/Projects/spring-boot/web/src/main/resources/res";
        File file=new File(basePath,filename);
        if(file.exists())
        {
            resp.setContentType("application/forc-download");
            resp.setHeader("Content-Disposition","attachment;filename="+filename);
            try(ServletOutputStream out=resp.getOutputStream();)
            {
                Path path=Path.of(file.toURI());
                byte[] bytes = Files.readAllBytes(path);
                out.write(bytes);
                out.flush();
                return "下載成功";
            }
            catch(IOException e)
            {
                e.printStackTrace();
            }
        }
    }
    return "下載失敗";
}