Problem description
Standard interface development is always inseparable from parameter verification. Naturally, Spring has prepared corresponding templates for us. Parameters can be checked and verified by using @ NotEmpty, @ NotBlank, @ NotNull and other annotations, but these annotations must be used with @ Valid to take effect. For details, please refer to: @Valid introduction and related notes - Jianshu (jianshu.com).
There are restrictions on the use of @ Valid, that is, the Validation of spring MVC only takes effect in the Controller. From the perspective of the whole interface ecology, this is a reasonable design, and the data verification does not pass, nor will it reach the business layer.
But what if we need to verify the data in the business layer? And the condition is not only non empty, but also includes some special format or scope requirements. It can be solved naturally by using simple if else, but the code is also complex and redundant.
terms of settlement
The parameter verification provided by spring cannot meet our needs, so write your own annotations to meet your needs.
Requirements: the parameter verification can be realized by adding annotation to the attribute, including non empty and specified regular verification, and the user-defined error information can be returned at the same time
User defined parameter verification annotation
Parameter verification class annotation: @ Validation
import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; /** * Parameter verification annotation * Perform non null and regular verification on the annotated attribute * * @author wyhao * @date 2021/5/18 **/ @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Validation { //error message String message() default "Parameter cannot be empty"; //regular expression String pattern() default ""; }
@Validation validator
package com.example.springtrain.caculate.processor.serviceUtils; import lombok.extern.slf4j.Slf4j; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Validation Validator * Verify the parameters with custom annotation @ Validation * * @author wyhao * @date 2021/5/19 **/ @Slf4j public class ValidationCheck { /** * Verification method * Scan the attributes in the object to see if there is @ Validation annotation, and verify if there is annotation * * @param o The object to be verified, such as the input parameter object */ public static void check(Object o) { if (null == o) { return; } Class clazz = o.getClass(); List<Field> fieldList = new ArrayList<Field>(); while (clazz != null) { fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()))); clazz = clazz.getSuperclass(); } //All properties of the variable object fieldList.forEach(field -> { field.setAccessible(true); try { Object value = field.get(o); //Get property value Validation annotation = field.getAnnotation(Validation.class); if (null == annotation) { //Those not annotated will not be processed return; } checkNotNull(value, annotation); checkPattern(value, annotation); } catch (IllegalArgumentException | IllegalAccessException e) { log.info("Validation Validator data parsing failed:{}", e.getMessage()); } }); } /** * Non null judgment * * @param value Attribute value * @param validation Annotation information */ private static void checkNotNull(Object value, Validation validation) { //log.info("start check is not empty"); if (validation != null && value == null) { throw new RuntimeException(validation.message()); } } /** * Regular check * * @param value Attribute value * @param validation Annotation information */ private static void checkPattern(Object value, Validation validation) { if (null != validation.pattern() && validation.pattern().length() > 0) {//Existence regularity //Compile and assign the regular expression given in validation to the Pattern class Pattern p = Pattern.compile(validation.pattern()); //Match the value in value with the rule of p Matcher m = p.matcher(value.toString()); if (!m.matches()) { //If the attribute value does not conform to the format specified by the regular, an exception is thrown throw new RuntimeException(validation.message()); } } } }
Annotation use
Add verification rules to the class attributes to be verified:
@Data public class Father { @Validation(message = "Name cannot be blank") //Non null check private String name; @Validation(pattern = "\\d+",message = "Age can only be a number") //Regular check, of course, the premise is also non empty private String age; public Father(String name, String age) { this.name = name; this.age = age; } public Father() { } }
First of all, our annotations must not affect the normal use. Here are the data that meet the requirements, and the code runs normally
Father father1 = new Father("Laodie","56"); ValidationCheck.check(father1); //Perform parameter verification System.out.println(father1);
When name is empty, the following code will directly throw an exception and prompt that the name cannot be empty
Father father2 = new Father(null,"56"); ValidationCheck.check(father2); //Perform parameter verification System.out.println(father2);
When the age does not meet the requirement that it must be a number, it will throw an exception and prompt that the age can only be a number
Father father3 = new Father(null,"a56"); ValidationCheck.check(father3); System.out.println(father3);
If we have other business needs, we can add corresponding attributes in the annotation and add custom rules in the verifier, which has certain expansibility.
Continuous optimization
You also need to use validationcheck every time you use it Code such as check (father1) may be troublesome, because the author is lazy because he doesn't need many parameter verification places. In fact, we can write another annotation and use it in the code or directly on the class, like this:
//Add to the code @ValidationCheck //Perform parameter verification Father father2 = new Father(null,"56"); //Or add class @ValidationCheck public class ValidationTest { @Test public void test() { Father father1 = new Father("Laodie","56"); System.out.println(father1); Father father2 = new Father(null,"56"); System.out.println(father2); Father father3 = new Father(null,"a56"); System.out.println(father3); } }