spring boot + Custom AOP Example Code for Global Verification

  • 2021-07-18 07:55:19
  • OfStack

Recently, the company reconstructed the project into the hottest micro-service framework spring boot. During the reconfiguration, it encountered several problems that can be handled by Uniform 1, which are often encountered in the project, such as: Uniform 1 check parameters and Uniform 1 catch exceptions. . .

It is sometimes redundant to control the verification of parameters only by code, but it is very friendly for developers to control the verification of parameters supported by the framework. Look at the following examples first


 @NotEmpty(message=" Mobile phone number cannot be empty ")
   @Size(min=11,max=11,message=" The length of mobile phone number is incorrect ")
   @Pattern(regexp=StringUtils.REGEXP_MOBILE,message=" The mobile phone number format is incorrect ")
  private String mobile;

This is the validation annotation supported by spring boot, and then we can achieve the purpose of validation by adding @ Valid annotation in contoller layer. This is a frame that comes with it

This chapter will show a custom AOP verification, first write a note, the note can be written in the rules we need to check, such as length, regularity. . .


@Documented
@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidateParam {
  int min() default 0;
  int max() default Integer.MAX_VALUE;
  String message() default "params is not null";
  String regexp();
  Class<?>[] groups() default { };
   Class<? extends Payload>[] payload() default { };
   boolean isNotNull() default true;
}

Then define an AOP class


package com.onecard.primecard.common.aop;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Pattern;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import com.jfcf.core.dto.ResultData;
import com.onecard.core.support.util.StringUtils;
import com.onecard.primecard.common.annotation.ValidateParam;
import com.onecard.primecard.common.utils.ResultDataUtil;
/**
 *  Global   Section class ( Check parameter )
 * 
 * @author Administrator
 *
 */
@Aspect
@Component
public class GobalHandlerAspect {
  private static Logger logger = LoggerFactory.getLogger(GobalHandlerAspect.class);
  @Pointcut("execution(*  Package name .controller..*.*(..)) && execution(*  Package name .controller..*.*(..))")
  public void checkAspect(){};
  @Before("checkAspect()")
  public void befor(JoinPoint joinPoint) throws Exception{
    // Pre-system 1 Output parameter 
    Object[] args = joinPoint.getArgs();
    if(args != null && args.length>0){
      Object obj = args[0];
      ParameterizedType pt = (ParameterizedType)obj.getClass().getGenericSuperclass();
      Class<?> classzz = (Class<?>) pt.getActualTypeArguments()[0];
      logger.info(" "Small X Card " - "Request Entity Entry": "+classzz.newInstance().toString());
    }
  }
  @Around("checkAspect()")
  public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
    // Check parameter 
    Object[] args = joinPoint.getArgs();
    Object obj = null;
    if(args != null && args.length > 0){
      obj = args[0];
      Class classzz = obj.getClass();
      // Arrays without order and order 
      Field[] fieldArray = classzz.getDeclaredFields();
      ArrayList<Field> fieldList = new ArrayList<Field>(Arrays.asList(fieldArray));
      String res = checkParam(fieldList,obj);
      if(StringUtils.isNotNull(res)){
        return ResultDataUtil.result(ResultData.STATUS_PARAM_ERROR, res);
      }
    }
    return joinPoint.proceed();
  }
  private String checkParam(ArrayList<Field> fieldList, Object obj) throws Exception {
    for(Field field : fieldList){
      ValidateParam validateParam = field.getAnnotation(ValidateParam.class);
      logger.info(" "Small X Card "gets the annotation value: "+validateParam.isNotNull()+"min="+validateParam.min()+"max="+validateParam.max());
      Method method = obj.getClass().getMethod("get"+getMethodName(field.getName()));
      logger.info(" "Small X Entity method name of card entry: "+method.getName());
      if(method != null){
        Object val = method.invoke(obj);
        logger.info(" "Small x Card callback method: "+val);
        if(validateParam != null && validateParam.isNotNull() == true){
          if(null == val || "".equals(val) ){
            return field.getName()+" Required parameter is blank ";
          }
        }
        if(validateParam.min()==11 && validateParam.max() == 11){
          if(val.toString().length() != 11){
            return field.getName()+" Please enter the correct length of the parameter ";
          }
        }
        if(validateParam.regexp().equals(StringUtils.REGEXP_MOBILE)){
          if(!Pattern.matches(StringUtils.REGEXP_MOBILE, val.toString())){
            return field.getName()+" Wrong parameter format ";
          }
        }
      }
    }
    return null;
  }
   /**
   *  Method initials capitalize 
   * @param fieldName
   * @return
   */
  private String getMethodName(String fieldName) {
    StringBuffer buffer = new StringBuffer();
    String firstLetter = fieldName.substring(0, 1).toUpperCase();
    return buffer.append(firstLetter).append(fieldName.substring(1, fieldName.length())).toString();
  }    
 }

Define a tangent point @ Pointcut, use execution expression to get a class and a method to be verified, that is, a connection point, and then define a notification. There are 2 notifications in the above code, 1 pre-notification @ Before, and 1 surround notification @ Around. We use the most powerful surround notification.

Through the above code, we can see that the parameters are obtained first, and then all the fields in the parameter object are obtained through the reflection mechanism, and then the fields that we add our custom annotations to the fields are obtained. Through the callback of the reflection method, the field values are obtained, the values are judged, and the verification results are returned.

Summarize

The above is the site to introduce you spring boot + custom AOP to achieve global verification of the example code, I hope to help you, if you have any questions welcome to leave me a message, this site will reply to you in time!


Related articles: