Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities

In order to ensure the stability and security of the interface, everyone must check the input parameter. This article will show you how to use the parameter validator provided by SpringBoot and extend it to enable custom validations. Of course in some Internet project, in order to guarantee the high performance of the interface, check are made of in front, but in the statute for ali and development is that the more simple interface more don’t need to check parameters, the more complex interface more parameters need to check, because of the complex interface trial-and-error cost is high, check the performance of the interface has little impact.

Engineering use can refer to my open source project: gitee.com/zhuhuijie/b…

Introduced in the common-Web module for use in examplebusiness

Use of SpringBoot parameter validators

This chapter introduces how to introduce SpringBoot parameter validator, so that we can build a simple Demo, the second part of the article, custom extension is the highlight of this article.

1 First, the POM file introduces the dependency of parameter validator

<! <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>Copy the code

2 enter VO and add relevant notes

Common notes:

  • @notnull Non-null validation

  • @min (value = 1, message = “age must not be less than 1″) @max (value = 25, message =” age must not be more than 25″)

    Value interval validation

  • @email (message = “must be a mailbox format “) Email format verification

  • @past (message = “birthday range is not correct, birthday must be before today “)

    Verify if it is in the past

import com.fasterxml.jackson.annotation.JsonFormat; import com.zhj.business.protocol.validhandler.BirthdayValidHandler; import com.zhj.common.web.valid.annotation.MyValid; import lombok.Data; import javax.validation.constraints.*; import java.util.Date; /** * @author ZHJ */ @data public class StudentInput {@notnull (message = "name cannot be null ") private String name; @min (value = 1, message = "age cannot be less than 1") @max (value = 25, message =" age cannot be more than 25") private Integer age; @notnull (message = "mailbox cannot be empty ") @email (message =" mailbox format must be ") private String Email; @notnull (message = "gender cannot be null ") private Integer sex; @notnull (message = "birthday cannot be empty ") @past (message =" birthday range is not correct, ") @jsonFormat (timezone = "GMT+8", pattern = "YYYY-MM-DD ") private Date birthday; }Copy the code

3 Check is enabled in Controller. It takes effect only when enabled

import com.zhj.business.protocol.input.StudentInput; import com.zhj.business.service.StudentService; import com.zhj.common.core.result.Result; import com.zhj.common.core.util.ResultUtils; import com.zhj.data.entity.example.Student; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import java.util.List; @Slf4j @RestController @RequestMapping("/student") public class StudentController { @Autowired private StudentService studentService; @postmapping ("/add") public Result add(@valid@requestBody StudentInput StudentInput) {log.info(" Received student information: " + studentInput); Student student = new Student(); BeanUtils.copyProperties(studentInput, student); boolean result = studentService.save(student); Log.info (" save student result "+ result); return ResultUtils.createSuccess(student); }}Copy the code

An extension to the SpringBoot parameter validator

This chapter will show us how to implement this kind of complex parameter verification through annotations by implementing the verification of age and birthday match as an example

1 First of all, our extension requires the parameter validator to be implemented through custom annotations

import com.zhj.common.web.valid.constraint.MyParameterValid; import com.zhj.common.web.valid.handler.MyValidHandler; import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author ZHJ */ @target ({elementtype.field, Elementtype.type}) @Retention(retentionPolicy.runtime) @constraint (validatedBy = myparameterValid. class Public @interface MyValid {/** * error message * @return */ String message() default "verification failed "; /** * check packet * @return */ Class<? >[] groups() default {}; /** * check the load * @return */ Class<? extends Payload>[] payload() default {}; /** * extension check method * @return */ Class<? extends MyValidHandler> handler(); }Copy the code

2 Implement custom extension of Springboot parameter validator

  • Implement ConstraintValidator<MyValid, Object> to initialize a custom annotation

  • Reimplement the validation method

    • Get the custom parameter validation handler MyValidHandler from the Spring container
    • The annotations and validation objects are then passed to the custom validation method
    • Execute a custom verification method and check whether the verification succeeds based on the returned result
import com.zhj.common.web.util.ApplicationContextUtils; import com.zhj.common.web.valid.annotation.MyValid; import com.zhj.common.web.valid.handler.MyValidHandler; import lombok.extern.slf4j.Slf4j; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.util.Optional; @author ZHJ */ @slf4j public class MyParameterValid implements ConstraintValidator<MyValid, Object> { private MyValid myValid; @Override public void initialize(MyValid constraintAnnotation) { this.myValid = constraintAnnotation; } / * * * * * @ @ param o check method param constraintValidatorContext * @ return * / @ Override public Boolean isValid (Object o, ConstraintValidatorContext ConstraintValidatorContext) {log. The info (" custom parameters calibration trigger "+ o); if (null ! = o) { Class<? extends MyValidHandler> handler = myValid.handler(); / / to handle calibration MyValidHandler MyValidHandler MyValidHandler = ApplicationContextUtils) getBean (handler); return Optional .ofNullable(myValidHandler) .map(myValidHandler1 -> { return myValidHandler.valid(myValid, o); }).orElse(false); } return true; }}Copy the code

3 Customize processing interfaces

User-defined verification method This interface is used to override the verification method

Multiple implementations of the interface enable various custom processing.

import com.zhj.common.web.valid.annotation.MyValid; /** * extension interface, developers implement this interface, * @author ZHJ */ Public Interface MyValidHandler<T> {@param data * @return */ Boolean valid(MyValid myValid, T data); }Copy the code

4 Get the utility classes for objects in the Spring container

Find the corresponding implementation based on the class name through the Spring context

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; /** * Spring container tool method * @author ZHJ */ @Component Public Class ApplicationContextUtils {@autoWired private ApplicationContext applicationContext; /** * private Static ApplicationContext staticApplicationContext; @PostConstruct private void init() { ApplicationContextUtils.staticApplicationContext = applicationContext; } public static <T> T getBean(Class<T> cls) { if (staticApplicationContext ! = null) { return staticApplicationContext.getBean(cls); } return null; }}Copy the code

5 Add a custom annotation to the VO class

Handler = BirthdayValidHandler. Class the class name of the custom checking method into the, the need to implement custom processing interface

import com.fasterxml.jackson.annotation.JsonFormat; import com.zhj.business.protocol.validhandler.BirthdayValidHandler; import com.zhj.common.web.valid.annotation.MyValid; import lombok.Data; import javax.validation.constraints.*; import java.util.Date; /** * @author ZHJ */ @data @myvalid (message = "age and birthday do not match ", Handler = BirthdayValidHandler. Class) public class StudentInput {@ NotNull (message = "name cannot be empty) private String name; @min (value = 1, message = "age cannot be less than 1") @max (value = 25, message =" age cannot be more than 25") private Integer age; @notnull (message = "mailbox cannot be empty ") @email (message =" mailbox format must be ") private String Email; @notnull (message = "gender cannot be null ") private Integer sex; @notnull (message = "birthday cannot be empty ") @past (message =" birthday range is not correct, ") @jsonFormat (timezone = "GMT+8", pattern = "YYYY-MM-DD ") private Date birthday; }Copy the code

6 Create a class name for the annotation to implement custom verification

Remember to register the object with the Spring container, otherwise you won’t be able to get the instance by extension

This example is a validation of the relationship between age and birthday. Age and birthday must match for the validation to succeed

import com.zhj.business.protocol.input.StudentInput; import com.zhj.common.web.valid.annotation.MyValid; import com.zhj.common.web.valid.handler.MyValidHandler; import org.springframework.stereotype.Component; import java.util.Calendar; import java.util.Date; /** * @author zhj */ @Component public class BirthdayValidHandler implements MyValidHandler<StudentInput> { @Override public boolean valid(MyValid myValid, StudentInput data) { Integer age = data.getAge(); Date birthday = data.getBirthday(); if (age == null || birthday == null) return true; Calendar calendar = Calendar.getInstance(); calendar.setTime(new Date()); int currYear = calendar.get(Calendar.YEAR); calendar.setTime(birthday); int birYear = calendar.get(Calendar.YEAR); return currYear - birYear == age; }}Copy the code