扩展mybatis-plus的BaseMapper类
mp的BaseMapper
只提供了简单的增删改查方法,一些复杂点的操作没有提供,或是在IService
类中提供。如果想要直接通过mapper类调用这些方法,可以通过扩展BaseMapper
来使其获取新的功能。
insertBatch
扩展一个批量插入insertBatch
的方法。
- 定义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);
}
}
- 配置SqlInjector:在mp的配置类中(也可以通过yml文件配置)
java
@Bean
public ExpandSqlInjector expandSqlInjector() {
return new ExpandSqlInjector();
}
- 具体mapper类加上
insertBatch
方法;或定义一个新的BaseMapper
,让其继承BaseMapper
(推荐后者,可以统一配置)
实际通过前面二步,生成的
BaseMapper
代理类已经有了扩展的方法,这一步了是为了让接口也拥有扩展方法。
java
public interface AppMapper<T> extends BaseMapper<T> {
/**
* 批量插入
* @param list 实体列表
* @return 插入条数
*/
int insertBatch(List<T> list);
}
insertIfNotExists
扩展一个不存在则插入insertIfNotExists
的方法。
- 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.");
}
}
- AppMapper类里添加以下内容:
java
/**
* 插入,如果满足指定条件的记录已存在则忽略
* @param entity 插入的实体类实例
* @param ew 条件对象
*/
int insertIfNotExists(@Param("entity") T entity, @Param(WRAPPER) Wrapper<T> ew);