AOP概念续及日志记录的实现

1. 添加日志思路分析

​ 1. 日志:是用于记录当前用户/系统进行了哪些操作的,会将操作信息 保存起来

  1. 在本项目中,日志管理模块中有添加日志的功能,不是由用户添加的,而是由程序来添加的。原理为:程序对当前用户进行的所有操作都会记录(将日志数据保存到数据库中)

  2. 本项目中日志添加功能分析:
    在这里插入图片描述

2. AOP:

  1. aop:Aspect oriented programming 面向切面编程,是一种编程思想

  2. aop的好处:将核心业务代码和横切关注点解耦,提高了项目的维护性以及扩展性

  3. aop的应用:日志记录,声明式事务管理,性能统计,shiro框架的授权功能

在这里插入图片描述

  1. 专业术语:

    1. Aspect(切面):切面类
    2. Join point(连接点):可能会成为切点的所有方法
    3. Pointcut(切点/切入点):调用时真正有切面注入的方法
    4. Advice(通知):切面类中的方法(前置,后置,环绕)
    5. Target object(目标对象):最终切面要切入的方法所在的对象
    6. Weaving(织入):动作,将通知注入到切点中
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-voxLG0XF-1596162062133)(4.png)]

    1. 练习识别:
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hji1wu02-1596162062150)(5.png)]
  2. 通知类型:

    1. 前置通知:通知的代码在业务代码之前执行  @Before
    2. 后置通过:通知的代码在业务代码之后执行  @After
    3. 环绕通知:在业务代码之前和之后都会有通知的代码执行  @Around 
    	返回值类型Object,表示业务代码的返回值
    4.返回后通知
    5.抛出异常后通知
    
  3. aop代理机制:

    1. JDK动态代理:只能为实现了接口的类生产代理对象
      1. 利用了反射
    2. CGLIB代理机制:可以直接为类生产代理对象

3. 日志添加实现:–aop的应用

  1. 持久层开发–添加日志数据

    1. 在接口中定义抽象方法

      Integer insertLog(Log log)

    2. 在映射文件中写sql语句

      1. id字段的值是自增长的,不需要插入

      2. createdTime字段的值

        1. 在Java代码中new Date()
        2. 也可在sql语句中调用数据库的now()函数
      3. sql语句”

        <insert id="insertLog">
           insert into
                    sys_logs(
            username,operation,
            method,params,
            time,ip,createdTime)
            values(
            #{userName},#{operation},
            #{method},#{params},
            #{time},#{ip},now()
        )
            </insert>
        
    3. 在测试类中完成测试

       @Test
      public void insertLogTest() {
          Log log = new Log(null, "test", "测试操作", "cn.tedu....", "visitor", 20L, "0.0.0.1", null);
          Integer rows = logMapper.insertLog(log);
          System.err.println(rows);
      }
      
  2. 添加日志的准备工作:

    1. 获取一个日志对象的数据包括:
      1. userName:当前用户名称,正常应该是从session对象中获取的,但是因为目前我们还没有实现登录,没有向session中存数据,此时先给出一个固定值。
      2. operation:删除xx,查询xx,更新xx—是根据调用的方法来给出的,此处我们自定义一个注解@Operation,该注解用于方法上方,给出操作的名称
      3. method:调用的方法名称,通知中会执行业务方法,通知的参数列表中会存在目标方法对象
      4. params:调用方式时传递的实参
      5. time:目标方法运行耗时 ,在业务方法执行前后分别获取时间,求差值即可
      6. ip:获取当前用户的ip地址 – IPUtil
  3. 自定义Operation注解

    1. 定义注解类

      @Target({ElementType.METHOD})   //表示Operation注解是作用在方法上的
      @Retention(RetentionPolicy.RUNTIME) //表示Operation注解的有效期至运行期
      public @interface Operation {
          String value() default "";
      }
      
    2. 在日志业务模块方法上方添加该注解进行测试:

      @Operation("删除日志")
      public void removeLogs(Integer[] ids) {
          
      @Operation("查询日志列表")
      public PageInfo<Log> findLogList(String us....
      
  4. 写添加日志记录的切面类

    1. 先导入相关的依赖–aspect

       	<dependency>
                  <groupId>org.aspectj</groupId>
                  <artifactId>aspectjtools</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.aspectj</groupId>
                  <artifactId>aspectjweaver</artifactId>
              </dependency>
      
    2. 定义切面类LogAspect,类上方添加注解@Aspect,@Component

      @Aspect
      @Component
      public class LogAspect {
          @Autowired
          private LogMapper logMapper;
      
          @Around("execution(* cn.tedu.sysmanagement.Service.impl.*.*(..))&&@annotation(anno)")
          public Object logAddAdvice(ProceedingJoinPoint pjp, Operation anno) throws Throwable {
              long beforTime = System.currentTimeMillis(); //获取当前时间
              Object returnVal = pjp.proceed();  //目标方法执行
              long afterTime =  System.currentTimeMillis(); //再次获取时间
              long time = afterTime-beforTime; //方法耗时得到
              //获取方法上方注解Operation的value值,表示方法的操作
              String operation = anno.value();
              //调用saveLog方法
              saveLog(pjp,time,operation);
              return returnVal;
          }
      
          public void saveLog(ProceedingJoinPoint pjp,long time,String operation) throws JsonProcessingException {
              //继续获取剩余的参数
              String userName = "visitor";
              //获取方法全名(包名.类名.方法名)--通过pjp获取类名+通过pjp获取的方法名
              String  className =  pjp.getTarget().getClass().getName();
              //获取方法名,Signature-方法签名
              String methodName = pjp.getSignature().getName();
              String method = className+"."+methodName;
              //获取方法的入参值
              Object[] paramsArr = pjp.getArgs();
              //将参数数组转换为字符串类型
              String params = new ObjectMapper().writeValueAsString(paramsArr);
              //获取用户的ip地址值,IPUtils工具类已提供
              String ip = IPUtils.getIpAddr();
              //将以上的属性封装到Log对象中
              Log log = new Log(null,userName,operation,method,params,time,ip,null);
              //调用持久层插入日志数据
              logMapper.insertLog(log);
          }
      }
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值