SpringBoot uses Validation for parameter verification and uniformly returns verification exceptions

In the development of the SpringBoot project, there is a point of view that do not trust the parameters passed in by the front end, because you do not know how the user operates our interface, so the parameters also need to be verified on the back end. This article mainly talks about our project The most commonly used authentication scheme in .

1. Introduce the corresponding dependencies

 pom copy code <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

The essence of spring-boot-starter-validation is to use Hibernate Validator, which does not have its own implementation.

2. Basic verification annotations of Validation

less copy code empty check
@Null verifies whether the object is null
@NotNull Verifies whether the object is not null, and cannot check a string with a length of 0
@NotBlank Checks whether the constraint string is Null and whether the length of Trim is greater than 0, only for strings, and will remove leading and trailing spaces.
@NotEmpty checks if the constrained element is NULL or EMPTY.

Booelan check
@AssertTrue verifies whether a Boolean object is true
@AssertFalse verifies whether the Boolean object is false

length check
@Size(min=, max=) Verify whether the length of the object (Array, Collection, Map, String) is within the given range
@Length(min=, max=) Verify that the element value length of the annotation is within the interval between min and max

date check
@Past verifies that Date and Calendar objects are before the current time
@Future validates that Date and Calendar objects are after the current time
@Pattern verifies whether the String object conforms to the rules of the regular expression

Numerical check, it is recommended to use Stirng, Integer type, not recommended to be used on int type, because the form value cannot be converted to int, but can be converted to Stirng is "", Integer is null
@Min verifies that Number and String objects are greater than or equal to the specified value
@Max validates that Number and String objects are less than or equal to the specified value
@DecimalMax The marked value must not be greater than the maximum value specified in the constraint. The parameter of this constraint is a string representation of the maximum value defined by BigDecimal. Decimals have precision
@DecimalMin The annotated value must not be less than the minimum value specified in the constraint. The parameter of this constraint is a string representation of the minimum value defined by BigDecimal. Decimals have precision
@Digits verifies whether the composition of Number and String is legal
@Digits(integer=,fraction=) Verify whether the string is a number conforming to the specified format, integer specifies the integer precision, and fraction specifies the decimal precision.

@Range(min=, max=) validates that the element value of the annotation is between the minimum and maximum values
@Range(min=10000, max=50000, message="range.bean.wage")

@Valid is written before the method parameter, and recursively checks the object. If the associated object is a collection or an array, then recursively check the elements in it. If it is a map, check the value part of it. (whether to perform recursive validation)
@CreditCardNumber credit card verification
@Email Verify whether it is an email address, if it is null, no verification is performed, and the verification is passed.
@ScriptAssert(lang= ,script=, alias=)
@URL(protocol=, host=, port=, regexp=, flags=)

3. Add parameter verification

Add validation on our corresponding DTO and on the controller.

  1. Add validation to DTO properties
java copy code import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok. AllArgsConstructor;
import lombok.Data;
import lombok. NoArgsConstructor;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.Email;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import java.util.UUID;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class registryUserDto {
    @NotBlank(message = "Username cannot be empty")
    private String username;
    @NotBlank(message = "Password cannot be empty")
    @Length(min = 6, max = 20, message = "The password length is between 6-20")
    private String password;
    @Min(value = 0, message = "The minimum age is 0")
    @Max(value = 200, message = "The maximum age is 200")
    private Integer age;
    @NotBlank(message = "Mailbox cannot be empty")
    @Email(message = "Email format is incorrect")
    private String email;
    @JsonIgnore
    private String salt = UUID.randomUUID().toString().replaceAll("-", "");
    private Boolean admin;
}

Validation is achieved by adding various validation annotations to parameters

  1. Add @Valid or @Validated to the DTO corresponding to the controller
java copy code @PostMapping("/registry")
public ResponseResult registryUser(@RequestBody @Valid registryUserDto registryUserDto) {
    return ResponseResult.okResult(registryUserDto);
}

After this addition, the parameters can be verified. When the verification fails, the interface will return a 500 exception and the corresponding exception information.

For complex String verification, we can use regularization to verify, as follows:

less copy code @Pattern(regexp = "^1(3|4|5|7|8)\d{9}$", message = "Mobile phone number format error")
@NotBlank(message = "Mobile phone number cannot be empty")
private String phone;

In addition, for the verification of a single parameter, parameters received without DTO objects can also be verified. First add @Validated to the controller class, and then add verification annotations before the corresponding parameters, as shown below:

lessCopy code@RestController
@RequestMapping("/user")
@Validated
public class UserController {
    @PostMapping("/registry")
    public ResponseResult registryUser(@NotBlank(message = "name cannot be empty") String name) {
        return ResponseResult.okResult(name);
    }
}

4. Custom validation annotation

For some common or complex verification needs, we need to customize the verification annotations, which are implemented as follows:

  1. Create a new custom annotation

annotation.validator.Status:

java copy code import com.jk.validator.StatusValidator;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy. RUNTIME)
@Documented
@Constraint(validatedBy = {StatusValidator. class})
public @interface Status {

    String[] statusType() default {};

    String message() default "There is an error in status transmission";

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

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

}
  1. implement the appropriate checks
java copy code import com.jk.annotation.validator.Status;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Arrays;
import java.util.List;

public class StatusValidator implements ConstraintValidator<Status, Integer> {

    private List<String> typeStatus ;

    @Override
    public void initialize(Status constraintAnnotation) {
        typeStatus = Arrays.asList(constraintAnnotation.statusType());
        ConstraintValidator.super.initialize(constraintAnnotation);
    }

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
        if(value !=null){
            if(!typeStatus.contains(String.valueOf(value))){
                return false;
            }
        }
        return true;
    }
}
  1. Use of custom annotations
java copy code @Status(statusType = {"1", "2"})
private Integer status;

5. Unified exception handling for verification failure

You can see that the msg response to our verification failure above is very unfriendly, and there are many messages that the front end does not need to know.

We add verification failure processing based on global unified exception handling. If you are not sure about unified exception handling, you can read my other article Unified Response Format and Unified Exception Handling in SpringBoot. You should do this

Add BindException processing in unified exception handling

exception.GlobalExceptionHandler:

kotlin copy code import com.jk.enums.AppHttpCodeEnum;
import com.jk.exception.SystemException;
import com.jk.domain.vo.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    @ExceptionHandler(SystemException. class)
    public ResponseResult systemExceptionHandler(SystemException e) {
        log.error("An exception occurred! {}", e);
        return ResponseResult. errorResult(e. getCode(), e. getMsg());
    }
    @ExceptionHandler(Exception. class)
    public ResponseResult exceptionHandler(Exception e) {
        log.error("An exception occurred! {}", e);
        return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(), e.getMessage());
    }
    /* Add validation parameter exception handling */
    @ExceptionHandler(BindException. class)
    public ResponseResult bindExceptionHandler(BindException e) {
        log.error("An exception occurred! {}", e);
        return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR, e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
    }
}

When the verification fails, the response received by the front end is as follows:

You can see that the exception information is very friendly, and it is also very convenient for the front-end to pop up a message box prompt!

In this way, parameter verification and unified exception handling are added to the SpringBoot project. In fact, the whole is very simple, and I hope everyone can use it in the project!

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. Java skill treeHomepageOverview 117576 people are studying systematically