Spring Boot 集成Mybatis-Plus(四)

374 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第26天,点击查看活动详情

前言

上一章讲解了Mybatis-plus的相关插件和插件的使用,虽然Mybatis-Plus已经提供了许多自定义的Sql注入器,但是针对一些特殊的场景,我们还是需要自定义SQL注入器,本文将讲解如何自定义SQL注入器和自动填充字段特性。

SQL注入器结构

图片.png

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注入器和自动填充,实际的项目中可以根据不同的需求来定制相关功能。