spring-boot - 在 SpringBoot 中,如何为 MultipartFile 参数创建自定义验证器?

标签 spring-boot validation spring-annotations spring-validator multipartfile

我正在使用 Spring Boot 2.4。我有以下 Controller ,其方法接受 MultipartFile 对象。

@RestController
public class MyController extends AbstractController

    ...
  @Override
  public ResponseEntity<ResponseData> add(
    ...
      @Parameter(description = "file detail") @Validated @RequestPart("myFile")
          MultipartFile myFile,
    ...
    ) {

我想验证此 MultipartFile 是否包含我想要的数据(例如,属于特定的 mime 类型)。所以我写了下面的验证器......

@Documented
@Constraint(validatedBy = MultipartFileValidator.class)
@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MultipartFileConstraint {
  String message() default "Incorrect file type.";

  Class<?>[] groups() default {};

  Class<? extends Payload>[] payload() default {};
}

及其实现类...

public class MultipartFileValidator
    implements ConstraintValidator<MultipartFileConstraint, MultipartFile> {

  @Override
  public void initialize(final MultipartFileConstraint constraintAnnotation) {
    log.info("\n\n\n\nconstructor called\n\n\n\n");
  }

  @Override
  public boolean isValid(
      MultipartFile file, ConstraintValidatorContext constraintValidatorContext) {
    log.info("Validating file");
    ...
  }
}

但是,当我调用端点时,我没有看到我的验证器被调用(例如,日志语句从未被打印,也从未命中断点)。我还需要做什么来为这个 MultipartFile 参数注册我的验证器?

最佳答案

根据 Spring Documentation :

Can also be used with method level validation, indicating that a specific class is supposed to be validated at the method level (acting as a pointcut for the corresponding validation interceptor), but also optionally specifying the validation groups for method-level validation in the annotated class.

Applying this annotation at the method level allows for overriding the validation groups for a specific method but does not serve as a pointcut; a class-level annotation is nevertheless necessary to trigger method validation for a specific bean to begin with. Can also be used as a meta-annotation on a custom stereotype annotation or a custom group-specific validated annotation.

所以,这里我们必须记住@Validated和验证器注释的放置位置。 代码:

Controller 类:在类级别添加@Validated,在方法中添加@ValidFile(自定义验证器注释)

@RestController
@Validated
@Slf4j
public  class MyController {

    @RequestMapping("/add")
    public ResponseEntity<ResponseData> add(@ValidFile @RequestParam("file")  MultipartFile file) {

        log.info("File Validated");
        return  ResponseEntity.status(HttpStatus.OK).body(new ResponseData("Valid file received"));
    }
}

验证器注释

@Documented
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {FileValidator.class})
public @interface ValidFile {
    Class<? extends Payload> [] payload() default{};
    Class<?>[] groups() default {};
    String message() default "Only pdf,xml,jpeg,jpg files are allowed";
}

验证器类

@Slf4j
public class FileValidator implements ConstraintValidator<ValidFile, MultipartFile> {

    @Override
    public void initialize(ValidFile validFile) {
        log.info("File validator initialized!!");
    }

    @Override
    public boolean isValid(MultipartFile multipartFile,
                           ConstraintValidatorContext   constraintValidatorContext) {
        log.info("Validating file");
        String contentType = multipartFile.getContentType();
        assert contentType != null;
        return isSupportedContentType(contentType);
    }
    private boolean isSupportedContentType(String contentType) {
        return contentType.equals("application/pdf")
                || contentType.equals("text/xml")
                || contentType.equals("image/jpg")
                || contentType.equals("image/jpeg");
    }
}

输出: 成功:

{
    "message": "Valid file received"
}

异常处理程序

 @ExceptionHandler(ConstraintViolationException.class)
 @ResponseStatus(HttpStatus.BAD_REQUEST)
 ResponseEntity<String> handleConstraintViolationException(ConstraintViolationException e) {
        return new ResponseEntity<>("Validation error: " + e.getMessage(), HttpStatus.BAD_REQUEST);
 }

失败:

Validation error: Only pdf,xml,jpeg,jpg files are allowed

关于spring-boot - 在 SpringBoot 中,如何为 MultipartFile 参数创建自定义验证器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74829053/

相关文章:

java - 如何在Spring中只允许用户修改自身的REST调用?

java - 如何在 spring application.properties 中指定我的 ssl keystore 文件的本地文件路径?

ruby-on-rails - 多个对象 Rails 上的相关验证

java - 如何将注释应用于类的每个方法?

java - 类型/类是否需要用 @Component 或 @Service 注释才能用 @Value 注释其属性

spring-boot - 如何使用Spring Boot和Kotlin启动Web应用程序

asp.net-mvc-3 - 如何范围验证整数 ASP.NET MVC 3

ruby-on-rails - Rails 在每个字段下方显示表单错误

java - 在没有 Spring 的情况下注入(inject)应用程序属性

java - 循环中的内循环与组合 th :field in Thymeleaf