扩展BaseMapper类

扩展mybatis-plus的BaseMapper类

mp的BaseMapper只提供了简单的增删改查方法,一些复杂点的操作没有提供,或是在IService类中提供。如果想要直接通过mapper类调用这些方法,可以通过扩展BaseMapper来使其获取新的功能。

insertBatch

扩展一个批量插入insertBatch的方法。

  1. 定义SqlInjector类,扩展功能
java 复制代码
public class ExpandSqlInjector extends DefaultSqlInjector {
    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass);
        methodList.add(new InsertBatchMethod());
        methodList.add(new InsertIfNotExistsMethod());
        return methodList;
    }

    /**
     * 批量插入方法
     */
    public static class InsertBatchMethod extends AbstractMethod {
        @Override
        public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
            String sql = "<script>INSERT INTO %s (%s) VALUES %s";

            List<String> columnList = new ArrayList<>();
            List<String> propertyList = new ArrayList<>();
            if (tableInfo.havePK() && !AUTO.equals(tableInfo.getIdType())) {
                columnList.add(tableInfo.getKeyColumn());
                propertyList.add(tableInfo.getKeyProperty());
            }
            // getFiledList等方法获取的内容会自动根据@TableField相关配置而改变
            for (TableFieldInfo fieldInfo : tableInfo.getFieldList()) {
                columnList.add(fieldInfo.getColumn());
                propertyList.add(fieldInfo.getProperty());
            }

            String columns = String.join(",", columnList);
            String values = "<foreach collection='list' item='item' separator=','>" +
                    "(#{item." + String.join("},#{item.", propertyList) + "})" +
                    "</foreach></script>";
            String sqlResult = String.format(sql, tableInfo.getTableName(), columns, values);

            SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
            return getMappedStatement(this::addInsertMappedStatement, mapperClass, "insertBatch", modelClass, tableInfo, sqlSource, "");
        }
    }

    private static MappedStatement getMappedStatement(MappedStatementMethod method, Class<?> mapperClass, String id, Class<?> modelClass, TableInfo tableInfo, SqlSource sqlSource, String prefix) {

        // 根据@TableId注解自动设置KeyGenerator
        KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE; // 默认值
        String keyColumn = null;
        String keyProperty = null;

        // 如果表有主键字段
        if (tableInfo.havePK()) {
            keyColumn = tableInfo.getKeyColumn();
            keyProperty = prefix + tableInfo.getKeyProperty();

            // 根据主键类型设置,INPUT、NONE:NoKeyGenerator,ASSIGN_ID, ASSIGN_UUID等策略,Java层面生成,不需要数据库生成
            if (AUTO.equals(tableInfo.getIdType())) {
                keyGenerator = Jdbc3KeyGenerator.INSTANCE;
            }
        }
        // 这里的keyGenerator与实际sql语句无关,是否插入id取决你构造的sql语句
        return method.accept(mapperClass, modelClass, id, sqlSource, keyGenerator, keyProperty, keyColumn);
    }

    @FunctionalInterface
    public interface MappedStatementMethod {
        MappedStatement accept(Class<?> mapperClass, Class<?> parameterType, String id, SqlSource sqlSource, KeyGenerator keyGenerator, String keyProperty, String keyColumn);
    }
}
  1. 配置SqlInjector:在mp的配置类中(也可以通过yml文件配置)
java 复制代码
@Bean
public ExpandSqlInjector expandSqlInjector() {
  	return new ExpandSqlInjector();
}
  1. 具体mapper类加上insertBatch方法;或定义一个新的BaseMapper,让其继承BaseMapper(推荐后者,可以统一配置)

实际通过前面二步,生成的BaseMapper代理类已经有了扩展的方法,这一步了是为了让接口也拥有扩展方法。

java 复制代码
public interface AppMapper<T> extends BaseMapper<T> {
    /**
     * 批量插入
     * @param list 实体列表
     * @return 插入条数
     */
    int insertBatch(List<T> list);
}

insertIfNotExists

扩展一个不存在则插入insertIfNotExists的方法。

  1. ExpandSqlInjector类中添加以下内容
java 复制代码
/**
 * 如果满足条件的记录不存在才插入
 */
public static class InsertIfNotExistsMethod extends AbstractMethod {
  @Override
  public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
    // 动态生成 SQL
    String sql = "<script>INSERT INTO %s (%s) " +
      "SELECT %s FROM dual " +
      "WHERE NOT EXISTS (" +
      "   SELECT 1 FROM %s ${ew.customSqlSegment}" +
      ")</script>";

    // 1. 插入的字段列表(会自动加上if标签,根据类型添加相关的非空判断,最后一个字段会多个逗号)
    String insertColumns = tableInfo.getAllInsertSqlColumnMaybeIf("entity.");
    insertColumns = SqlScriptUtils.convertTrim(insertColumns, null, null, null, ",");
    // 2. 插入的值(会自动加上if标签,根据类型添加相关的非空判断,最后一个值会多个逗号)
    String insertValues = tableInfo.getAllInsertSqlPropertyMaybeIf("entity.");
    insertValues = SqlScriptUtils.convertTrim(insertValues, null, null, null, ",");

    String tableName = tableInfo.getTableName();
    String sqlResult = String.format(sql, tableName, insertColumns, insertValues, tableName);

    SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
    return getMappedStatement(this::addInsertMappedStatement, mapperClass, "insertIfNotExists", modelClass, tableInfo, sqlSource, "entity.");
  }
}
  1. AppMapper类里添加以下内容:
java 复制代码
/**
 * 插入,如果满足指定条件的记录已存在则忽略
 * @param entity 插入的实体类实例
 * @param ew 条件对象
 */
int insertIfNotExists(@Param("entity") T entity, @Param(WRAPPER) Wrapper<T> ew);
相关推荐
小许学java14 小时前
数据结构-模拟实现顺序表和链表
java·数据结构·链表·arraylist·linkedlist·顺序表模拟实现·链表的模拟实现
+VX:Fegn089514 小时前
计算机毕业设计|基于springboot + vue零食商城管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
Query*14 小时前
杭州2024.08 Java开发岗面试题分类整理【附面试技巧】
java·开发语言·面试
WZTTMoon15 小时前
Spring Boot 4.0 迁移核心注意点总结
java·spring boot·后端
旷野说15 小时前
为什么 MyBatis 原生二级缓存“难以修复”?
java·java-ee·mybatis
8***235515 小时前
【wiki知识库】07.用户管理后端SpringBoot部分
java
阿蔹15 小时前
JavaWeb-Selenium 配置以及Selenim classnotfound问题解决
java·软件测试·python·selenium·测试工具·自动化
小毅&Nora16 小时前
【后端】【C++】从裸指针到 C++20 协程:现代 C++ 内存与并发编程的双重革命
java·c++20
张np16 小时前
java基础-ArrayList
java·开发语言
Swizard16 小时前
别让 AI 假装在工作:Android "Vibe Coding" 的生存指南
android·java·vibe coding