Mybatis-Plus SQL注入器
今天看Mybatis-plus官网发现了这个SQL注入器,感觉以后有机会用上,记录一手。
重要的话说前面:MP的官网确实不友好,但是他们将示例代码都放在了gitee上:https://gitee.com/baomidou/mybatis-plus-samples/tree/master/mybatis-plus-sample-deluxe.
里面基本都有示例代码,可拉取下来找些博客对着看
两篇不错的博客:
参考:Mybatis-Plus的应用场景及注入SQL原理分析.
参考:Mybatis-Plus入门系列(11)- MybatisPlus之Sql注入器及源码分析.
SQL注入器是什么?
官网其实等于没说,这对我们这种小白来说非常不友好。大概就是MP的官方文档槽点如此多的原因。
说回正题,从字面意思理解:把SQL注入到某个地方。
SQL注入器的作用就是:你可以在Mapper层自定义方法,然后将SQL模板注入到MP中
注意,注入器和我们自定义方法+自己写sql.xml的区别:
使用SQL注入器,通常是使用自定义Mapper(MyBaseMapper)接口继承BaseMapper接口,我们自定义的方法就写在MyBaseMapper里。然后我们业务相关的Mapper继承MyBaseMapper就都可以使用该方法。这一切只需要我们自定义一个SQL模板,注入到MP即可,而不是换一个表就得重写一个xml
如何实现SQL注入器?
环境准备
利用springboot快速初始化项目,需要用到Mysql driver、spring web
plus依赖如下:
com.baomidou
mybatis-plus-boot-starter
3.5.1
配置文件:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/demo_xp?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
//打印执行的sql
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
如果嫌构建项目结构繁琐,可以看看这篇plus代码生成器的使用:https://blog.csdn.net/qq_42682745/article/details/120626012
实现SQL注入器
在此说明,为了简单起见(我也不太会),我定义的方法名叫testxp(),功能是查询所有
1.写一个方法类,在类中写SQL模板,需继承AbstractMethod
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
public class Testxp extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class> mapperClass, Class> modelClass, TableInfo tableInfo) {
/* 执行 SQL ,动态 SQL 参考类 SqlMethod */
String sql = "select * from " + tableInfo.getTableName();
/* mapper 接口方法名一致 */
String method = "testxp";
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
// 查询方法对应addSelectMappedStatementForTable
return addSelectMappedStatementForTable(mapperClass, method, sqlSource, tableInfo);
}
}
其中SQL模板,官方示例的通过id查找是这样的:
String sql = "select * from " + tableInfo.getTableName()
+ " where " + tableInfo.getKeyColumn() + "=#{" + tableInfo.getKeyProperty() + "}";
所以SQL模板大概就是这样写的。
然后,就是你的返回类型了,定义的查询方法就找select的,删除方法就返回delete的
2.写一个SQL注入类,将你定义的方法注入MP,继承DefaultSqlInjector就好了
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.extension.injector.methods.AlwaysUpdateSomeColumnById;
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
import com.baomidou.mybatisplus.extension.injector.methods.LogicDeleteByIdWithFill;
import java.util.List;
public class MySqlInjector extends DefaultSqlInjector {
@Override
public List getMethodList(Class> mapperClass, TableInfo tableInfo) {
List methodList = super.getMethodList(mapperClass, tableInfo);
//增加自定义方法
methodList.add(new Testxp());
/**
* 以下 3 个为内置选装件
* 头 2 个支持字段筛选函数
*/
// 例: 不要指定了 update 填充的字段
methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE));
methodList.add(new AlwaysUpdateSomeColumnById());
methodList.add(new LogicDeleteByIdWithFill());
return methodList;
}
}
把第一步自定义的方法类放进去就好了,
至于下面的内置选装件,意思就是MP给你提供的”组件“类,你可以用也可以不用。看情况,这里我们就全都加上
3.写一个用于被继承的Mapper接口(比如MyBaseMapper)
public interface MyBaseMapper extends BaseMapper {
List testxp();
}
需继承BaseMapper(当然测试阶段可以不继承BaseMapper,不继承意味着我们无法使用MP封装的方法),在接口中添加你自定义的方法,我这里就是testxp()
4.写一个配置类,把我们写的SQL注入类装进Spring容器
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
@Bean
public MySqlInjector sqlInjector() {
return new MySqlInjector();
}
}
5.写你的业务Mapper层,继承自定义的MyBaseMapper
@Mapper
@Repository
public interface BucketMapper extends MyBaseMapper {
}
6.写测试类或测试接口
@SpringBootTest
class BucketApplicationTests {
@Autowired
private BucketMapper bucketMapper;
@Test
void contextLoads() {
List testxp = bucketMapper.testxp();
for (Bucket bucket : testxp) {
System.out.println(bucket);
}
}
}
大功告成!
谈谈它的优缺点:(仅学习过程的看法)
优点:不用重复写格式相同的sql,将方法注册到MP内部可直接调用
缺点:个人觉得,对于MP而言,基本的CRUD已经内置了,我们需要动手写SQL的地方往往是多表查询、条件分页,除此之外的情况并且还要经常用的很少见,可见SQL注入器的使用范围很小,感觉地位很低啊。因为配置SQL注入器还是挺麻烦的,封装的方法如果使用不多还是别搞