在 spring 引导验证中使用 messages.properties 文件在自定义验证消息中出现问题

Issue in custom validation message using messages.properties file in spring boot validation

我正在使用 spring 验证来验证 Rest Controller 输入,如果有人能告诉我是否有可能在异常和自定义的情况下抛出自定义消息,我将不胜感激消息应来自属性文件。

UserController.java

@CrossOrigin(origins = "http://localhost:3000")
@RequestMapping(
        value="/",
        method=RequestMethod.POST,
        consumes = MimeTypeUtils.APPLICATION_JSON_VALUE,
        produces = MimeTypeUtils.APPLICATION_JSON_VALUE
)
public Object[] createUser(@ModelAttribute("user") User user, BindingResult bindingResult) {
    new UserValidator().validate(user,bindingResult);
    if (bindingResult.hasErrors()) {
        return  bindingResult.getFieldErrors().toArray();
    }
}

UserValidator.java

public class UserValidator implements Validator{

@Override
public boolean supports(Class<?> aClass) {
    return User.class.equals(aClass);
}

@Override
public void validate(Object obj, Errors errors) {
    ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "user.firstName.empty");
    ValidationUtils.rejectIfEmptyOrWhitespace(errors, "lastName", "user.lastName.empty");
    ValidationUtils.rejectIfEmptyOrWhitespace(errors, "slug", "user.slug.empty");
    ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email", "user.email.empty");
    ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "user.password.empty");
    ValidationUtils.rejectIfEmptyOrWhitespace(errors, "phone", "user.phone.empty");
    ValidationUtils.rejectIfEmptyOrWhitespace(errors, "address", "user.address.empty");
    ValidationUtils.rejectIfEmptyOrWhitespace(errors, "country", "user.country.empty");
    ValidationUtils.rejectIfEmptyOrWhitespace(errors, "gender", "user.gender.empty");

    User user = (User) obj;
    Pattern pattern = Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,6}$", 
    Pattern.CASE_INSENSITIVE);
    if(!errors.hasErrors()) {
        if (!(pattern.matcher(user.getEmail()).matches())) {
            errors.rejectValue("email", "user.email.invalid");
        }
    }
}
}

messages.properties

# messages.properties
user.firstName.empty=Enter a valid first name.
user.lastName.empty = Enter a valid last name.
user.slug.empty = Select gender.
user.phone.empty = Select gender.
user.address.empty = Select gender.
user.country.empty = Select gender.
user.password.empty = Select gender.
user.gender.empty = Select gender. 
user.email.empty = Enter a valid email.
user.email.invalid = Invalid email! Please enter valid email.

CustomMessageSourceConfiguration.java

@Configuration
public class CustomMessageSourceConfiguration {
@Bean
public MessageSource messageSource() {
    ReloadableResourceBundleMessageSource messageSource = new 
ReloadableResourceBundleMessageSource();
    messageSource.setBasename("classpath:messages");
    messageSource.setDefaultEncoding("UTF-8");
    return messageSource;
}

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

浏览器响应

 {codes: ["user.firstName.empty.user.firstName", "user.firstName.empty.firstName",…], arguments: 
null,…} 
codes: ["user.firstName.empty.user.firstName", "user.firstName.empty.firstName",…]
0: "user.firstName.empty.user.firstName"
1: "user.firstName.empty.firstName"
2: "user.firstName.empty.java.lang.String"
3: "user.firstName.empty"
arguments: null
defaultMessage: null
objectName: "user"
field: "firstName"
rejectedValue: null
bindingFailure: false
code: "user.firstName.empty"

另一种验证方式

我们可以将 MessageSource 自动连接到 CustomMessageSourceConfiguration.java 中配置的 UserController.java 以获取 messages.properties 文件。

@Autowired
private MessageSource messageSource;

public  User  createUser(@Valid @ModelAttribute("user") @RequestBody User 
user) {
   final ArrayList errorList = new ArrayList<>() {};
    bindingResult.getFieldErrors().forEach(fieldError -> {
        errorList.add(new 
  ObjectError(fieldError.getField(),messageSource.getMessage(fieldError.getCode(), 
  null, Locale.getDefault())));
    });

现在我们从 messages.properties 文件中获取所需的错误消息映射。

另一种验证方式

我们可以在不使用 messages.properties 文件的情况下将第 4 个参数添加为错误消息。

public class UserValidator implements Validator{

@Override
public boolean supports(Class<?> aClass) {
return User.class.equals(aClass);
}

@Override
public void validate(Object obj, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", 
"user.firstName.empty","Error Message Here");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "lastName", 
"user.lastName.empty","Error Message Here");
...
... 
}
}

验证方式

我们可以创建单独的 bean 验证。

Users.java

@Entity
@Table(name = "users")
public class User{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

   @NotNull
   @InBetweenNumberCustom(min = 12,max = 18)
   private Integer age;

   //getters and setters 
}

这里我们将创建@InBetweenNumberCustom 验证注释。

import com.something.validator.ConstraintValidator.InBetweenNumberValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, 
ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(InBetweenNumberCustom.List.class)
@Documented
@Constraint(validatedBy = {InBetweenNumberValidator.class})
public @interface InBetweenNumberCustom {

String message() default "Must be in between {min} and {max}";

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

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

int min() default 0;

int max() default 2147483647;

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, 
ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented

public @interface List {
    InBetweenNumberCustom[] value();
}
}

InBetweenNumberValidator.java

import com.something.validator.annonations.InBetweenNumberCustom;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class InBetweenNumberValidator implements 
ConstraintValidator<InBetweenNumberCustom,Integer> {
private int minValue;
private int maxValue;

@Override
public void initialize(InBetweenNumberCustom inBetweenNumberCustom) {
    this.minValue = inBetweenNumberCustom.min();
    this.maxValue = inBetweenNumberCustom.max();
}

@Override
public boolean isValid(Integer aInteger, ConstraintValidatorContext 
constraintValidatorContext) {
    // null values are not valid
    if ( aInteger == null ) return false;
    else return aInteger <= this.maxValue && aInteger >= this.minValue;
}
}

UserController.java

public JSONObject createUser(@Validated @RequestBody User user, 
BindingResult bindingResult) {
...
...
}