自定义SpringBoot切面aop日志

1.自定义注解

package cn.wwkj.pms.basis.annotation;

import cn.wwkj.pms.basis.entity.vo.EnumLogCode;

import java.lang.annotation.*;

/**
 * 日志注解    日志记录注解使用方法@SysLogAnno(value = "添加年份",operateType = EnumLogCode .SYS)
 * @author GaoDongYang
 * @date 2020/8/12 14:33
 */
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SysLogAnno {
    /**
     * 操作内容
     * @return String
     */
    String value() default "";
    /**
     *  日志code类型
     * @return EnumLogCode
     */
    EnumLogCode operateType() default EnumLogCode.SYS;

}

  1. @Target({ElementType.METHOD}) 注解 表明作用在方法上的注解
    ElementType 是一个枚举类型的常量提供了一个简单的分类:表示你自定义的注解可能出现在Java程序中的语法位置,常用的有METHOD、PARAMETER
    可用位置和类型有:
package java.lang.annotation;
 
/**
 1. The constants of this enumerated type provide a simple classification of the
 2. syntactic locations where annotations may appear in a Java program. These
 3. constants are used in {@link Target java.lang.annotation.Target}
 4. meta-annotations to specify where it is legal to write annotations of a
 5. given type.
 6. @author  Joshua Bloch
 7. @since 1.5
 8. @jls 9.6.4.1 @Target
 9. @jls 4.1 The Kinds of Types and Values
 */
public enum ElementType {
    /** 类, 接口 (包括注释类型), 或 枚举 声明 */
    TYPE,
 
    /** 字段声明(包括枚举常量) */
    FIELD,
 
    /** 方法声明(Method declaration) */
    METHOD,
 
    /** 正式的参数声明 */
    PARAMETER,
 
    /** 构造函数声明 */
    CONSTRUCTOR,
 
    /** 局部变量声明 */
    LOCAL_VARIABLE,
 
    /** 注释类型声明 */
    ANNOTATION_TYPE,
 
    /** 包声明 */
    PACKAGE,
 
    /**
     * 类型参数声明
     *
     * @since 1.8
     */
    TYPE_PARAMETER,
 
    /**
     * 使用的类型
     *
     * @since 1.8
     */
    TYPE_USE
}

  1. @Retention({RetentionPolicy.Runtime}) 注解
    RetentionPolicy这个枚举类型的常量描述保留注释的各种策略,它们与元注释(@Retention)一起指定注释要保留多长时间,一般Runtime
package java.lang.annotation;
/**
 1. Annotation retention policy.  The constants of this enumerated type
 2. describe the various policies for retaining annotations.  They are used
 3. in conjunction with the {@link Retention} meta-annotation type to specify
 4. how long annotations are to be retained.
 5.  6. @author  Joshua Bloch
 7. @since 1.5
 */
public enum RetentionPolicy {
    /**
     * 注释只在源代码级别保留,编译时被忽略
     */
    SOURCE,
    /**
     * 注释将被编译器在类文件中记录
     * 但在运行时不需要JVM保留。这是默认的
     * 行为.
     */
    CLASS,
    /**
     *注释将被编译器记录在类文件中
     *在运行时保留VM,因此可以反读。
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}
  1. @Documented注解 就是一个声明

    Documented注解表明这个注释是由 javadoc记录的,在默认情况下也有类似的记录工具。 如果一个类型声明被注释了文档化,它的注释成为公共API的一部分。

2.引入aop依赖

pom文件中


        <!--spring切面aop依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

3.自定义切面类

package cn.wwkj.pms.basis.aspect;

import cn.wwkj.pms.basis.annotation.SysLogAnno;
import cn.wwkj.pms.basis.entity.bo.Log;
import cn.wwkj.pms.basis.entity.vo.EnumLogCode;
import cn.wwkj.pms.basis.service.SysLogService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
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.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 日志切面
 * @author gaodongyang
 * @date 2020/8/12 14:37
 **/

@Aspect
@Component
@Order(0)
@Slf4j
public class LogAspect {

    private final SysLogService sysLogService;
    private final ObjectMapper objectMapper;

    /**
     * 构造注入
     * @param sysLogService 日志
     * @param objectMapper json序列化映射器
     */
    public LogAspect(SysLogService sysLogService, ObjectMapper objectMapper) {
        this.sysLogService = sysLogService;
        this.objectMapper = objectMapper;
    }

    /**
    * 设置切点  对有@SysLogAnno注释的方法生效
    * @author gaodongyang
    * @date 2020/8/12 14:42
    **/
    @Pointcut("@annotation(cn.wwkj.pms.basis.annotation.SysLogAnno)")
    public void logPointCut() {

    }

    /**
    * 环绕通知
    * @author gaodongyang
    * @date 2020/8/12 16:47
    * @param  point 连接点
    * @return Object 结果
    **/
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        log.info("环绕通知开始。。。。。");
        //日志
        Log sysLog = new Log();
        Object result = null;
        try {
            // 执行方法
            result = point.proceed();
            sysLog.setRet(0);
        }catch (Exception e){
            log.error(e.getMessage(),e);
            sysLog.setRet(1)
                    .setRetStr(e.getMessage());
        }finally {
            //从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) point.getSignature();
            //获取切入点所在的方法
            Method method = signature.getMethod();
            // 获得注解 操作
            SysLogAnno monitorLog = method.getAnnotation(SysLogAnno.class);
            // 获得code
            EnumLogCode operateType = monitorLog.operateType();
            // 获得操作内容
            String value = monitorLog.value();
            System.out.print(result);
            sysLog.setCont1(value);
            //请求的参数
            Object[] args = point.getArgs();
            //将参数所在的数组转换成json
            StringBuilder params = new StringBuilder();
            for(Object o : args){
                params.append(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(o));
            }

            sysLog.setRemark1(params.toString());
            //添加日志
            sysLogService.add(operateType,sysLog);
            log.info("环绕通知结束。。。。。");
        }
        return result;
    }
}

4.日志有关数据库,这里只写插入方法

日志插入service层的add方法,主要就是在本方法上加上**@Transactional(propagation = Propagation.NOT_SUPPORTED)**事务,防止在其他方法上加日志注解时,因其方法内部的错误导致事务回归,日志也回滚,不能在其他方法执行失败时把日志插入数据库中。

 /**
     * 添加日志
     * @param logParam 日志字段实体
     * @author GaoDongYang, GongLiHai
     * @date 2020/8/11 10:38
     **/
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void addLog(Log logParam) {
        //初始化日志对象,并设置设备信息,用户信息,ip等内容
        SysLog sysLog = new SysLog(logParam)
                .setDevice(getDevice(request.getHeader("User-Agent")))
                .setUserDept(CurrentUserService.currentUserDetails())
                .setIp(((WebAuthenticationDetails) SecurityContextHolder.getContext().getAuthentication().getDetails()).getRemoteAddress())
                .setInParam(getFmtInParam(logParam.getInParam()));
        sysLogMapper.insert(sysLog);
    }


5.使用时,只需加上注解


    /**
     * 添加要素详情
     * @param elementDetail 要添加的要素详情信息
     * @param year          年份
     * @return 返回添加结果
     * @author WeiJian
     **/
    @RequestMapping("/addElementDetail")
    @SysLogAnno(value = "添加年份",operateType = EnumLogCode .SYS)
    public Result<?> addElementDetail(@Valid ElementDetail elementDetail, @CurrentYear int year) {
        elementDetail.setYear(year);
        return ResultUtil.updateResult(elementDetailService.addElementDetail(elementDetail));
    }


6.我定义的注解中operateType = EnumLogCode .SYS时枚举类型

也可不用枚举,传字符串什么的都一样

package cn.wwkj.pms.basis.entity.vo;

/**
 * 日志 code name 枚举类
 * @author gaodongyang
 * @date 2020/8/11 10:00
 **/
@SuppressWarnings("unused")
public enum EnumLogCode {

    //code数据库映射
    SYS("001","系统日志"),
    SYS_LOGIN("001001","登录日志");


    private String name;
    private String code;

    EnumLogCode(String code, String name){
        this.name = name;
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public String getCode() {
        return code;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

成年人的苦衷

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值