To write an interface, perform the following steps:
- Parameter calibration
- Write Service, Dao (SQL)
- Result Encapsulates the returned value
- If distributed, it may also involve gateway configuration, service references, and so on
In the final analysis, there are two kinds of parameter verification: manual verification and automatic verification
In real life, there are two kinds:
Encapsulation ValidationUtils
Validation is automated using Spring
Spring provides solutions to both approaches. In addition to Spring Validation, Spring also provides Assert
Assert:
- A string exists in hasText. If no string exists, an error is reported
-
NotNull is notNull. If null, an error is reportedCopy the code
-
An error is reported if isTrue isTrue or falseCopy the code
Illegalargumentexceptions are thrown when a condition is not met, so use Assert to handle invalid argument exceptions.
If the degree of freedom for checking is too high, you can encapsulate a ValidationUtils yourself
Encapsulation ValidationUtils
There are two ways to encapsulate and verify tool classes:
- Verifies and returns the result, at the caller’s discretion
- Check failure directly throw exception
Method one: verify and return the result, and the caller handles it himself
1. The method returns true/false only. 2
@param id @return/public static final Boolean isNotId(Long ID){if (id == null){return true; } return id < 0; Public void method(){Long id = -1l; ValidationUtilsV1.isNotId(id); }
In fact, this approach is not much different from no encapsulation, just put the judgment logic in the validation tool class
Method 2: If the check fails, throw an exception directly
Generally, @restControllerAdvice is used to handle global exceptions.
public class ValidationUtilsV3 {
Public static final String NULL_FORMAT = "%s cannot be null "; Public static final String LESS_THAN_ZERO = "%s cannot be less than 0"; public static final void isNotNull(Object o,String filedName){ if (o == null){ throw new ValidationException(String.format(NULL_FORMAT,filedName)); } } public static final void isLessThan0(Integer num,String filedName){ isNotNull(num,filedName); if (num < 0){ throw new ValidationException(String.format(LESS_THAN_ZERO,filedName)); }}Copy the code
}
@Slf4j @RestControllerAdvice public class GlobalExceptionHandler {
Public <T> T handleValidationExcepion(ValidationException e){// Prints accurate error logs. Log. Warn ({}, LLDB message (),e); Return (T) "Check parameter abnormal "; }Copy the code
}
Spring Validation
Common examples of Spring’s annotation-based validation logic are:
- @Validated
- @NotNull
- @NotBlank
- @NotEmpty
- @Positive
- @Length
- @Max
- @Min
What is the relationship between @Valid of JSR303 and @Validated of Spring?
The @Validated function of Spring is relatively more powerful because it is based on the @VALID extension. However, in nested verification, the @VALID function is supported.
Before springboot2.3. x, you can directly use @validated and @valid. After springboot2.3. x, additional dependencies need to be introduced:
GET bulk parameter check: check throw exceptions ConstraintViolationException violates the constraint does not meet the conditions.
1. If the parameters of GET are few, bulk parameter verification can be used. The @Validated annotation should be added to the class of the verification method
2. Because an exception will be thrown when the test condition is not met, we can catch the exception in global exception handling and return a friendly message to the foreground. Prior to Spring2.3.X, Spring’s default exception JSON was returned if no exception was caught. The server is thrown ConstraintViolationException
Get DTO parameter verification: If the verification condition is not met, a BindException binding exception is thrown
1. When the Get Dto parameter verification is used, in addition to the VERIFICATION parameters in the Dto class, add the @Validated annotation to the VERIFIED Dto.
2. If the test does not meet the conditions, the exception thrown is BindException. If the backend global exception processor processes the exception, SpringBoot will process the exception Json information to the front end. So we can do this in a global exception handler.
Post parameters calibration: MethodArgumentNoValidException method parameters not check exception
1. If a Json string is received from the front-end, use @RequestBody to convert it, and add an @ “Validated” annotation to the parameter to be verified.
2. The inspection does not satisfy the conditions, at this point the exception thrown into MethodArgumentNoValidException
Verification of other Scenarios
- Nested check
- Packet check
- Check the List
- Nested check
@Validated Does not support nested verification, and @Valid does
@Data public class User {
@notnull (message = "id cannot be null ") private Long ID; @notnull (message = "age cannot be empty ") @max (value = 30,message = "programmer must be at least 30 years old ") @min (value = 16,message =" programmer must be at least 16 years old ") private Integer age; @notnull (message = "Department cannot be empty ") @valid private Department Department;Copy the code
} class Department{
@notnull (message = "id cannot be null ") Long id;Copy the code
}
1. Add @VALID of JSR303 to the front of the class object for nested verification
2. IllegalStateException will be thrown if the nested check does not meet the criteria
Packet check
1. Firstly, attach the group value (usually the class object of the interface) to the group annotation of the verification annotation. Secondly, specify the verification group during the verification, that is, specify @Validated (add.class).
Note: Interface Add These interfaces are used only as tokens that can be extracted and reused.
These interfaces can all be based on Default
After inheriting Default, unless specified, as long as the annotation such as @notnull is added, the Default is the Group, but after the specified Group is displayed, the specified Group will be verified.
Use Default is not recommended. Understand confusion
Check the List
@ Does not support this kind of verification. You can refer to the @VALID nested verification method and regard it as a special nested verification. You can create List objects inside the package layer. Implementing the List interface
In actual development, you can create a special package to hold Spring Validated classes
Public Final Class SpringValidatorUtils {Public final class SpringValidatorUtils {public final class SpringValidatorUtils {public final class SpringValidatorUtils {
private SpringValidatorUtils(){}
public static final Validator VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator();
public static final <T> void valid(T param,Class<?> ... groupClass){
Set<ConstraintViolation<T>> validateSet = VALIDATOR.validate(param, groupClass);
if (CollectionUtils.isEmpty(validateSet)){
return;
}
String errorMsg = validateSet.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining("&"));
throw new ValidationException(errorMsg);
}
Copy the code
}
So the code is pretty simple, and it actually does the same thing at sign, Validated. @ Validated through annotations let Spring using the Validator to help us to check, exception thrown by the Spring (various), and the utility class is our Validator borrowed from Spring check, the exception thrown can custom exception for himself.
More flexible Spring ValidatorUtils encapsulation
It is up to the caller to throw an exception or return an error message. public final class SpringValidatorAndReturnUtils {
private SpringValidatorAndReturnUtils(){} public static final Validator VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator(); Public static final <T> String validReq(T); public static final <T> String validReq(T) Param,Boolean isThrow){if (param == null){return exceptionHandle(" Check object cannot be empty ",isThrow); } Set<ConstraintViolation<T>> validateSet = VALIDATOR.validate(param); ConstraintViolation<T> first = Iterables.getFirst(validateSet, null); if (CollectionUtils.isEmpty(validateSet)){ return ""; } String errorMsg = validateSet.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining("&")); return exceptionHandle(errorMsg,isThrow); } private static String exceptionHandle(String message, Boolean isThrow) { if (isThrow){ throw new ValidationException(message); } return message; }Copy the code
}
Why does Spring encapsulate a utility class when @Validated is so convenient?
If you want to do validation at the Service layer, it’s easier to use SpringValidatorUtils, which has interfaces and implementation classes; Of course, services can also be annotated.
While utility classes can write whatever Validation they want without worrying about miscellaneous grouping, Spring Validation is more about grouping.