springMVC custom annotations using AOP to implement logging methods

  • 2021-01-02 21:50:54
  • OfStack

Demand background

In a recent project, at the completion stage of the project, the customer proposed to log all business operations into the database and extract some key business information (such as transaction order number) to reflect in the log.

In order to ensure the duration, after consulting the materials, it was decided to use AOP+ custom annotations to complete the requirement.

The preparatory work

The jar packages on which custom annotations are required are ES11en-ES12en. jar, ES14en-ES15en. jar, XXX for version number.

Custom annotations

A separate log package was created under the project to hold the log-related content


**.common.log.annotation // Custom annotation storage location 
**.common.log.aop     //aop Where the utility classes are stored 

Create a new custom annotation class under the annotation package:


package **.common.log.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface XXXOperateLog {
  /**
   *  Operation type description 
   * @return
   */
  String operateTypeDesc() default "";
  /**
   *  Operation type 
   * @return
   */
  long operateType() default -1;
  /**
   *  Module coding 
   * @return
   */
  String moudleCode() default "M30";
  /**
   *  The name of the module 
   * @return
   */
  String moudleName() default "XX The module ";
  /**
   *  Business types 
   * @return
   */
  String bussType() default "";
  /**
   *  Description of business type 
   * @return
   */
  String bussTypeDesc() default "";
}

Create new XXXOperateLogAop under the aop package


package **.common.log.aop;
import ** ;// omit 
@Aspect
@Component
public class XXXOperateLogAop{
  @Autowired
  SystemLogService systemLogService;
   HttpServletRequest request = null;
   Logger logger = LoggerFactory.getLogger(XXXOperateLogAop.class);
  ThreadLocal<Long> time = new ThreadLocal<Long>();
  // Unique for generating action logs 1 Identity for business process audit log invocation 
  public static ThreadLocal<String> tag = new ThreadLocal<String>();
  // The statement AOP Pointcuts, usually used XXXOperateLog All methods are intercepted 
  @Pointcut("@annotation(**.common.log.annotation.XXXOperateLog)")
  public void log() {
    System.out.println(" I am a 1 A starting point ");
  }
  /**
   *  In all labels @Log Place cut 
   * @param joinPoint
   */
  @Before("log()")
  public void beforeExec(JoinPoint joinPoint) {
    time.set(System.currentTimeMillis());  
    info(joinPoint);
    // Set the only for logging 1 Id no. 
    tag.set(UUID.randomUUID().toString());
    request= ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  }
  @After("log()")
  public void afterExec(JoinPoint joinPoint) {
    MethodSignature ms = (MethodSignature) joinPoint.getSignature();
    Method method = ms.getMethod();
    logger.debug(" Marked as " + tag.get() + " The method of " + method.getName()
        + " Run the consumption " + (System.currentTimeMillis() - time.get()) + "ms");  
  }
  // This method is executed during the execution of the target method, where logging can be implemented 
  @Around("log()")
  public Object aroundExec(ProceedingJoinPoint pjp) throws Throwable {
    Object ret = pjp.proceed();
    try {
      Object[] orgs = pjp.getArgs();
      SystemLog valueReturn = null;
      for (int i = 0; i < orgs.length; i++) {
        if(orgs[i] instanceof SystemLog){
          valueReturn = (SystemLog) orgs[i];
        }  
      }  
      if(valueReturn==null){
        valueReturn = new SystemLog();
      }
      if(valueReturn!=null&&request!=null){
        MethodSignature ms = (MethodSignature) pjp.getSignature();
        Method method = ms.getMethod();
        // Gets the operation log information for the annotation 
        XXXOperateLog log = method.getAnnotation(XXXOperateLog.class);
        String businessType = log.bussType();
        String businessDesc = log.bussTypeDesc();
        HashMap requestMap = ServletUtils.getParametersToHashMap(request) ;
        // Look for the business type in the parameter 
        if(businessType.equals(""))
        {
          Object objBusinessType = requestMap.get("business_type");
          businessType = objBusinessType == null ? "" : objBusinessType.toString();
        }
        // Find the business type from the request form for the execution result 
        Object apply = request.getAttribute("apply") ;
        if(apply != null){
          JSONObject obj = JSONFactory.toJSONAbstractEntity(apply);
          if(obj != null)
          {
            valueReturn.setOtherDesc(" Application no. :"+obj.getString("apply_no"));
            if(businessType.equals(""))
            {
              businessType = obj.getString("business_type");
            }
          }
        }
        // Find the business type from the method's execution process parameters (1 Usually it is set manually )
        if(businessType.equals(""))
        {
          businessType = (String) request.getAttribute("business_type");
          businessType = businessType == null ? "" : businessType;
        }
        if(!businessType.equals("") && businessDesc.equals(""))
        {
          businessDesc = XXXSysConstant.BUSINESS_TYPE.getName(businessType);
        }
        valueReturn.setBussType(XXXSysConstant.BUSINESS_TYPE.getNumber(businessType));
        valueReturn.setBussTypeDesc(businessDesc);
        valueReturn.setMoudleCode(log.moudleCode());
        valueReturn.setMoudleName(log.moudleName());
        valueReturn.setOperateResult(XXXSysConstant.YesOrNo.YES);
        valueReturn.setOperateType(log.operateType());
        valueReturn.setInputUserId(((UserContext)WebUtils.getSessionAttribute(request, "XXXuserContext")).getSysUser().getId());
        valueReturn.setOperateTypeDesc(log.operateTypeDesc());
        valueReturn.setRequestIp(getRemoteHost(request));
        valueReturn.setRequestUrl(request.getRequestURI());
        valueReturn.setServerIp(request.getLocalAddr());
        valueReturn.setUids(tag.get());
        // Save operation log 
        systemLogService.saveSystemLog(valueReturn);
      }else{
        logger.info(" Do not log information ");
      }
      // Save operation result   
    } catch (Exception e) {
      e.printStackTrace();
    }
    return ret;
  }
  // Log exception 
  @AfterThrowing(pointcut = "log()",throwing="e")
  public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
    try {
      info(joinPoint);
      Object[] orgs = joinPoint.getArgs();
      SystemLog valueReturn = null;
      for (int i = 0; i < orgs.length; i++) {
        if(orgs[i] instanceof SystemLog){
          valueReturn = (SystemLog) orgs[i];
        }      
      }
      if(valueReturn==null){
        valueReturn = new SystemLog();
      }
      if(valueReturn!=null&&request!=null){
        MethodSignature ms = (MethodSignature) joinPoint.getSignature();
        Method method = ms.getMethod();
        XXXOperateLog log = method.getAnnotation(XXXOperateLog.class);
        String businessType = log.bussType();
        String businessDesc = log.bussTypeDesc();
        if(businessType.equals(""))
        {
          Object objBusinessType = ServletUtils.getParametersToHashMap(request).get("business_type");
          businessType = objBusinessType == null ? "" : objBusinessType.toString();
          businessDesc = XXXSysConstant.BUSINESS_TYPE.getName(businessType);
        }
        valueReturn.setBussType(XXXSysConstant.BUSINESS_TYPE.getNumber(businessType));
        valueReturn.setBussTypeDesc(businessDesc);
        valueReturn.setMoudleCode(log.moudleCode());
        valueReturn.setMoudleName(log.moudleName());
        valueReturn.setOperateType(log.operateType());
        valueReturn.setOperateTypeDesc(log.operateTypeDesc());
        valueReturn.setInputUserId(((UserContext)WebUtils.getSessionAttribute(request, "XXXuserContext")).getSysUser().getId());
        valueReturn.setOperateResult(XXXSysConstant.YesOrNo.NO);
        String errMes = e.getMessage();
        if(errMes!=null && errMes.length()>800){
          errMes = errMes.substring(0, 800);
        }
        valueReturn.setErrorMessage(errMes);
        valueReturn.setRequestIp(getRemoteHost(request));
        valueReturn.setRequestUrl(request.getRequestURI());
        valueReturn.setServerIp(request.getLocalAddr());
        valueReturn.setUids(tag.get());
        systemLogService.saveSystemLog(valueReturn);
      }else{
        logger.info(" Do not log information ");
      }
    } catch (Exception e1) {
      e1.printStackTrace();
    }
  }
  private void info(JoinPoint joinPoint) {
    logger.debug("--------------------------------------------------");
    logger.debug("King:\t" + joinPoint.getKind());
    logger.debug("Target:\t" + joinPoint.getTarget().toString());
    Object[] os = joinPoint.getArgs();
    logger.debug("Args:");
    for (int i = 0; i < os.length; i++) {
      logger.debug("\t==> parameter [" + i + "]:\t" + os[i].toString());
    }
    logger.debug("Signature:\t" + joinPoint.getSignature());
    logger.debug("SourceLocation:\t" + joinPoint.getSourceLocation());
    logger.debug("StaticPart:\t" + joinPoint.getStaticPart());
    logger.debug("--------------------------------------------------");
  }
  /**
   *  Get the remote client Ip
   * @param request
   * @return
   */
  private String getRemoteHost(javax.servlet.http.HttpServletRequest request){
    String ip = request.getHeader("x-forwarded-for");
    if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
      ip = request.getHeader("Proxy-Client-IP");
    }
    if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
      ip = request.getHeader("WL-Proxy-Client-IP");
    }
    if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
      ip = request.getRemoteAddr();
    }
    return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip;
  }  
}

Modify the configuration file ES35en-ES36en. xml to add the following configuration


  <!--  open AOP intercept  -->
  <aop:aspectj-autoproxy proxy-target-class="true" /> 
  <mvc:annotation-driven />
  <!--  define Spring describe Bean The scope of the  -->
  <context:component-scan base-package="**.common.log" >
     <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
  </context:component-scan>

It is important to note that the above configuration must be placed in the same xml file, either spring-ES43en.xml or ES45en-ES46en.xml, otherwise it may not take effect. It is not yet known why.

Use of annotations


@XXXOperateLog(
      bussType=XXXSysConstant.BUSINESS_TYPE.YYYY
      ,bussTypeDesc=" Description of business type "
      ,operateType = XXXSysConstant.LogOperateType.QUERY
      ,operateTypeDesc = " Operation description "
  )
  @RequestMapping(value = "/**/**/queryXXXXX4DataGrid.json", method = RequestMethod.POST)
  public void queryXXXXX4DataGrid(HttpServletRequest request, HttpServletResponse arg1, Model model, Writer writer)
  {
    logger.info("========== Recount the query ( outbound ) Trading information   start =====================");
    try {
      //do something for business
    } catch (SystemException se) {
      throw se;
    } catch (BusinessException be) {
      throw be;
    } catch (Exception e) {
      throw new SystemException(e);
    }
  }

Related articles: