Detailed explanation of Hibernate Validation validation annotations

When transferring data between the front-end and the back-end, the back-end often needs to verify the format of the transmitted data, such as the format of the user name and whether the password is empty. We can write code judgments at the service layer, but when we need to verify the transmitted data in multiple places, there will be a lot of repetitive code. Once an error occurs, it needs to be modified in multiple places, which is very troublesome, and in this way our software will be very bad. At this time, we can use the annotations of Hibernate Validation to verify, which is very convenient and concise. Hibernate Validation is the verification framework that comes with Spring, which can be found under the javax.validation package. Let's explain in detail the use of Hibernate Validation and how to customize annotations to process data validation.

1. Use Hibernate Validation to verify annotations

How to use Hibernate Validation? Let's assume such a scenario, we need to create a user, and the backend needs to verify the data from the frontend. Let's take a look at how to write code for this example.

First, use MockMvc to forge requests for testing. For convenience, no front-end code is written here.

@Test
    public void whenPostSuccess() throws Exception {
        Date date=(Date) new java.util.Date();
        System.out.println(date.getTime());

        String content="{\"username\":\"shinelon\",\"password\":null,\"birthday\":"+date.getTime()+"}";
        String result=mockMvc.perform(post("/user")
                .content(content)
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").value(1))
                .andReturn().getResponse().getContentAsString();
        System.out.println(result);
    }

The above code passes a json string to the background. Unlike form submission, the parameters of form submission will be automatically encapsulated into the user entity class, but the json string will not be encapsulated into the entity class, so what should I do? At this time, we need to use the @RequestBody annotation, add this parameter before the parameter, it will automatically map the json string to the corresponding field, and when the backend processes the business, the data returned to the frontend will also be processed as json string, which brings great benefits to our development.

We continue the above scenario, the front-end creates users, and the back-end receives parameters for verification:
Controller layer code:

@PostMapping("/user")
    public User create(@Valid @RequestBody User user,BindingResult errors) {

        if(errors.hasErrors()) {
            errors.getAllErrors().forEach(error->System.out.println(error.getDefaultMessage()));;
        }

        user.setId(1);
        System.out.println(user.getId());
        System.out.println(user.getUsername());
        System.out.println(user.getPassword());
        System.out.println(user.getBirthday());
        return user;
    }

In the above code, we will see the @Valid annotation and BindingResult errors, this is our topic Hibernate Validation annotation, when we add the @Valid annotation in front of the parameter user, it will automatically verify the corresponding on the class Of course, in the User class, the field must be limited to the verification format, which we will explain below. Let's take a look at the last parameter, BindingResult. This parameter is used to handle some error messages when the data verification passed by your foreground fails. If there is no BindingResult parameter, when the passed data fails to pass the verification in the @Valid annotation, it will directly return an error status to the user, which may be unfriendly, and we sometimes need to collect some logs, such as recording your For some error information entered, the BindingResult parameter needs to be used at this time. It will still enter the URL mapping method for some output when the verification fails. At this time, we can print the specific error information to be friendly to the user. Display, it must be noted that this parameter must be after the parameter of the @Valid annotation.

Let's take a look at the annotations in the user class.

public class User {

    private int id;
    public String username;
    @NotBlank
    public String password;
    private Date birthday;
    //省略get,set方法

We verify the data with the password not empty. In the previous code, we set the password to null, and the verification failed, but we added the BindingResult parameter, which will enter the method body to print the error log, and the following is the printed error log:
write picture description here

The above is the default error message that comes with Hibernate Validation. Sometimes we need to set a custom error message. At this time, we can use the message parameter to specify.

public class User {

    private int id;
    public String username;
    //使用这个注解表示前台传回来的密码不能为空
    @NotBlank(message="密码不能为空")         //这个注解是hibernate validator中提供的开源项目
    public String password;
    @Past(message="生日的日期必须是过去的时间")      //表示生日必须是过去的时间
    private Date birthday;

The following is the test code, the code of the Controller layer remains unchanged, or the above:

@Test
    public void whenPostSuccess() throws Exception {
        //一年以后的时间
        Date date=(Date) new java.util.Date(LocalDateTime.now().plusYears(1).
                atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
        System.out.println(date.getTime());
        String content="{\"username\":\"shinelon\",\"password\":null,\"birthday\":"+date.getTime()+"}";
        String result=mockMvc.perform(post("/user")
                .content(content)
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").value(1))
                .andReturn().getResponse().getContentAsString();
        System.out.println(result);
    }

As a result of running, we will find that a custom error message is printed:
write picture description here

The above are a few simple annotation examples of Hibernate Validation. The following picture is a detailed explanation of the annotations of Hibernate Validation:
write picture description here
write picture description here

Some readers can test the above annotations by themselves, which is introduced here. Let's take a look at how to customize the annotations.

2. Custom verification annotations

In some scenarios, Hibernate Validation is not enough to meet our needs. In this case, we need custom annotations to verify the code.
How to customize annotations?

First, we need to write an annotation class:
MyValidator.java:

package cn.shinelon.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MyConstraintValidator.class)
public @interface MyValidator {
    //自定义注解必须实现这三个属性
    String message();
    Class<?>[] groups() default{};
    Class<? extends Payload>[] payload() default{};

}

Then write the class
MyConstraintValidator.java that the annotation will handle validation:

/**
 * 
 */
package cn.shinelon.annotation;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.springframework.beans.factory.annotation.Autowired;

import cn.shinelon.service.impl.HelloServiceImpl;

/**
 * @author Shinelon
 *
 */
public class MyConstraintValidator implements ConstraintValidator<MyValidator, Object> {

    @Autowired
    public HelloServiceImpl helloServiceImpl;
    @Override
    public boolean isValid(Object arg0, ConstraintValidatorContext arg1) {
        helloServiceImpl.hello(" "+arg0);
        System.out.println(arg0);
        //返回true或者false表示是否校验成功
        return false;
    }
    //初始化
    @Override
    public void initialize(MyValidator arg0) {
        System.out.println("my validator init");
    }

}

This class implements ConstraintValidator

public interface HelloService {
    public void hello(String name);
}

Implementation class:

@Service
public class HelloServiceImpl implements HelloService {
    /* (non-Javadoc)
     * @see cn.shinelon.service.HelloService#hello()
     */
    @Override
    public void hello(String name) {
        System.out.println("hello"+name);
    }
}

After defining the annotation, we will load the annotation on the username field for testing, because the isValid method in the annotation returns false, which means that the verification fails.

    @MyValidator(message="这是一个自定义注解")
    public String username;

Then we continue to run the unit test above and we can see that our custom annotation takes effect.
write picture description here

So far, we have introduced the use of Hibernate Validation validation annotations and custom annotations for validation. Welcome to leave a message for discussion.


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325450039&siteId=291194637