Spring boot and Hibernate validate verify data

Posted by M4F on Sat, 23 Oct 2021 04:34:32 +0200

Spring boot combined with hibernate validate verification data learning

Hibernate validate data verification dependency has been introduced into the web Start dependency of spring boot. As long as the web Start dependency of the project depends, there is no need to introduce dependency.

Dependency introduction

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

Introduction to common notes

validate implements the specified verification functions one by one by adding annotations to the fields. Common annotations are:

annotationdescribe
@NotNullCannot be empty
@NotBlankThe string cannot be empty or empty
@NullThe verified object can only be null
@Size(min=2,max=6)The length of the verified string can only be between 2 and 6
@Max(value=7)The maximum verified parameter can only be 7
@AssertTrueThe attribute value of the label must be true
@AssertFalseThe attribute value of a dimension must be false
@PastTime must be in the past
@FutureFuture time
@PatternUsed to specify a regular expression
@NotEmptyString content is not empty
@Emailmailbox
@RangeUsed to specify numbers. Note that the range of numbers has two values, min and max
@DigitsContent must be numeric
@PositiveOrZero0 or integer

Simple use

Using validate to validate data, you can define validation annotations in object fields or method parameters

Define validation annotations in pojo
public class Entity {

    @NotBlank(message = "User name cannot be empty")
    private String username;

    @NotBlank(message = "Password cannot be empty")
    @Length(min = 6,message="Length must be greater than or equal to 6")  //Password length must be greater than six
    private String password;

    @Email(message="Illegal email address")
    private String email;

    @NotBlank(message = "Mobile phone number cannot be empty")
    @Length(min = 11, max = 11, message = "Mobile phone number can only be 11 digits")
    @Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "Wrong mobile phone number format")
    private String phone;

}

Define validation annotations on method parameters

Note that the @ Validated annotation needs to be added to the class name to use the validation annotation on the method parameters

@RestController
@RequestMapping("/demo")
@Validated //Parameter verification
public class DemoController {

    @PostMapping("/search/{page}/{size}")
    public Entity demo(@RequestBody @Validated Entity entity,
                       @PathVariable("page") @Min(value = 0)  Integer page,
                       @PathVariable("size") @Min(value = 0) Integer size){
        System.out.println(entity.getUsername()+"---"+entity.getPassword());
        System.out.println(page+"----------"+size);
        return entity;

    }
}

Unified exception handling

If it is defined on the object field, if it is verified that the data is invalid, the following will be thrown:

MethodArgumentNotValidException extends Exception  //Invalid method parameter exception

If it is defined in the method parameter, if the data is invalid, throw:

ConstraintViolationException extends ValidationException  //Constraint exception

We can define a global exception handler in spring boot to intercept the prompt information returned after an exception occurs in the verification

/**
 * Global exception handler
 */
@ControllerAdvice
public class ExceptionGlobalHandler {

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result handle(Exception e){
        //System.out.println(e);
        String message = null;
        if(e instanceof MethodArgumentNotValidException){  //Parameter verification - object data verification exception
            //get prompting information
            for (ObjectError error : ((MethodArgumentNotValidException) e).getBindingResult().getAllErrors()) {
                message = error.getDefaultMessage();//Get custom error message
            }
        }else if(e instanceof ConstraintViolationException){  //Method parameter verification exception
            Iterator<ConstraintViolation<?>> iterator = ((ConstraintViolationException) e).getConstraintViolations().iterator();
            ConstraintViolation<?> next = iterator.next();
            message = next.getMessage();  //Get custom error message
        }else{
            message = e.getMessage(); //Other exceptions
        }
        return Result.error().setMessage(message);
    }
}

Extension 1: Group verification

When using hibernate validate for data verification, we sometimes verify the data by situation. For example, when adding, we do not verify that the id is not empty, but when modifying, we need to verify that the id is not empty. If @ NotNull is used for verification, null verification will also be performed during insert operation, which is not what we want. At this time, we can group the verification and use different groups for data verification under different circumstances.

Each group needs an interface as the flag of the group, but no content can be added in the interface

General grouping includes: add insert; Modify ipdate; delete; Query select

I use internal interfaces to manage these tag class interfaces

public class ValidateGroupFalg {
    /**
     * Add operation group
     */
    public static interface  InsertFlag{}
    /**
     * Delete action group
     */
    public static interface  DeleteFlag{}
    /**
     * Modify operation group
     */
    public static interface  UpdateFlag{}
    /**
     * Query operation group
     */
    public static interface  SelectFlag{}
}

For the verification user id, group verification is performed

@TableName("tb_demo")
public class TbDemo implements Serializable {

    @TableId(type = IdType.INPUT)
    @NotNull(message = "Please specify the number to modify",groups = ValidateGroupFalg.UpdateFlag.class)
    private String id;
}

When using, you only need to add verification annotation and specify grouping mark in the parameters of the receiving method

public  Result updateById(@RequestBody @Validated(ValidateGroupFalg.UpdateFlag.class) TbDemo tbDemo){
   // ....
}

Extension 1: user defined verification

When we need to perform some specified verifications, we can create custom verifications through the AIP provided by hibernate validator.

step

1. Create annotations and specify data processing classes

2. Create a data processing class to implement internal methods

3. Using annotations

realization

1. Create annotations and specify data processing classes

/**
 * Time string format verification annotation
 */
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = DateTimeValidator.class)  //Used to specify the data processing class
public @interface DateFormatValidate {
    String message() default "Time format error";

    String format() default "yyyy-MM-dd";

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

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

2. Create a data processing class to implement internal methods

import com.bishe.common.validate.DateFormatValidate;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.text.SimpleDateFormat;

/**
 * Time string format verification
 */
public class DateTimeValidator implements ConstraintValidator<DateFormatValidate, String> {

   private DateFormatValidate dateFormatValidate ;  //Annotation reference

    
   public void initialize(DateFormatValidate constraint) {
      this.dateFormatValidate = constraint;
      //System.out.println("initialization method call...);
   }

    //The verification method returns true successfully; If it fails, false will be returned. Validate will judge and false will throw an exception
   public boolean isValid(String value, ConstraintValidatorContext context) {
      //System.out.println("start verification...);
      if (value == null) {
         return true;
      }
      String format = dateFormatValidate.format();  //Get custom time format

      if (value.length() != format.length()) {  //If the length of 2020-10-10 is different from yyyy MM DD, false is returned
         return false;
      }

       try {
     	 SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format); //Create time format object
         simpleDateFormat.parse(value);  //An attempt is made to convert the verified parameters by format. A success is returned as true. A failure is returned as false
      } catch (Exception e){
         return false;  //Conversion failed
      }
      return true; //Verification successful
   }
}

3. Using annotations

@DateFormatValidate(format = "yyyy/MM/dd", message = "Format error, correct format is: yyyy/MM/dd")
    private Date birthday;

Done!

Topics: Java Spring Boot