mybatisplusSQL注入器详解

一、什么是SQL注入器?

我们在使用mybatis-plus的时候,dao层都会继承BaseMapper接口,这样就可以使用BaseMapper接口的所有方法,BaseMapper接口的每一个方法其实就是一个SQL注入器。

在Mybatis-Plus的核心(core)的injector.methods包下,提供的很多注入方法。

二、自带的SQL注入器

在Mybatis-Plus(extension)的injector.methods包下有四个可拓展的注入方法。

AlwaysUpdateSomeColumnById:根据id更新字段(全量更新不忽略null字段),updateById默认会自动忽略实体类中null值字段

InsertBatchSomeColumn:真实批量插入,saveBatch其实是伪批量插入
LogicDeleteByIdWithFill:逻辑删除增加填充功能,比如删除的时候填充更新时间、更新人
Upsert:插入一条数据,选择字段插入

三、测试自带的SQL注入器

1.SQL注入器全局配置

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.extension.injector.methods.AlwaysUpdateSomeColumnById;
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @author wjj
 */
@Component
public class MySqlInjector extends DefaultSqlInjector {
    public MySqlInjector() {
        super();
    }
    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        List<AbstractMethod> methods = super.getMethodList(mapperClass);
        methods.add(new InsertBatchSomeColumn(i-> i.getFieldFill() != FieldFill.UPDATE));
        methods.add(new AlwaysUpdateSomeColumnById(i-> i.getFieldFill() != FieldFill.INSERT));
        return methods;
    }
}

2.自定义MyBaseMapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface MyBaseMapper<T> extends BaseMapper<T> {

    int alwaysUpdateSomeColumnById(@Param("et")T entity);

    int insertBatchSomeColumn(List<T> entityList);

}

3.实体类mapper继承MyBaseMapper

public interface UserMapper extends MyBaseMapper<UserPO> {

}

4.测试

四、自定义Sql注入器

1.创建一个方法FindList继承mybatisplus的AbstractMethod

书写一个非逻辑删除查询所有的方法(其他同理)

参考Mybatis-Plus的核心(core)的injector.methods包下的selectList方法

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.toolkit.sql.SqlScriptUtils;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;

public class FindList extends AbstractMethod {
    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        SqlMethod sqlMethod = SqlMethod.SELECT_LIST;
        String sql = String.format(sqlMethod.getSql(), this.sqlFirst(), this.sqlSelectColumns(tableInfo, true), tableInfo.getTableName(), this.sqlWhereEntityWrapper(true, tableInfo), this.sqlComment());
        SqlSource sqlSource = this.languageDriver.createSqlSource(this.configuration, sql, modelClass);
        return this.addSelectMappedStatementForTable(mapperClass, "finList", sqlSource, tableInfo);
    }

    @Override
    protected String sqlWhereEntityWrapper(boolean newLine, TableInfo table) {
        String sqlScript;
        sqlScript = table.getAllSqlWhere(false, true, "ew.entity.");
        sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", "ew.entity"), true);
        sqlScript = sqlScript + "\n";
        sqlScript = sqlScript + SqlScriptUtils.convertIf(String.format(SqlScriptUtils.convertIf(" AND", String.format("%s and %s", "ew.nonEmptyOfEntity", "ew.nonEmptyOfNormal"), false) + " ${%s}", "ew.sqlSegment"), String.format("%s != null and %s != '' and %s", "ew.sqlSegment", "ew.sqlSegment", "ew.nonEmptyOfWhere"), true);
        sqlScript = SqlScriptUtils.convertWhere(sqlScript) + "\n";
        sqlScript = sqlScript + SqlScriptUtils.convertIf(String.format(" ${%s}", "ew.sqlSegment"), String.format("%s != null and %s != '' and %s", "ew.sqlSegment", "ew.sqlSegment", "ew.emptyOfWhere"), true);
        sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", "ew"), true);
        return newLine ? "\n" + sqlScript : sqlScript;

    }
}

2.在MyBaseMapper添加方法

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface MyBaseMapper<T> extends BaseMapper<T> {

    int alwaysUpdateSomeColumnById(@Param("et")T entity);

    int insertBatchSomeColumn(List<T> entityList);

    List<T> finList();
}

3.SQL注入器全局配置

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.extension.injector.methods.AlwaysUpdateSomeColumnById;
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class MySqlInjector extends DefaultSqlInjector {
    public MySqlInjector() {
        super();
    }
    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        List<AbstractMethod> methods = super.getMethodList(mapperClass);
        methods.add(new InsertBatchSomeColumn(i-> i.getFieldFill() != FieldFill.UPDATE));
        methods.add(new AlwaysUpdateSomeColumnById(i-> i.getFieldFill() != FieldFill.INSERT));
        methods.add(new FindList());
        return methods;
    }
}

4.测试