Springboot uses custom annotations to implement log monitoring

First, you need to define an annotation interface, which is the annotation name of our custom annotation, and also define the internal parameters inside

package com.common.log.vo;
import java.lang.annotation.*;

@Target({<!-- -->ElementType. METHOD})
@Retention(RetentionPolicy. RUNTIME)
@Documented
public @interface OperationLog {<!-- -->


    /**
     * module
     *
     */
    String moduleName() default "";


   
    String sheetType() default "";


   
    String operationDesc() default "";


  
    String sourceNoField() default "";


    /**
     * Document code field name
     *
     */
    String businessKeyField();
}

In SpringBoot, there are four meta-annotations, which are called annotation annotations. We will use them when customizing annotations. Here is a brief introduction to them:

@Target: This annotation specifies the scope of our custom annotations. There is an attribute called ElementType, which has many values:

@Target(ElementType.TYPE) interface, class
@Target(ElementType.FIELD) attribute
@Target(ElementType.METHOD) method
@Target(ElementType.PARAMETER) method parameter parameter
@Target(ElementType.CONSTRUCTOR) constructor constructor
@Target(ElementType.LOCAL_VARIABLE) local variable
@Target(ElementType.ANNOTATION_TYPE) annotation
@Target(ElementType.PACKAGE) package

@Retention: There are three types of retention strategies for defining annotations:

@Retention(RetentionPolicy.SOURCE) //Annotations only exist in the source code, not in the class bytecode file
@Retention(RetentionPolicy.CLASS) //The default retention policy, the annotation will exist in the class bytecode file, but it cannot be obtained at runtime,
@Retention(RetentionPolicy.RUNTIME) //The annotation will exist in the class bytecode file and can be obtained through reflection at runtime

@Documented: Specifies that the modified Annotation can be extracted into a document by the javadoc tool.
@Inherited: This annotation is a marker annotation, indicating that the annotated type can be inherited.

Two write aspect logic

Realize the capture and processing of method output results in the logic, and persist them. We know that the output result of a method is nothing more than two kinds, one is that the method is executed successfully, and the correct result is output; the other is that the method fails to execute, and an error is reported halfway. For these two different execution results, different logics are required for processing.

package com.cpit.ycyt.psc.common.logaspect;

import com.cpit.ycyt.common.core.util.JsonUtil;
import com.cpit.ycyt.common.security.util.SecurityUtil;
import com.cpit.ycyt.psc.common.domain.PscLog;
import com.cpit.ycyt.psc.common.logaspect.vo.OperationLog;
import com.cpit.ycyt.psc.common.mapper.PscLogCommonMapper;
import com.cpit.ycyt.upms.api.domain.UserDetail;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


@Component
@Aspect
@Slf4j
public class OperationLogAspect {<!-- -->
    @Autowired
    SecurityUtil securityUtil;
    @Autowired
    PscLogCommonMapper pscLogCommonMapper;

    @Pointcut(value = "@annotation(com.cpit.ycyt.psc.common.logaspect.vo.OperationLog)")
    public void beanAnnotatedWithController() {<!-- -->
    }

    @Pointcut(value = "@annotation(operationLog)", argNames = "operationLog")
    private void operationLogMethod(OperationLog operationLog) {<!-- -->
    }

    /**
     * Admin comment interception operation log
     *
     * @param joinPoint cut point
     * @param operationLog custom annotation
     * @return Object
     * @throws Throwable
     */
       @Around(value = "beanAnnotatedWithController() & amp; & amp; @annotation(operationLog)", argNames = "joinPoint, operationLog")
    public Object around(ProceedingJoinPoint joinPoint, OperationLog operationLog) throws Throwable {<!-- -->
        long startTime = System. currentTimeMillis();
        final Object retVal = joinPoint. proceed();
        long endTime = System. currentTimeMillis();

        String moduleName = operationLog. moduleName();
        String sheetType = operationLog. sheetType();
        String operationDesc = operationLog. operationDesc();
        String businessKeyField = operationLog. businessKeyField();
        String sourceNoField = operationLog. sourceNoField();

 
        Map<String, Object> nameAndArgs = joinArgs(joinPoint);
        // process operator information
        UserDetail user = getUser();

        String reqMsg = JsonUtil.toJSONString(nameAndArgs);
        PscLog model = new PscLog();
        model.setModuleName(moduleName).setSheetType(sheetType).setRequestTime(startTime).setOperationDesc(operationDesc).setSourceNo(sourceNo).setSheetNo(sheetNo)
                .setReqMsg(reqMsg).setErrorMsg(JsonUtil.toJSONString(retVal)).setOperator(user.getUserCode() + "_" + user.getUserName())
                .setOperatingTime((endTime - startTime) / 1000).setCreateTime(new Date());

        pscLogCommonMapper.insert(model);
        return retVal;
    }

    /**
     * Admin comment interception operation exception log
     *
     * @param joinPoint cut point
     * @param operationLog custom annotation
     * @return
     * @throws Throwable
     */
    @AfterThrowing(value = "beanAnnotatedWithController() & amp; & amp; operationLogMethod(operationLog)", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, OperationLog operationLog, Exception ex) {<!-- -->
        long startTime = System. currentTimeMillis();

        String moduleName = operationLog. moduleName();
        String sheetType = operationLog. sheetType();
        String operationDesc = operationLog. operationDesc();
        String businessKeyField = operationLog. businessKeyField();
        String sourceNoField = operationLog. sourceNoField();

       
        // process operator information
        UserDetail user = getUser();
        String reqMsg = JsonUtil.toJSONString(nameAndArgs);

        PscLog model = new PscLog();
        model.setModuleName(moduleName).setSheetType(sheetType).setRequestTime(startTime).setOperationDesc(operationDesc).setSourceNo(sourceNo)
                .setSheetNo(sheetNo).setReqMsg(reqMsg).setErrorMsg(ex.toString() + "," + JsonUtil.toJSONString(ex.getStackTrace()).substring(0, 500))
                .setOperator(user.getUserCode() + "_" + user.getUserName()).setOperatingTime(0L).setCreateTime(new Date());

        pscLogCommonMapper.insert(model);
    }

    /**
     * Get login user information
     *
     * @return
     */
    private UserDetail getUser() {<!-- -->
        try {<!-- -->
            UserDetail user = securityUtil. getUser();
            if (Objects.isNull(user)) {<!-- -->
                user = new UserDetail();
                user.setUserCode("auto");
                user.setUserName("auto");
            }
            return user;
        } catch (NullPointerException e) {<!-- -->
            // Interface calls without TOKEN will report a null pointer exception and will not log
            UserDetail user = new UserDetail();
            user.setUserCode("error");
            user.setUserName("error");
            return user;
        } catch (Exception e) {<!-- -->
            log.error("=======log record aspect - getting user information is abnormal. Exception information: {}=======", e.getMessage());
            UserDetail user = new UserDetail();
            user.setUserCode("error");
            user.setUserName("error");
            return user;
        }

    }


    /**
     * Combination method parameter is Map
     *
     * @param joinPoint
     * @return
     */
    public static Map<String, Object> joinArgs(JoinPoint joinPoint) {<!-- -->
        Map<String, Object> map = new HashMap<>();
        Object[] objects = joinPoint. getArgs();
        MethodSignature methodSignature = (MethodSignature) joinPoint. getSignature();
        String[] names = methodSignature. getParameterNames();
        for (int i = 0; i < names. length; i ++ ) {<!-- -->
            map. put(names[i], objects[i]);
        }
        return map;
    }
}

Finally, you can successfully use it by adding annotations on the calling interface

 @OperationLog(moduleName = "web", sheetType = "", operationDesc = "manually generated", businessKeyField = "sheetNo")
    public HttpResult getUserInfo(@RequestParam("sheetNo") String sheetNo, @RequestParam("sheetType") String sheetType) {<!-- -->```