起源
最近在学习mybatis plus(下文简称mp)
的进阶操作,有一个自定义全局操作。
简单来说就是你在mapper
中定义一个方法,常规的方法就是在xml
文件中写具体sql
或者方法上面打注解,注解里面写具体sql实现
。
初次之外,mp
还支持一种注入方式。这种方式类似mp
提供的BaseMapper
,并没有直接在xml
中写sql
,而是在mp
启动的时候注入sql
。
在实际项目使用过程中,遇到一些小问题,花费了不少时间,查阅不少资料才解决,故此记录下。
先交代下使用的mp
坐标:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatisplus-spring-boot-starter</artifactId>
<version>1.0.5</version>
</dependency>
现场还原
定义自己的Mapper
public interface CustomBaseMapper<T> extends BaseMapper<T> {
List<Integer> customCount(
@Param("city_code") String cityCode,
@Param("company_code") String companyCode);
}
继承AutoSqlInjector
public class CustomSqlInjector extends AutoSqlInjector {
private static final String CUSTOM_COUNT = "select count(*) from %1$s where city_code = 'all' union all"
+ " select count(*) from %1$s where city_code = #{city_code} and company_code = 'all' union all"
+ " select count(*) from %1$s where city_code = #{city_code} and company_code = #{company_code}";
@Override
public void inject(Configuration configuration, MapperBuilderAssistant builderAssistant, Class<?> mapperClass, Class<?> modelClass, TableInfo table) {
String sql = String.format(CUSTOM_COUNT, table.getTableName());
String method = "customCount";
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
this.addSelectMappedStatement(mapperClass, method, sqlSource, Integer.class, table);
}
}
到这里我们基本写完,最后一步就是在Spring中注入CustomSqlInjector
这个Bean
。
@Bean
public ISqlInjector sqlInjector() {
return new CustomSqlInjector();
}
实际使用时候,如果想获得自定义方法customCount
,只需要继承CustomBaseMapper
即可。
踩坑一
项目一启动就报错,定睛一看:
sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class异常解决方法
这个报错有点莫名奇妙,去官网搜索一下,发现作者给了解决方案:
MapperScan 需要排除 com.baomidou.mybatisplus.mapper.BaseMapper 类 及其 子类(自定义公共 Mapper)
这句话当时一下子没看明白,简单浏览了下MapperScan
注解,发现好像并没有排除相关的属性。后来百度了下,在一份博客下面的评论找到了答案。
今天我也遇到类似的问题,是UserMapper文件继承了CommonMapper文件,都放在Mapper包下,然后就出现了父子Bean的问题了,将commonMapper文件从CommonMapper挪出来后,就可以了
事后想了下应该跟官网作者说的是一个意思,只是下面这个更通俗易懂。
踩坑二
上面说到,需要注入自己的CustomSqlInjector
。常规操作就是在标识 @Configuration
的类里写上一个方法即可:
@Bean
public ISqlInjector sqlInjector() {
return new CustomSqlInjector();
}
实际看来效果可能如下,但这样启动发现自定义操作并没有注入进去。经过一番摸索,去翻阅了官网2.x
的文档,跳转到自定义全局操作 一节。
当时文档上写的注入方式是用配置文件完成:
<!-- 定义 MP 全局策略,安装集成文档部分结合 -->
<bean id="globalConfig" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
.....
<!-- 自定义注入 deleteAll 方法 -->
<property name="sqlInjector" ref="mySqlInjector" />
</bean>
<!-- 自定义注入器 -->
<bean id="mySqlInjector" class="com.baomidou.test.MySqlInjector" />
定睛一看,写在GlobalConfiguration
这个标签下,于是我想到是否可以尝试在application.yml
文件进行同样的配置:
mybatis-plus:
mapper-locations:
- classpath*:mapper/*.xml
typeAliasesPackage: com.test.tao.*.model.domain
global-config:
id-type: 0
field-strategy: 2
db-column-underline: true
sql-injector: com.test.tao.operation.inject.CustomSqlInjector
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
经过这样一配置,发现成功了,注入成功了。
虽然解决方案很简单,但那天晚上缺尝试了很久。
后来我看了mp
官方给的示例,注入方式改变了,简化了很多。其实把mp
官方给的demo
来下来调试运行下,可以学到不少新的技巧,值得尝试。