用户操作日志实现之AOP+注解+枚举方式


项目开发中,日志监控是不可少的。一个是系统日志,主要跟踪和排查各种系统异常情况,一般使用各种log就可以。还有一种是操作日志,用来跟踪和监控用户的操作情况和异常操作等,可用于用户画像等地方。

相关技术

现在做java开发的,肯定涉及到spring,那么对AOP也就不陌生——面向切面编程,是对OOP的补充,适用于日志、事务、权限等。
spring aop 官方文档

AOP基本概念
  • Aspect(切面): 是对横切关注点的抽象

  • Join point(连接点): 程序执行期间的一个点

  • Advice(通知):切面在连接点上执行的操作

  • Pointcut(切点):连接点的基础上定义切入点

  • Introduction(引入): 代表类型声明其他方法或字段

  • Target object(目标对象):一个或多个切面通知的对象,代理目标对象

  • AOP proxy(AOP代理): 将切面织入目标对象后所得到的就是代理对象

  • Weaving(织入): 将切面应用到目标对象并导致代理对象创建的过程

AOP通知类型
  • Before advice: 前置通知
  • After returning advice: 后置通知
  • After throwing advice: 异常通知
  • After (finally) advice: 最终通知
  • Around advice: Advice 环绕通知

aop相关详细内容可以参考上面的官方文档,毕竟是最正版的。我在这里只是稍微介绍一下,主要内容后面的日志实现。

功能实现

1.创建项目
  • 创建一个简单的springboot项目
2.添加依赖
  • web
  • lombok
  • aop
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	     <artifactId>spring-boot-starter-web</artifactId>
	 </dependency>
	
	 <!--aop-->
	 <dependency>
	     <groupId>org.springframework.boot</groupId>
	     <artifactId>spring-boot-starter-aop</artifactId>
	 </dependency>
	<dependency>
	    <groupId>org.projectlombok</groupId>
	    <artifactId>lombok</artifactId>
	    <optional>true</optional>
	</dependency>
3.枚举类型
/**
 * 对应日志的操作类型
 */
public enum OperType {
    FIND(1,"查询操作"),
    DELETE(2,"删除操作"),
    UPDATE(3,"更新操作"),
    CREATE(4,"新增操作");

    @Getter
    @Setter
    private Integer code;
    @Getter
    @Setter
    private String msg;
    OperType(Integer code, String msg){
        this.code = code;
        this.msg = msg;
    }
}
4.注解类型
/**
 * 操作日志的对应注解
 */
@Target({ElementType.METHOD})// 定义了注解声明在那些元素上,当前用在方法名上
@Retention(RetentionPolicy.RUNTIME)// 运行时有效
public @interface OperLog {
    String msg();
    OperType type();
}
5.切面功能
**
 * aop 面向切面应用
 * 方法执行时间
 */
@Aspect
@Component
public class TimeConsumeAspect {

    /**
     * 扫描所有controller包下的请求
     * 使用路径作为切点会使得该路径下的所有接口都被拦截处理,不够灵活
     * 但是该种方式不需要额外自定义枚举和注解类
     */
/*    @Pointcut("execution(* com.minion.demo.controller.*.*(..))")
    public void controllerAspect() {
    }*/

    /**
     * 定义拦截器的切入点,拦截注解的方法
     * 把枚举类作为切入点,可以根据业务需求调整,更灵活
     */
    @Pointcut("@annotation(com.minion.demo.util.OperLog)")
    public void annotationAspect() {
    }

    /**
     * 具体实现功能,使用环绕通知获取参数和返回数据
     * @param joinPoint
     * @return
     * @throws Throwable
     */
  @AfterReturning
    @Around("annotationAspect()")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object obj = joinPoint.proceed();

        //拦截实体类,被代理的对象
        Object target= joinPoint.getTarget();
        //拦截方法参数
        Object[] args = joinPoint.getArgs();

        //获取注解中的信息
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        String name = joinPoint.getSignature().getName();   //拦截方法名称
        Method method = target.getClass().getMethod(name, signature.getParameterTypes());
        OperLog annotation = method.getAnnotation(OperLog.class);
        System.out.println("annotation: "+annotation);

        //拦截方式
        String kind = joinPoint.getKind();
        //存储位置
        SourceLocation sourceLocation = joinPoint.getSourceLocation();


        //切入点
        JoinPoint.StaticPart staticPart = joinPoint.getStaticPart();
        //返回值
        String proceed = (String) joinPoint.proceed();       
        
        //剩下的可以根据业务将相关数据入库至日志表中
        //...

 		System.out.println("target: "+target);
        for (Object arg : args) {
            System.out.println("args: "+arg);
        }
        System.out.println("name: "+name);
        System.out.println("kind: "+kind);
        System.out.println("sourceLocation: "+sourceLocation);
        System.out.println("staticPart: "+staticPart);
        System.out.println("proceed: "+proceed);

        System.out.println("执行时间"+(System.currentTimeMillis()-start));
        return obj;
    }
}
6.请求处理
    @PostMapping
    @OperLog(msg = "嗨喽的跑斯特方法",type = OperType.CREATE)
    public String helloPost(String info){
        log.info(info);
        return info+"-返回数据";
    }
7.功能测试
1)idea自带的rest测试功能

在这里插入图片描述

2)配置请求接口和参数

在这里插入图片描述

3)执行结果
  • 接口返回数据
    在这里插入图片描述
  • 后台打印数据
    在这里插入图片描述

强行总结

至此,aop实用户操作日志的功能已经实现,至于入库的相关代码涉及到业务了,我就省略了,大家可以根绝自己项目进行实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值