Aop实现公共字段自动填充

文章目录

    • 1、问题:
      • 2.常规冗余不利于维护操作:
      • 3.实现思路:
    • 2、步骤:搭建一个简单的SpringBoot+MyPlus项目:
      • 表结构:
      • 1. 依赖:
      • 2. 配置连接信息:
      • 3. 创建三层架构:
      • 4. 代码开发:
        • 4.1 **定义数据库操作类型枚举**
        • 4.2、**自定义注解 AutoFill**
        • 4.3、**自定义切面,实现公共字段自动填充处理逻辑**
        • 4.4 mapper方法上面添加相应注解,和操作类型
        • 4.5 mapper.xml 文件:
        • 4.6. 测试:
          • 新增:
          • 修改:

1、问题:

在这里插入图片描述

2.常规冗余不利于维护操作:

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

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

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

目前,在我们的项目中处理这些字段都是在每一个业务方法中进行赋值操作,如下:

在这里插入图片描述

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

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

3.实现思路:

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

在这里插入图片描述

  • 自定义注解AutoFill,用于标识需要进行公共字段自动填充的方法
  • 自定义切面类AutoFillAspect,统一拦截加入了AutoFill 注解的方法,通过反射为公共字段赋值
  • 在 Mapper 的方法上加入 AutoFill 注解

2、步骤:搭建一个简单的SpringBoot+MyPlus项目:

表结构:

CREATE TABLE `user` (`id` bigint(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) DEFAULT NULL COMMENT '学生名称',`age` int(10) DEFAULT NULL COMMENT '学生年龄',`create_time` datetime DEFAULT NULL COMMENT '创建时间',`create_name` varchar(255) DEFAULT NULL COMMENT '创建人姓名',`update_time` datetime DEFAULT NULL COMMENT '修改时间',`update_name` varchar(255) DEFAULT NULL COMMENT '修改人姓名',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

在这里插入图片描述

1. 依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.js</groupId><artifactId>AopMybatisTest</artifactId><version>1.0-SNAPSHOT</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.5</version><relativePath/> <!-- lookup parent from repository --></parent><properties><java.version>1.8</java.version><log4j.version>1.2.17</log4j.version><druid.version>1.2.8</druid.version><mybatisplus.version>3.4.2</mybatisplus.version></properties><dependencies><!--web启动依赖--><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><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!--mybatis plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatisplus.version}</version></dependency><!--druid--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid.version}</version></dependency><!--log4j--><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>${log4j.version}</version></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--热部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><!--单元测试--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>

2. 配置连接信息:

#配置端口
server:port: 80spring:#配置数据源datasource:#配置数据源类型type: com.zaxxer.hikari.HikariDataSource#配置连接数据库的信息driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=falseusername: rootpassword: root#MyBatis-Plus相关配置
mybatis-plus:configuration:#配置日志log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3. 创建三层架构:

略~

4. 代码开发:

4.1 定义数据库操作类型枚举
package com.js.Enum;/*** 数据库操作类型*/
public enum OperationType {/*** 更新操作*/UPDATE,/*** 插入操作*/INSERT
}
4.2、自定义注解 AutoFill
package com.js.annotation;import com.js.Enum.OperationType;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 自定义注解,用于标识某个方法需要进行功能字段自动填充处理*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {//数据库操作类型:UPDATE INSERTOperationType value();
}
4.3、自定义切面,实现公共字段自动填充处理逻辑
package com.js.constant;/*** @ClassName AutoFillConstant* @Author lenovo* @Date 2024-04-02 23:00* @Version 1.0**/
public class AutoFillConstant {public static final  String SET_CREATE_TIME = "setCreateTime";public static final  String SET_CREATE_NAME = "setCreateName";public static final  String SET_UPDATE_TIME = "setUpdateTime";public static final  String SET_UPDATE_NAME = "setUpdateName";
}
package com.js.aspect;import com.js.Enum.OperationType;
import com.js.annotation.AutoFill;
import com.js.constant.AutoFillConstant;
import com.sun.prism.impl.BaseContext;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.time.LocalDateTime;/*** 自定义切面,实现公共字段自动填充处理逻辑*/
@Aspect//声明这个类是一个切面类
@Component//他也是个Bean 也需要交个Spring进行管理
@Slf4j
public class AutoFillAspect {/*** 切入点:对那些类,那些方法进行拦截* 在切入点表达式里:如果想要缩小Spring的扫描范围,可以使用多切入点表达式连接 连接符 &&进行条件组合*  “ * ”:返回值是所有的*  “ com.js.mapper.*.*(..) ”:拦截这个mapper文件夹下面的所有类.方法(参数类型)*  “@annotation(com.js.annotation.AutoFill)” :拦截com.js.mapper中方法加了这个注解的方法*  。*/@Pointcut("execution(* com.js.mapper.*.*(..)) && @annotation(com.js.annotation.AutoFill)")public void autoFillPointCut(){}/*** 前置通知,在通知中进行公共字段的赋值* “joinPoint” :连接点,知道那个被拦截到的方法具体的参数是啥样的*/@Before("autoFillPointCut()")public void autoFill(JoinPoint joinPoint){log.info("开始进行公共字段自动填充...");/*** Java里如果要调用一个方法,有两种方式*   方式1:对象名.方法名(实参)*   方式2:反射调用方法*       先获取目标类的字节码*       在获取想要调用的方法*       最后反射执行这个方法*///1.获取到当前被拦截的方法上的数据库操作类型MethodSignature signature = (MethodSignature) joinPoint.getSignature();//方法签名对象AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获得方法上的注解对象OperationType operationType = autoFill.value();//获得数据库操作类型:新增,还是修改//2.获取所有添加注解并且被拦截的方法所有的参数--实体对象/*** 注意:*   如果想实现自动填充的话,一定要保证方法中参数的实体对象 Name Name,放在第一个位置,接下来我们要获取的话,*   就获取第一个就行,不管之后有多少参数,我们就获取第一个就行,这就是我们的约定*/// 为了提高程序的健壮性,加一个判断:如果方法没有实参,就什么都不做Object[] args = joinPoint.getArgs();if(args == null || args.length == 0){return;}Object entity = args[0];//3.准备赋值的数据LocalDateTime now = LocalDateTime.now();//---创建人信息:一般从ThreadLocal中获取,这里就给个默认值String currentId = "张三";//新增String updateId = "丰奶大硕";//修改//根据当前不同的操作类型,为对应的属性通过反射来赋值if(operationType == OperationType.INSERT){//新增操作//为4个公共字段赋值try {Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);Method setCreateName = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_NAME, String.class);//通过反射为对象属性赋值setCreateTime.invoke(entity,now);setCreateName.invoke(entity,currentId);} catch (Exception e) {e.printStackTrace();}}else if(operationType == OperationType.UPDATE){//为2个公共字段赋值try {Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateName = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_NAME, String.class);//通过反射为对象属性赋值setUpdateTime.invoke(entity,now);setUpdateName.invoke(entity,updateId);} catch (Exception e) {e.printStackTrace();}}}
}
4.4 mapper方法上面添加相应注解,和操作类型
package com.js.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.js.Enum.OperationType;
import com.js.annotation.AutoFill;
import com.js.domain.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;/*** @description: 用户mapper* @author:js* @date:2024/1/17 14:55* @version:3.0*/@Mapper
public interface UserMapper extends BaseMapper<User> {/*** 插入数据** @param user* @return*/@Insert("insert into User( name, age , create_time, update_time, create_name, update_name)" +" VALUES" +" (#{name}, #{age}, #{createTime}, #{updateTime}, #{createName}, #{updateName})")@AutoFill(value = OperationType.INSERT)int insert(User user);/*** 根据id修改分类* @param User*/@AutoFill(value = OperationType.UPDATE)void updated( @Param("user") User user);
}
4.5 mapper.xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.js.mapper.UserMapper"><update id="updated">update userset name=#{user.name},age=#{user.age},update_time=#{user.updateTime},update_name=#{user.updateName}whereid=#{user.id}</update>
</mapper>
4.6. 测试:
新增:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

修改:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

MySQL之索引详细总结

索引简介 索引是帮助MySQL高效获取数据的数据结构(有序)。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种方式引用(指向)数据&#xff0c;这样就可以在这些数据结构上实现高级查法&#xff0c;这种数据结构就是索引 为什…

基于rip环境下的MGRE综合实验

实验要求 1、R5为ISP&#xff0c;只能进行IP地址配置&#xff0c;其所有地址均配为公有IP地址。 2、&#xff08;1&#xff09;R1和R5间使用PPP的PAP认证&#xff0c;R5为主认证方。 &#xff08;2&#xff09;R2与R5之间使用ppp的CHAP认证&#xff0c;R5为主认证方。 &#…

YoloV8改进策略:Neck改进|GCNet(独家原创)|附结构图

摘要 本文使用GCNet注意力改进YoloV8,在YoloV8的Neck中加入GCNet实现涨点。改进方法简单易用&#xff0c;欢迎大家使用&#xff01; 论文:《GCNet: Non-local Networks Meet Squeeze-Excitation Networks and Beyond》 非局部网络&#xff08;NLNet&#xff09;通过为每个查…

ElasticSearch7.8的下载与安装和Kibana 7.8.0工具使用安装

1、ElasticSearch7.8.0下载 elasticsearch: 官方下载地址&#xff1a;https://www.elastic.co/cn/downloads/elasticsearch 链接: https://pan.baidu.com/s/1wAKQoB3nhLhcnBlPfVOLxQ 提取码: t83n kibana: 链接: https://pan.baidu.com/s/156aD9zDdvUv8LFgDEIPoSw 提取码:…

PSCAD的使用

1. Canvas Settings中设置母线电压监测和虚拟连线十分重要。 2. Project Settings中snapshot可以实现分段仿真。 3. .out文献导出数据

操作系统—读者-写者问题及Peterson算法实现

文章目录 I.读者-写者问题1.读者-写者问题和分析2.读者—写者问题基本解法3.饥饿现象和解决方案总结 II.Peterson算法实现1.Peterson算法问题与分析(1).如何无锁访问临界区呢&#xff1f;(2).Peterson算法的基本逻辑(3).写对方/自己进程号的区别是&#xff1f; 2.只包含意向的解…

图神经网络实战(7)——图卷积网络(Graph Convolutional Network, GCN)详解与实现

图神经网络实战&#xff08;7&#xff09;——图卷积网络详解与实现 前言1. 图卷积层2. 比较 GCN 和 GNN2.1 数据集分析2.2 实现 GCN 架构 小结系列链接 前言 图卷积网络 (Graph Convolutional Network, GCN) 架构由 Kipf 和 Welling 于 2017 年提出&#xff0c;其理念是创建一…

基于springboot+vue+Mysql的教学视频点播系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

idea使用docker将Java项目生成镜像并使用

1&#xff1a;开启docker 远程访问 使用 vim 编辑docker服务配置文件 vim /lib/systemd/system/docker.service [Service] Typenotify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not suppor…

操作系统内功篇:内存管理之虚拟内存

一 虚拟内存 在这种情况下&#xff0c;要想在内存中同时运行两个程序是不可能的。如果第一个程序在 2000 的位置写入一个新的值&#xff0c;将会擦掉第二个程序存放在相同位置上的所有内容&#xff0c;所以同时运行两个程序是根本行不通的&#xff0c;这两个程序会立刻崩溃。 …

最简单的 AAC 音频码流解析程序

最简单的 AAC 音频码流解析程序 最简单的 AAC 音频码流解析程序原理源程序运行结果下载链接参考 最简单的 AAC 音频码流解析程序 参考雷霄骅博士的文章&#xff1a;视音频数据处理入门&#xff1a;AAC音频码流解析 本文中的程序是一个AAC码流解析程序。该程序可以从AAC码流中…

Linux(05) Debian 系统修改主机名

查看主机名 方法1&#xff1a;hostname hostname 方法2&#xff1a;cat etc/hostname cat /etc/hostname 如果在创建Linux系统的时候忘记修改主机名&#xff0c;可以采用以下的方式来修改主机名称。 修改主机名 注意&#xff0c;在linux中下划线“_”可能是无效的字符&…

数据结构(初阶)第一节:数据结构概论

本篇文章是对数据结构概念的纯理论介绍&#xff0c;希望系统了解数据结构概念的友友可以看看&#xff0c;对概念要求不高的友友稍做了解后移步下一节&#xff1a; 数据结构&#xff08;初阶&#xff09;第二节&#xff1a;顺序表-CSDN博客 正文 目录 正文 1.数据结构的相关概…

qqqqqqq

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…

Polardb MySQL 产品架构及特性

一、产品概述; 1、产品族 参考&#xff1a;https://edu.aliyun.com/course/3121700/lesson/341900000?spma2cwt.28120015.3121700.6.166d71c1wwp2px 2、polardb mysql架构优势 1&#xff09;大容量高弹性&#xff1a;最大支持存储100T&#xff0c;最高超1000核CPU&#xff0…

open Gauss 数据库-03 openGauss数据库维护管理指导手册

发文章是为了证明自己真的掌握了一个知识&#xff0c;同时给他人带来帮助&#xff0c;如有问题&#xff0c;欢迎指正&#xff0c;祝大家万事胜意&#xff01; 目录 前言 openGauss数据库维护管理 1 操作系统参数检查 1.1 实验介绍 1.2 场景设置及操作步骤 2 openGauss 运…

认识什么是Webpack

目录 1. 认识Webpack 1.1. 什么是Webpack?&#xff08;定义&#xff09; 1.2. 使用Webpack 1.2.1. 需求 1.2.2. 步骤 1.3. 入口和出口默认值 1.3.1. 需求代码如下 2. 修改Webpack打包入口和出口 2.1. 步骤&#xff1a; 2.2. 注意 3. Webpack自动生成html文件 3.1.…

D-迷恋网游(遇到过的题,做个笔记)

我的代码&#xff1a; #include <iostream> using namespace std; int main() {int a, b, c; //a表示内向&#xff0c;b表示外向&#xff0c;c表示无所谓cin >> a >> b >> c; //读入数 if (b % 3 0 || 3-b % 3 < c) //如果外向的人能够3人组成…

真·面试题总结——JVM虚拟机

JVM虚拟机 JVM虚拟机规范与实现 JVM虚拟机规范 JVM虚拟机实现 JVM的常见实现 JVM虚拟机物理架构 JVM虚拟机的运转流程 JVM类加载过程 JVM类加载器及类加载器类型 JVM类加载器双亲委派机制 JVM运行时数据区的内存模型 JVM运行时数据区的内存模型&#xff1a;程序计数器…

蓝桥杯第八届c++大学B组详解

目录 1.购物单 2.等差素数列 3.承压计算 4.方格分割 5.日期问题 6.包子凑数 7.全球变暖 8.k倍区间 1.购物单 题目解析&#xff1a;就是将折扣字符串转化为数字&#xff0c;进行相加求和。 #include<iostream> #include<string> #include<cmath> usin…