使用AOP记录日志

 2023-02-14
原文作者:豆浆咸饼可度日 原文地址:https://juejin.cn/post/7032286194587140104

@Aspect注解将表示它是一个切面
@Component表示它是一个Spring的组件

切片Aspect,既然Spring那么支持AOP,就肯定都能拿。有人会问如何拿原始的HTTP请求和响应的信息,通过以下代码应该拿得到啊哈哈哈哈
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();

    <aop:config>
        <!-- order:指定切面bean的优先级,值越小,优先级越高 -->
        <aop:aspect id="fourAdviceAspect" ref="fourAdviceBean" order="2">
            <aop:around method="processTask" pointcut="execution(* com.wangjun.aop.xml.*.*(..))"/>
            <aop:before method="authority" pointcut="execution(* com.wangjun.aop.xml.*.*(..))"/>
            <aop:after-returning method="log" returning="rvt" pointcut="execution(* com.wangjun.aop.xml.*.*(..))"/>
        </aop:aspect>
    </aop:config>

其中aop:aspect/标签就是切面,此标签下面的aop:around/aop:before/这些就是增强处理,那么在哪里进行增强处理呢?pointcut属性就定义了切入点,也就是在哪里进行增强处理。这里的表达式比如execution(* com.wangjun.aop.xml..(..))含义如下:

指定在com.wangjun.aop.xml包中任意类方法;
第一个表示返回值不限,第二个表示类名不限;
第三个*表示方法名不限,圆括号中的(..)表示任意个数、类型不限的形参。

使用场景
日志记录、审计、声明式事务、安全性和缓存等。

AspectJ和Spring AOP的区别
正好代表了实现AOP的两种方式:
AspectJ是静态实现AOP的,即在编译阶段对程序进行修改,需要特殊的编译器,具有较好的性能;
Spring AOP是动态实现AOP的,即在运行阶段动态生成AOP代理,纯java实现,因此无需特殊的编译器,但是通常性能较差。

案例:记录日志

业务日志表

    package chin.common;
    
    /**
     * 操作类型枚举
     */
    public enum OpearteType {
        QUERY("检索","QUERY"),
        CREATE("录入","CREATE"),
        UPDATE("维护","UPDATE"),
        DELETE("删除","DELETE"),
        REVIEW("审核","REVIEW"),;
    
        private String name;
        private String code;
    
        private OpearteType(String name, String code) {
            this.name = name;
            this.code = code;
        }
    
        public static String getName(String code) {
            for (OpearteType c : OpearteType.values()) {
                if (c.getCode().equals(code)) {
                    return c.name;
                }
            }
            return null;
        }
    
        public static String getCode(String name) {
            for (OpearteType c : OpearteType.values()) {
                if (c.getName().equals(name)) {
                    return c.code;
                }
            }
            return null;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getCode() {
            return code;
        }
    
        public void setCode(String code) {
            this.code = code;
        }
    }
    package chin.annotation;
    
    import chin.common.BusinessModule;
    
    import java.lang.annotation.*;
    
    /**
     * 业务模块注解
     */
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(value = ElementType.TYPE)
    public @interface BusinessModuleAttributes {
        BusinessModule businessModule();
    }
    package chin.annotation;
    
    import chin.common.OpearteType;
    
    import java.lang.annotation.*;
    
    /**
     * 业务日志注解
     */
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(value = ElementType.METHOD)
    public @interface BusinessLogAttributes {
        OpearteType opearteType();
        String opearteDescription();
    }
    package chin.aspect;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.serializer.SerializerFeature;
    import com.beyondbit.ias.core.base.BaseController;
    import com.beyondbit.ias.core.util.IPUtil;
    import chin.annotation.BusinessLogAttributes;
    import chin.annotation.BusinessModuleAttributes;
    import chin.entity.BusinessLog;
    import chin.service.BusinessLogService;
    import org.aspectj.lang.ProceedingJoinPoint;
    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 org.springframework.ui.Model;
    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.lang.reflect.Method;
    import java.util.Date;
    
    /**
     * 业务日志切面
     */
    @Aspect
    @Component
    public class BusinessLogAspect extends BaseController {
    
        @Autowired
        private BusinessLogService businessLogService;
    
        @Pointcut("@annotation(chin.annotation.BusinessLogAttributes)")
        public void logPointCut() {
    
        }
    
        @Around("logPointCut()")
        public Object around(ProceedingJoinPoint point) throws Throwable {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    
            BusinessModuleAttributes moduleAttributes = point.getTarget().getClass().getAnnotation(BusinessModuleAttributes.class);
    
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
    
            BusinessLogAttributes logAttributes = method.getAnnotation(BusinessLogAttributes.class);
    
            //获取请求参数:
            MethodSignature ms = (MethodSignature) point.getSignature();
            //获取请求参数类型
            String[] parameterNames = ms.getParameterNames();
            //获取请求参数值
            Object[] parameterValues = point.getArgs();
            StringBuilder strParams = new StringBuilder();
            //组合请求参数,进行日志打印
            if (parameterNames != null && parameterNames.length > 0) {
                for (int i = 0; i < parameterNames.length; i++) {
                    if (parameterNames[i].equals("bindingResult")) {
                        break;
                    }
                    if ((parameterValues[i] instanceof HttpServletRequest) || (parameterValues[i] instanceof HttpServletResponse)||(parameterValues[i] instanceof Model)||(parameterValues[i] instanceof MultipartFile)) {
                        strParams.
                                append("[").
                                append(parameterNames[i]).append("=").append(parameterValues[i])
                                .append("]");
                    } else {
                        try
                        {
                            strParams.
                                    append("[").
                                    append(parameterNames[i]).append("=")
                                    .append(JSON.toJSONString(parameterValues[i], SerializerFeature.WriteDateUseDateFormat))
                                    .append("]");
                        }
                        catch(Throwable throwable){
                            strParams.
                                    append("[").
                                    append(parameterNames[i]).append("=").append(parameterValues[i])
                                    .append("]");
                        }
    
                    }
                }
            }
    
            Object result = null;
            BusinessLog log = new BusinessLog();
            log.setUuid(java.util.UUID.randomUUID().toString());
            log.setClientIP(IPUtil.getClientIp(request));
            log.setBusinessModule(moduleAttributes.businessModule().getCode());
            log.setOpearteType(logAttributes.opearteType().getCode());
            log.setOpearteDescription(logAttributes.opearteDescription());
            log.setOpeartor(super.getCurrentUser().getUserUid());
            log.setOpeartorName(super.getCurrentUser().getName());
            log.setOpearteDateTime(new Date());
            log.setReqUrl(request.getRequestURL().toString());
            log.setClazz(point.getTarget().getClass().getName());
            log.setMethod(method.getName());
            log.setParams(strParams.toString());
            try {
                // 执行方法
                result = point.proceed();
                log.setStatus("1");
            } catch (Exception e) {
    
                log.setStatus("0");
                log.setException(e.getStackTrace().toString());
                throw e;
            } finally {
                businessLogService.insertBusinessLog(log);
            }
            return result;
        }
    
    }