一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第26天,点击查看活动详情
前言
上一章讲解了Mybatis-plus的相关插件和插件的使用,虽然Mybatis-Plus已经提供了许多自定义的Sql注入器,但是针对一些特殊的场景,我们还是需要自定义SQL注入器,本文将讲解如何自定义SQL注入器和自动填充字段特性。
SQL注入器结构
Mybatis-plus的SQL注入器采用的模板设计模式,其中的AbstractSqlInjector类中实现了核心的注入逻辑,提供了一个抽象的方法去获取方法集合。
核心逻辑
//核心注入逻辑
public abstract class AbstractSqlInjector implements ISqlInjector {
protected final Log logger = LogFactory.getLog(this.getClass());
@Override
public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {
Class<?> modelClass = ReflectionKit.getSuperClassGenericType(mapperClass, Mapper.class, 0);
if (modelClass != null) {
String className = mapperClass.toString();
Set<String> mapperRegistryCache = GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());
//检查缓存中是否存在,防止重复注入
if (!mapperRegistryCache.contains(className))
{
TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass);
List<AbstractMethod> methodList = this.getMethodList(mapperClass, tableInfo);
if (CollectionUtils.isNotEmpty(methodList))
{
// 循环注入自定义方法
methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));
} else {
logger.debug(mapperClass.toString() + ", No effective injection method was found.");
}
mapperRegistryCache.add(className);
}
}
}
// 抽象方法
public abstract List<AbstractMethod> getMethodList(Class<?> mapperClass,TableInfo tableInfo);
}
自定义SQL注入器
本文将自定义一个全量删除的注入器
编写自定义方法类继承抽象方法类
public class DeleteAllMethod extends AbstractMethod
{
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass,
Class<?> modelClass, TableInfo tableInfo)
{
String sql = "delete from " + tableInfo.getTableName();
//方法名需要与mapper定义的名称一样
String method = "deleteAll";
SqlSource sqlSource = languageDriver.createSqlSource(configuration,
sql, modelClass);
return this.addDeleteMappedStatement(mapperClass, method, sqlSource);
}
}
注意:Method:方法的名称需要与Mapper定义的名称一样。
编写自定义注入器继承默认的注入器
public class LogicSqlInjector extends DefaultSqlInjector
{
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass)
{
List<AbstractMethod> methodList = super.getMethodList(mapperClass);
methodList.add(new DeleteAllMethod());
return methodList;
}
}
说明:也可以继承AbstractSqlInjector或者直接实现ISqlInjector来实现自定义的SQL注入器
在MybatisPlusConfig注入自定义SQL注入器
@Bean
public LogicSqlInjector logicSqlInjector()
{
return new LogicSqlInjector();
}
Mapper定义删除所有接口
public interface SuperMapper<T> extends BaseMapper<T>
{
void deleteAll();
}
Service方法实现删除所有接口
//公共mapper
public interface SuperService<T> extends IService<T>
{
void deleteAll();
}
// 公共service类
public class SuperServiceImpl<T> extends ServiceImpl<SuperMapper<T>, T> implements SuperService<T>
{
@Override
public void deleteAll()
{
baseMapper.deleteAll();
}
}
//子类只需要继承
@Service
@Transactional(rollbackFor=Exception.class)
public class UserServiceImpl extends SuperServiceImpl<TUser> implements UserService
{
}
示例代码
@GetMapping("/deleteAll")
public String deleteAll()
{
userService.deleteAll();
return "成功";
}
执行结果
[http-nio-9090-exec-1] INFO []
==> Preparing: delete from t_user_1
==> Parameters:
<== Updates: 1
从执行结果来看说明自定义的SQL注入器已经成功执行了。需要注意的是自定义SQL注入器尽量不要与Mybatis-Plus的相关插件有冲突,本文中定义的删除所有的注入器与防全表更新与删除插件冲突,所以测试的时候需要将此插件测试。
自动填充字段
数据库表中通常会包含创建时间、创建人、修改人、修改时间字段,如果每次新增或者修改时都来设置这几个字段值比较麻烦,Mybatis-plus提供了自动填充字段功能来满足此需求。
示例
编写逻辑类实现MetaObjectHandler接口
@Component
public class MyMetaObjectHandler implements MetaObjectHandler,Serializable
{
private static final long serialVersionUID = -6667195040118615500L;
/**
* 插入填充
*/
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createUser", String.class, "jiansheng");
this.strictInsertFill(metaObject, "createDate", Date.class, new Date());
}
/**
* 更新填充
*/
@Override
public void updateFill(MetaObject metaObject)
{
this.strictUpdateFill(metaObject, "updateUser", String.class, "jiansheng");
this.strictUpdateFill(metaObject, "updateDate", Date.class, new Date());
}
}
实体类中添加字段填充策略
Mybatis-plus提供了四种填充策略
- DEFAULT:默认不处理
- INSERT:入时填充字段
- UPDATE:更新时填充字段
- INSERT_UPDATE:插入和更新时填充字段
@TableField(value="createUser",fill = FieldFill.INSERT)
private String createUser;
@TableField(value="createDate",fill = FieldFill.INSERT)
private Date createDate;
@TableField(value="updateUser",fill = FieldFill.UPDATE)
private String updateUser;
@TableField(value="updateDate",fill = FieldFill.UPDATE)
private Date updateDate;
测试示例
@RequestMapping("/addUser")
public String addUser()
{
TUser tUser =new TUser();
tUser.setName("mybatis-plus");
tUser.setAge(18);
tUser.setAddress("SZ");
userService.save(tUser);
return "成功";
}
执行结果
==> Preparing: INSERT INTO t_user_1 ( name, age, address, deleteFlag, createUser, createDate, version ) VALUES ( ?, ?, ?, ?, ?, ?, ? )
==> Parameters: mybatis-plus(String), 18(Integer), SZ(String), false(Boolean), jiansheng(String), 2022-04-27 18:07:57.854(Timestamp), 0(Integer)
<== Updates: 1
从执行结果可以看出,新增用户时默认已经插入了创建人和创建时间字段。
总结
本文讲解了Mybatis-plus的自定义SQL注入器和自动填充,实际的项目中可以根据不同的需求来定制相关功能。