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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/672974.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

pytest框架用例命名规则详解

pytest 测试用例的命名规则是为了确保 pytest 能够正确地识别和执行测试用例。 以下是关于 pytest 测试用例命名规则的详细解释&#xff1a; 1 编写单个测试文件 单个测试文件须以‘test_’开头或者以‘_test’结尾 比如我们创建test_case1.py case2_test.py文件。 2 在单个…

【Mac】Lightroom Classic 2024(LrC 2024中文版) v13.1安装教程

软件介绍 Lightroom Classic 2024 for Mac是一款功能强大的照片编辑和组织软件&#xff0c;专为专业摄影师和爱好者设计。它提供了一系列工具和功能来增强和管理您的数码照片。Lightroom Classic 2024在照片组织和管理方面进行了重大改进。它新增了一个智能化的“发现”面板&a…

电容的电路应用

电容的电路应用 1、陶瓷电容应用于滤波 电源电路&#xff0c;负载电流较小时&#xff0c;可以使用陶瓷电容进行滤波。 C18电容起到滤波作用&#xff0c;因为负载电流比较小&#xff0c;所以可以用小容量的电容&#xff0c;比如经典的10uF、1uF、4.7uF都是可以的 滤波过程&am…

名下企业查询,清晰明了;在线操作,方便快捷

在现代社会&#xff0c;越来越多的人开始涉足创业和投资&#xff0c;拥有自己的企业成为一种时尚。然而&#xff0c;随之而来的是繁琐的企业注册流程和复杂的信息查询。为了解决这个问题&#xff0c;挖数据平台推出了一项名下企业查询接口&#xff0c;提供了一种方便快捷的方式…

easy-captcha生成验证码

引入依赖 <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>…

【Docker】学习笔记(超万字图文整理)

前言 再此感谢黑马程序员提供的Docker课程&#xff01; 什么是Docker&#xff1f;看这一篇干货文章就够了&#xff01; UPD: 补充更新微服务集群、Docker镜像仓库部分内容 所有笔记、生活分享首发于个人博客 想要获得最佳的阅读体验&#xff08;无广告且清爽&#xff09;&#…

低代码开发系统是什么?它有那些部分组成?

低代码开发系统是什么&#xff1f;它有那些部分组成&#xff1f; 一、引言 在当今快速变化的商业环境中&#xff0c;企业对于快速响应市场需求、降低开发成本和提高开发效率的需求日益增强。低代码开发系统&#xff08;Low-Code Development Platform&#xff09;应运而生&am…

视频监控平台AS1000:通过网络SDK接入松下视频监控设备(Panasonic监控摄像机) 的源代码的函数和功能介绍及分享

目录 一、视频监控平台介绍 1、概述 2、视频接入能力介绍 3、功能介绍 二、PANASONIC网络摄像机 1、产品种类与定位 2、规格参数 3、功能特点 4、环境适应性 5、网络功能 6、其他特性 三、代码和解释 1、代码和注释 2、函数功能说明 &#xff08;1&#xff09;处…

SpringBoot项目启动时提示程序包不存在和找不到符号

一、前言 最近接手同事开发的一个Springboot工作项目&#xff0c;从svn上整体拉取下来后&#xff0c;构建完成后&#xff0c;启动的时候遇到了程序包找不到的情况&#xff0c;记录一下处理过程&#xff1b; 二、项目问题 1、报错信息&#xff1a;启动后报 java: 程序包org.sp…

MySql 查询缓存

前言 MySQL的查询缓存&#xff08;Query Cache&#xff09;是一个在内存中存储SELECT语句及其结果集的机制&#xff0c;目的是避免对相同的查询进行重复的解析、编译和执行&#xff0c;从而提高数据库性能。 Mysql 结构图如下&#xff1a; 查询缓存的工作流程大致如下&#…

UE5 读取本地图片并转换为base64字符串

调试网址&#xff1a;在线图像转Base64 - 码工具 (matools.com) 注意要加&#xff08;data:image/png;base64,&#xff09; FString UBasicFuncLib::LoadImageToBase64(const FString& ImagePath) {TArray<uint8> ImageData;// Step 1: 读取图片文件到字节数组if (!…

1、pyton环境的安装-windows系统下

python官网 https://www.python.org/ 点击黄色的按钮&#xff0c;下载完成&#xff0c;如下&#xff1a; 双击安装&#xff0c;我现在以3.10.4版本进行安装说明&#xff1a; 一定要勾选上下边的to path&#xff0c;然后选择自定义安装 全选&#xff0c;点击next 选择要安装的路…

面试官:Spring中都应用了哪些设计模式?

设计模式是我们项目中经常会涉及到的项目进行重构、解构时的一种方法。 比如我们常见的单例模式、工厂模式、策略模式、装饰器模式等都是比较常用的&#xff1b;关于 23 种设计模式&#xff0c;大家可以找本书专门去学习一下&#xff0c;在 Java 框架的源码中也不例外&#xf…

动态SQL where, choose语句

where语句就一个<where>标签, 很简单, 不再过多赘述 接下来我们来看 choose语句的使用 其实choose语句就像java里的swith语句 , 如果语句前面的生效 , 后面的就不会生效了 可以定义查询的优先级

Flutter开发效率提升1000%,Flutter Quick教程之定义构造参数和State成员变量

一个Flutter页面&#xff0c;可以定义页面构造参数和State成员变量。所谓页面构造参数&#xff0c;就是当前页面构造函数里面的参数。 比如下面代码&#xff0c;a就是构造参数&#xff0c;a1就是State成员变量。 class Testpage extends StatefulWidget {String a;const Test…

Java web应用性能分析之【jvisualvm远程连接云服务器】

Java web应用性能分析之【java进程问题分析概叙】-CSDN博客 Java web应用性能分析之【java进程问题分析工具】-CSDN博客 前面整理了java进程问题分析和分析工具&#xff0c;现在可以详细看看jvisualvm的使用&#xff0c;一般java进程都是部署云服务器&#xff0c;或者托管IDC机…

Apache Calcite - 自定义标量函数

前言 上一篇文章中我们介绍了calcite中内置函数的使用。实际需求中会遇到一些场景标准内置函数无法满足需求&#xff0c;这时候就需要用到自定义函数。在 Apache Calcite 中添加自定义函数&#xff0c;以便在 SQL 查询中使用自定义的逻辑。这对于执行特定的数据处理或分析任务…

scButterfly:单细胞跨模态翻译

技术限制导致了高噪声的多模态数据。尽管已经提出了计算方法来跨模态翻译单细胞数据&#xff0c;但是这些方法的泛化性仍然受到制约。scButterfly是一种基于双重对齐变分自编码器和数据增强方案的多功能单细胞跨模态翻译方法。通过对多个数据集进行全面的实验&#xff0c;证明了…

YOLOv8改进(一)-- 轻量化模型ShuffleNetV2

文章目录 1、前言2、ShuffleNetV2代码实现2.1、创建ShuffleNet类2.2、修改tasks.py2.3、创建shufflenetv2.yaml文件2.4、跑通示例 3、碰到的问题4、目标检测系列文章 1、前言 移动端设备也需要既准确又快的小模型。为了满足这些需求&#xff0c;一些轻量级的CNN网络如MobileNe…

低代码设计中的组织结构的作用与模式

一、组织结构的作用 在低代码设计中&#xff0c;组织结构是系统运作的基石&#xff0c;它定义了系统中的关键元素&#xff0c;包括人员、部门、角色&#xff0c;以及一人多部门、一人多部门多角色的复杂关系。这种定义不仅为系统提供了清晰的运行框架&#xff0c;还确保了系统…