Brief introduction: When doing Web development, basically every interface has to check the parameters. If the parameters are less, it is easier to deal with, but if the parameters are more, the code will appear a lot of if-else statements. Although this approach is simple and straightforward, it can greatly reduce development efficiency and code readability. So we can use the Validator component instead of doing unnecessary coding for us. This paper will be based on the introduction of validator data, combined with the author’s own practical experience in the project to summarize.

The author | | ali Jiang Yan source technology public number

A preface

One of the annoying things about web development is that you have to verify front-end input parameters. Basically every interface has to verify parameters, such as some non-null check, format check, etc. It’s easy to handle if you have fewer arguments but if you have more arguments you get a lot of if-else statements in your code.

Although this method is simple and straightforward, it also has some disadvantages. First, it reduces the development efficiency, because the parameters we need to check will exist in many places, and there will be repeated checks in different places. Second, it reduces the readability of the code, because there are too many extra code work in the business code.

So we can use the Validator component instead of doing unnecessary coding for us. In this paper, based on the introduction of validator and combined with my own practical experience in the project, I hope it can help you.

1 What is a 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 to version 2.0 of JSR 380 (2.0 was completed in 2017.08). It is important to note that JSR is a standard, it provides the specification of some validation annotations, but there is no implementation, such as @ Null, @ NotNull, @ the Pattern and so on, they lie javax.mail. Validation. Constraints under this package. The hibernate validator is implementation of the specification, and added some other validation annotations, such as @ NotBlank, @ NotEmpty, @ Length, etc., they are in org.. Hibernate validator. Constraints under the packet.

If our project uses Spring Boot, the Hibernate Validator framework is already integrated into the Spring-boot-starter – Web, so there is no need to add additional dependencies. If it is not a Spring Boot project, you need to add the following dependencies.

2. Annotation Introduction

1. Built-in annotations for validator

The Hibernate Validator extension defines the following annotations:

Three USES

Use is relatively simple, are used in the annotated way to use. Specifically, it is divided into single parameter verification and object parameter verification. Single parameter verification means that the controller interface receives the value transmitted by the front end according to the single parameter, and receives without encapsulated object. If there is encapsulated object, it is object parameter verification.

1 Single-parameter verification

Single-parameter verification only needs to add annotations before the parameters, as shown below:

Public Result deleteUser(@notnull (message = "id cannot be null ") Long id) {// do something}Copy the code

Note, however, that if single-argument validation is used, the @validated annotation must be used on the Controller class, as shown below:

Public class UserController {// do something} @restController @requestMapping ("/user") @validated // Public class UserController {// do something}Copy the code

2 Object parameter verification

To use the object parameter verification, you need to add the annotation on the verification property of the object first, 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; ... }Copy the code

Annotation grouping

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 an 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 {
}
Copy the code

2) Add the groups attribute to the annotation for the attributes to be verified in the parameter class:

Public class UserAO {@notnull (groups = updateAction.class, message = "updateAction.class ") public class UserAO {@notnull (groups = updateAction.class, message =" updateAction.class ") private Long id; @NotBlank private String name; @NotNull private Integer age; ... }Copy the code

As shown above, this means that only the ID field is validated under the UpdateAction group. By default, the name and age fields are validated.

Then in the Controller method, you can specify any of the scenarios in the @Validated annotation. If not, Default. Class is used. The following code indicates that the parameters are verified by default in the addUser() interface and by default in the updateUser() interface and the UpdateAction group.

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

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

Nested object

If there is also an object property nested in the parameter object that needs to be validated, you need to add the @Valid annotation to the object property.

Public class UserAO {@notnull (groups = updateAction.class, message = "updateAction.class ") public class UserAO {@notnull (groups = updateAction.class, message =" updateAction.class ") 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; }Copy the code

3 Error message capture

If the parameter verification fails, an exception will be thrown. We just 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 to catch an exception is shown below. The return value Result is our system’s custom return value class.

@RestControllerAdvice(basePackages= {"com.alibaba.dc.controller","com.alibaba.dc.service"}) public class GlobalExceptionHandler { @ExceptionHandler(value = {Throwable.class}) Result handleException(Throwable e, HttpServletRequest Request){// Exception handling}}Copy the code

It is important to note that in the absence of parameters is the exception thrown MissingServletRequestParameterException, single parameter calibration is the exception thrown ConstraintViolationException after failure, Get request object parameters calibration is the exception thrown BindException after failure, the object of the post request parameter calibration is the exception thrown MethodArgumentNotValidException after failure, different structure of the exception object, to extract the exception message way is different also. As shown in the figure below:

1) MissingServletRequestParameterException

if(e instanceof MissingServletRequestParameterException){ Result result = Result.buildErrorResult(ErrorCodeEnum.PARAM_ILLEGAL); String MSG = MessageFormat. The format (" lack of parameter {0} ", ((MissingServletRequestParameterException) e) getParameterName ()); result.setMessage(msg); return result; }Copy the code

2) ConstraintViolationException anomalies

If (e instanceof ConstraintViolationException) {/ / a single parameter calibration abnormal 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; }Copy the code

3) BindException is abnormal

If (e instanceof BindException){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; }Copy the code

4) MethodArgumentNotValidException anomalies

If (e instanceof MethodArgumentNotValidException) {/ / post request object parameters calibration abnormal 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; }Copy the code

The original link

This article is ali Cloud original content, shall not be reproduced without permission.