如何给Mybatis-plus再增加点plus

来源公众号:赵侠客

一、Mybatis-plus基本功能

1.1 Mybatis-plus内置方法

Mybatis-plus给我们造了很多轮子,让我们可以开箱即用,在BaseMapper中有19种操作数据库常用的方法,如Insert()deleteById()updateById()selectById()等。

我们在开发时只需要将我们的UserMapper 继承BaseMapper就可以获取这些操作数据库的常用方法,不需要再重复写这些方法了,比较方便。

java 复制代码
@Repository
public interface UserMapper extends BaseMapper<User> {

}

Mybatis-plus在IService给我们提供了更多更为丰富的操作数据库的方法。我们在使用时只需要将我们的UserServiceImpl 继承ServiceImpl并实现IService 接口就可轻松获取这些方法。

java 复制代码
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IService {


}

1.2 存在的问题

Mybatis-plus确实给我们提供了很多方法,同时也限制了我们的需求,比如我有一些很常见的需求:

  • 逻辑删除数据时,将操作人记录到数据库中。 如果你使用Mybatis-plusremoveById(1L),这个方法只能将数据库逻辑位设置成删除状态,操作人是无法记录到数据库的。

  • 每张表都有一个tenant_id,我想通过tenant_id把表中的id查出来Mybatis-plus也没有一个selectIdByTenantId()的方法。那我们只能每张表都写一个selectIdByTenantId,代码确实有点冗余了。

    所以针对以上存在的问题,我们可以 Mybatis-plus再增加点plus。

二、给BaseMapper增加几个plus

2.1 给BaseMapper增加点方法

Mybatis-plus内置的方法都是承AbstractMethod

java 复制代码
public class DeleteById extends AbstractMethod {

    public DeleteById() {
        super("deleteById");
    }
}

所以我们可以写一个DeleteAndUpdateById 类然后仿照UpdateById的写法将我们的实体中的字段更新到数据库的同时将逻辑删除位设置为删除状态。

java 复制代码
public class DeleteAndUpdateById extends AbstractMethod {


    /**
     * 注入自定义 MappedStatement
     * 根据id逻辑删除,顺带更新数据
     *
     * @param mapperClass mapper 接口
     * @param modelClass  mapper 泛型
     * @param tableInfo   数据库表反射信息
     * @return MappedStatement
     */
    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        String methodName = CustomSqlMethod.DELETE_AND_UPDATE_BY_ID.getMethod();
        String logicSql = CustomSqlMethod.DELETE_AND_UPDATE_BY_ID.getSql();
        final String additional = optlockVersion(tableInfo) + tableInfo.getLogicDeleteSql(true, true);
        logicSql = String.format(logicSql,
                tableInfo.getTableName(),
                sqlSet(false, false, tableInfo, false, ENTITY, ENTITY_DOT),
                tableInfo.getKeyColumn(),
                ENTITY_DOT + tableInfo.getKeyProperty(),
                additional);
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, logicSql, modelClass);
        return addUpdateMappedStatement(mapperClass, modelClass, methodName, sqlSource);
    }

    /**
     * SQL 更新 set 语句
     *
     * @param logic          是否逻辑删除注入器
     * @param ew             是否存在 UpdateWrapper 条件
     * @param table          表信息
     * @param judgeAliasNull
     * @param alias          别名
     * @param prefix         前缀
     * @return sql
     */
    @Override
    protected String sqlSet(boolean logic, boolean ew, TableInfo table, boolean judgeAliasNull, String alias, String prefix) {
        StringBuilder sqlScriptBuilder = new StringBuilder();
        // 添加删除的sql
        sqlScriptBuilder.append(table.getLogicDeleteSql(false, false))
                .append(DOT_NEWLINE);
        // 添加更新的sql
        sqlScriptBuilder.append(table.getAllSqlSet(true, prefix));
        String sqlScript = sqlScriptBuilder.toString();
        if (judgeAliasNull) {
            sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", alias), true);
        }
        if (ew) {
            sqlScript += NEWLINE;
            sqlScript += convertIfEwParam(U_WRAPPER_SQL_SET, false);
        }
        sqlScript = SqlScriptUtils.convertSet(sqlScript);
        return sqlScript;
    }
}

然后我们需要将DeleteAndUpdateById方法添加到DefaultSqlInjector 中。

java 复制代码
@Component
public class CustomSqlInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
        methodList.add(new DeleteAndUpdateById());
        return methodList;
    }
}

写个CustomBaseMapper,继承BaseMapper、再增加我们的deleteAndUpdateById方法

java 复制代码
public interface CustomBaseMapper<T> extends com.baomidou.mybatisplus.core.mapper.BaseMapper<T> {

    /**
     * 根据id做逻辑删除,并同时修改内容
     *
     * @param entity
     * @return
     */
    int deleteAndUpdateById(@Param(Constants.ENTITY) T entity);
}

最后将UserMapper继承CustomBaseMapper这样UserMapper就有了deleteAndUpdateById方法了

java 复制代码
@Repository
public interface UserMapper extends CustomBaseMapper<User> {

}

2.2 给ISerivce增加点方法

定义 ICustomService方法继承IService

java 复制代码
public interface ICustomService<T> extends IService<T> {
    List<Long> selectByTenantIds(List<Long> tenantIds);
    int deleteAndUpdateById(@Param(Constants.ENTITY) T entity);
}

然后创建CustomBaseServiceImpl实现ICustomService中的方法

java 复制代码
public class CustomBaseServiceImpl<M extends CustomBaseMapper<T>, T extends BaseDomain> extends ServiceImpl<M, T> {
    /**
     * 删除并更新内容 根据ID
     *
     * @param entity 对象
     * @return
     */
    public int deleteAndUpdateById(T entity) {
        return baseMapper.deleteAndUpdateById(entity);
    }


    public List<Long> selectByTenantIds(List<Long> tenantIds) {
        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id");
        queryWrapper.in(!tenantIds.contains(0L), "tenant_id", tenantIds);
        return listObjs(queryWrapper, id -> Long.valueOf(id.toString()));
    }
}      

最后将我们的UserService改成继承我们自己的ICustomServiceUserServiceImpl

java 复制代码
public interface ICustomService<T> extends IService<T> {
    List<Long> selectByTenantIds(List<Long> tenantIds);
    int deleteAndUpdateById(@Param(Constants.ENTITY) T entity);
}

三、测试

3.1 测试方法

通过上面的改造,我们所有的Service都有了deleteAndUpdateById()方法和selectByTenantIds()方法。

java 复制代码
class ApplicationTests {

    @Resource
    private UserService userService;

    @Test
    void testDeleteAndUpadteById() {
        User user = userService.getById(1L);
        user.setModifiedBy("赵侠客");
        user.setModifiedAt(LocalDateTime.now());
        userService.deleteAndUpdateById(user);
        User dbUser = userService.getById(1L);
        Assert.isTrue(dbUser == null, "删除成功");
    }

    @Test
    void test() {
        var userIds = userService.selectByTenantIds(List.of(1L));
        log.info("userIds:{}", userIds);
        Assert.isTrue(userIds != null);
    }
}

四、总结

这里我只是给Mybatis-plus增加了两个plus功能,更多的功能可以要根据自己的需求在CustomBaseMapperICustomService中添加就好了,主要可以扩展的Plus点有以下:

  • 改写Mybatis-plus内置满足不了我们实际需求的方法

  • 代码中很多通用的方法可以抽取成Plus公共功能

源码地址:gitee.com/whzhaochao/...
原文地址:mp.weixin.qq.com/s/JnS9pmZvl...

相关推荐
曹牧21 分钟前
文档格式:OFD
java
豆角焖肉1 小时前
Maven进阶与搭建私服
java·maven
大不点wow1 小时前
Java序列化与反序列化:让对象走出JVM
java·开发语言·jvm
止语Lab1 小时前
好的 DX 不等于少写代码——三种语言的摩擦力设计课
后端
吃饱了得干活1 小时前
别再手动解析 LLM 输出了!LangChain 四种结构化输出方案对比
后端·python·langchain
噢,我明白了1 小时前
Java中日期和字符串的处理
java·开发语言·日期
程序员天天困1 小时前
Arthas trace 命令怎么用?一行定位最慢那行代码
jvm·后端
Huiturn1 小时前
GPT 5.6 连续编码 10 小时,纯 Python 啃下 Word 二进制格式——doc2docx 实现拆解
后端
dkbnull1 小时前
Spring Boot请求处理组件对比详解
java·spring boot
jun_bai1 小时前
Orthanc服务器使用java上传dicom影像文件
java·运维·服务器