原文: http://zetcode.com/springboot/uploadfile/

Spring Boot 上传文件教程展示了如何使用 Spring Boot 框架上传单个文件。

Spring 是流行的 Java 应用框架,而 Spring Boot 是 Spring 的演进,可以帮助轻松地创建独立的,生产级的基于 Spring 的应用。

HTML 表单的编码类型

POST 请求有三种编码 HTML 表单类型:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

application/x-www-form-urlencoded是默认编码,其中值编码在由&分隔的键值元组中。 =字符用于键和值之间。 非字母数字字符采用百分比编码。 此编码类型不适用于二进制文件。

multipart/form-data用于非 acsii 数据和二进制文件。 input元素的type属性设置为file

text/plain用于调试。

Spring 上传文件示例

在下面的示例中,我们有一个 Web 表单来选择要上传到服务器的文件。 该文件被上传到/var/www/upload目录。

上传目录

/var/www目录是 Debian Linux 中 Web 内容的标准目录。

  1. $ ls -ld /var/www/upload/
  2. drwxrwxr-x 2 www-data www-data 4096 Dec 3 14:29 /var/www/upload/

我们将文件上传到/var/www/upload目录。 www-data组中的用户可以修改目录文件。 因此,运行 Web 服务器的用户必须在此组中。

应用

以下是 Spring Boot Web 应用的来源。

  1. pom.xml
  2. src
  3. ├───main
  4. ├───java
  5. └───com
  6. └───zetcode
  7. Application.java
  8. ├───controller
  9. MyController.java
  10. ├───exception
  11. StorageException.java
  12. └───service
  13. StorageService.java
  14. └───resources
  15. application.properties
  16. └───static
  17. failure.html
  18. index.html
  19. success.html
  20. └───test
  21. └───java

这是 Spring 应用的项目结构。

pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  5. http://maven.apache.org/xsd/maven-4.0.0.xsd">
  6. <modelVersion>4.0.0</modelVersion>
  7. <groupId>com.zetcode</groupId>
  8. <artifactId>springbootuploadfile</artifactId>
  9. <version>1.0-SNAPSHOT</version>
  10. <packaging>jar</packaging>
  11. <properties>
  12. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  13. <maven.compiler.source>11</maven.compiler.source>
  14. <maven.compiler.target>11</maven.compiler.target>
  15. </properties>
  16. <parent>
  17. <groupId>org.springframework.boot</groupId>
  18. <artifactId>spring-boot-starter-parent</artifactId>
  19. <version>1.5.9.RELEASE</version>
  20. </parent>
  21. <dependencies>
  22. <dependency>
  23. <groupId>org.springframework.boot</groupId>
  24. <artifactId>spring-boot-starter-web</artifactId>
  25. </dependency>
  26. </dependencies>
  27. <build>
  28. <plugins>
  29. <plugin>
  30. <groupId>org.springframework.boot</groupId>
  31. <artifactId>spring-boot-maven-plugin</artifactId>
  32. </plugin>
  33. </plugins>
  34. </build>
  35. </project>

这是 Maven pom.xml文件。

com/zetcode/controller/MyController.java

  1. package com.zetcode.controller;
  2. import com.zetcode.exception.StorageException;
  3. import com.zetcode.service.StorageService;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.stereotype.Controller;
  6. import org.springframework.web.bind.annotation.ExceptionHandler;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.RequestMethod;
  9. import org.springframework.web.bind.annotation.RequestParam;
  10. import org.springframework.web.multipart.MultipartFile;
  11. @Controller
  12. public class MyController {
  13. @Autowired
  14. private StorageService storageService;
  15. @RequestMapping(value = "/doUpload", method = RequestMethod.POST,
  16. consumes = {"multipart/form-data"})
  17. public String upload(@RequestParam MultipartFile file) {
  18. storageService.uploadFile(file);
  19. return "redirect:/success.html";
  20. }
  21. @ExceptionHandler(StorageException.class)
  22. public String handleStorageFileNotFound(StorageException e) {
  23. return "redirect:/failure.html";
  24. }
  25. }

MyController从请求中读取文件并将其保存到所选目录中。

  1. @Autowired
  2. private StorageService storageService;

StoreageService将文件存储在磁盘上。

  1. @RequestMapping(value = "/doUpload", method = RequestMethod.POST,
  2. consumes = {"multipart/form-data"})
  3. public String upload(@RequestParam MultipartFile file) {

upload()方法映射到doUpload URL 模式。 由于我们正在将数据发送到服务器,因此我们使用 POST 请求。 请求参数具有MultipartFile类型。

  1. return "redirect:/success.html";

成功上传文件后,我们会显示一条消息。

  1. @ExceptionHandler(StorageException.class)
  2. public String handleStorageFileNotFound(StorageException e) {
  3. return "redirect:/failure.html";
  4. }

我们有StorageException的处理器。

com/zetcode/StorageException.java

  1. package com.zetcode.exception;
  2. public class StorageException extends RuntimeException {
  3. public StorageException(String message) {
  4. super(message);
  5. }
  6. public StorageException(String message, Throwable cause) {
  7. super(message, cause);
  8. }
  9. }

这是我们的自定义StorageException。 当文件无法存储在文件系统上时,将引发该错误。

com/zetcode/service/StorageService.java

  1. package com.zetcode.service;
  2. import com.zetcode.exception.StorageException;
  3. import org.springframework.beans.factory.annotation.Value;
  4. import org.springframework.stereotype.Service;
  5. import org.springframework.web.multipart.MultipartFile;
  6. import java.io.IOException;
  7. import java.nio.file.Files;
  8. import java.nio.file.Paths;
  9. import java.nio.file.StandardCopyOption;
  10. @Service
  11. public class StorageService {
  12. @Value("${upload.path}")
  13. private String path;
  14. public void uploadFile(MultipartFile file) {
  15. if (file.isEmpty()) {
  16. throw new StorageException("Failed to store empty file");
  17. }
  18. try {
  19. var fileName = file.getOriginalFilename();
  20. var is = file.getInputStream();
  21. Files.copy(is, Paths.get(path + fileName),
  22. StandardCopyOption.REPLACE_EXISTING);
  23. } catch (IOException e) {
  24. var msg = String.format("Failed to store file", file.getName());
  25. throw new StorageException(msg, e);
  26. }
  27. }
  28. }

StorageService从输入流复制数据并将其保存在磁盘上。

  1. @Value("${upload.path}")
  2. private String path;

我们使用@Value注解从application.properties文件中读取上传目录。

  1. if (file.isEmpty()) {
  2. throw new StorageException("Failed to store empty file");
  3. }

我们确保已使用isEmpty()方法选择了一个文件。

  1. var fileName = file.getOriginalFilename();

我们使用getOriginalFilename()方法获得文件名。

  1. var is = file.getInputStream();

我们使用getInputStream()方法获得输入流。

  1. Files.copy(is, Paths.get(path + fileName),
  2. StandardCopyOption.REPLACE_EXISTING);

该文件被复制到从与Files.copy()输入流源的目标目录。

resources/application.properties

  1. upload.path=/var/www/upload/

application.properties中,我们有一个upload.path属性,用于指定上传目录。

resources/static/index.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Uploading file</title>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. </head>
  8. <body>
  9. <h1>Uploading file</h1>
  10. <form action="/doUpload" method="post" enctype="multipart/form-data">
  11. <label>Enter file</label>
  12. <input type="file" name="file">
  13. <button type="submit">Upload</button>
  14. </form>
  15. </body>
  16. </html>

这是主页。 它是src/main/resources/static目录中的静态文件。 它包含一个用于选择文件并将其发送到 Spring 应用的表单。

  1. <form action="/doUpload" method="post" enctype="multipart/form-data">

我们选择了doUpload URL 模式。 此表单创建的请求将由 Spring 控制器处理。 enctype属性指定multipart/form-data编码类型,这是使用 HTML 格式上传文件所必需的。

  1. <input type="file" name="file">

input标签的type属性使用户可以选择文件。

  1. <button type="submit">Upload</button>

最后,这是一个提交按钮。

resources/static/success.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Success</title>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. </head>
  8. <body>
  9. <p>File successfully uploaded</p>
  10. </body>
  11. </html>

文件成功上传到服务器后,将显示success.html

resources/static/failure.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Failure</title>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. </head>
  8. <body>
  9. <p>Failed to upload file</p>
  10. </body>
  11. </html>

文件上传失败时,将显示failure.html

Application.java

  1. package com.zetcode;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication
  5. public class Application {
  6. public static void main(String[] args) {
  7. SpringApplication.run(Application.class, args);
  8. }
  9. }

这段代码设置了 Spring Boot 应用。

在本教程中,我们学习了如何在 Spring 应用中上传文件。 您可能也对相关教程感兴趣: Spring Boot @ExceptionHandler教程Spring Boot @PathVariable教程Spring Boot @RequestParam教程Spring Boot REST H2 教程独立的 Spring 应用Java 教程