外卖项目:使用AOP切面,完成公共字段自动填充(断点调试详细讲解)

news2024/11/24 14:53:31

文章目录

  • 一、问题描述
  • 二、实现思路
  • 三、实现步骤
  • 四、断点实操
  • 五、代码演示

一、问题描述

我们已经完成了后台系统的员工管理功能菜品分类功能的开发,在新增员工或者新增菜品分类时需要设置创建时间、创建人、修改时间、修改人等字段,在编辑员工或者编辑菜品分类时需要设置修改时间、修改人等字段。这些字段属于公共字段,也就是也就是在我们的系统中很多表中都会有这些字段,如下:

序号字段名含义数据类型
1create_time创建时间datetime
2create_user创建人idbigint
3update_time修改时间datetime
4update_user修改人idbigint

而针对于这些字段,我们的赋值方式为:

1). 在新增数据时, 将createTime、updateTime 设置为当前时间, createUser、updateUser设置为当前登录用户ID。

2). 在更新数据时, 将updateTime 设置为当前时间, updateUser设置为当前登录用户ID。

如果都按照上述的操作方式来处理这些公共字段, 需要在每一个业务方法中进行操作, 编码相对冗余、繁琐,那能不能对于这些公共字段在某个地方统一处理,来简化开发呢?

答案是可以的,我们使用AOP切面编程,实现功能增强,来完成公共字段自动填充功能。

二、实现思路

在实现公共字段自动填充,也就是在插入或者更新的时候为指定字段赋予指定的值,使用它的好处就是可以统一对这些字段进行处理,避免了重复代码。在上述的问题分析中,我们提到有四个公共字段,需要在新增/更新中进行赋值操作, 具体情况如下:

序号字段名含义数据类型操作类型
1create_time创建时间datetimeinsert
2create_user创建人idbigintinsert
3update_time修改时间datetimeinsert、update
4update_user修改人idbigintinsert、update

三、实现步骤

1、自定义注解 AutoFill,用于标识需要进行公共字段自动填充的方法

2、自定义切面类 AutoFillAspect,统一拦截加入了 AutoFill 注解的方法,通过反射为公共字段赋值

3、在 Mapper 的方法上加入 AutoFill 注解

四、断点实操

我们接下来debug一下,先看看update更新数据的情况:

在这里插入图片描述在这里插入图片描述

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
最后来看看新增员工时的情况:

首先来到controller类:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

五、代码演示

/**
 * 自定义注解,用于标识某个方法需要进行功能字段自动填充处理
 * @Retention(RetentionPolicy.RUNTIME):定义注解的保留策略,
 * 注解会在class字节码文件中存在,在运行时可以通过反射获取到
 * @Target:指定被修饰的Annotation可以放置的位置(被修饰的目标)方法
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
//    数据库操作类型:update、insert
    OperationType value();
}
/**
 * 数据库操作类型
 */
public enum OperationType {
    /**
     * 更新操作
     */
    UPDATE,
    /**
     * 插入操作
     */
    INSERT
}

自定义切面 AutoFillAspect

/**
 * 自定义切面,实现公共字段自动填充处理逻辑
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {

    /**
     * 切入点表达式
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointCut() {
    }

    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint) {
        log.info("开始进行公共字段自动填充...");
        //获取到当前被拦截的方法上的数据库操作类型
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();//方法前面对象
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获得方法上的注解对象
        OperationType operationType = autoFill.value();//获得数据库操作类型
        //获取到当前被拦截的方法的参数--实体对象
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length == 0) {
            return;
        }
        Object entity = args[0];
        //准备赋值的数据
        Long currentId = BaseContext.getCurrentId();
        LocalDateTime now = LocalDateTime.now();
        //根据当前不同的操作类型,为对应的属性通过反射来赋值
        if (operationType == OperationType.INSERT) {
            //为4个公共字段赋值
            try {
                Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                //通过反射为对象属性赋值
                setCreateTime.invoke(entity, now);
                setUpdateTime.invoke(entity, now);
                setCreateUser.invoke(entity, currentId);
                setUpdateUser.invoke(entity, currentId);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else if (operationType == OperationType.UPDATE) {
            try {
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                setUpdateTime.invoke(entity, now);
                setUpdateUser.invoke(entity, currentId);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Sentinel持久化(nacos)

导入依赖 <!--SpringCloud ailibaba sentinel-datasource-nacos --><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId></dependency> yml配置 rule-type: naco配置: resource&am…

javaweb遇到的servlet问题,jar包问题

有时候会遇到这种问题&#xff0c;有的地方会报红 这是因为这个找不到这个包&#xff0c;这个项目缺少jar包 在tomcat9之前还不是Jakarta这个名字&#xff0c;我的运行环境与服务器是jdk17与tomcat10 解决方法&#xff1a; 在项目结构中&#xff0c;找到模块&#xff0c;再…

踏“时间”与“空间”前来探寻复杂度的奥妙(Java篇)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

机器人路径规划:基于广度优先搜索算法的机器人路径规划(提供Python代码)

一、广度优先搜索算法简介 广度优先搜索&#xff08;BFS&#xff09;是一种用于图或树的遍历算法&#xff0c;它从根节点开始&#xff0c;逐层地向下搜索&#xff0c;直到找到目标节点或遍历完整个图。BFS使用队列数据结构来实现&#xff0c;保证了节点的访问顺序是按照层级逐…

拌合楼管理系统(八) c#海康威视摄像头车牌识别

前言: c#调用海康威视SDK实现车牌识别 原本以为海康威视sdk的Demo里面没有车牌识别的实例,后来发现自己肤浅了,官方是有提供的,只是车牌识别是通过安防布警的方式实现的.程序主动监听,触发告警后获取到车牌信息. 一、接口调用的流程&#xff1a; 首先初始化sdk -> 开…

PHP使用PHP_DIO读取串口数据

一、安装PHP_DIO扩展 1. 下载对应版本的dll扩展 根据你的操作系统类型选择对应的扩展名 PECL :: Package :: dio 下载地址&#xff1a; PECL :: Package :: dio 0.2.1 for Windows 以我使用的为例 我本地使用的是phpStudy PHP为7.4.3nts 64位的那就需要下载 注意你的是线程安全…

嵌入式学习42-数据结构-双向链表

知识散记&#xff1a; 1.程序使用时&#xff08;开闭原则&#xff09; …

iOS常见崩溃简介

1. 崩溃 多指在移动设备&#xff08;如iOS、Android设备&#xff09;中或不可移动设备&#xff08;如:Windows、Linux等设备&#xff09;&#xff0c; 在打开或使用应用程序时出现的突然退出中断的情况&#xff08;类似于Windows的应用程序崩溃&#xff09;。 多表现为&#…

全网最详细介绍如何实现图片存储阿里OSS实现资源持久化存储

什么是阿里云OSS 阿里云OSS&#xff08;Object Storage Service&#xff0c;对象存储服务&#xff09;是阿里云提供的一种存储服务&#xff0c;它支持任意类型的数据存储&#xff0c;如图片、视频、日志文件等。OSS以对象&#xff08;Object&#xff09;的形式组织数据&#x…

【导论】数据可信流通 从运维信任到技术信任

信任 信任概念由于其抽象性和结构复杂性&#xff0c;在社会学、心理学、营销学、经济学、管理学等不同 的领域定义是不同的&#xff0c;但是达成共识的观点是&#xff1a;信任是涉及交易或交换关系的基础。 信任的基石 ①身份可确认&#xff0c;②利益可依赖&#xff0c;③能…

docker实战(3)

1, jdk17版本的dockerfile FROM eclipse-temurin:17-jre ADD ./target/ods-poc-0.0.1-SNAPSHOT.jar /home/app/app.jar WORKDIR /home/app ENV TZ Asia/Shanghai ENTRYPOINT ["java","-jar","/home/app/app.jar"] EXPOSE 8083dockerfile 1, …

数据结构的概念大合集02(线性表)

概念大合集02 1、线性表及其逻辑结构1.1 线性表的定义1.2 线性表的基本操作 2、线性表的顺序存储结构2.1 顺序表 3、线性表的链式存储3.1 链表3.1.1 头结点&#xff08;头指针&#xff09;&#xff0c;首指针&#xff0c;尾指针&#xff0c;尾结点3.1.2 单链表3.1.3 双链表3.1.…

Linux第79步_使用自旋锁保护某个全局变量来实现“互斥访问”共享资源

自旋锁使用注意事项:自旋锁保护的“临界区”要尽可能的短。 因此&#xff0c;在open()函数中申请“spinlock_t自旋锁结构变量”&#xff0c;然后在release()函数中释放“spinlock_t自旋锁结构变量”&#xff0c;这种方法就行不通了。如果使用一个变量“dev_stats”来表示“共享…

Nanya(南亚科技)DRAM芯片选型详解

一、DRAM产品选型 普通SDRAM只在时钟的上升期进行数据传输&#xff0c;DDR内存能够在时钟的上升期和下降期各传输一次数据&#xff0c;因此性能翻倍&#xff0c;被称为双倍速率同步动态随机存储器。因此DDR内存可以在与SDRAM相同的总线频率下达到更高的数据传输率。DDR是一种掉…

Pygame AttributeError no attribute ‘display‘问题及其解决方法

目录 前言 错误原因 解决方法 1. 确保正确安装 Pygame 2. 检查 Python 路径和 Pygame 模块位置 3. 修复模块命名冲突 4. 检查代码错误 5. 检查 Pygame 版本兼容性 代码示例 总结 前言 Pygame 是一个非常受欢迎的 Python 游戏开发库&#xff0c;它提供了丰富的功能和…

Linux 学习必备:CentOS 技能提升一站式平台!

介绍&#xff1a;CentOS是一种广泛使用的Linux发行版&#xff0c;特别受到企业用户的青睐。 首先&#xff0c;CentOS的全称是Community Enterprise Operating System&#xff0c;中文意思是“社区企业操作系统”。它起源于Red Hat Enterprise Linux (RHEL)的源代码&#xff0c;…

极智压缩 ——帮你高清无损压缩 JPG/PNG/GIF 图片!

引言 图片太大怎么办&#xff1f;图片该如何压缩&#xff1f;压缩后图片为什么变模糊了&#xff1f;屏幕前的你是不是经常被这些问题所困扰&#xff0c;腾讯云数据万象推出的图片极智压缩服务&#xff0c;可以帮你高清无损压缩 JPG/PNG/GIF 图片&#xff0c;解决你95%以上的图片…

解决虚拟机Linux ens33 没有 IP 地址

解决方法&#xff1a; 先进入 root 模式 sudo su 查看目录 ls /etc/sysconfig 找到上述文件夹 ls /etc/sysconfig/network-scripts/ 用 vim 打开 ifcfg-ens33 这个文件&#xff08;不都是这个名字&#xff0c;按这个方法找到这个文件就行&#xff09; vim /etc/sysconfig/netw…

学习笔记-华为IPD转型2020:3,IPD的实施

3. IPD的实施 1999 年开始的 IPD 转型是计划中的多个转型项目中的第一个&#xff08;Liu&#xff0c;2015&#xff09;。华为为此次转型成立了一个专门的团队&#xff0c;从大约20人开始&#xff0c;他们是华为第一产业的高层领导。董事会主席孙雅芳是这个团队的负责人。该团…