Spring Boot 上传文件
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 内容的标准目录。
$ ls -ld /var/www/upload/
drwxrwxr-x 2 www-data www-data 4096 Dec 3 14:29 /var/www/upload/
我们将文件上传到/var/www/upload
目录。 www-data
组中的用户可以修改目录文件。 因此,运行 Web 服务器的用户必须在此组中。
应用
以下是 Spring Boot Web 应用的来源。
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ │ Application.java
│ │ ├───controller
│ │ │ MyController.java
│ │ ├───exception
│ │ │ StorageException.java
│ │ └───service
│ │ StorageService.java
│ └───resources
│ │ application.properties
│ └───static
│ failure.html
│ index.html
│ success.html
└───test
└───java
这是 Spring 应用的项目结构。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zetcode</groupId>
<artifactId>springbootuploadfile</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven pom.xml
文件。
com/zetcode/controller/MyController.java
package com.zetcode.controller;
import com.zetcode.exception.StorageException;
import com.zetcode.service.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
@Controller
public class MyController {
@Autowired
private StorageService storageService;
@RequestMapping(value = "/doUpload", method = RequestMethod.POST,
consumes = {"multipart/form-data"})
public String upload(@RequestParam MultipartFile file) {
storageService.uploadFile(file);
return "redirect:/success.html";
}
@ExceptionHandler(StorageException.class)
public String handleStorageFileNotFound(StorageException e) {
return "redirect:/failure.html";
}
}
MyController
从请求中读取文件并将其保存到所选目录中。
@Autowired
private StorageService storageService;
StoreageService
将文件存储在磁盘上。
@RequestMapping(value = "/doUpload", method = RequestMethod.POST,
consumes = {"multipart/form-data"})
public String upload(@RequestParam MultipartFile file) {
upload()
方法映射到doUpload
URL 模式。 由于我们正在将数据发送到服务器,因此我们使用 POST 请求。 请求参数具有MultipartFile
类型。
return "redirect:/success.html";
成功上传文件后,我们会显示一条消息。
@ExceptionHandler(StorageException.class)
public String handleStorageFileNotFound(StorageException e) {
return "redirect:/failure.html";
}
我们有StorageException
的处理器。
com/zetcode/StorageException.java
package com.zetcode.exception;
public class StorageException extends RuntimeException {
public StorageException(String message) {
super(message);
}
public StorageException(String message, Throwable cause) {
super(message, cause);
}
}
这是我们的自定义StorageException
。 当文件无法存储在文件系统上时,将引发该错误。
com/zetcode/service/StorageService.java
package com.zetcode.service;
import com.zetcode.exception.StorageException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
@Service
public class StorageService {
@Value("${upload.path}")
private String path;
public void uploadFile(MultipartFile file) {
if (file.isEmpty()) {
throw new StorageException("Failed to store empty file");
}
try {
var fileName = file.getOriginalFilename();
var is = file.getInputStream();
Files.copy(is, Paths.get(path + fileName),
StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
var msg = String.format("Failed to store file", file.getName());
throw new StorageException(msg, e);
}
}
}
StorageService
从输入流复制数据并将其保存在磁盘上。
@Value("${upload.path}")
private String path;
我们使用@Value
注解从application.properties
文件中读取上传目录。
if (file.isEmpty()) {
throw new StorageException("Failed to store empty file");
}
我们确保已使用isEmpty()
方法选择了一个文件。
var fileName = file.getOriginalFilename();
我们使用getOriginalFilename()
方法获得文件名。
var is = file.getInputStream();
我们使用getInputStream()
方法获得输入流。
Files.copy(is, Paths.get(path + fileName),
StandardCopyOption.REPLACE_EXISTING);
该文件被复制到从与Files.copy()
输入流源的目标目录。
resources/application.properties
upload.path=/var/www/upload/
在application.properties
中,我们有一个upload.path
属性,用于指定上传目录。
resources/static/index.html
<!DOCTYPE html>
<html>
<head>
<title>Uploading file</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h1>Uploading file</h1>
<form action="/doUpload" method="post" enctype="multipart/form-data">
<label>Enter file</label>
<input type="file" name="file">
<button type="submit">Upload</button>
</form>
</body>
</html>
这是主页。 它是src/main/resources/static
目录中的静态文件。 它包含一个用于选择文件并将其发送到 Spring 应用的表单。
<form action="/doUpload" method="post" enctype="multipart/form-data">
我们选择了doUpload
URL 模式。 此表单创建的请求将由 Spring 控制器处理。 enctype
属性指定multipart/form-data
编码类型,这是使用 HTML 格式上传文件所必需的。
<input type="file" name="file">
input
标签的type
属性使用户可以选择文件。
<button type="submit">Upload</button>
最后,这是一个提交按钮。
resources/static/success.html
<!DOCTYPE html>
<html>
<head>
<title>Success</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<p>File successfully uploaded</p>
</body>
</html>
文件成功上传到服务器后,将显示success.html
。
resources/static/failure.html
<!DOCTYPE html>
<html>
<head>
<title>Failure</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<p>Failed to upload file</p>
</body>
</html>
文件上传失败时,将显示failure.html
。
Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
这段代码设置了 Spring Boot 应用。
在本教程中,我们学习了如何在 Spring 应用中上传文件。 您可能也对相关教程感兴趣: Spring Boot @ExceptionHandler
教程, Spring Boot @PathVariable
教程, Spring Boot @RequestParam
教程, Spring Boot REST H2 教程,独立的 Spring 应用, Java 教程。