Directory
Quote:
final effect:
Implementation steps
Customize two annotations
Define a regular enumeration class
Define the aspect class (important!)
Validation class:
Quotation:
This technical solution can be used for many verification types of businesses (login status, permissions…), here we start with the parameter verification business (the specific implementation is relatively simple, it is important to understand the realization of the technical solution) , I hope that everyone can appreciate the benefits of AOP + custom annotations, and further understand the usage patterns of AOP and custom annotations, not only limited to theoretical concepts, but also to implement knowledge into practice. Every step of the code is well-composed with comments, I believe everyone can understand every step.
Final effect:
It is said that this kind of plan is good, but what does it look like? Let’s take a look at the final implementation scenario
Through two annotations, you can customize the verification rules for different parameters, which is convenient and quick, once and for all, and the coupling degree of this scheme is very low, which conforms to the principle of opening and closing. The new verification scheme does not need to change the original Code
Steps to Implementation
Customize two annotations
/** * @author global parameter validator */ @Retention(RetentionPolicy. RUNTIME) @Target({ElementType.PARAMETER, ElementType.FIELD}) public @interface VerifyParam { int min() default -1; int max() default -1; boolean required() default false; // Define regular check, no check by default VerifyRegexEnum regex() default VerifyRegexEnum.NO; }
/** * @author wzx */ @Target({ElementType. METHOD}) @Retention(RetentionPolicy. RUNTIME) @Documented @Mapping public @interface GlobalInterceptor { /** * Check parameter * @return */ boolean checkParams() default false; }
@GlobalInterceptor: It acts as a tangent locator, and uses this annotation as the entry point of the verification logic
@VerifyParam: Determine the custom verification type and pass a certain range of data for the customization of the verification process
Define regular enumeration class
Customize a regular enumeration to meet the parameter selection of @VerifyParem. In this class, you can set a series of verification type rules. Selecting different verification rules can play a corresponding verification process
/** * @author wzx * Define regular enumeration */ public enum VerifyRegexEnum { NO("", "No validation"), EMAIL("^[a-zA-Z0-9] + ([-_.][a-zA-Z0-9] + )*@[qQ][qQ]\.com$", "Mailbox"), PASSWORD("^[a-zA-Z0-9!@#$%^ & amp;*()_ + \-=\[\]{};':\\ "\\|,.<>\/?]{8,18}$", "It can only be numbers, letters, special characters 8-18"); private String regex; private String desc; VerifyRegexEnum(String regex, String desc) { this.regex = regex; this.desc = desc; } public String getRegex(){return regex;} public String getDesc(){return desc; } }
Define the aspect class (emphasis!)
In this class, it is mainly used to perform specific verification logic operations, and the overall process can be divided into
- First lock the point of cut by scanning custom annotations
- Cutting into the cutting plane.
- Lock to the method through the annotation, and get the parameter list, annotation, method name and other data of the method through reflection
- According to the obtained @GlobalInterceptor object, obtain its internal checkParams data value to determine whether to perform verification
- If the verification is performed, the parameter list and other data of the method will be sent to the verification module for verification
- Loop through the actual parameter list and find the parameter containing @VerifyParam
- Branch judgment is performed on this parameter, and two verification schemes are divided according to whether the parameter is a basic data type or a reference data type
- For the basic data type checks around 1. Whether it is empty 2. Whether the length is appropriate 3. Whether it meets the regular expression of your choice
- For reference data type verification, the above verification logic is mainly performed through violent reflection
/** * @author wzx * Global parameter validation aspect */ @Aspect @Component public class GlobalOperationAspect { // It is used to judge whether the parameter to be verified is of these basic types, if not, the parameter is regarded as an object for verification private static final String[] TYPE_BASE = {"java. lang. String", "java. lang. Integer", "java. lang. Long"}; // Define a pointcut. Here, the custom annotation is used as a cut point. In fact, the purpose of this step is to let us lock the position to be woven into the cut surface @Pointcut("@annotation(com.example.bfwp.annotation.GloballInterceptor)") private void requestInterceptor(){ } @Before("requestInterceptor()") public void interceptorDo(JoinPoint point){ try { // Obtain all the objects marked by the annotation through reflection // Get the target object where the pointcut is located Object target = point. getTarget() ; // Get the parameter list of the method where the pointcut is located Object[] arguments = point. getArgs(); // Get the method name of the method where the pointcut is located String methodName = point. getSignature(). getName(); // Get the type of the parameter list of the method where the pointcut is located Class<?>[] parameterTypes = ((MethodSignature) point. getSignature()). getMethod(). getParameterTypes(); // Obtain the method object through method name + type of parameter list + reflection Method method = target.getClass().getMethod(methodName, parameterTypes); // Get the global interceptor (that is, the custom annotation) - this step is mainly to obtain the attribute data of the custom annotation GlobalInterceptor interceptor = method. getAnnotation(Global Interceptor. class); // Obtain the attribute data of custom annotations for logical operations // Whether to verify the parameters if (interceptor. checkParams()){ // Throw in the parameters for validation validateParams(method, arguments); } } catch (Exception e) { throw new RuntimeException(e); } } /** * Check parameter * @param method check method * @param arguments check method object */ private void validateParams(Method method, Object[] arguments) { // Get the formal parameter group of the validation method Parameter[] parameters = method. getParameters(); for (int i = 0; i < parameters. length; i ++ ) { // Get a specific formal parameter object Parameter parameter = parameters[i]; // Get a specific actual parameter object Object value = arguments[i]; // Find the parameters containing @VerfyParam, that is to say, find the parameters to be verified VerifyParam verifyParam = parameter. getAnnotation(VerifyParam. class); if (verifyParam == null){ // If it is empty, it means that the parameter has not been added with the custom annotation, and no verification is required continue; } // If it is not empty, it means that the custom annotation has been added to the parameter and needs to be verified /* There are two cases for parameter verification 1. Basic data types (and their wrappers) 2. Reference data type * */ if (ArrayUtils.contains(TYPE_BASE,parameter.getParameterizedType().getTypeName())){ // Included means that the parameter is a basic data type checkValue(value, verifyParam); } else { // If it does not contain, it means that the parameter is a reference data type checkObjectValue(parameter, value); } } } /** * Reference data type validation * @param parameter The formal parameter object of the verification object * @param object the object to check */ private void checkObjectValue(Parameter parameter, Object object){ try { // Get parameter type String typeName = parameter.getParameterizedType() .getTypeName(); // Get the bytecode file of the object's class Class<?> classz = Class. forName(typeName); // Get all attribute objects in this class Field[] fields = classz. getDeclaredFields(); for (Field field : fields){ // See if the property has a validation annotation set VerifyParam fieldVerifyParam = field. getAnnotation(VerifyParam. class); if (fieldVerifyParam == null){ // Attributes that do not need to be checked are skipped continue; } // Attributes that need to be verified, first skip violent reflection to ensure that you can get their values, because general attributes are modified as private field.setAccessible(true); // get attribute value Object resultValue = field. get(object); checkValue(resultValue, fieldVerifyParam); } } catch (ClassNotFoundException e) { //todo throw new RuntimeException(e); } catch (IllegalAccessException e) { //todo throw new RuntimeException(e); } } /** * Validation logic of basic data types (and their packaging classes) * @param value specific data value (actual parameter object) * @param verifyParam Annotation object annotating this parameter (used to obtain its attribute data) */ private void checkValue(Object value, VerifyParam verifyParam) { // First, see if he really wants to check if he added the annotation if (!verifyParam.required()) {return;} Boolean isEmpty = value == null || "".equals(value.toString()); Integer length = value == null ? 0 : value .toString () .length(); /** * check if empty */ if (isEmpty) { // TODO is empty throw new RuntimeException("The passed value cannot be empty"); } /** * check length */ if ((verifyParam.max() != -1 & amp; & amp; verifyParam.max() < length || verifyParam.min() != -1 & amp; & amp; verifyParam.min() > length) ) { // TODO length is wrong throw new RuntimeException("The length of the passed value is incorrect"); } /** * Validation regularity */ if (!VerifyRegexEnum.NO.equals(verifyParam.regex()) & amp; & amp; !VerifyUtils.verify(verifyParam.regex(), String.valueOf(value))){ // TODO regex check is incorrect throw new RuntimeException("regular check is incorrect"); } } }
Validation class:
/** * @author wzx */ public class VerifyUtils { /** * The eligibility of regular check parameters * @param regs regular expression * @param value the value to validate * @return check result */ public static Boolean verify(String regs, String value){ Pattern pattern = Pattern.compile(regs); Matcher matcher = pattern. matcher(value); return matcher. matches(); } public static Boolean verify(VerifyRegexEnum verifyRegexEnum, String value){ return verify(verifyRegexEnum.getRegex(), value); } }