当前位置: 首页 > 工具软件 > kot-mybatis > 使用案例 >

基于tk.mybatis扩展自己的通用mapper

郑佐
2023-12-01


目的
tk.mybatis 提供的通用mapper,虽然使用方便,不过在有些sql还是不能满足我们的需要的,而且我们希望对于deleted语句进行管控(因为通用mapper提供的都是物理删除,有时我们对一些敏感数据只能进行逻辑删除),因此我们将基于原有的通用mapper进行自己的扩展

1 jar引入

     <!-- 非springboot -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper</artifactId>
            <version>3.4.0</version>
        </dependency>

非springboot项目引这个包

      <!-- springboot -->
             <dependency>
                <groupId>tk.mybatis</groupId>
                <artifactId>mapper-spring-boot-starter</artifactId>
                <version>2.0.2</version>
            </dependency>

springboot项目直接引这个包,本次我们将基于springboot进行开发,这里注意jar包版本,过低的版本将会出现问题,下面会介绍

2 编写配置类

package com.example.configuration;

import com.example.common.mapper.commonMapper.CommonMapper;
import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tk.mybatis.spring.mapper.MapperScannerConfigurer;

import java.util.Properties;

@Configuration
@AutoConfigureAfter(MybatisAutoConfiguration.class)
public class MyBatisConfiguration {
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        mapperScannerConfigurer.setBasePackage("com.example.dao.mapper");
        Properties properties = new Properties();
        properties.setProperty("mappers", CommonMapper.class.getName());
        properties.setProperty("notEmpty", "false");
        properties.setProperty("identity", "MYSQL");
        properties.setProperty("order","BEFORE");
        mapperScannerConfigurer.setProperties(properties);
        return mapperScannerConfigurer;
    }
}

这里要注意两点:

1>CommonMapper这个是我们自己定义的通用mapper,它放置一个单独的包下面。也就是说这个包下面只有这个一个mapper,否则我们在实用泛型时会出现类型转换的问题。(我在这里纠结了好久)

2>这里我们配置了自定义mapper的扫描路径。注意springboot项目一定要注意jar包版本,版本过低的话,在配置类中的定义是没有用的。还是扫描不到,我之前使用的版本1.2.3就会出现这个问题,更换更高的版本就可以解决了。

3 常规方法接口整合到自己的自定义Mapper接口上

因为我们使用的是mysql数据库,所以在使用通用功能的时候就选择性引入一些经常使用的方法,下面是自己定义的常用mapper类的整合(这里会抛弃一些不常用的类或不是mysql的方法类)。这些基类不要放在 BasePackage的路径下,这个路径下的mapper都是要指定明确的泛型类型的。
1 > 提供查询功能Mapper:

package com.example.common.mapper.basics;

import tk.mybatis.mapper.common.Marker;
import tk.mybatis.mapper.common.base.select.*;
import tk.mybatis.mapper.common.condition.SelectByConditionMapper;
import tk.mybatis.mapper.common.condition.SelectCountByConditionMapper;
import tk.mybatis.mapper.common.example.SelectByExampleMapper;
import tk.mybatis.mapper.common.ids.SelectByIdsMapper;

/**
 * @desc 基础查询功能mapper
 *
 */
public interface SelectMapper<T> extends Marker,
        SelectOneMapper<T>,
        tk.mybatis.mapper.common.base.select.SelectMapper<T>,
        SelectAllMapper<T>,
        SelectCountMapper<T>,
        SelectByPrimaryKeyMapper<T>,
        ExistsWithPrimaryKeyMapper<T>,
        SelectByIdsMapper<T>,
        SelectByConditionMapper<T>,
        SelectCountByConditionMapper<T>,
        SelectByExampleMapper<T> {
}

2>提供新增功能mapper

package com.example.common.mapper.basics;

import tk.mybatis.mapper.common.Marker;
import tk.mybatis.mapper.common.MySqlMapper;
import tk.mybatis.mapper.common.base.insert.InsertSelectiveMapper;

/**
 * @desc 基础插入功能mapper
 */
public interface InsertMapper<T> extends Marker,
        tk.mybatis.mapper.common.base.insert.InsertMapper<T>,
        InsertSelectiveMapper<T>,
        MySqlMapper<T>{
}

3>提供更新功能mapper

package com.example.common.mapper.basics;

import tk.mybatis.mapper.common.Marker;
import tk.mybatis.mapper.common.base.update.UpdateByPrimaryKeyMapper;
import tk.mybatis.mapper.common.base.update.UpdateByPrimaryKeySelectiveMapper;
import tk.mybatis.mapper.common.condition.UpdateByConditionMapper;
import tk.mybatis.mapper.common.condition.UpdateByConditionSelectiveMapper;
import tk.mybatis.mapper.common.example.UpdateByExampleSelectiveMapper;

/**
 * @desc 基础更新功能mapper
 *
 */
public interface UpdateMapper<T> extends Marker,
        UpdateByPrimaryKeyMapper<T>,
        UpdateByPrimaryKeySelectiveMapper<T>,
        UpdateByConditionMapper<T>,
        UpdateByConditionSelectiveMapper<T>,
        UpdateByExampleSelectiveMapper<T> {
}

4>提供删除功能mapper

package com.example.common.mapper.basics;

import com.example.common.mapper.defined.DeleteShamByIdsMapper;
import tk.mybatis.mapper.common.Marker;
import tk.mybatis.mapper.common.base.delete.DeleteByPrimaryKeyMapper;
import tk.mybatis.mapper.common.condition.DeleteByConditionMapper;
import tk.mybatis.mapper.common.ids.DeleteByIdsMapper;

/**
 * @desc 基础删除功能mapper
 *
 */
public interface DeleteMapper<T> extends Marker,
        tk.mybatis.mapper.common.base.delete.DeleteMapper<T>,
        DeleteByPrimaryKeyMapper<T>,
        DeleteByConditionMapper<T>,
        DeleteByIdsMapper<T>{
}

5>提供增删改查的基类 CommonMapper

package com.example.common.mapper.commonMapper;


import com.example.common.mapper.basics.DeleteMapper;
import com.example.common.mapper.basics.InsertMapper;
import com.example.common.mapper.basics.SelectMapper;
import com.example.common.mapper.basics.UpdateMapper;

/**
 * @param <T>
 * @desc 基础增删改查功能mapper
 */
public interface CommonMapper<T> extends
        DeleteMapper<T>,
        InsertMapper<T>,
        SelectMapper<T>,
        UpdateMapper<T> {
}

6>实体对象

package com.example.dao.entity;

import lombok.Data;

import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;

@Table(name="user")
@Data
public class User implements Serializable {

    @Id
    private Integer id;

    private String trueName;

    private String userName;
    
    private Integer isDeleted;

}

7>让自定义mapper继承CommenMapper,就可以使用这些语句了

package com.example.dao.mapper;

import com.example.common.mapper.commonMapper.CommonMapper;
import com.example.dao.entity.User;

public interface UserMapper extends CommonMapper<User> {

}

接下来我们会对 CommonMapper中提供删除方法的DeleteMapper进行增强,来给他添加逻辑删除的语句

1>我们自定义的Provider需要去继承 MapperTemplate并覆写构造方法
这个是源码中的批量删除

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package tk.mybatis.mapper.provider;

import java.util.Set;
import org.apache.ibatis.mapping.MappedStatement;
import tk.mybatis.mapper.MapperException;
import tk.mybatis.mapper.entity.EntityColumn;
import tk.mybatis.mapper.mapperhelper.EntityHelper;
import tk.mybatis.mapper.mapperhelper.MapperHelper;
import tk.mybatis.mapper.mapperhelper.MapperTemplate;
import tk.mybatis.mapper.mapperhelper.SqlHelper;

public class IdsProvider extends MapperTemplate {
    public IdsProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
        super(mapperClass, mapperHelper);
    }

    public String deleteByIds(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.deleteFromTable(entityClass, this.tableName(entityClass)));
        Set<EntityColumn> columnList = EntityHelper.getPKColumns(entityClass);
        if (columnList.size() == 1) {
            EntityColumn column = (EntityColumn)columnList.iterator().next();
            sql.append(" where ");
            sql.append(column.getColumn());
            sql.append(" in (${_parameter})");
            return sql.toString();
        } else {
            throw new MapperException("继承 deleteByIds 方法的实体类[" + entityClass.getCanonicalName() + "]中必须只有一个带有 @Id 注解的字段");
        }
    }

    public String selectByIds(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        this.setResultType(ms, entityClass);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.selectAllColumns(entityClass));
        sql.append(SqlHelper.fromTable(entityClass, this.tableName(entityClass)));
        Set<EntityColumn> columnList = EntityHelper.getPKColumns(entityClass);
        if (columnList.size() == 1) {
            EntityColumn column = (EntityColumn)columnList.iterator().next();
            sql.append(" where ");
            sql.append(column.getColumn());
            sql.append(" in (${_parameter})");
            return sql.toString();
        } else {
            throw new MapperException("继承 selectByIds 方法的实体类[" + entityClass.getCanonicalName() + "]中必须只有一个带有 @Id 注解的字段");
        }
    }
}

接下来我们对IdsProvider 进行扩展使他支持批量逻辑删除
1>创建IdsProvider的子类

package com.example.common.mapper.defined;

import org.apache.ibatis.mapping.MappedStatement;
import tk.mybatis.mapper.MapperException;
import tk.mybatis.mapper.entity.EntityColumn;
import tk.mybatis.mapper.mapperhelper.EntityHelper;
import tk.mybatis.mapper.mapperhelper.MapperHelper;
import tk.mybatis.mapper.mapperhelper.SqlHelper;
import tk.mybatis.mapper.provider.IdsProvider;

import java.util.Set;

public class IdsProviderDefined extends IdsProvider {

    public IdsProviderDefined(Class<?> mapperClass, MapperHelper mapperHelper) {
        super(mapperClass, mapperHelper);
    }

    public String deleteShamByIds(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.updateTable(entityClass, this.tableName(entityClass)));
        sql.append("<set> is_deleted='1' </set>");
        Set<EntityColumn> columnList = EntityHelper.getPKColumns(entityClass);
        if (columnList.size() == 1) {
            EntityColumn column = (EntityColumn)columnList.iterator().next();
            sql.append(" where ");
            sql.append(column.getColumn());
            sql.append(" in (${_parameter})");
            return sql.toString();
        } else {
            throw new MapperException("继承 deleteByIds 方法的实体类[" + entityClass.getCanonicalName() + "]中必须只有一个带有 @Id 注解的字段");
        }
    }


}

deleteShamByIds就是我们门批量逻辑删除的方法,这个方法其实就是再拼装sql,tk中提供了很多帮助我们拼装sql,和参数的类(SqlHelper,EntityHelper),我们可以使用
2>创建DeleteShamByIdsMapper接口

package com.example.common.mapper.defined;

import org.apache.ibatis.annotations.DeleteProvider;

public interface DeleteShamByIdsMapper<T> {
    @DeleteProvider(
            type = IdsProviderDefined.class,
            method = "dynamicSQL"
    )
    int deleteShamByIds(String var1);
    //这里的抽象方法的名称必须和IdsProviderDefined 中的方法一致
}

3>在DeleteMapper中继承我们自定义的逻辑删除接口DeleteShamByIdsMapper

package com.example.common.mapper.basics;

import com.example.common.mapper.defined.DeleteShamByIdsMapper;
import tk.mybatis.mapper.common.Marker;
import tk.mybatis.mapper.common.base.delete.DeleteByPrimaryKeyMapper;
import tk.mybatis.mapper.common.condition.DeleteByConditionMapper;
import tk.mybatis.mapper.common.ids.DeleteByIdsMapper;

/**
 * @desc 基础删除功能mapper
 *
 */
public interface DeleteMapper<T> extends Marker,
        tk.mybatis.mapper.common.base.delete.DeleteMapper<T>,
        DeleteByPrimaryKeyMapper<T>,
        DeleteByConditionMapper<T>,
        DeleteByIdsMapper<T>,
        DeleteShamByIdsMapper<T>{
}

到这里我们自定义的批量逻辑删除就定义好了,我们可以通过这种方式扩展通用mapper
大家有什么更好的方式欢迎留言

 类似资料: