AOP案例

黑马程序员JavaWeb开发教程

文章目录

  • 一、案例
    • 1.1 案例
    • 1.2 步骤
      • 1.2.1 准备
      • 1.2.2 编码

一、案例

1.1 案例

  • 将之前案例中增、删、改相关节后的操作日志记录到数据库表中。
  1. 操作日志:日志信息包含:操作人、操作时间、执行方法的全类名、执行方法名、方法运行时参数、返回值、方法执行时长
  2. 思路分析
    • 需要对所有业务中的增、删、改方法添加同一功能,使用AOP技术最为方便,@Around 环绕通知
    • 由于增、删、改方法名没有规律,可以自定义@Log 注解完成目标方法匹配

1.2 步骤

1.2.1 准备

  1. 在案例工程中引入AOP的起步依赖
<!--        AOP起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
  1. 在数据库中新建日志数据表,并引入对应的实体类
  • 创建数据表语句
-- 操作日志表
create table operate_log(
    id int unsigned primary key auto_increment comment 'ID',
    operate_user int unsigned comment '操作人ID',
    operate_time datetime comment '操作时间',
    class_name varchar(100) comment '操作的类名',
    method_name varchar(100) comment '操作的方法名',
    method_params varchar(1000) comment '方法参数',
    return_value varchar(2000) comment '返回值',
    cost_time bigint comment '方法执行耗时, 单位:ms'
) comment '操作日志表';
  • 实体类代码
package com.itheima.mytlias.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.math.BigInteger;
import java.time.LocalDateTime;

//操作日志表
@Data//getter、setter等
@NoArgsConstructor//无参构造函数
@AllArgsConstructor//全参构造函数
public class OperateLog {
    private Integer id;//id
    private Integer operateUser;//操作人id
    private LocalDateTime operateTime;//操作时间
    private String className;//操作的类名
    private String methodName;//操作的方法名
    private String methodParas;//方法参数
    private String returnValue;//返回值
    private BigInteger costTime;//方法执行时间,单位ms
}

  • 另外还需要mapper接口,以向日志记录表中插入数据
package com.itheima.mytlias.mapper;

import com.itheima.mytlias.pojo.OperateLog;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface OperateLogMapper {

    @Insert("insert into operate_log(operate_user,operate_time,class_name,method_name,method_params,return_value,cost_time) values(#{operateUser},#{operateTime},#{className},#{methodName},#{methodParams},#{returnValue},#{costTime})")
    public void insert(OperateLog operateLog);
}

获取当前登录用户:获取request对象,从轻去偷中获取到jwt令牌,解析令牌获取出当前用户的id

1.2.2 编码

  1. 自定义注解@Log
    • 在com.itheima.mytilas 包下新建包 anno,创建注解 @Log
    • 在这里插入图片描述
package com.itheima.mytlias.anno;


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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {
}

  1. 定义切面类,完成记录操作日志的逻辑
package com.itheima.mytlias.aop;

import com.alibaba.fastjson.JSONObject;
import com.itheima.mytlias.mapper.OperateLogMapper;
import com.itheima.mytlias.pojo.OperateLog;
import com.itheima.mytlias.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;

@Slf4j//日志
@Component//交给IOC容器管理
@Aspect//切面类
public class LogAspect {
    //为了拿到当前这次请求的请求头对象,我们直接注入一个HttpServletRequest 对象
    @Autowired
    HttpServletRequest request;
    //调用mapper接口中的insert方法记录日志,因此注入一个OperateLogMapper对象
    @Autowired
    OperateLogMapper operateLogMapper;


    @Around("@annotation(com.itheima.mytlias.anno.Log)")
    public Object recordLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        //操作人id(通过获取请求头张的jwt令牌来解析令牌)
        String jwt = request.getHeader("token");
        Claims claims = JwtUtils.parseJWT(jwt);//使用JWT工具类解析jwt令牌
        Integer operateUser = (Integer) claims.get("id");//操作用户的id
        log.info("用户id,{}", operateUser);
        //操作时间
        LocalDateTime operateTime = LocalDateTime.now();
        //操作的类名
        String className = proceedingJoinPoint.getTarget().getClass().getName();
        // 操作的方法名
        String methodName = proceedingJoinPoint.getSignature().getName();
        // 操作的方法参数
        Object[] args = proceedingJoinPoint.getArgs();
        String methodParms = Arrays.toString(args);
        //调用方法之前的时间(用于计算方法运行耗时)
        long begin = System.currentTimeMillis();

        //调用原始目标方法
        Object result = proceedingJoinPoint.proceed();

        //调用方法之后的时间(用于计算方法运行耗时)
        long end = System.currentTimeMillis();

        // 返回值
        String returnValue = JSONObject.toJSONString(result);
        // 操作耗时
        long costTime = (end - begin);

        //记录操作日志
        OperateLog operateLog = new OperateLog(null, operateUser, operateTime, className, methodName, methodParms, returnValue, costTime);

        operateLogMapper.insert(operateLog);
        //在控制打印输出日志
        log.info("AOP记录操作日志:{}", operateLog);
        //返回值
        return result;


    }
}

  1. 在所有增删改的方法上加上注解@Log
上一篇:EasyExcel实现导入导出-使用


下一篇:chat4-Server端保存聊天消息到mysql