提高开发效率:公共字段自动化填充方案

目录

问题描述

解决方案

Mybatis-Plus

AOP+注解

方案比较

MyBatis-Plus 自动填充功能

AOP + 注解


问题描述

当我们在开发过程中,处理像创建时间、创建人等这样的公共字段会显得比较繁琐,尤其是在每个实体都需要这些信息的情况下。就比如,每次执行新增操作时,总要在业务逻辑中进行繁琐的添加。

解决方案

Mybatis-Plus

MyBatis-Plus 是一个 MyBatis 的增强工具,旨在简化开发、提高效率。它提供了许多便捷的功能,包括自动填充功能(Field Fill),可以用于实现公共字段如创建时间、更新时间等的自动填充.

第一步,加入BaseContex工具类,获取当前用户线程ID

/***  功能:实现了一个基于ThreadLocal的线程上下文管理工具类*/
public class BaseContext {public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();// 提供静态方法setCurrentId用于设置当前线程的IDpublic static void setCurrentId(Long id) {threadLocal.set(id);}// 提供静态方法getCurrentId用于获取当前线程的IDpublic static Long getCurrentId() {return threadLocal.get();}// 提供静态方法removeCurrentId用于清除当前线程的IDpublic static void removeCurrentId() {threadLocal.remove();}}

第二步,实现 MetaObjectHandler 接口:创建一个类实现 MetaObjectHandler 接口,并重写其中的方法,以指定在插入或更新操作时如何填充字段。

@Component
public class MybatisPlusHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {// 插入时,填充字段this.setFieldValByName("createTime", LocalDateTime.now(), metaObject);this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);this.setFieldValByName("createUser", BaseContext.getCurrentId(), metaObject);this.setFieldValByName("updateUser", BaseContext.getCurrentId(), metaObject);}@Overridepublic void updateFill(MetaObject metaObject) {// 更新时,填充字段this.setFieldValByName("updateTime", System.currentTimeMillis(), metaObject);this.setFieldValByName("updateUser", BaseContext.getCurrentId(), metaObject);}
}

第三步配置实体类:在需要自动填充的实体类字段上添加 @TableField 注解,并指定 fill 属性。

    /*** 创建时间*/@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;/*** 创建人*/@TableField(fill = FieldFill.INSERT)private String createUser;/*** 更新时间*/@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime updateTime;/*** 更新人*/@TableField(fill = FieldFill.INSERT_UPDATE)private String updateUser;

事实上,虽然 MyBatis-Plus 提供了自己的注解 @TableField 来支持字段填充策略,但你也可以自定义注解来满足特定需求。

AOP+注解

我们都知道自定义注解结合AOP(面向切面编程):可以创建自定义注解,并结合AOP技术,在方法执行前后自动注入如创建时间、创建人等信息。这种方法特别适合于需要在多个地方复用的场景,而且不会侵入原有的业务逻辑代码。

在真实企业开发中,为了规范化与提高扩展性,我们往往会加入枚举,常量来进行优化设计。

首先,假设我们有创建时间,创建人,修改时间,修改人四个公共字段

第一步,创建一个常量类(原因:规范化操作)

/*** 公共字段自动填充相关常量*/
public class AutoFillConstant {/*** 实体类中的方法名称*/public static final String SET_CREATE_TIME = "setCreateTime";public static final String SET_UPDATE_TIME = "setUpdateTime";public static final String SET_CREATE_USER = "setCreateUser";public static final String SET_UPDATE_USER = "setUpdateUser";
}

第二步,创建一个枚举类(原因:可以区分数据库操作类型,方便进行不同的操作)

/*** 数据库操作类型*/
public enum OperationType {/*** 更新操作*/UPDATE,/*** 插入操作*/INSERT}

第三步,创建一个注解类(原因:方便在方法上使用)

/*
* 自定义注解,用于标识某个方法需要进行功能字段自动填充处理
* */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {//数据库操作类型 UPDATE INSERTOperationType value();
}

第四步,自定义切面类(实现公共字段填充逻辑)

/*
* 自定义切面,实现公共字段自动填充处理逻辑
* */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {/*** 切入点* 匹配com.sky.mapper包下所有方法的执行。* 仅对标注了@AutoFill注解的方法生效。*/@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];//准备赋值的数据LocalDateTime now = LocalDateTime.now();Long currentId = BaseContext.getCurrentId();//根据当前不同的操作类型,为对应的属性通过反射来赋值if(operationType == OperationType.INSERT){//为4个公共字段赋值try {//过反射获取实体类中的四个方法Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);//通过反射为对象属性赋值setCreateTime.invoke(entity,now);setCreateUser.invoke(entity,currentId);setUpdateTime.invoke(entity,now);setUpdateUser.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 setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);//通过反射为对象属性赋值setUpdateTime.invoke(entity,now);setUpdateUser.invoke(entity,currentId);} catch (Exception e) {e.printStackTrace();}}}
}

使用前置通知的原因:我们必须在方法执行前就完成赋值,不能等SQL语句执行完,否则无意义。

实现原理:我们通过反射得到实体类中的setter方法,对公共字段进行值填充,通过注解直接加入到方法上,实现需求。

方案比较

MyBatis-Plus 自动填充功能

优势:

  1. 集成简便:MyBatis-Plus 的自动填充功能与框架本身紧密结合,只需少量配置即可快速上手。
  2. 性能优化:由于是直接在数据访问层进行操作,相比AOP方式可能会有更少的性能开销。
  3. 代码简洁:通过简单的注解和少量的处理器类代码就可以实现对公共字段的自动管理,减少了样板代码。
  4. 易于维护:所有关于公共字段填充的逻辑都集中在一处,便于统一管理和调整。

AOP + 注解

优势:

  1. 灵活性高:可以针对不同的数据库操作类型(如插入、更新)灵活地应用不同的填充策略,并且能够方便地扩展以支持更多类型的处理。
  2. 不侵入业务逻辑:通过AOP切面的方式,在不修改原有业务逻辑的情况下完成公共字段的自动填充,保持了业务代码的清晰度。
  3. 高度定制化:可以根据实际需要自定义注解、常量、枚举等元素,为系统提供更加细致和个性化的控制。
  4. 增强的可读性:利用注解明确标识出哪些方法需要进行公共字段的自动填充,提高了代码的可读性和自我解释能力。

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

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

相关文章

【2025】基于python+django的慢性病健康管理系统(源码、万字文档、图文修改、调试答疑)

系统功能结构图如下 慢性病健康管理系统 课题背景 随着全球人口老龄化的加剧以及生活方式的改变&#xff0c;慢性病的发病率呈上升趋势&#xff0c;给个人健康和社会医疗资源带来了巨大压力。传统的慢性病管理模式存在信息不畅、患者参与度低、医疗资源分配不均等问题&#xf…

2.2 B/S架构和Tomcat服务器

本文介绍了B/S架构、Tomcat服务器及其与IDEA的整合。B/S架构是一种基于浏览器的网络计算模式&#xff0c;具有跨平台、易用性强的特点&#xff0c;适用于互联网应用。Tomcat是Apache开源的Web服务器&#xff0c;支持Java Web应用的部署和运行。文章通过实例演示了如何下载、安装…

QT非UI设计器生成界面的国际化

目的 UI设计器生成界面的国际化&#xff0c;比较容易实现些&#xff0c;因为有现成的函数可以调用&#xff0c;基本过程如下&#xff1a; void MainWindow::on_actLang_CN_triggered() {//中文界面qApp->removeTranslator(trans);delete trans;transnew QTranslator;trans…

Hackme靶机通关攻略

1&#xff0c;打开靶机和kali&#xff0c;在kali终端中扫描靶机ip,得到靶机ip为192.168.50.137 arp-scan -l 2&#xff0c;使用工具扫描出后台目录后访问login.php 3&#xff0c;注册后登陆发现有输入框&#xff0c;可以尝试使用sql注入来得到用户名和密码&#xff0c;密码需要…

国产编辑器EverEdit - 工具栏自定义及认识工具栏上的按钮

1 设置-高级-工具条 1.1 设置说明 1.1.1 工具条自定义 选择主菜单工具 -> 设置 -> 常规&#xff0c;在弹出的选项窗口中选择工具条分类&#xff0c;如下图所示&#xff1a; 左侧窗口是当前支持所有功能按钮列表(上图中居中栏)&#xff0c;右侧的窗口是当前显示在工具栏…

docker安装rabbitmq

第一步直接dokce拉取rabbitmq镜像docker 利用docker直接拉取镜像最新版&#xff1a;docker search rabbitmq 运行mq&#xff1a; 需要注意的是-p 5673:5672 解释&#xff1a;-p 外网端口&#xff1a;docker的内部端口 &#xff0c;你们可以改成自己的外网端口号&#xff0c;我这…

【实战ES】实战 Elasticsearch:快速上手与深度实践-8.2.2成本优化与冷热数据分离

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 8.2.2AWS OpenSearch Serverless 成本优化与冷热数据分离深度实践1. 成本构成分析与优化机会识别1.1 Serverless模式成本分布1.2 冷热数据特征分析数据特征矩阵 2. 冷热数据…

安卓edge://inspect 和 chrome://inspect调试移动设备上的网页

edge://inspect 和 chrome://inspect 是用于调试浏览器中运行的网页和移动设备上的网页的工具。这两个工具分别属于 Microsoft Edge 和 Google Chrome 浏览器。以下是它们的详细介绍&#xff1a; chrome://inspect 如果是直接使用数据线调试&#xff0c;则只需要执行下面的第一…

checkpoint机制

1、什么是checkpoint 将缓冲池中的脏页刷新到磁盘&#xff0c;并更新redo log的checkpoint位点&#xff0c;确保数据库在发生故障时可以快速恢复到一致的状态。 2、checkpoint执行过程 确保需要刷新的脏页&#xff1a;从缓冲池中选取一部分需要刷新的页数据页刷新&#xff1…

【微服务日志收集①】使用FileBeat+Logstash+ES搭建ELK日志系统

使用FileBeatLogstashES搭建ELK日志系统&#xff0c;架构图如下&#xff1a; 1、 使用docker快速创建ES服务和Kibana服务 前置条件&#xff1a;需要在linux上提前安装好docker和docker-compose 1.1、在linux创建好一个用于存放docker-compose配置文件的文件夹 我的目录是/app/…

Centos 7 安装达梦数据库

一、环境准备 1. 确认操作系统的版本和数据库的版本是否一致 cat /etc/redhat-release 2. 关闭防火墙 查看防火墙状态 firewall-cmd --state 停止firewall systemctl stop firewalld.service 禁止firewall开机启动 systemctl disable firewalld.service 3. 修改文件l…

仿“东方甄选”直播商城小程序运营平台

在公域直播流量红利趋于饱和、流量成本大幅攀升的当下&#xff0c;私域直播为企业开辟了新的流量聚集和转化渠道&#xff0c;特别是对于那些希望在私域流量领域取得突破的品牌商家来说&#xff0c;直播场景以其独特的高频互动氛围&#xff0c;相比其他运营方式&#xff0c;展现…

ZED X系列双目3D相机的耐用性与创新设计解析

在工业自动化和学术研究领域&#xff0c;高精度的视觉设备正成为提升效率和质量的关键。ZED X系列AI立体相机&#xff0c;凭借其先进的技术和耐用的设计&#xff0c;为这一领域带来了新的可能。 核心技术&#xff1a;深度感知与精准追踪 ZED X系列的核心技术之一是Neural Dept…

Cursor的使用感受,帮你使用好自动化编程工具,整理笔记

使用感受 说实话&#xff0c;我觉得cursor还是好用的&#xff0c;可能我刚开始使用&#xff0c;没有使用的非常的熟练&#xff0c;运用也没有非常的透彻&#xff0c;总体体验还是不错的&#xff0c;在使用它时&#xff0c;我优先考虑&#xff0c;前端页面功能复用的时候&#…

《C#上位机开发从门外到门内》3-5:基于FastAPI的Web上位机系统

文章目录 一、项目概述二、系统架构设计三、前后端开发四、数据可视化五、远程控制六、系统安全性与稳定性七、性能优化与测试八、实际应用案例九、结论 随着互联网技术的快速发展&#xff0c;Web上位机系统在工业自动化、智能家居、环境监测等领域的应用日益广泛。基于FastAPI…

vue3单独引用element-plus的Infinite Scroll无限滚动;vue3自定义指令

文章目录 1.正常单独使用element-plus其他功能组件2.引入类似与指令的插件3.自定义指令钩子 1.正常单独使用element-plus其他功能组件 引入即可使用 import { ElSelect, ElOption } from "element-plus"2.引入类似与指令的插件 需要先引入&#xff0c;再注册&…

CMake学习笔记(二):变量设值,源文件/文件查找

一_变量设值: 在上一节中我们知道了如何去链接起来多个源文件并且生成可执行文件&#xff0c;但是当我们的源文件过多的时候会导致我们在add_executable里面写很长的一串&#xff0c;所以我们可以使用变量来进行设值: set(<variable> <value>... [PARENT_SCOPE])…

【Function】Azure Function通过托管身份或访问令牌连接Azure SQL数据库

【Function】Azure Function通过托管身份或访问令牌连接Azure SQL数据库 推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战目录 【Function】Azure Function通过托管身份或访问令牌连接Azu…

案例5_1:单位数码管显示0

文章目录 文章介绍效果图仿真图5_1放置单位数码管 代码5_1.c 文章介绍 效果图 仿真图5_1 复制案例1_2的仿真图&#xff0c;在此基础上修改 注意&#xff1a;栅格大小需要缩小 放置单位数码管 代码5_1.c #include <reg52.h>#define uchar unsigned char #define uint un…

helm部署metricbeat

背景 在Elastic Stack 7.5版本之前&#xff0c;系统默认采用内置服务进行监控数据采集&#xff08;称为内部收集机制&#xff09;&#xff0c;这种设计存在显著局限性&#xff1a; 当ES集群崩溃时自带的节点监控也会随之崩溃&#xff0c;直到集群恢复前&#xff0c;崩溃期间的…