Format validation Hibernate Validator

In early websites, users entered an email address and needed to send the email address to the server. The server verified it. After the verification was successful, a response was sent to the front end.

With JavaScript, verification can be performed on the front end. So why do you need server-side verification? Because the data from the front end is not trusted. The front end can easily obtain the back-end interface. If someone calls the interface directly, illegal data may appear, so the server also needs data verification.

in general:

  • [] front end verification: mainly to improve the user experience
  • [] back end verification: mainly to ensure data security and reliability

Checking parameters is basically a manual work, and there are many redundant codes, which also affects the readability of the code. We need a more elegant way to solve this problem. Hibernate Validator framework just solves this problem. It can implement parameter verification in a very elegant way, separate business code from verification logic, and no longer write duplicate verification logic.

Hibernate validator advantages:

  • [] the verification logic is separated from the business logic to reduce the program coupling
  • [] unified and standardized verification method, without you writing repeated verification code again
  • [] you will focus more on your business and put all these cumbersome things aside

maven coordinates of Hibernate validator:

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

Hibernate validator common annotations

The verification method provided by hibernate validator is to add corresponding annotations to the class properties to achieve the purpose of verification. The comments provided by hibernate validator for verification are as follows:

annotation explain
@AssertTrue Used for boolean field, which can only be true
@AssertFalse Used for boolean field, which can only be false
@CreditCardNumber Make a general verification of the credit card number
@DecimalMax Can only be less than or equal to this value
@DecimalMin Can only be greater than or equal to this value
@Email Check whether it is a valid email address
@Future Check whether the date in this field belongs to the future
@Length(min=,max=) Check whether the length of the field is between min and max, which can only be used for string
@Max The value of this field can only be less than or equal to this value
@Min The value of this field can only be greater than or equal to this value
@NotNull Cannot be null
@NotBlank Cannot be empty. Spaces will be ignored during inspection
@NotEmpty Cannot be null. Null here refers to an empty string
@Pattern(regex=) The annotated element must conform to the specified regular expression
@URL(protocol=,host,port) Check whether it is a valid URL. If protocol, host, etc. are provided, the URL also needs to meet the provided conditions

Introduction to hibernate validator

Step 1: create maven project hibernate validator_ Demo and configure pom.xml file

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/>
    </parent>
    <groupId>cn.itcast</groupId>
    <artifactId>hibernate-validator_demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <!--
		spring-boot-starter-web Has been dependent on hibernate-validator
		-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--
		<dependency>
              <groupId>org.hibernate</groupId>
              <artifactId>hibernate-validator</artifactId>
              <version>6.0.18.Final</version>
        </dependency>
		-->
    </dependencies>
</project>

Note: spring boot starter web already relies on Hibernate validator, so you don't need to import it again.

Step 2: create User class

package cn.itcast.entity;

import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.*;

@Data
public class User {
    @NotNull(message = "user id Cannot be empty")
    private Integer id;

    @NotEmpty(message = "User name cannot be empty")
    @Length(max = 50, message = "User name length cannot exceed 50")
    private String username;

    @Max(value = 80,message = "The maximum age is 80")
    @Min(value = 18,message = "The minimum age is 18")
    private int age;

    @Pattern(regexp = "[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$",
             message = "The mailbox format is incorrect")
    private String email;
}

Step 3: create UserController

package cn.itcast.controller;

import cn.itcast.entity.User;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.NotBlank;

@RestController
@RequestMapping("/user")
@Validated //Turn on the verification function
public class UserController {
    //Simple data type verification
    @RequestMapping("/delete")
    public String delete(@NotBlank(message = "id Cannot be empty") String id){
        System.out.println("delete..." + id);
        return "OK";
    }

    //Object attribute verification
    @RequestMapping("/save")
    public String save(@Validated User user){
        System.out.println("save..." + user);
        return "OK";
    }
}

Step 4: create application.yml

server:
  port: 9100

Step 5: create a startup class

package cn.itcast;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class HibernateValidatorApp {
    public static void main(String[] args) {
        SpringApplication.run(HibernateValidatorApp.class,args);
    }
}

Start the project at: http://localhost:9100/user/save , it can be seen from the console output that the data can be verified as follows:

Field error in object 'user' on field 'age': rejected value [3]; codes [Min.user.age,Min.age,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.age,age]; arguments []; default message [age],18]; default message [The minimum age is 18]]
2020-03-02 16:44:35.504  WARN 14896 --- [nio-9100-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 3 errors
Field error in object 'user' on field 'id': rejected value [null]; codes [NotNull.user.id,NotNull.id,NotNull.java.lang.Integer,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.id,id]; arguments []; default message [id]]; default message [user id Cannot be empty]
Field error in object 'user' on field 'age': rejected value [0]; codes [Min.user.age,Min.age,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.age,age]; arguments []; default message [age],18]; default message [The minimum age is 18]
Field error in object 'user' on field 'username': rejected value [null]; codes [NotEmpty.user.username,NotEmpty.username,NotEmpty.java.lang.String,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.username,username]; arguments []; default message [username]]; default message [User name cannot be empty]]

The browser page directly reports an error:

Step 6: in order to display the data verification results friendly on the page, you can solve it through global exception handling and create a global exception handling class

package cn.itcast.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;

/**
 * Global exception handling
 */
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
public class ExceptionConfiguration {
    @ExceptionHandler({ConstraintViolationException.class,BindException.class})
    public String validateException(Exception ex, HttpServletRequest request) {
        ex.printStackTrace();
        String msg = null;
        if(ex instanceof ConstraintViolationException){
            ConstraintViolationException constraintViolationException = 
                (ConstraintViolationException)ex;
            Set<ConstraintViolation<?>> violations = 
                constraintViolationException.getConstraintViolations();
            ConstraintViolation<?> next = violations.iterator().next();
            msg = next.getMessage();
        }else if(ex instanceof BindException){
            BindException bindException = (BindException)ex;
            msg = bindException.getBindingResult().getFieldError().getDefaultMessage();
        }
        return msg;
    }
}

Restart the program and you can find that the verification information can be displayed on the page friendly:

From the output of the console, we can see that the verification framework performs data verification on multiple attributes (the default behavior). If we want to directly return a prompt message as long as one attribute fails to be verified, how can we implement it?

Step 7: create the ValidatorConfiguration class and specify the fast failure return mode to be used during verification

package cn.itcast.config;

import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

public class ValidatorConfiguration {
    @Bean
    public Validator validator() {
        ValidatorFactory validatorFactory = 
            Validation.byProvider(HibernateValidator.class)
                .configure()
                //Quick failure return mode
                .addProperty("hibernate.validator.fail_fast", "true")
                .buildValidatorFactory();
        return validatorFactory.getValidator();
    }

    /**
     * Turn on quick return
     * If there is an exception in the parameter verification, throw the exception directly and will not enter the controller. Use global exception interception to intercept
     */
    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        MethodValidationPostProcessor postProcessor = 
            new MethodValidationPostProcessor();
        /**Set the validator mode to fast failure return*/
        postProcessor.setValidator(validator());
        return postProcessor;
    }
}

Note: the class created above is not a configuration class, so the quick failure return mode will not take effect so far. In order to make it take effect, you need to create an annotation to control the opening of this mode

Step 8: create the annotation EnableFormValidator to control the startup of the quick failure return mode

package cn.itcast.config;

import org.springframework.context.annotation.Import;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Add this annotation on the startup class to start the form verification function - fast failure return mode
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ValidatorConfiguration.class)
public @interface EnableFormValidator {
}

Step 9: add the EnableFormValidator annotation on the startup class to enable the quick failure return mode

package cn.itcast;

import cn.itcast.config.EnableFormValidator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableFormValidator
public class HibernateValidatorApp {
    public static void main(String[] args) {
        SpringApplication.run(HibernateValidatorApp.class,args);
    }
}

It can be seen from the console output that although many of the data we entered do not comply with the verification rules, there is only one verification failure exception message, which indicates that the fast failure return mode has been enabled.

Posted by Weiry on Sun, 05 Dec 2021 04:29:18 -0800