We discussed how to use @min, @max and other annotations to verify parameters, mainly for basic data types and cascaded objects. However, in practice, we often need more complex verification rules. For example, the password and confirmation password of registered users are verified. At this time, the basic annotations cannot meet our requirements. We need to customize annotations for verification according to business requirements

Yuan notes

Before customizing annotations, it is necessary to understand some meta annotations. Meta annotations are annotations on annotations. You can configure an annotation

  • @Retention, meaning how long do annotations stay, there are three modes, right

    • @Retention(retentionPolicy.source) indicates that annotations exist only in the SOURCE code and are not included in the class bytecode file
    • @Retention(retentionPolicy.class) indicates the default Retention policy. Annotations are present in the CLASS bytecode file but not available at runtime
    • @Retention(retentionPolicy.runtime) indicates that annotations exist in class bytecode files and can be retrieved by reflection at RUNTIME
  • @target indicates what the annotation is for. Just list the following. Google the rest

    • @target (elementtype.type) indicates that annotations can be applied to interfaces, classes, enumerations, annotations
    • @target (elementType.field) represents constants that can be applied to fields, member variables, enumerations, and so on
    • @target (elementType.method) indicates that methods can be applied
  • @document indicates that the annotation is included in Javadoc

  • @Inherited Indicates that annotations can be Inherited

Custom validation annotations

Taking user registration as an example, we need to verify the password and confirm whether the password is consistent and whether it conforms to the password rules, first create a PasswordEqual annotation class

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Constraint(validatedBy = PasswordValidator.class)
public @interface PasswordEqual {

    String message(a) default"Different passwords."; Class<? >[] groups()default {};
    Class<? extends Payload>[] payload() default {};
}
Copy the code

Let’s explain the above comment. In the PasswordEqual comment, four more comments are marked, the first three of which we’ve already covered.

The @constraint annotation indicates that the annotation is a validation annotation, and we specify the custom validation annotation association class by validatedBy. The PasswordValidator class is the one we defined for the annotation.

The groups and payload methods in annotations are template methods that you must write to implement custom annotations.

Defining validation classes

Validation class contains specific validation logic, the following is a simple version:

public class PasswordValidator implements ConstraintValidator<PasswordEqual.BannerCreateDto> {

    @Override
    public boolean isValid(BannerCreateDto dto, ConstraintValidatorContext constraintValidatorContext) {
        
        return false; }}Copy the code

The above code needs to be explained here, to implement the custom validation class must be implemented

ConstraintValidator interface, which is a generic interface that needs to specify two type parameters: the first is the custom annotation type, and the second type specifies the type to which the custom annotation is to be tagged.

We must override the isValid method, which contains all the validation logic.

@Override
public boolean isValid(UserDto dto, ConstraintValidatorContext constraintValidatorContext) {
    if (dto.getPassword().equals(dto.getConfirmPassword())){
        return true;
    }
    return false;
}
Copy the code

We then mark our custom annotation class to the UserDto class:

@Builder
@Getter
@Setter
@PasswordEqual
public class UserDto {

    @Length(min = 4, max = 10, message = "Username must be between 4 and 10 characters long")
    private String name;

    private String password;

    private String confirmPassword;
}
Copy the code

Next we write a simple interface to create a user:

@RestController
public class UserController {


    @PostMapping("/v2/user/create")
    @ResponseBody
    public UserDto createUser(@RequestBody @Validated UserDto dto){
        returndto; }}Copy the code

Notice that we’re going to use @responseBody to return a custom object that automatically serializes, and we’re going to say, “@”, “validate”.

Let’s enter the correct password and confirm the password:

You can see that the data returned normally, then change the two password to different, try:

At this point, an exception is thrown. The exception message here is because it entered the global exception handler. If you are not clear, please refer to the previous article. Let’s look at the console output again:

The console has printed a checksum error message.

conclusion

Today we introduced the customization parameters calibration, and write the validation annotations and check class, but finally returned to the user information is very unfriendly, need for parameter calibration error, can return to define the message, to let users know where is wrong, the next article we will introduce the content, attention please!!!!!

You are welcome to check out my blog, where there is more about the actual test content oh!!