This is the 23rd day of my participation in the August More Text Challenge.More challenges in August

We are using Hibernate-Validator as an object parameter validator, so before we introduce SpringBoot parameter validation, we need to take a quick look at hibernate-Validator.

Hibernate – Validator is basically used

Introduction of depend on

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.17. The Final</version>
</dependency>
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
</dependency>
Copy the code

Write the required validation object

Validation requires that the user name of the Person object be non-empty and between the ages of 1 and 150.

@Data
public class Person {

    @NotBlank(message = "username must not be null")
    private String username;

    @Min(value = 1, message = "age must be >= 1")
    @Max(value = 150, message = "age must be < 150")
    private Integer age;
}
Copy the code

Verify that the object properties meet the requirements

    /** * Object validator */
    public Validator validator(a) {
        ValidatorFactory validatorFactory =
                Validation
                        .byProvider(HibernateValidator.class)
                        .configure()
                        // When validating attributes, if one of the validations fails, it is returned without validating all attributes
                        .addProperty("hibernate.validator.fail_fast"."true")
                        .buildValidatorFactory();
        return validatorFactory.getValidator();
    }

    @Test
    public void test(a) throws Exception {
        Person person = new Person();
        Set<ConstraintViolation<Person>> validate = validator().validate(person);
        validate.forEach(errorParam -> {
            System.out.println(errorParam.getMessage());
        });
    }
Copy the code
  1. We only need the verified object instance to complete the object validation. If the validation succeeds, an empty collection is returned, and if the validation fails, the specific failed attribute information is returned.
  2. We output the following error message for validation failure:
username must not be null
Copy the code

The validation rules

Validator provides a large number of validation annotations to use, mainly in the following categories:

Null/non-null validation

  1. @NullThe element must be empty
  2. @NotNullElement cannot be empty, empty string""Is empty

All of the following validation rules only validate if the element is not empty, and if the element passed is empty, the validation will pass.

bool

  1. @AssertTrueThe element must be true
  2. @AssertFalseThe element must be false

time

  1. @FutureThe element must be some time in the future.
  2. @FutureOrPresentThe element must be some time in the future or present.
  3. @PastThe element must be some time in the past.
  4. @PastOrPresentThe element must be some time in the past or present.

mathematics

The numeric types can be BigDecimal, BigInteger, CharSequence, byte, short, int, long, and their respective wrapper types

  1. @DigitsThe element must be within the range of acceptable values for the numeric type.
  2. @NegativeThe element must be negative
  3. @NegativeOrZeroThe element must be less than or equal to 0
  4. @PositiveThe element must be greater than 0
  5. @PositiveOrZeroThe element must be greater than or equal to 0
  6. @Max.@MinThe size of the element must match the specified size

string

  1. @EmailMailbox format verification
  2. @NotBlackVerify that string is not empty, empty string""Also belong to empty
  3. @PatternString regular validation

Template is a regular

Validator provides annotations for string template regulars. Here is a list of common regular expressions that you can use directly in your project as a constant utility class

public interface ValidatorPattern {

    /** * Regular expression: verify the user name * 1. The length is 5-17 * 2. The value consists of uppercase and lowercase letters */
    String REGEX_USERNAME = "^ \ w [a zA - Z] {5} in 2 $";

    /** * Regular expression: Verify password * The password can contain only 6 to 12 digits, letters, and common symbols. * /
    String REGEX_PASSWORD = "^ (? =.*[a-zA-Z])(? =. * [0-9]) [A - Za - z0-9. _ ~! @ # $^ & *] {6, 12} $";

    /** * Regular expression: verify mobile phone number */
    String REGEX_MOBILE = "^[1][34578]\d{9}$";

    /** * Regular expression: verify mailbox */
    String REGEX_EMAIL = "^.+@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)? \.) +[a-zA-Z]{2,}$";

    /** * Regular expressions: verify Chinese characters */
    String REGEX_CHINESE = "^[\u4e00-\u9fa5],*$";

    /** * Regular expression: verify id */
    String REGEX_ID_CARD = "(^\d{18}$)|(^\d{15}$)";

    /** * Regular expression: validate URL */
    String REGEX_URL = "http(s)? ://([\w-]+\.) +[\w-]+(/[\w- ./?%&=]*)?";

    /** * Regular expression: verify the IP address */
    String REGEX_IP_ADDR = "(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]? \d)";

    /** * the license plate is regular */
    String LICENSE_NO = "^[a-z][a-z][a-z0-9]{4,5}[a-z0-9 hang students Hong Kong and Macao]$";

    /** * Name verification * 1 to 15 characters * The name supports Spaces and periods (*/)
    String NAME = "[\ u4e00 - \ u9fa5 \ u00b7 \ sA - Za - z] {2} 1 $";

    /** ** */
    String EMOJI = "[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]";

    /** ** digital regular */
    String NUMBER = "^ [0-9] * $";

    /** * n digits */
    String N_NUMS = "^\d{n}$";

}
Copy the code

SpringBoot integrate hibernate validator

Introduction of depend on

This will not be repeated, directly copy the dependency information above

Configure the Hibernate-Validator object

Add a Hibernate-Validator object to the configuration class

    @Bean
    @Primary
    public Validator validator(a) {
        ValidatorFactory validatorFactory =
                Validation
                        .byProvider(HibernateValidator.class)
                        .configure()
                        .addProperty("hibernate.validator.fail_fast"."true")
                        .buildValidatorFactory();
        return validatorFactory.getValidator();
    }
Copy the code

With SpringMVC unified exception handling, parameter verification results are processed

Once configured, Spring automatically validates the parameters and throws a BindException that gets the Set

> that we just manually validated. We can handle this exception by leveraging SpringMVC’s ability to unify exception handling

@Slf4j
@RestControllerAdvice
public class BaseExceptionHandler {
    /** * Spring Validation automatically validates an invalid parameter **@param e BindException
     * @return R<Void>
     */
    @ResponseStatus(org.springframework.http.HttpStatus.PAYMENT_REQUIRED)
    @ExceptionHandler(BindException.class)
    public R<Void> handler(BindException e) {
        String defaultMsg = e.getBindingResult().getAllErrors()
                .stream()
                .map(ObjectError::getDefaultMessage)
                .collect(Collectors.joining(":"));
        log.warn(defaultMsg);
        returnR.of(IRespCode.PARAMETERS_ANOMALIES.getCode(), e.getMessage()); }}Copy the code

Checking with parameters

We only need to mark @Valid or @Validated on the method pass parameter

    @PostMapping("register")
    public R<Void> register(@Valid @RequestBody Person person) {
        // todo 
        return R.ok();
    }
Copy the code

Packet check

So what’s the difference between @Valid and @Validated? “Validated” contains one more attribute than “Valid”. This attribute is used for group verification

public @interface Valid {
}
public @interfaceValidated { Class<? >[] value()default {};
}
Copy the code

What is grouping check?

Attributes are attributes in an entity class that require different attributes in different methods. For example, the Person class has three attributes: a user name, a mailbox, and an age. In the register user interface, the user name, email address, and age cannot be empty, but in the Change user information interface, the user’s age and email address can be empty, but the user name cannot be empty. At this point, we can group the attributes according to the verification requirements.

  1. Create a newRegisterGroupA group, which is just an empty interface, used only to mark the validation requirement
public interface RegisterGroup {}Copy the code
  1. Group verification requirements
@Data
public class Person {

    @NotBlank(message = "username must not be null")
    private String username;

    @Min(value = 1, message = "age must be >= 1")
    @Max(value = 150, message = "age must be < 150")
    @NotNull(message = "age must not be null", groups = RegisterGroup.class)
    private Integer age;

    @Email(message = "email format error")
    @NotBlank(message = "email must not be null",groups = RegisterGroup.class)
    private String email;
}
Copy the code
  1. Add a grouping requirement when a method is called
    @PostMapping("register")
    public R<Void> register(@Validated(value = RegisterGroup.class) @RequestBody Person person) {
        // todo
        return R.ok();
    }
Copy the code

Actually don’t recommend using this way, when I was in the title, also has been marked as “outdated”, because, we can for the two different interfaces to create two different entity class, instead of using the grouping in isolation to check request, because the actual production environment, the group may have very many, this will set a dangerous precedent for readability of our programs, Late developer maintenance is difficult and not friendly to automatically generating API documentation. You only need to know about groupings and they are not recommended for use in project development.