Spring 启动 - 表单上的自定义验证注释不起作用

Spring Boot - Custom validation annotation on form not working

我想要一个注释来验证 MultipartFile 是一个图像。我创建了一个 @interface 和一个 ConstraintValidator,并将注释添加到我的字段中。

其他验证注释,如 @NotEmpty@Size(min = 0, max = 2) 工作正常。

这里是代码的总结。 This question有同样的问题,但答案对我不起作用。

Form.java:

@Validated
public class Form {

    @MultipartImage
    private MultipartFile image;

    ...
}

@Interface MultipartImage

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

import validation.MultipartFileImageConstraintValidator;

@Documented
@Constraint(validatedBy = { MultipartFileImageConstraintValidator.class })
@Target({ LOCAL_VARIABLE, FIELD, METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface MultipartImage {

    String message() default "{MultipartImage.message}";

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

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

}

验证者,MultipartFileConstraintValidator.java

import java.io.IOException;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.springframework.web.multipart.MultipartFile;

public class MultipartFileConstraintValidator implements ConstraintValidator<MultipartImage, MultipartFile> {


@Override
public void initialize(final MultipartImage constraintAnnotation) {
}

@Override
public boolean isValid(final MultipartFile file, final ConstraintValidatorContext context) {
    return false;
}

这是控制器中的表单提交方法

@RequestMapping(value = "/formsubmit", method = RequestMethod.POST)
public ModelAndView handleForm(@Validated final Form form,
        final BindingResult bindingResult) {

    if (bindingResult.hasErrors()) {
        ...
        // returns the model
    }
}

验证器在@Configuration 文件中设置,参见

@Configuration
@ConfigurationProperties("static")
@AutoConfigureAfter(DispatcherServletAutoConfiguration.class)
public class StaticResourceConfig extends WebMvcConfigurerAdapter {

...

@Bean(name = "validator")
public LocalValidatorFactoryBean validator() {
    LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
    bean.setValidationMessageSource(messageSource());
    return bean;
}

@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
    final MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
    methodValidationPostProcessor.setValidator(validator());

    return methodValidationPostProcessor;
}

@Override
public Validator getValidator() {
    return validator();
}

@Bean
public ReloadableResourceBundleMessageSource messageSource() {
    ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    // Load files containing message keys.
    // Order matters. The first files override later files.
    messageSource.setBasenames(//
            // load messages and ValidationMessages from a folder relative to the jar
            "file:locale/messages", //
            "file:locale/ValidationMessages", //
            // load from within the jar
            "classpath:locale/messages", //
            "classpath:locale/ValidationMessages" //
    );
    messageSource.getBasenameSet();
    messageSource.setCacheSeconds(10); // reload messages every 10 seconds
    return messageSource;
}

}

我的原始代码中缺少信息,特别是关于控制器的信息,其中定义和绑定了一个额外的验证器。它使用了错误的方法来包含验证器 FormValidator,并覆盖了注释验证。

binder.setValidator(formValidator) 覆盖任何其他验证器。相反,应该使用 binder.addValidators(formValidator)

@Controller
public class FormController {

     @Autowired
     final private FormValidator formValidator;

     @InitBinder("form")
     protected void initBinder(WebDataBinder binder) {
        // correct
        binder.addValidators(formValidator);
        // wrong
        //binder.setValidator(formValidator);
    }

    ...

    @RequestMapping(value = "/formsubmit", method = RequestMethod.POST)
    public ModelAndView handleForm(@Validated final Form form, final BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            ...
            // returns the model
        }
    ...
    }
}

我还删除了 @Configuration class 中的 Bean MethodValidationPostProcessor