Java parameter validation (Validator)

# Java parameter validation (Validator)

Before the application executes the business logic, it must ensure that the received input data is legal and correct through verification. However, many times, the same verification occurs many times. In different layers and different methods, it leads to code redundancy, waste of time and violation of the DRY principle.

  • Each controller shall be verified
  • Too many verification parameters will cause the code to be too long
  • The reuse rate of code is too poor. If the same code occurs multiple times, the maintenance cost increases exponentially when the business is more and more complex.

You can consider encapsulating the verification code to solve these problems.

# Usage example

maven

	<dependency>
		<groupId>org.hibernate</groupId>
		<artifactId>hibernate-validator</artifactId>
		<version>5.2.4.Final</version>
	</dependency>     

# 1, Verification object

  1. Write verification object
public class User {
    // The name cannot be empty, and the length of the name is between 2 and 30 digits
    // If the length check of the name fails, an error message will be prompted
    @NotNull
    @Size(min=2, max=30,message = "Please check the length of the name")
    private String name;

    // Null is not allowed, and the minimum age is 18
    @NotNull
    @Min(18)
    private Integer age;
}
  1. Create controller
    // 1. Add @ Valid annotation before the parameter to be verified
    // 2. Next, a BindingResult is used to store the verification information
    @RequestMapping("/test1")
    public Object test1(@Valid User user) {
        return "OK";
    }

# 2, Direct verification parameters

@Controller
@Validated
@RequestMapping(value = "validator")
public class ParameterValidatorDemoController {

    @ResponseBody
    @GetMapping(value = "simple")
    public String validateParameter(@Size(min = 1, max = 5) String name) {
        System.out.println(name);
        return "OK";
    }

}

The * * @ Validated * * annotation on the class tells spring that it needs to scan the class to check the constraint annotation.

# Common verification comments

@Null the annotated element must be null @NotNull the annotated element must not be null @AssertTrue the annotated element must be true @AssertFalse the annotated element must be false @Min(value) the annotated element must be a number and its value must be greater than or equal to the specified minimum value @Max(value) the annotated element must be a number whose value must be less than or equal to the specified maximum value @DecimalMin(value) the annotated element must be a number whose value must be greater than or equal to the specified minimum value @DecimalMax(value) the annotated element must be a number whose value must be less than or equal to the specified maximum value @Size(max=, min =) the size of the annotated element must be within the specified range @Digits (integer, fraction) the annotated element must be a number and its value must be within an acceptable range @Past annotated element must be a past date @Future the annotated element must be a future date @Pattern(regex=,flag =) the annotated element must conform to the specified regular expression

Verification comments provided by Hibernate Validator: @NotBlank(message =) validation string is not null and must be longer than 0 @The annotated element of Email must be an Email address @Length(min=,max =) the size of the annotated string must be within the specified range @NotEmpty the of the annotated string must be non empty @Range(min=,max=,message =) the annotated element must be within the appropriate range

# Custom verification annotation

Sometimes, the verification type we want is not available in the third-party library. Fortunately, the system provides good extensibility, and we can customize the verification. For example, we want to verify the user's mobile phone format and write a mobile phone number verifier

1. Write verification notes

// We can directly copy the annotation in the system, such as @ Min, into our new annotation, and then modify it as needed.
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
//Annotation implementation class.
@Constraint(validatedBy = {IsMobileValidator.class})
public @interface IsMobile {
    //Default information for validation errors
    String message() default "There is a problem with the mobile phone number format";

    //Whether to force verification
    boolean isRequired() default false;
    
    Class<?>[] groups() default {};

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

2. When writing a specific implementation class, we know that the annotation is only a tag, and the real logic needs to be implemented in a specific class. The annotation in the previous step specifies that the class implementing the verification function is IsMobileValidator.

// The user-defined annotation must implement the two parameters in the ConstraintValidator interface
// The first is the specific annotation to be verified
// The second is the parameter type of verification
public class IsMobileValidator implements ConstraintValidator<IsMobile, String> {

    private boolean required = false;

    private static final Pattern mobile_pattern = Pattern.compile("1\\d{10}");
    //Tools and methods to determine whether it is a mobile phone number
    public static boolean isMobile(String src) {
        if (StringUtils.isEmpty(src)) {
            return false;
        }
        Matcher m = mobile_pattern.matcher(src);
        return m.matches();
    }

    @Override
    public void initialize(IsMobile constraintAnnotation) {
        required = constraintAnnotation.isRequired();
    }

    @Override
    public boolean isValid(String phone, ConstraintValidatorContext constraintValidatorContext) {
        //Is it the implementation of mobile phone number
        if (required) {
            return isMobile(phone);
        } else {
            if (StringUtils.isEmpty(phone)) {
                return true;
            } else {
                return isMobile(phone);
            }
        }
    }
    
}

3. Test the function of custom annotation

@Data
public class User {
    @NotNull
    @Size(min=2, max=30,message = "Please check the length of the name")
    private String name;

    @NotNull
    @Min(18)
    private Integer age;

    //Here is the newly added annotation
    @IsMobile
    private String phone;
}

Added by Hades on Fri, 17 Dec 2021 06:13:46 +0200