上传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”。

广告
将在 10 秒后关闭
bannerAds