1. 创建自定义注解接口
package com.example.lambda.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author: WZ
 * @create: 2022-10-17 09:18
 * @description: 1、自定义日志注解接口
 * @Target(ElementType.TYPE) // 接口、类、枚举、注解
 * @Target(ElementType.FIELD) // 字段、枚举的常量
 * @Target(ElementType.METHOD) //方法
 * @Target(ElementType.PARAMETER) //方法参数
 * @Target(ElementType.CONSTRUCTOR) //构造函数
 * @Target(ElementType.LOCAL_VARIABLE)//局部变量
 * @Target(ElementType.ANNOTATION_TYPE)//注解
 * @Target(ElementType.PACKAGE) ///包
 * @Retention注解: 这个参数有三种,一般默认第三种
 * <p>
 * 1. RetentionPolicy.SOURCE —— 这种类型的Annotations只在源代码级别保留,
 * <p>
 * 编译时就会被忽略
 * <p>
 * 2. RetentionPolicy.CLASS —— 这种类型的Annotations编译时被保留,在class文件中存在,
 * <p>
 * 但JVM将会忽略
 * <p>
 * 3. RetentionPolicy.RUNTIME —— 这种类型的Annotations将被JVM保留,
 * <p>
 * 所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。
 * 第二种写法:
 * @Documented 和 @Order(优先级:数字越小优先级越高)
 * @Documented 注解表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的. 但如果声明注解时指定了 @Documented,则它会被 javadoc 之类的工具处理, 所以注解类型信息也会被包括在生成的文档中。
 * @Order标记定义了组件的加载顺序,这个标记包含一个value属性。属性接受整形值。 如:1,2 等等。值越小拥有越高的优先级。
 * <p>
 * Ordered.HIGHEST_PRECEDENCE这个属性值是最高优先级的属性,它的值是-2147483648,对应的最低属性值是Ordered.LOWEST_PRECEDENCE,它的值是2147483647。
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
    /**
     * 模块
     */
    String title() default "";

    /**
     * 是否保存请求的参数
     */
    boolean isSaveRequestData() default true;

    /**
     * 是否保存响应的参数
     */
    boolean isSaveResponseData() default true;
}
  1. 创建LogAspect类对自定义注解进行操作
package com.example.lambda.annotation;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.Map;

/**
 * 操作日志记录处理
 *
 * @author: WZ
 * @create: 2022-10-17 09:18
 * @description: 2、自定义注解操作
 */
@Aspect
@Component
@Slf4j
public class LogAspect {


    /**
     * 配置织入点
     */
    @Pointcut("@annotation(com.example.lambda.annotation.Log)")
    public void logPointCut() {
    }

    /**
     * 处理完请求后执行
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
        handleLog(joinPoint, controllerLog, null, jsonResult);
    }

    /**
     * 拦截异常操作
     *
     * @param joinPoint 切点
     * @param e         异常
     */
    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
        handleLog(joinPoint, controllerLog, e, null);
    }

    protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
        try {
            //获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
            Signature signature = joinPoint.getSignature();
            //获取传入目标方法的参数对象
            Object[] args = joinPoint.getArgs();
            //获取被代理的对象
            Object target = joinPoint.getTarget();
            //获取代理的对象
            Object aThis = joinPoint.getThis();
            //接口请求方式
            String method = getHttpMethod();

            String params = argsArrayToString(joinPoint.getArgs());
            /**
             * 是否保存请求的参数
             */
            if (controllerLog.isSaveRequestData()) {

            }
            /**
             * 是否保存响应的参数
             */
            if (controllerLog.isSaveResponseData()) {

            }

            log.info("---------------------signature:{}", signature);
            log.info("---------------------params:{}", params);
            log.info("---------------------target:{}", target);
            log.info("---------------------aThis:{}", aThis);
            log.info("---------------------method:{}", method);
            log.info("---------------------异常信息:{}", e);
            log.info("---------------------jsonResult:{}", jsonResult);

        } catch (Exception exp) {
            // 记录本地异常日志
            log.error("==前置通知异常==");
            log.error("异常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }

    /**
     * 获取请求方式
     *
     * @return
     */
    public static ServletRequestAttributes getAttributes() {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        return (ServletRequestAttributes) attributes;
    }

    public static String getHttpMethod() {
        String method = getAttributes().getRequest().getMethod();
        return method;
    }

    /**
     * 参数拼装
     */
    private String argsArrayToString(Object[] paramsArray) {
        String params = "";
        if (paramsArray != null && paramsArray.length > 0) {
            for (Object o : paramsArray) {
                if (o != null && !isFilterObject(o)) {
                    try {
                        Object jsonObj = JSONObject.toJSONString(o);
                        params += jsonObj.toString() + " ";
                    } catch (Exception e) {
                    }
                }
            }
        }
        return params.trim();
    }

    /**
     * 判断是否需要过滤的对象。
     *
     * @param o 对象信息。
     * @return 如果是需要过滤的对象,则返回true;否则返回false。
     */
    @SuppressWarnings("rawtypes")
    public boolean isFilterObject(final Object o) {
        Class<?> clazz = o.getClass();
        if (clazz.isArray()) {
            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
        } else if (Collection.class.isAssignableFrom(clazz)) {
            Collection collection = (Collection) o;
            for (Object value : collection) {
                return value instanceof MultipartFile;
            }
        } else if (Map.class.isAssignableFrom(clazz)) {
            Map map = (Map) o;
            for (Object value : map.entrySet()) {
                Map.Entry entry = (Map.Entry) value;
                return entry.getValue() instanceof MultipartFile;
            }
        }
        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
            || o instanceof BindingResult;
    }
}
  1. 使用自定义注解@Log
@PostMapping("test2")
    @Log(title = "测试自定义日志post")
    public Object test1(@RequestBody Map map) {
        return new HashMap<String,Object>(){
            {
                put("name", "张三");
                put("age", 18);
                put("sex", "男");
            }
        };
    }