mybatis-plus添加replace(自定义)方法,添加sql注入器SqlInjector

news2024/12/26 10:57:20

1. 继承DefaultSqlInjector

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 自定义sql注入器
 *
 * @author yz
 * @since 2024/08/23
 */
@Component
public class AntaiSqlInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);

        // 添加一个替换方法
        methodList.add(new Replace());
        return methodList;
    }
}

import lombok.Getter;

/**
 * 自定义MybatisPlus 支持 SQL 方法
 *
 * @author yz
 * @since 2024/8/23 17:55
 */
@Getter
public enum AntaiSqlMethod {
    REPLACE("replace", "替换一条数据", "<script>\nREPLACE INTO %s %s VALUES %s\n</script>");


    private final String method;
    private final String desc;

    private final String sql;

    AntaiSqlMethod(String method, String desc, String sql) {
        this.method = method;
        this.desc = desc;
        this.sql = sql;
    }

}

2. 实现Replace 的 sql 方法

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlInjectionUtils;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;

/**
 * 替换一条数据(选择字段插入)存在则更新,不存在则插入
 *
 * @author yz
 * @since 2024/08/23
 */
@SuppressWarnings("all")
public class Replace extends AbstractMethod {

    /**
     * 自增主键字段是否忽略
     *
     * @since 3.5.4
     */
    private boolean ignoreAutoIncrementColumn;

    public Replace() {
        this(AntaiSqlMethod.REPLACE.getMethod());
    }

    /**
     * @param ignoreAutoIncrementColumn 是否忽略自增长主键字段
     * @since 3.5.4
     */
    public Replace(boolean ignoreAutoIncrementColumn) {
        this(AntaiSqlMethod.REPLACE.getMethod());
        this.ignoreAutoIncrementColumn = ignoreAutoIncrementColumn;
    }


    /**
     * @param name 方法名
     * @since 3.5.0
     */
    public Replace(String name) {
        super(name);
    }

    /**
     * @param name                      方法名
     * @param ignoreAutoIncrementColumn 是否忽略自增长主键字段
     * @since 3.5.4
     */
    public Replace(String name, boolean ignoreAutoIncrementColumn) {
        super(name);
        this.ignoreAutoIncrementColumn = ignoreAutoIncrementColumn;
    }

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;
        SqlMethod sqlMethod = SqlMethod.INSERT_ONE;
        String columnScript = SqlScriptUtils.convertTrim(tableInfo.getAllInsertSqlColumnMaybeIf(null, ignoreAutoIncrementColumn),
                LEFT_BRACKET, RIGHT_BRACKET, null, COMMA);
        String valuesScript = LEFT_BRACKET + NEWLINE + SqlScriptUtils.convertTrim(tableInfo.getAllInsertSqlPropertyMaybeIf(null, ignoreAutoIncrementColumn),
                null, null, null, COMMA) + NEWLINE + RIGHT_BRACKET;
        String keyProperty = null;
        String keyColumn = null;
        // 表包含主键处理逻辑,如果不包含主键当普通字段处理
        if (StringUtils.isNotBlank(tableInfo.getKeyProperty())) {
            if (tableInfo.getIdType() == IdType.AUTO) {
                /* 自增主键 */
                keyGenerator = Jdbc3KeyGenerator.INSTANCE;
                keyProperty = tableInfo.getKeyProperty();
                // 去除转义符
                keyColumn = SqlInjectionUtils.removeEscapeCharacter(tableInfo.getKeyColumn());
            } else if (null != tableInfo.getKeySequence()) {
                keyGenerator = TableInfoHelper.genKeyGenerator(methodName, tableInfo, builderAssistant);
                keyProperty = tableInfo.getKeyProperty();
                keyColumn = tableInfo.getKeyColumn();
            }
        }
        String sql = String.format(AntaiSqlMethod.REPLACE.getSql(), tableInfo.getTableName(), columnScript, valuesScript);
        SqlSource sqlSource = super.createSqlSource(configuration, sql, modelClass);
        return this.addInsertMappedStatement(mapperClass, modelClass, methodName, sqlSource, keyGenerator, keyProperty, keyColumn);
    }
}

3. 实现一个批量替换的方法,作为调用入口

    /**
     * 批量替换
     *
     * @param entityList 实体列表
     * @param batchSize  批量大小
     * @return {@link Boolean }
     */
    default Boolean replaceBatch(Collection<T> entityList, int batchSize) {
        if (CollectionUtils.isEmpty(entityList)) {
            return false;
        }
        Class<T> entityClass = getEntityClass(entityList);
        Class<?> mapperClass = ClassUtils.toClassConfident(getTableInfo(entityClass).getCurrentNamespace());
        String sqlStatement = mapperClass.getName()
                + StringPool.DOT
                + AntaiSqlMethod.REPLACE.getMethod();
        return SqlHelper.executeBatch(entityClass, log, entityList, batchSize, (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity));
    }

    /**
     * 从集合中获取实体类型
     *
     * @param entityList 实体集合
     * @param <T>        实体类型
     * @return 实体类型
     */
    static <T> Class<T> getEntityClass(Collection<T> entityList) {
        Class<T> entityClass = null;
        for (T entity : entityList) {
            if (entity != null && entity.getClass() != null) {
                entityClass = (Class<T>) entity.getClass();
                break;
            }
        }
        Assert.notNull(entityClass, "error: can not get entityClass from entityList");
        return entityClass;
    }

4. 最终效果

image.png
image.png

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

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

相关文章

网络安全宣传周知识竞赛答题小程序怎么做?

随着网络安全宣传周的到来&#xff0c;越来越多的单位开始组织员工进行线上学习网络安全相关知识&#xff0c;其中举办网络安全知识竞赛答题活动的效果尤为明显&#xff0c;以下是一些网络安全答题系统的功能亮点&#xff1a; 多样化的题目类型与灵活的出题方式&#xff1a; 丰…

92.游戏的启动与多开-多开检测概述

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;易道云信息技术研究院 上一个内容&#xff1a;91.游戏的启动与多开-游戏启动 正常来说任何一个软件一双击就会打开&#xff0c;只要软…

一文读懂PINGPONG:0成本在普通家用机上运行多个网络节点

概述 l pingpong项目设计的愿景便是降低去中心化网络的节点运行难度&#xff0c;让普通人也可以参与到节点运行中&#xff1b; l 这个周期里&#xff0c;随着Depin和AIWeb3叙事的爆发&#xff0c;众多中小型去中心化网络面临着节点运行者供需不匹配的问题&#xff0c;严重影响…

MySQL约束与事务

一、MySQL约束 参考【MySQL】约束_mysql约束-CSDN博客 not null&#xff1a;非空约束unique&#xff1a;唯一性约束primary key&#xff1a;主键约束foreign key&#xff1a;外键约束check&#xff1a;检查约束default&#xff1a;默认值约束 如何添加约束 在CREATE TABLE时…

zyx青岛实训day34 初步了解Docker与套接字的应用

回顾 1、主从复制&#xff08;高可用&#xff09; 2、传统的主从复制 3、gtids事务型的主从复制 4、注意 1&#xff09;server_id唯一 2&#xff09;8.X版本需要get_ssl_pub_key 3&#xff09;5.X不需要 4&#xff09;change master to 5&#xff09;stop | start slave 5…

YOLOv5调用海康工业相机实时检测

目录 一、调用海康工业摄像头 1.1 DirectShow插件安装 1.2 查找摄像头编号 1.3 摄像头调用测试 二、修改YOLOv5相关参数 2.1 detect.py修改 2.2 datasets.py修改 一、调用海康工业摄像头 现在可直接利用cv2.VideoCapture()接口调用海康机器人工业相机&#xff0c;首先在官…

【数据结构】二叉搜索树的功能实现详解

文章目录 二叉搜索树查找插入删除找到要删除的节点删除节点1. 要删除节点的左孩子为空2. 要删除节点的右孩子为空3. 要删除的节点的左右孩子都不为空 完整代码 二叉搜索树 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它…

IOS17双开微信且自动刷新

前提文件 需要在Sideloadly官网下载iTunes和iCloud这2个文件&#xff1a;https://sideloadly.io/&#xff0c; SideStore侧载商店官网下载另外4个文件&#xff1a;https://sidestore.io/ 如图&#xff0c;如果文件无法下载(需要科学上网)可以下载我的资源包尝试 安装步骤 …

C语言学习笔记 Day15(文件管理--下)

Day15 内容梳理&#xff1a; 目录 C语言学习笔记 Day14&#xff08;文件管理--上&#xff09;-CSDN博客 Chapter 10 文件操作 10.2 文件加密、解密 &#xff08;1&#xff09;文件加密 &#xff08;2&#xff09;文件解密 10.3 文件读取、写入 &#xff08;1&#xff…

可视化数据大屏设计案例

可视化数据大屏开发-能源调度大屏展示 可视化数据大屏开发-房地产经营分析 可视化大屏开发-预售业务数据看板 可视化大屏开发-城市路况监测大屏

深入Redis:细谈持久化

Redis的数据是保存在内存中的&#xff0c;内存里面的数据是不持久的&#xff0c;要想做到持久化&#xff0c;必须要把在内存中的数据储存到硬盘上。 Redis速度非常快&#xff0c;数据只有在内存中才有这样的速度&#xff0c;但是为了持久&#xff0c;数据还是要想办法保存到硬…

【分治——归并排序】排序数组的归并方法

目录 1.前言2.题目简介3.求解思路4.示例代码 1.前言 今天简单展示一个归并排序解题&#xff0c;难度简单。 2.题目简介 题目链接&#xff1a;LINK 3.求解思路 4.示例代码 //归并排序 class Solution { public:vector<int> tmp;vector<int> sortArray(vector&…

【Web开发工具】基于Windows系统下的WebStorm安装教程

目录 安装WebStorm1.官网下载WebStorm2.选择安装位置3.关闭应用 下载并解压工具下载地址解压执行Done输入Code 安装WebStorm 1.官网下载WebStorm 我自己的网盘链接: https://pan.baidu.com/s/17PJu8Kf_fdX3gi588ubTqQ?pwd6666 2.选择安装位置 下一步下一步就行&#xff0c…

有手就会之使用Dify构建RAG聊天应用(基于私有知识库和搜索引擎)

之前我的文章里写的是通过langchain来构建RAG应用&#xff0c;对于很多人来说。langchain作为一个框架上手难度大&#xff0c;代码不够直观。但是通过dify你将学会可视化搭建工作流。 什么是dify&#xff1f; Dify 是一款开源的大语言模型(LLM) 应用开发平台。它融合了后端即…

如何判断B端真实需求?5大经验技巧

准确判断B端真实需求能确保软件开发项目紧贴用户实际需求&#xff0c;减少返工&#xff0c;加快开发速度&#xff0c;提升客户满意度和产品竞争力。如果没有采用有效的技巧和经验来判断B端的真实需求&#xff0c;可能会导致软件开发项目偏离客户实际需求&#xff0c;引发频繁的…

【数据分析预备】Numpy入门

Jupyter Notebook 是一个基于网页的交互式计算环境编写代码、运行代码、查看输出、可视化数据、分享报告文档按单元格运行代码可展示的信息格式更丰富&#xff08;支持Markdown和Latex)交互式运行环境 安装 cmd窗口 pip install notebook启动 jupyter notebook退出 CtrlC …

阿里巴巴alibaba商品采集API获取商品列表商品详情接口

在跨境电商和B2B贸易日益繁荣的今天&#xff0c;如何高效、准确地获取商品信息成为了商家们关注的焦点。阿里巴巴作为全球领先的B2B电商平台&#xff0c;凭借其庞大的商品数据库和强大的技术支持&#xff0c;为商家们提供了丰富的API接口服务&#xff0c;其中alibaba.item_get接…

第十三节:学习Springboot整合mybatis——完整篇(自学Spring boot 3.x的第三天)

大家好&#xff0c;今天记录下学习springboot的第三天。​网创有方 这节详细记录了如何使用springboot整合mybatis方法&#xff0c;并成功实现将请求信息插入本地的mysql数据库。 由于只是为了方便本地验证&#xff0c;实际项目是需要部署到服务器上去的&#xff0c;所以就采用…

MQ专题:消费幂等性

一、提要 1.1 通过本文将获得 消息投递的通用代码 非事务消息的投递事务消息的投递任意延迟消息的投递&#xff0c;不依赖于任何MQ上面这些投递都支持批量的方式投递失败自动重试的代码 幂等消费的通用代码消费失败&#xff0c;衰减式自动重试的通用代码 1.2本文涉及到的主要…