Hibernate Validator - object grouping validation (probably the most comprehensive explanation in the old world)

Keywords: less Hibernate Attribute Excel

Then I broke it down last time. I didn't see the children's shoes in the first chapter Click here Play back the content of the previous chapter
Entity class

@Data
@AgeSalaryType
public class Student {

    private Long id;

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

    @NotNull
    @Min(value = 5, message = "No less than 5 years old")
    private int age;

    @IdentifyFieldValue(enumClass = OrderType.class)
    private String orderType;

    @NotNull
    @Digits(integer = 10, fraction = 2, message = "Please keep 2 decimal places")
    private BigDecimal salary;

}

Business scenario

To add student information, just check the above
Update student information. id is required. Add @ NotNull annotation on id attribute
If you want to create a new entity class, it's a little tricky. groups specifically solve this kind of problem

The validation group allows you to select which constraints to apply during validation. In this way, in some cases (such as wizard), you can select the constraints corresponding to each step for validation. The validation group is passed to validate, validateProperty and validateValue through variable parameters
If a constraint belongs to more than one group, the order of each group is unpredictable. If a constraint does not indicate which group it belongs to, it will be classified into the default group( javax.validation.groups.Default).

  • New group interface
public interface UpdateGroup {
}
public interface AddGroup {
}
  • Assign groups to annotations on entity classes
@Data
@AgeSalaryType(groups = AddGroup.class)
public class Student {

    @NotNull(message = "id Primary key cannot be empty", groups = UpdateGroup.class)
    private Long id;

    @NotBlank(message = "Name cannot be empty", groups = Default.class)
    private String name;

    @NotNull
    @Min(value = 5, message = "No less than 5 years old")
    private int age;

    @IdentifyFieldValue(enumClass = OrderType.class)
    private String orderType;

    @NotNull
    @Digits(integer = 10, fraction = 2, message = "Please keep 2 decimal places")
    private BigDecimal salary;

}

Note: Default.class It's the default group. There's no need to display the declaration. I just annotate it to show you an example

  • Test class
    def testStudent() {
        Student student = new Student();
        student.setAge(20);
        student.setSalary(new BigDecimal(50));

        Set<ConstraintViolation<Student>> result = validator.validate(student, Default.class);
        printfError(result);

        Set<ConstraintViolation<Student>> result2 = validator.validate(student, UpdateGroup.class);
        printfError(result2);

        Set<ConstraintViolation<Student>> result3 = validator.validate(student, AddGroup.class);
        printfError(result3);

        expect:
        true
    }
  • test result
==================
Name cannot be empty
==================
id primary key cannot be empty
==================
When the age is over 18, the monthly salary shall not be less than 100 yuan

<T> Set < constraintviolation < T > > validate (t object, class <? >... Groups); a group can be independently verified. This is a separate split verification, which is represented on the Controller layer interface as follows:

@PostMapping(value = "all")
public String allTableType(@RequestBody @Validated(Update.class) TableType tableType) {
     return JSONObject.toJSONString(tableTypeService.list());
}

In this way, you need to bind BindingResult to get error information and write a complete instance

  • Just use the entity class above and the interface below
@RequestMapping("/add")
    public Map<String, Object> addStudent(@Validated({Default.class, AddGroup.class}) Student student, BindingResult bindingResult) {
        Map<String, Object> resultMap = new HashMap<>(10);
        resultMap.put("success", true);
        if (bindingResult.hasErrors()) {
            resultMap.put("success", false);
            StringBuilder stringBuilder = new StringBuilder();
            bindingResult.getAllErrors().stream().forEach(it -> stringBuilder.append(it.getDefaultMessage()));
            resultMap.put("message", stringBuilder.toString());
            return resultMap;
        }
        ยทยทยท
        return resultMap;
    }
  • PostMan feedback

Next, consider another problem. You can't add BindingResult bindingResult object to every interface. It's a weak thing. You can catch and output in global exceptions

@ControllerAdvice
public class ValidateExceptionHandle {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public RestResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        StringBuilder stringBuilder = new StringBuilder("Basic parameter validation failed:");
        if (ex.getBindingResult().getAllErrors().size() > 0) {
            for (ObjectError allError : ex.getBindingResult().getAllErrors()) {
                stringBuilder.append("[").append(allError.getDefaultMessage()).append("]  ");
            }
        }
        return RestResponse.failedMessage(stringBuilder.toString());
    }

    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public RestResponse resolveConstraintViolationException(ConstraintViolationException ex) {
        StringBuilder stringBuilder = new StringBuilder("Basic parameter validation failed:");
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        if (!CollectionUtils.isEmpty(constraintViolations)) {
            for (ConstraintViolation constraintViolation : constraintViolations) {
                stringBuilder.append("[").append(constraintViolation.getMessage()).append("]");
            }
        }
        return RestResponse.failedMessage(stringBuilder.toString());
    }

Next, consider another scenario. In the above entity class, if you need to verify many groups, verify them in order. If one of the previous groups fails to verify, you will no longer verify the next group

@GroupSequence defines the order of validation between groups

  • Entity class
@Data
@AgeSalaryType(groups = AddGroup.class)
@GroupSequence({UpdateGroup.class, AddGroup.class, Student.class})
public class Student {

    @NotNull(message = "id Primary key cannot be empty", groups = UpdateGroup.class)
    private Long id;

    @Size(min = 5, max = 10, message = "Name length is 5-10")
    private String name;

    @NotNull
    @Min(value = 5, message = "No less than 5 years old")
    private int age;

    @IdentifyFieldValue(enumClass = OrderType.class)
    private String orderType;

    @NotNull
    @Digits(integer = 10, fraction = 2, message = "Please keep 2 decimal places")
    private BigDecimal salary;

}
  • Test class
def testStudent() {
        Student student = new Student();
        student.setName("You ha")
        student.setAge(20);
        student.setSalary(new BigDecimal(50));

        Set<ConstraintViolation<Student>> result = validator.validate(student);
        printfError(result);

        expect:
        true
    }
  • Test results (UpdateGroup only verifies the Id and returns directly if there is an error)
id primary key cannot be empty

Change the group on the entity class to @GroupSequence({AddGroup.class, UpdateGroup.class, Student.class }

  • Test result (if only AddGroup is verified, the result will be returned)
When the age is over 18, the monthly salary shall not be less than 100 yuan

@GroupSequenceProvider dynamically redefines the default grouping according to the object state

public class StudentGsProvider implements DefaultGroupSequenceProvider<Student> {
    @Override
    public List<Class<?>> getValidationGroups(Student student) {
        List<Class<?>> defaultGroupSequence = new ArrayList<>();
        defaultGroupSequence.add(Student.class);

        if (student != null && student.getAge() < 18) {
            defaultGroupSequence.add(AddGroup.class);
        }
        return defaultGroupSequence;
    }
}

According to the object conditions, group information can be added to the Default group. It is also feasible for online blogs to solve the problem of dependency between object attributes in this way
Well, there are so many knowledge points about Hibernate Validator. The next section describes how to use Hibernate Validator to implement the logic of Excel full table verification

Java is the besat language in the world
Recently, the emergency response level of Beijing's new lung epidemic has risen to the second level. I hope that friends in the capital will pay more attention, improve their awareness of prevention and broadcast

Posted by apol on Fri, 19 Jun 2020 04:52:25 -0700