上传Spring MVC文件
使用Spring MVC,可以轻松接收从Web浏览器上传的文件。在这里,我们将从基本的实现方法开始,详细介绍文件上传的深度方法。
基本的实施方法
我們將創建一個上傳文件的界面。在這裡,我們將使用Thymeleaf作為模板引擎。
這是一個僅包含選擇上傳文件的字段和上傳按鈕的簡單界面。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>File Upload</title>
</head>
<body>
<form action="/sample/upload" th:action="@{/sample/upload}" method="post" enctype="multipart/form-data">
<input type="file" name="upload_file" /><br />
<button type="submit">upload</button>
</form>
</body>
</html>
接下来,我们将创建一个控制器方法,用于处理用户点击上传按钮后的提交操作。
@PostMapping("upload")
public String upload(@RequestParam("upload_file") MultipartFile multipartFile, Model model) {
model.addAttribute("originalFilename", multipartFile.getOriginalFilename());
return "sample/result";
}
在控制器的参数中添加MultipartFile,并使用@RequestParam注释指定该参数。这个@RequestParam注释的value属性用于指定要选择上传文件的字段的name属性的值,这是关键所在。
<input type="file" name="upload_file" />
public String upload(@RequestParam("upload_file") MultipartFile multipartFile, ...) {
与选择文件的字段进行映射
先前的示例中,我們使用了@RequestParam註解來將畫面上選擇檔案的欄位的name屬性與控制器的引數MultipartFile進行映射。但是我們還可以更簡單地進行映射。只需讓畫面上選擇檔案的欄位的name屬性和控制器的引數MultipartFile的變數名稱相同,就可以自動進行映射,而無需使用@RequestParam註解。
<input type="file" name="multipartFile" />
public String upload(MultipartFile multipartFile, ...) {
我们可以看到控制器的实现变得简单了。
对表单的绑定
通常的输入字段和选择文件的字段一样,也可以绑定到表单的成员变量上。
首先,创建一个Form类。使用lombok来省略访问方法的实现。
@Getter
@Setter
public class UploadForm {
private MultipartFile multipartFile;
}
为了将选择图像文件的字段与Form类的成员变量进行映射,我们需要对其进行少量修改。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>File Upload</title>
</head>
<body>
<form action="/sample/upload" th:action="@{/sample/upload}" method="post" enctype="multipart/form-data" th:object="${uploadForm}">
<input type="file" th:field="*{multipartFile}" /><br />
<button type="submit">upload</button>
</form>
</body>
</html>
只需将控制器的Form类作为参数,即可接收上传的文件。
@PostMapping("upload")
public String upload(UploadForm uploadForm, Model model) {
model.addAttribute("originalFilename", uploadForm.getMultipartFile()
.getOriginalFilename());
return "sample/result";
}
上传文件的验证
和常规的输入字段一样,上传的文件通常也需要进行验证。
您可以在控制器内实现对接收到的MultipartFile对象进行验证,但是将验证过程和常规处理分开会使源代码更易读。
通过Bean Validation进行验证。
我们可以通过为Form类的成员变量指定注解来实现上传文件的验证,这是通过Bean Validation实现的。然而,Bean Validation并没有提供上传文件的验证功能。
由于Bean Validation是在JSR(即Java规范要求)中定义的,因此它无法与Spring Framework的独特规范MultipartFile对文件上传进行兼容,这是可以理解的。
在Bean Validation中,提供了开发人员实现自定义验证的方法,因此我们可以利用这个机制来创建适用于上传文件的验证。
在这里,我们将创建一个@FileRequired注解,该注解必须指定文件。
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = FileRequiredValidator.class)
public @interface FileRequired {
String message() default "{com.example.demo.validation.FileRequired.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface List {
FileRequired[] value();
}
}
接下来,创建与注释相对应的验证器类。验证处理本身将在该类中实现。
如果未指定上传文件,则通过MultipartFile对象的getOriginalFilename()方法返回的文件名将为空字符串(“”),因此将使用该方法的返回值进行验证。
public class FileRequiredValidator implements ConstraintValidator<FileRequired, MultipartFile> {
@Override
public void initialize(FileRequired constraint) {}
@Override
public boolean isValid(MultipartFile multipartFile, ConstraintValidatorContext context) {
return multipartFile != null
&& !multipartFile.getOriginalFilename().isEmpty();
}
}
到目前为止,自定义验证的实现已经完成了。剩下的就是通过正常的Bean Validation实现方式,可以对上传文件进行验证。
具体来说,您需要为表单的成员变量指定验证的注解。
@FileRequired
private MultipartFile multipartFile;
接下来,在控制器的Form参数上标注@Validated注解,并添加BindingResult参数,同时添加对验证错误的处理。
@PostMapping("upload")
public String upload(@Valid UploadForm uploadForm, BindingResult result, Model model) {
if (result.hasErrors()) {
return "sample/upload";
}
通过使用与普通的Bean Validation相同的实现,可以验证上传文件。
准备好Bean Validation可以减少常见的上传文件验证的实现成本。
例如,以下这种Bean Validation看起来具有较高的可重用性。
-
- ファイルの指定必須。
-
- ファイルが空(0バイト)でない。
- ファイルの種類が特定のものである。
使用Spring Validator进行验证
使用Bean Validation和Spring验证程序,已为Form类的每个成员变量添加了可重用的通用验证。相比之下,Spring验证程序通过表单来实现验证。
在此示例中,我们将使用Spring验证程序来实现上传文件的验证。
我们将实现具有org.springframework.validation.Validator接口的类的验证处理。
@Component
public class MultipartFileValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return UploadForm.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
UploadForm uploadForm = (UploadForm) target;
if (uploadForm.getMultipartFile().getOriginalFilename().isEmpty()) {
errors.rejectValue("multipartFile", "com.example.demo.validation.FileLinesLarge.message");
}
}
}
只需这样,Spring Validator的实现就完成了。接下来,您只需在控制器类中设置使用Spring Validator来验证表单即可。
@Autowired
private MultipartFileValidator multipartFileValidator;
@InitBinder
private void initBinderFileBucket(WebDataBinder binder) {
binder.setValidator(multipartFileValidator);
}
在中国,控制器方法的更改与Bean Validator相似。
@PostMapping("upload")
public String upload(@Valid UploadForm uploadForm, BindingResult result, Model model) {
if (result.hasErrors()) {
return "sample/upload";
}
文件上载设置
在Spring中,有一些与文件上传相关的配置项。在这里,我们将解释如何使用Spring Boot进行文件上传的配置。
spring.servlet.multipart.max-file-size的中文含义是指上传文件的最大大小限制。
请指定每个上传文件的最大大小。默认为“1MB”。您可以在数字之后添加单位“MB”或“KB”来指定最大大小。
请注意,这是单个文件的最大大小。例如,如果指定为“1MB”,则可以上传10个“1MB”文件,但不能上传一个“10MB”文件。
spring.servlet.multipart.max-file-size=50MB
这个属性的键名已经在Spring Boot 2.0.0中被改变了。如果使用的是Spring Boot 2.0.0之前的版本,则需要使用之前的键名”spring.http.multipart.max-file-size”。
spring.servlet.multipart.max-request-size 可以翻译为 “春季.服务器.多部分.最大请求大小”
设置整个Multipart请求的最大大小。默认为”10MB”。在数字后面加上单位”MB”或”KB”来指定最大大小。
请注意,这个”最大大小”是指上传文件以及其他输入项目等发送到服务器的所有数据的总”最大大小”。
spring.servlet.multipart.max-request-size=100MB
这个属性的键名在Spring Boot 2.0.0中已经被更改。如果使用的是Spring Boot 2.0.0之前的版本,需要使用先前的键名”spring.http.multipart.max-request-size”。
spring.servlet.multipart.enabled 的中文解释为:启用 Spring 的文件上传功能。
指定是否开启Spring的默认实现MultipartResolver来处理Multipart请求。默认情况下,MultipartResolver是启用的,值为true。
Multipart文件上传的接口是由RFC 1867定义的,并且可以轻松进行交换。如果要使用除了Spring默认实现MultipartResolver以外的其他实现,将此属性设置为false。
spring.servlet.multipart.enabled=false
这个属性的键名在Spring Boot 2.0.0版本中已经被修改。如果使用的是Spring Boot 2.0.0之前的版本,则需要使用以前的键名“spring.http.multipart.enabled”。
spring.servlet.multipart.file-size-threshold 可以被理解为 “Spring 框架中的文件大小阈值”。
上传文件大小的阈值是指文件被写入服务器磁盘的大小。当上传的文件大小超过此属性的设定值时,该文件将被写入服务器磁盘。如果上传的文件大小低于此属性的设定值,那么该文件将不会被写入磁盘,而是在内存中保留。默认值为“0”。可以在数字后面添加单位“MB”或“KB”来指定阈值。
spring.servlet.multipart.file-size-threshold=100MB
这个属性的键名在Spring Boot 2.0.0中已经改变。如果使用Spring Boot 2.0.0之前的版本,需要使用之前的键名“spring.http.multipart.file-size-threshold”。
春天. servlet. 多部分. 位置
指定您在将上传的文件作为中间文件写入服务器硬盘时的位置(目录)。默认情况下未指定,将使用应用服务器默认的临时文件目录。
spring.servlet.multipart.location=/upload/temp
这个属性的键名在Spring Boot 2.0.0中已经更改。如果使用的是Spring Boot 2.0.0之前的版本,则需要使用以前的键名”spring.http.multipart.location”。
spring.servlet.multipart.resolve-lazily 可以懒加载进行解析。
设置是否延迟确认已上传文件。默认设置为false,不延迟确认文件。
如果要处理MultipartException异常,则设置为true。
通过延迟确认,可以改变在上传的文件大小较大时发生MultipartException的时间,从而可以在控制器的@ExceptionHandler中捕获它。
spring.servlet.multipart.resolve-lazily=true
这个属性的键名在Spring Boot 2.0.0中已经更改。如果使用早于Spring Boot 2.0.0的版本,则需要使用以前的键名“spring.http.multipart.resolve-lazily”。