手写Mybatis自动填充插件

目录

  • 一、Mybatis插件简介🥙
  • 二、工程创建及前期准备工作🥫
    • 实现代码
    • 配置文件
  • 三、插件核心代码实现🍗
  • 四、测试🥓

一、Mybatis插件简介🥙

Mybatis插件运行原理及自定义插件_简述mybatis的插件运行原理,以及如何编写一个插件-CSDN博客

MyBatis 是一款优秀的持久层框架,它简化了数据库操作过程,提供了强大的 SQL 映射功能。MyBatis 插件是用来扩展 MyBatis 框架功能的工具,可以通过插件来定制和增强 MyBatis 的功能。

MyBatis 插件可以用来实现一些自定义的功能,比如拦截 SQL 语句、修改 SQL 语句、添加新的功能等。通过插件,我们可以在 MyBatis 框架的各个阶段进行干预和扩展,从而实现更灵活、更强大的功能。

通常情况下,编写一个 MyBatis 插件需要实现 MyBatis 提供的接口,并在配置文件中注册插件。Mybatis只支持针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口

总的来说,MyBatis 插件是一种扩展机制,可以让我们更好地定制和增强 MyBatis 框架的功能,使得我们能够更好地适应各种不同的业务需求。

二、工程创建及前期准备工作🥫

以下都为前期准备工作,可直接略过,插件核心实现代码在第三节

PixPin_2024-03-11_14-26-17

PixPin_2024-03-11_14-27-44

创建test数据库

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (`id` int NOT NULL AUTO_INCREMENT,`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,`create_time` datetime NULL DEFAULT NULL,`update_time` datetime NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;

实现代码

本实验省略了Controller和Service

User.java

package com.example.mybatisplugin.entity;import com.example.mybatisplugin.anno.FiledFill;import java.io.Serial;
import java.time.LocalDateTime;
import java.util.Date;
import java.io.Serializable;/*** (User)实体类** @author makejava* @since 2024-03-11 14:41:35*/
public class User implements Serializable {@Serialprivate static final long serialVersionUID = 813676794892349198L;private Integer id;private String username;private String password;@FiledFill(fill = FiledFill.FillType.INSERT)private Date createTime;@FiledFill(fill = FiledFill.FillType.INSERT_UPDATE)private Date updateTime;//省略了getter和setter方法@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +", createTime=" + createTime +", updateTime=" + updateTime +'}';}
}

其中@FiledFill注解是自定义注解,文章后面会写到,可暂时不用添加

UserDao.java

@Mapper
public interface UserDao {/*** 新增数据** @param user 实例对象* @return 影响行数*/int insert(User user);/*** 修改数据** @param user 实例对象* @return 影响行数*/int update(User user);}

UserDao.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mybatisplugin.dao.UserDao"><resultMap type="com.example.mybatisplugin.entity.User" id="UserMap"><result property="id" column="id" jdbcType="INTEGER"/><result property="username" column="username" jdbcType="VARCHAR"/><result property="password" column="password" jdbcType="VARCHAR"/><result property="createTime" column="create_time" jdbcType="TIMESTAMP"/><result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/></resultMap><!--新增所有列--><insert id="insert" keyProperty="id" useGeneratedKeys="true">insert into user(username,password,create_time,update_time)values (#{username},#{password},#{createTime},#{updateTime})</insert><!--通过主键修改数据--><update id="update">update user<set><if test="username != null and username != ''">username = #{username},</if><if test="password != null and password != ''">password = #{password},</if><if test="createTime != null">create_time = #{createTime},</if><if test="updateTime != null">update_time = #{updateTime},</if></set>where id = #{id}</update>
</mapper>

配置文件

application.yaml
数据库密码记得改成自己的

spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: *****url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
server:port: 8080
mybatis:config-location: classpath:mybatis-config.xmlmapper-locations: classpath:mapper/*.xml

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC"-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><settings><!-- 设置驼峰标识 --><setting name="mapUnderscoreToCamelCase" value="true"/><!-- 打印SQL语句 --><setting name="logImpl" value="STDOUT_LOGGING"/></settings>
</configuration>

三、插件核心代码实现🍗

自定义注解FiledFill

package com.example.mybatisplugin.anno;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @Author YZK* @Date 2024/3/11*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FiledFill {enum FillType {INSERT, INSERT_UPDATE,}FillType fill();
}

插件核心代码

package com.example.mybatisplugin.plugin;import com.example.mybatisplugin.anno.FiledFill;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;/*** @Author YZK* @Date 2024/3/11* @Desc*/
@Intercepts({@Signature(type = Executor.class,method = "update",args = {MappedStatement.class, Object.class})})
public class MybatisAutoFill implements Interceptor {private static final Logger LOGGER = Logger.getLogger(MybatisAutoFill.class.getName());public Object intercept(Invocation invocation) throws Throwable {MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];//获取操作类型(INSERT和UPDATE)SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();//拿到SQL中传入的对象Object obj = invocation.getArgs()[1];//获取其字节对象Class<?> clazz = obj.getClass();//获取User类声明的所有字段Field[] fields = clazz.getDeclaredFields();//通过区分SQL的操作来进行不同的字段填充if (sqlCommandType == SqlCommandType.INSERT) {//是INSERT操作的话就同时填充createTime和updateTime字段fillInsertFields(obj, fields);} else if (sqlCommandType == SqlCommandType.UPDATE) {//是updateTime字段的话就只填充updateTime字段fillUpdateFields(obj, fields);}return invocation.proceed();}private void fillInsertFields(Object obj, Field[] fields) {Arrays.stream(fields)//过滤出所有带有@FiledFill注解的字段.filter(field -> field.isAnnotationPresent(FiledFill.class)).forEach(field -> {try {//对字段进行填充setFieldValue(obj, field);} catch (IllegalAccessException e) {LOGGER.log(Level.SEVERE, "字段填充错误", e);}});}private void fillUpdateFields(Object obj, Field[] fields) {Arrays.stream(fields)//过滤出所有带有@FiledFill注解的字段,以及注解值为INSERT_UPDATE的字段.filter(field -> field.isAnnotationPresent(FiledFill.class) &&field.getAnnotation(FiledFill.class).fill() == FiledFill.FillType.INSERT_UPDATE).forEach(field -> {try {//对字段进行填充setFieldValue(obj, field);} catch (IllegalAccessException e) {LOGGER.log(Level.SEVERE, "字段填充错误", e);}});}private void setFieldValue(Object obj, Field field) throws IllegalAccessException {//填充字段field.setAccessible(true);field.set(obj, new Date());}
}

mybatis-condig.xml配置文件中进行配置,将自定义的插件注册

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC"-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><settings><!-- 设置驼峰标识 --><setting name="mapUnderscoreToCamelCase" value="true"/><!-- 打印SQL语句 --><setting name="logImpl" value="STDOUT_LOGGING"/></settings><plugins><plugin interceptor="com.example.mybatisplugin.plugin.MybatisAutoFill"/></plugins>
</configuration>

四、测试🥓

插入操作

@Test
void contextLoads() {User user = new User();user.setUsername("笑的像个child");user.setPassword("123456");userDao.insert(user);
}

控制台打印的SQL

image-20240311225847571

image-20240311225857627

进行插入操作时create_time和update_time字段被同时填充

更新操作

    @Testvoid contextLoads() {User user = new User();user.setId(33);user.setUsername("笑的像个child");user.setPassword("12345678");userDao.update(user);}

控制台打印的SQL

image-20240311225948551

image-20240311230032331

进行更新时操作时update_time字段被填充

进行删除操作时,如果是硬删除,则记录被删除,软删除时同样是更新操作,字段也会被自动填充。

本插件还有许多需要完善的地方,只是自动填充的简单实现,如有需要,可以自己完善。

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

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

相关文章

macOS Ventura 13.6.5 (22G621) Boot ISO 原版可引导镜像下载

macOS Ventura 13.6.5 (22G621) Boot ISO 原版可引导镜像下载 3 月 8 日凌晨&#xff0c;macOS Sonoma 14.4 发布&#xff0c;同时带来了 macOS Ventru 13.6.5 和 macOS Monterey 12.7.4 安全更新。 macOS Ventura 13.6 及更新版本&#xff0c;如无特殊说明皆为安全更新&…

springboot学习(八十六) springboot使用graalvm编译native程序

一、windows环境下 1.下载graalvm的jdk https://injdk.cn/ 下载windows版本 配置java环境变量&#xff0c;配置过程略 2.下载visual Studio Build Tools 下载地址&#xff1a;https://aka.ms/vs/17/release/vs_BuildTools.exe 安装后选择组件&#xff1a; 其中windows S…

ChatGPT-Next-Web SSRF漏洞+XSS漏洞复现(CVE-2023-49785)

0x01 产品简介 ChatGPT-Next-Web 是一种基于 OpenAI 的 GPT-3.5 、GPT-4.0语言模型的产品。它是设计用于 Web 环境中的聊天机器人,旨在为用户提供自然语言交互和智能对话的能力。 0x02 漏洞概述 2024年3月,互联网上披露CVE-2023-49785 ChatGPT-Next-Web SSRF/XSS 漏洞,未经…

信号与系统学习笔记——信号的分类

目录 一、确定与随机 二、连续与离散 三、周期与非周期 判断是否为周期函数 离散信号的周期 结论 四、能量与功率 定义 结论 五、因果与反因果 六、阶跃函数 定义 性质 七、冲激函数 定义 重要关系 作用 一、确定与随机 确定信号&#xff1a;可以确定时间函数…

Arcgis新建位置分配求解最佳商店位置

背景 借用Arcgis帮助文档中的说明:在本练习中,您将为连锁零售店选择可以获得最大业务量的商店位置。主要目标是要将商店定位在人口集中地区附近,因为这种区域对商店的需求量较大。设立这一目标的前提是假设人们往往更多光顾附近的商店,而对于距离较远的商店则较少光顾。您…

【Redis】Redis常用命令之Hash

1.hset&#xff1a;设置hash中指定的字段&#xff08;field&#xff09;的值&#xff08;value&#xff09;。 HSET key field value [field value ...]时间复杂度&#xff1a;插⼊⼀组field为O(1),插⼊N组field为O(N)。 返回值&#xff1a;添加的字段的个数。 2.hget&#xf…

MySQL删除数据 文件大小不变的原因以及处理空洞问题

数据删除流程 InnoDB 里的数据都是用 B 树的结构组织的。 假设&#xff0c;我们要删掉 R4 这个记录&#xff0c;InnoDB 引擎只会把 R4 这个记录标记为删除。如果之后要再插入一个 ID 在 300 和 600 之间的记录时&#xff0c;可能会复用这个位置。但是&#xff0c;磁盘文件的大…

Elastic Agent 的安装及使用

概述 Elastic Agent是Elastic Stack中的一个全新组件&#xff0c;旨在简化和统一监控和集成管理流程。它是一个轻量级的代理&#xff0c;可以部署到各种不同类型的主机和容器中&#xff0c;用于收集系统指标、日志和事件数据&#xff0c;并将其发送到Elasticsearch进行存储和分…

Python网络基础爬虫-python基本语法

文章目录 逻辑语句if,else,elifforwhile异常处理 函数与类defpassclass 逻辑语句 熟悉C/C语言的人们可能很希望Python提供switch语句&#xff0c;但Python中并没有这个关键词&#xff0c;也没有这个语句结构。但是可以通过if-elif-elif-…这样的结构代替&#xff0c;或者使用字…

挑战OpenAI的新模型免费上线,40%计算量性能逼近GPT-4

据介绍,Inflection-2.5 将强大的 LLM 能力与 Inflection 标志性的「同理心微调」结合在一起,兼具高情商与高智商,可联网获取事实信息,其性能可与 GPT-4、Gemini 等领先大模型相媲美。 本周四,美国 AI 创业公司 Inflection AI 正式发布新一代大语言模型 Inflection-2.5。 …

福派斯猫粮的适口性有何特点?

亲爱的朋友们&#xff0c;今天我想和大家分享一下福派斯猫粮的适口性特点。作为一位养猫多年的铲屎官&#xff0c;我深知猫粮的适口性对于猫咪的健康和幸福是多么重要。那么&#xff0c;福派斯猫粮在这方面究竟有何独到之处呢&#xff1f; 1️⃣ 首先&#xff0c;福派斯猫粮的口…

分类预测 | Matlab实现GSWOA-KELM混合策略改进的鲸鱼优化算法优化核极限学习机的数据分类预测

分类预测 | Matlab实现GSWOA-KELM混合策略改进的鲸鱼优化算法优化核极限学习机的数据分类预测 目录 分类预测 | Matlab实现GSWOA-KELM混合策略改进的鲸鱼优化算法优化核极限学习机的数据分类预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 GSWOA-KELM分类&#xff0…

sqllab第十九关通关笔记

知识点&#xff1a; 错误注入 最大长度为32位&#xff1b;如果目标长度>32时&#xff0c;需要利用截取函数进行分段读取referer注入 insert语句update语句 通过admin admin进行登录发现页面打印除了referer字段的信息 这应该是一个referer注入 首先进行测试一下 构造payl…

Windows安装Kibana之保姆级教程

Kibana 安装 介绍&#xff1a;一款开源的数据分析和可视化平台&#xff0c;可对Elasticsearch 索引中的数据进行搜索、查看、交互操作&#xff1b;可理解为 Elasticsearch 的web管理后台 下载&#xff1a;点击https://www.elastic.co/cn/downloads/past-releases#kibana-->…

探索编程新纪元:Code GeeX、Copilot与通义灵码的智能辅助之旅

在人工智能技术日新月异的今天&#xff0c;编程领域的革新也正以前所未有的速度推进。新一代的编程辅助工具&#xff0c;如Code GeeX、Copilot和通义灵码&#xff0c;正在重塑开发者的工作流程&#xff0c;提升编程效率&#xff0c;并推动编程教育的普及。本文将深入探讨这三款…

2023 收入最高的十大编程语言

本期共享的是 —— 地球上目前已知超过 200 种可用的编程语言&#xff0c;了解哪些语言在 2023 为开发者提供更高的薪水至关重要。 过去一年里&#xff0c;DevJobsScanner 分析了来自地球各地超过 1000 万个开发职位空缺&#xff0c;辅助我们了解市场&#xff0c;以及人气最高…

SpringMVC请求、响应和拦截器的使用

SpringMVC请求 RequestMapping注解 RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系 RequestMapping注解可以作用在方法和类上 1. 作用在类上&#xff1a;第一级的访问目录 2. 作用在方法上&#xff1a;第二级的访问目录 3. 细节&#xff1a;路径可以不编写…

基于大语言模型(LLM)的表格理解任务探索与实践

大语言模型&#xff08;LLMs&#xff09;的发展日新月异&#xff0c;为表格理解任务带来了新的可能性。表格理解任务&#xff0c;如基于表格的问答和表格事实验证&#xff0c;要求从自由形式的文本和半结构化的表格数据中提取深层次的语义信息。与泛化的文本推理任务不同&#…

外包干了5天,技术明显退步。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入南京某软件公司&#xff0c;干了接近2年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了2年的功能测试&…

深入理解TCP的四次分手过程

文章目录 深入理解TCP的四次分手过程四次分手的意义四次分手的工作原理四次分手的重要性实际应用中的考虑结论补充:TIME_WAIT在哪一步?TIME_WAIT状态的目的TIME_WAIT状态的影响 深入理解TCP的四次分手过程 在网络通信中&#xff0c;TCP&#xff08;传输控制协议&#xff09;确…