Location>code7788 >text

SpringBoot + validator easily achieves fully annotated parameter validation.

Popularity:813 ℃/2024-07-24 10:40:13

I. Background

Without going into the importance of parameter legitimacy validation, even if the front-end does basic validation of the parameters, the back-end still needs to validate them as well to prevent non-compliant data from going directly to the server, and if it's not intercepted, theSevere cases can even cause an outright system crash

In this paper, we combine our practical experience in using the projectThe main focus is practical, to do a summary of the data legitimacy verificationIf you don't know it, you can learn it, and at the same time, you can immediately practice it on your projects.

Here we have a few examples to demonstrate how to determine whether the parameter is legal or not, without further ado, directly jack up!

II. Assertion Validation

For validating the legitimacy of parameters, it was initially simpler to customize an exception class.

public class CommonException extends RuntimeException {

    private Integer code;

    public Integer getCode() {
        return code;
    }

    public CommonException(String message) {
        super(message);
         = 500;
    }

    public CommonException(Integer code, String message) {
        super(message);
         = code;
    }
}

When a parameter is checked to be illegal, an exception is thrown directly!

@RestController
public class HelloController {

    @RequestMapping("/upload")
    public void upload(MultipartFile file) {
        if (file == null) {
            throw new CommonException("Please choose to upload a file!");
        }
        //.....
    }
}

Finally, write a unified exception blocker that underpins the logic that throws exceptions.

This approach is simpler and more intuitive.If the current parameter has to determine both if it is null and if the length exceeds the maximum limit, the code is bloated and has poor reusability

So, the programmers thought of a more elegant and code-saving way to create an assertion class tool class, specifically used to determine the legitimacy of the parameter, and if it is not legitimate to throw an exception, the example is as follows:

/**
 * Assertion Tool Class
 */
public abstract class LocalAssert {
    
    public static void isTrue(boolean expression, String message) throws CommonException {
        if (!expression) {
            throw new CommonException(message);
        }
    }
    public static void isStringEmpty(String param, String message) throws CommonException{
        if((param)) {
            throw new CommonException(message);
        }
    }

    public static void isObjectEmpty(Object object, String message) throws CommonException {
        if (object == null) {
            throw new CommonException(message);
        }
    }

    public static void isCollectionEmpty(Collection coll, String message) throws CommonException {
        if (coll == null || (() == 0)) {
            throw new CommonException(message);
        }
    }
}

When we need to validate the parameters, we can do it directly through this class, the example is as follows:

@RestController
public class HelloController {

    @RequestMapping("/save")
    public void save(String name, String email) {
        (name, "User name cannot be empty!");
        (email, "Mailbox cannot be empty!");
        
        //.....
    }
}

Compared to the above implementation, this processing logic, the code is significantly more concise!

There are many more tool classes like this, such asspringalso provides a function calledAssertThe assertion toolkit class of the

III. Annotation Validation

Here we are going to introduce another more concise parameter validation logic, using annotations to validate the legitimacy of the data, not only will the code become very concise, but also very pleasing to read!

Using the Spring Boot project as an example, let's take a look at how this is practiced.

3.1 Adding dependency packages

first inintroduced inspring-boot-starter-webDependency packages are sufficient, and it will automatically type the annotation validation related dependency packages into the project!

<!-- spring boot web -->
<dependency>
    <groupId></groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

3.2. Write annotations to verify the request object

Then create an entityUserwhich is used to encapsulate the request parameters for user registration.and add the corresponding annotation validation rules to the parameter properties

import ;
import ;
import ;

public class User {

    @NotBlank(message = "User name can't be empty!")
    private String userName;

    @Email(message = "Mailbox format is incorrect!")
    @NotBlank(message = "Mailbox cannot be empty!")
    private String email;

    @NotBlank(message = "Password cannot be empty!")
    @Size(min = 8, max = 16,message = "Please enter a password with a length between 8 and 16 digits")
    private String userPwd;

    @NotBlank(message = "Confirm password cannot be empty!")
    private String confirmPwd;

    // set, get methods, etc...
}

3.3 Writing the request interface

existweblayer creates aregister()Register the interface method and also add the request parameters to the@Validannotation, an example is shown below:

import ;

@RestController
public class UserController {

    @RequestMapping("/register")
    public ResultMsg register(@RequestBody @Valid User user){
        if(!().equals(())){
            throw new CommonException(4001, "Confirmation password is not the same as the password,please confirm!");
        }
        //business processing...
        return ();
    }
}

3.4. Write a global exception handler

Finally customize an exception global handler for exception logic as follows:

@ControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger LOGGER = ();

    /**
     * interdictionControllerLayer Exception
     * @param e
     * @return
     */
    @ExceptionHandler(value = {})
    @ResponseBody
    public Object exceptionHandler(HttpServletRequest request, Exception e){
        ("【统一异常interdiction】request address:{}, error message:{}", (), ());
        // Annotation validation of thrown exceptions
        if(e instanceof MethodArgumentNotValidException){
            // 获取error message
            String error = ((MethodArgumentNotValidException) e).getBindingResult().getFieldError().getDefaultMessage();
            return (500, error);
        }
        // Customizing thrown exceptions
        if(e instanceof CommonException){
            return (((CommonException) e).getCode(), ());
        }
        return (999, ());
    }
}

Uniform Response Object (URO)ResultMsg, as follows:

public class ResultMsg<T> {

    /**status code**/
    private int code;

    /**Description of results**/
    private String message;

    /**result set**/
    private T data;

    /**timestamp**/
    private long timestamp;

    // set、getmethodologies...
}

3.5 Service testing

To start the project, use thepostmanLet's verify that the code is correct and see how it works.

  • Test if a field is empty

  • Test the legitimacy of the mailbox

  • Test that the password length meets the requirements

  • Test password is the same as the confirmation password

It can be seen that the validation results are as expected!

IV. Custom annotation validation

In fact, those familiar with the SpringMVC source code may know that Spring Boot has a built-inhibernate-validatorThe validation component, which was used above to accomplish the validation of the annotations on the incoming parameters at the time of the request.

By default, the dependency package already gives us a very large number of checksum annotations as follows!

  • JSR-provided validation annotations!

  • Validation annotations provided by Hibernate Validator

But some cases, such as the parameter gender, may require us to manually validate it ourselves.

For this case, we can also customize an annotation to complete the parameter verification, but also facilitate further understanding of the principle of annotation validation.

Custom annotation validation, implemented as follows!

First, create aSexAnnotation.

@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = )
@Documented
public @interface Sex {

    String message() default "Gender values are not optional";

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

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

Then, create aSexValidatorclass, which implements a class from theConstraintValidatorconnector

public class SexValidator implements ConstraintValidator<Sex, String> {

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        Set<String> sexSet = new HashSet<String>();
        ("male");
        ("women");
        return (value);
    }
}

Finally, in theUserAdd a gender parameter on the entity class and use a custom annotation for validation!

public class User {

    @NotBlank(message = "User name can't be empty!")
    private String userName;

    @Email(message = "Mailbox format is incorrect!")
    @NotBlank(message = "Mailbox cannot be empty!")
    private String email;

    @NotBlank(message = "Password cannot be empty!")
    @Size(min = 8, max = 16,message = "Please enter a password with a length between 8 and 16 digits")
    private String userPwd;

    /**
     * Customized annotation checksum
     */
    @Sex(message = "The gender was entered incorrectly!")
    private String sex;

    // set, get methods, etc...
}

Start the service, re-request it, and run it as follows:

The results were consistent with expectations!

V. Summary

Parameter validation, which is used very frequently in development, and how to do it elegantly and make the code more readable, is a goal that industry gurus have been pursuing!

This article is mainly around the realization of the parameters in Spring Boot unified validation of the relevant knowledge summary and introduction, if there is a description of the wrong place, welcome to leave a message of support.

Sample code:spring-boot-example-valid