Development and application of spring boot parameter verification

Posted by gameshints on Mon, 10 Jan 2022 21:53:37 +0100

1, Parameter verification of SpringBoot

1. Parameter verification annotation provided by SpringBoot

Except that @ NotEmpty and @ NotBlank consider null values illegal, other annotations such as @ Size, @ Max, @ Min, etc. consider null as valid. If null values are not allowed, additional @ NotNull annotations need to be added.

annotation

explain

@NotEmpty

String, collection, Map, array, etc. cannot be null or empty

@NotBlank

The string cannot be null and contains at least one non empty character

@NotNull

Any type cannot be null

@Size

The number of string, set, Map, array and other elements must be within the specified min and max range

@Email

The string is a valid mailbox

@Digits

String, integer and floating point number are numbers. The parameter integer represents the number of integer digits and fraction represents the number of decimal digits

@CreditCardNumber

The string is a valid credit card number. The validity of the credit card itself is not verified

@AssertTrue

Boolean type must be true, null value is considered valid

@Max

Integer and floating point numbers must be less than or equal to the specified maximum value

@Min

Integer and floating point numbers must be greater than or equal to the specified minimum value

@Range

The string and number must be within the specified min and max range

@Pattern

The string must match the specified regular expression

@Data
public class Employee implements Serializable {

  private static final long serialVersionUID = -8224860450904540019L;

  @NotEmpty(message = "Name cannot be empty")
  @UTF8Size(max = 16, message = "name should be short than 128")
  private String name;
    
  @Email
  private String email;

  @NotBlank(message = "city is required")
  @Size(max = 128, message = "city should be short than 128")
  private String city;

  @CreditCardNumber(message = "invalid credit card number")
  private String ccNumber;

  @Pattern(regexp = "^(0[1-9]|1[0-2])([\\\\/])([1-9][0-9])$", message = "required format MM/YY")
  private String ccExpiration;

  @Digits(integer = 3, fraction = 0, message = "invalid CVV")
  private String ccCVV;

}

2. Custom verification annotation

@Size cannot support Chinese characters. You can customize the following, and then use @ UTF8Size on the fields that need to verify characters (Chinese and English).

@Documented
@Constraint(validatedBy = Utf8SizeValidator.class)
@Target({METHOD, FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface UTF8Size {
  String message() default "{javax.validation.constraints.Size.message}";

  int min() default 0;
  int max() default Integer.MAX_VALUE;

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

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

}

public class Utf8SizeValidator implements ConstraintValidator<UTF8Size, String> {

  private int maxCharSize;

  @Override
  public void initialize(UTF8Size constraintAnnotation) {
    this.maxCharSize = constraintAnnotation.max();
  }

  @Override
  public boolean isValid(String value, ConstraintValidatorContext context) {
    if (Objects.isNull(value)) {
      return true;
    }
    return value.getBytes(Charset.forName("GB18030")).length <= maxCharSize;
  }
}

2, Use of field verification

Use the @ Valid annotation of the Bean Validation API or the @ Validated annotation provided by Spring Context to enable Bean validation. The main difference is that @ Validated is a variant of @ Valid and supports validation groups.

1. This method will throw the exception information to the global exception handler

@PostMapping("/emp")
public String addEmploy(@RequestBody  @Valid Employee employee) {
  log.info("employee to create: {}", employee);

  String employeeId = UUID.randomUUID().toString();
  return employeeId;
}

2. If you need to capture the abnormal result of parameter verification, write it as follows

This method does not return the result of exception handling to global exception handling

@PostMapping()
UserInfo addUser(@RequestBody @Valid UserInfo userInfo, BindingResult bindingResult) {
    userService.addUser(userInfo);
    return userInfo;
}

3, Global exception handling for field verification

package com.example.springboot.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
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.ResponseStatus;

import java.util.stream.Collectors;

@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public String handleMethodArgumentNotValidException(
            MethodArgumentNotValidException exception) {
        log.error("method argument not valid: {}", exception.getMessage());
        String errorMessage = "field error";

        BindingResult bindingResult = exception.getBindingResult();
        if (bindingResult.hasErrors()) {
            errorMessage = bindingResult.getFieldErrors().stream()
                    .map(FieldError::getDefaultMessage)
                    .collect(Collectors.joining(" | "));
        }

        return errorMessage;
    }
}

4, Group check

The same field requires different verification strategies in different scenarios

1. Group interface

public class GroupVaildDTO {

    public interface SaveGroup extends Default {}

    public interface UpdateGroup extends Default {}
}

2. Checked JavaBean properties

public class GroupsValidForm {

    @Null(message = "id Must be null", groups = {GroupVaildDTO.SaveGroup.class})
    @NotNull(message = "id Cannot be null", groups = {GroupVaildDTO.UpdateGroup.class})
    private Integer id;

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

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("GroupsValidForm{");
        sb.append("id=").append(id);
        sb.append(", userName='").append(userName).append('\'');
        sb.append('}');
        return sb.toString();
    }
}

3. Use of Controller layer group verification

The same field requires different verification strategies in different scenarios

@PostMapping(value = "update")
    public ServerResponse update(@RequestBody @Validated(value = GroupVaildDTO.UpdateGroup.class)
                                            GroupsValidForm groupsValidForm, BindingResult results) {
    if (results.hasErrors()) {
        return ServerResponse.createByErrorMessage(results.getFieldError().getDefaultMessage());
    }
    return ServerResponse.createBySuccess();
}