10
Introduction to web development, basically every interface needs to check the parameters. If there are fewer parameters, it is easier to handle. Once there are more parameters, there will be a lot of if-else statements in the code. Although this method is simple and straightforward, it will greatly reduce development efficiency and code readability. So we can use the validator component to replace us for unnecessary coding operations. This article will be based on the introduction material of validator, combined with the author's own actual use experience in the project to make a summary.

image.png

Author | Jiang Yan
Source | Alibaba Technical Official Account

I. Introduction

One thing that is annoying to do web development is to verify the front-end input parameters. Basically, every interface needs to verify the parameters, such as some non-null verification, format verification, etc. If there are fewer parameters, it is easy to handle, but if there are more parameters, there will be a lot of if-else statements in the code.

Although using this method is simple and straightforward, there are disadvantages. First, it reduces development efficiency, because the parameters we need to verify will exist in many places, and there will be repeated verifications in different places, and secondly, it reduces code readability. , Because there is too much extra work code mixed in the business code.

So we can use the validator component to replace us for unnecessary coding operations. This article is based on validator's introduction materials, and also summarizes my own actual use experience in the project, I hope to help everyone.

1 What is validator

Bean Validation is a set of annotation-based data validation specifications defined by Java. It has been upgraded from version 1.0 of JSR 303 to version 1.1 of JSR 349, and then to version 2.0 of JSR 380 (2.0 completed on 2017.08). It has gone through three Versions. It should be noted that JSR is only a standard. It stipulates some validation annotation specifications, but has not been implemented, such as @Null, @NotNull, @Pattern, etc., which are located in the javax.validation.constraints package. The hibernate validator is the implementation of this specification, and adds some other validation annotations, such as @NotBlank, @NotEmpty, @Length, etc., which are located in the org.hibernate.validator.constraints package.

If our project uses Spring Boot, the hibernate validator framework has been integrated in spring-boot-starter-web, so there is no need to add other dependencies. If it is not a Spring Boot project, you need to add the following dependencies.

image.png

Two annotation introduction

1 Validator built-in annotation

image.png

The following annotations are defined in the hibernate validator extension:

image.png

Three use

It is relatively simple to use, and they are all used in the way of annotations. Specifically, it is divided into single parameter verification and object parameter verification. Single parameter verification means that the controller interface receives the front-end transfer value according to a single parameter. There is no encapsulated object to receive. If there is an encapsulated object, it is object parameter verification.

1 Single parameter verification

Single parameter verification only needs to add a comment before the parameter, as shown below:

public Result deleteUser(@NotNull(message = "id不能为空") Long id) {
  // do something
}

But one thing to note is that if you use single-parameter validation, you must add the @Validated annotation to the controller class, as shown below:

@RestController
@RequestMapping("/user")
@Validated // 单参数校验需要加的注解
public class UserController {
  // do something
}

2 Object parameter verification

When using object parameter validation, you need to add an annotation to the validation attribute of the object, and then add the @Validated annotation before the object parameter of the Controller method, as shown below:

public Result addUser(@Validated UserAO userAo) {
    // do something
}

public class UserAO {
  @NotBlank
  private String name;

  @NotNull
  private Integer age;
  
  ……
}

Annotation group

In the object parameter verification scenario, there is a special scenario in which the same parameter object has different verification rules in different scenarios. For example, you do not need to pass in the id field when creating an object (the id field is the primary key, generated by the system, and not specified by the user), but you must pass in the id field when modifying the object. In such a scenario, annotations need to be grouped.

1) The component has a default group Default.class, so we can create another group UpdateAction.class, as shown below:

public interface UpdateAction {
}

2) On the attributes that need to be verified in the parameter class, add the groups attribute in the annotation:

public class UserAO {

    @NotNull(groups = UpdateAction.class, message = "id不能为空")
    private Long id;
    
    @NotBlank
    private String name;

    @NotNull
    private Integer age;
    
    ……
}

As shown above, it means that the id field is only checked under the UpdateAction group, and the name field and age field are checked by default.

Then in the controller's method, specify which scenario is required in the @Validated annotation. If there is no specification, it means that Default.class is used, and other groups need to be displayed and specified. The following code means that the parameter verification is performed according to the default condition in the addUser() interface, and the parameters are jointly checked according to the default condition and the UpdateAction grouping in the updateUser() interface.

public Result addUser(@Validated UserAO userAo) {
  // do something
}
public Result updateUser(@Validated({Default.class, UpdateAction.class}) UserAO userAo) {
  // do something
}

Object nesting

If there is an object property nested in the parameter object that needs to be verified, and the nested object property also needs to be verified, then the @Valid annotation needs to be added to the object property.

public class UserAO {

    @NotNull(groups = UpdateAction.class, message = "id不能为空")
    private Long id;
    
    @NotBlank
    private String name;

    @NotNull
    private Integer age;
    
    @Valid
    private Phone phone;
    
    ……
}

public class Phone {
    @NotBlank
    private String operatorType;
    
    @NotBlank
    private String phoneNum;
}

3 Capture of error messages

An exception will be thrown after the parameter verification fails. We only need to catch the parameter verification failure exception in the global exception handling class, and then add the error message to the return value. The method of catching the exception is shown below, the return value Result is a custom return value class of our system.

@RestControllerAdvice(basePackages= {"com.alibaba.dc.controller","com.alibaba.dc.service"})
public class GlobalExceptionHandler {

  @ExceptionHandler(value = {Throwable.class})
  Result handleException(Throwable e, HttpServletRequest request){
    // 异常处理
        }
}

It should be noted that if the parameter is missing, the exception thrown is MissingServletRequestParameterException, the exception thrown after the single parameter verification fails is ConstraintViolationException, the exception thrown after the object parameter verification of the get request fails is BindException, and the object parameter verification of the post request is The exception thrown after the verification fails is MethodArgumentNotValidException. Different exception objects have different structures, so the methods for extracting exception messages are also different. As shown below:

1)MissingServletRequestParameterException

if(e instanceof MissingServletRequestParameterException){
    Result result = Result.buildErrorResult(ErrorCodeEnum.PARAM_ILLEGAL);
    String msg = MessageFormat.format("缺少参数{0}", ((MissingServletRequestParameterException) e).getParameterName());
    result.setMessage(msg);
    return result;
}

2) ConstraintViolationException

if(e instanceof ConstraintViolationException){
  // 单个参数校验异常
  Result result = Result.buildErrorResult(ErrorCodeEnum.PARAM_ILLEGAL);
  Set<ConstraintViolation<?>> sets = ((ConstraintViolationException) e).getConstraintViolations();
  if(CollectionUtils.isNotEmpty(sets)){
    StringBuilder sb = new StringBuilder();
    sets.forEach(error -> {
                    if (error instanceof FieldError) {
                        sb.append(((FieldError)error).getField()).append(":");
                    }
                    sb.append(error.getMessage()).append(";");
                });
    String msg = sb.toString();
    msg = StringUtils.substring(msg, 0, msg.length() -1);
    result.setMessage(msg);
  }
  return result;
}

3) BindException

if (e instanceof BindException){
      // get请求的对象参数校验异常
      Result result = Result.buildErrorResult(ErrorCodeEnum.PARAM_ILLEGAL);
      List<ObjectError> errors = ((BindException) e).getBindingResult().getAllErrors();
      String msg = getValidExceptionMsg(errors);
      if (StringUtils.isNotBlank(msg)){
        result.setMessage(msg);
      }
      return result;
}
private String getValidExceptionMsg(List<ObjectError> errors) {
  if(CollectionUtils.isNotEmpty(errors)){
    StringBuilder sb = new StringBuilder();
    errors.forEach(error -> {
                    if (error instanceof FieldError) {
                       sb.append(((FieldError)error).getField()).append(":");
                    }
                    sb.append(error.getDefaultMessage()).append(";");
                });
    String msg = sb.toString();
    msg = StringUtils.substring(msg, 0, msg.length() -1);
    return msg;
  }
  return null;
}

4) MethodArgumentNotValidException exception

if (e instanceof MethodArgumentNotValidException){
      // post请求的对象参数校验异常
      Result result = Result.buildErrorResult(ErrorCodeEnum.PARAM_ILLEGAL);
      List<ObjectError> errors = ((MethodArgumentNotValidException) e).getBindingResult().getAllErrors();
      String msg = getValidExceptionMsg(errors);
      if (StringUtils.isNotBlank(msg)){
        result.setMessage(msg);
      }
      return result;
}

The official e-book of "One-stop Big Data Development and Governance DataWorks Use Collection" is open for download

DataWorks official introductory e-book has been published, zero-based introductory big data development management, a comprehensive understanding of the ten major functional modules of DataWorks, and quick access to the core functions of DataWorks.

click here to download

Copyright Notice: content of this article is contributed spontaneously by Alibaba Cloud real-name registered users. The copyright belongs to the original author. The Alibaba Cloud Developer Community does not own its copyright and does not assume corresponding legal responsibilities. For specific rules, please refer to the "Alibaba Cloud Developer Community User Service Agreement" and the "Alibaba Cloud Developer Community Intellectual Property Protection Guidelines". If you find suspected plagiarism in this community, fill in the infringement complaint form to report it. Once verified, the community will immediately delete the suspected infringing content.

阿里云开发者
3.2k 声望6.3k 粉丝

阿里巴巴官方技术号,关于阿里巴巴经济体的技术创新、实战经验、技术人的成长心得均呈现于此。