Mybatis通用接口-基于Provider

新项目的话建议使用Mybatis-plus会好点

1、创建实体类注解

java 复制代码
/****
 * 表名
 * @author
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface TableName {

    String value() default "";
    /***
     * 别名 
     */
    String alias() default "";
}
java 复制代码
/**
 * 表主键
 * @author
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface TableId {
    String value() default "";
}
java 复制代码
public enum FieldStrategy {
    IGNORED,
    NOT_NULL,
    NOT_EMPTY,
    DEFAULT,
    NEVER;

    private FieldStrategy() {
    }
}
java 复制代码
import java.lang.annotation.*;

/****
 * 实体属性注解
 *@author chenzhongchao
 *@date 2024/9/6
 *@time 11:09
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface TableField {
    /**
     * 数据库字段名
     */
    String value() default "";
    FieldStrategy insertStrategy() default FieldStrategy.DEFAULT;
    /**
     * 字段是否存在
     */
    boolean exist() default true;
    FieldStrategy updateStrategy() default FieldStrategy.DEFAULT;
    FieldStrategy whereStrategy() default FieldStrategy.DEFAULT;
    /**
     * jdbc类型
     */
    JdbcType jdbcType() default JdbcType.UNDEFINED;
}

2、创建Mapper基类

java 复制代码
/****
 * 通用mapper基类,采用Provider方式省略xml编写sql,复杂性sql请自行编写xml
 * 实体必须有@TableName注解
 * 属性必须有@TableField注解
 * 否则默认类名、属性名作为表名列名
 *@author
 */
public interface BaseMapper<T> {
    /****
     * 根据实体新增数据,为空的字段不处理
     *@param var1 实体
     *@return 影响行数
     */
    @InsertProvider(type = InsertSqlProvider.class, method = "sql")
    int insert(T var1);
    /**
     * 根据主键查询
     * @param var1 主键
     * @return  实体
     */
    @SelectProvider(type = SelectByPrimarySqlProvider.class, method = "sql")
    T selectByPrimaryKey(String var1);
    /**
     * 根据实体查询列表(非空属性作为条件,只做等于,复杂请写xml)
     * @param var1 实体
     * @return  实体列表
     */
    @SelectProvider(type = SelectListSqlProvider.class, method = "sql")
    List<T> selectList(T var1);
    @UpdateProvider(type = UpdateSqlProvider.class, method = "sql")
    int updateByPrimaryKey(T var1);

    @DeleteProvider(type = DeleteSqlProvider.class, method = "sql")
    int deleteByPrimaryKey(String var1);
   

}

3、实体类处理

java 复制代码
public class TableInfo {

    /**
     * 表名
     */
    private String tableName;
    /**
     * 表名
     */
    private String tableAliasName;
    /**
     * 实体类型field
     */
    private Field[] fields;
    /**
     * 实体类型非空field
     */
    private Field[] notNullFields;
    /**
     * 所有列名
     */
    private String[] notNullColumns;
    /**
     * 主键列名
     */
    private String primaryKeyColumn;

    /**
     * 所有列名
     */
    private String[] columns;

    public String getTableName() {
        return tableName;
    }
    public String getTableAliasName() {
        return tableAliasName;
    }
    public String[] getColumns() {
        return columns;
    }

    public Field[] getFields() {
        return fields;
    }

    public Field[] getNotNullFields() {
        return notNullFields;
    }

    public String[] getNotNullColumns() {
        return notNullColumns;
    }

    private TableInfo() {}

    /**
     * 获取主键的where条件,如 id = #{id}
     *
     * @return  主键where条件
     */
    public String getPrimaryKeyWhere() {
        String pk = this.primaryKeyColumn;
        return pk + " = #{" + pk + "}";
    }

    /**
     * 获取TableInfo的简单工厂
     *
     * @param mapperType mapper类型
     * @return    {@link TableInfo}
     */
    public static TableInfo of(Class<?> mapperType) {
        Class<?> entityClass = entityType(mapperType);
        // 获取不含有@NoColumn注解的fields
        TableInfo tableInfo = new TableInfo();
        Field[] fields = excludeNoColumnField(entityClass,tableInfo);

        tableInfo.fields = fields;
        TableName tableName = tableName(entityClass);
        tableInfo.tableName = tableName== null ?  entityClass.getSimpleName() : tableName.value();
        tableInfo.tableAliasName = tableName== null ?  entityClass.getSimpleName() : tableName.alias();
        return tableInfo;
    }
    /**
     * 过滤静态的field
     *
     * @param entityClass 实体类型
     * @return 不包含@NoColumn注解的fields
     */
    public static Field[] excludeNoColumnField(Class<?> entityClass,TableInfo tableInfo) {
        List<Field> fields = new ArrayList<>();
        List<Field> noNullFields = new ArrayList<>();
        List<String> columns = new ArrayList<>();
        List<String> notNullColumns = new ArrayList<>();
        Field[] allFields = entityClass.getDeclaredFields();
        for (Field field:allFields
             ) {
            TableId id = field.getAnnotation(TableId.class);
            if (id != null){
                tableInfo.primaryKeyColumn = StringUtils.isEmpty(id.value())?field.getName():id.value();
                columns.add(StringUtils.isEmpty(id.value())?field.getName():id.value());
            }
            TableField tableField = field.getAnnotation(TableField.class);
            if (tableField != null&&!Modifier.isStatic(field.getModifiers())&&tableField.exist()){
                fields.add(field);
                columns.add(StringUtils.isEmpty(tableField.value())?field.getName():tableField.value());
            }
        }
        tableInfo.columns = columns.toArray(new String[0]);
        return fields.toArray(new Field[0]);
    }
    public static Field[] getNoColumnField(Object entityClass,TableInfo tableInfo) {
        List<Field> noNullFields = new ArrayList<>();
        List<String> notNullColumns = new ArrayList<>();
        Field[] allFields = entityClass.getClass().getDeclaredFields();
        for (Field field:allFields
        ) {
            TableId id = field.getAnnotation(TableId.class);
            if (id != null){
                try {
                    field.setAccessible(true);
                    Object value =  field.get(entityClass);
                    if (value!=null){
                        noNullFields.add(field);
                        notNullColumns.add(StringUtils.isEmpty(id.value())?field.getName():id.value());
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            TableField tableField = field.getAnnotation(TableField.class);
            if (tableField != null&&!Modifier.isStatic(field.getModifiers())&&tableField.exist()){
                try {
                    field.setAccessible(true);
                    Object value =  field.get(entityClass);
                    if (value!=null){
                        noNullFields.add(field);
                        notNullColumns.add(StringUtils.isEmpty(tableField.value())?field.getName():tableField.value());
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }

            }
        }
        tableInfo.notNullColumns = notNullColumns.toArray(new String[0]);
        tableInfo.notNullFields = noNullFields.toArray(new Field[0]);

        return noNullFields.toArray(new Field[0]);
    }
    /**
     * 获取表名
     *
     * @param entityType  实体类型
     * @return      表名
     */
    public static TableName tableName(Class<?> entityType) {
        TableName tableName = entityType.getAnnotation(TableName.class);
        return tableName ;
    }

    /**
     * 获取BaseMapper接口中的泛型类型
     *
     * @param mapperType  mapper类型
     * @return       实体类型
     */
    public static Class<?> entityType(Class<?> mapperType) {
        return Stream.of(mapperType.getGenericInterfaces())
                .filter(ParameterizedType.class::isInstance)
                .map(ParameterizedType.class::cast)
                .filter(type -> type.getRawType() == BaseMapper.class)
                .findFirst()
                .map(type -> type.getActualTypeArguments()[0])
                .filter(Class.class::isInstance).map(Class.class::cast)
                .orElseThrow(() -> new IllegalStateException("未找到BaseMapper的泛型类 " + mapperType.getName() + "."));
    }

    /**
     * 绑定参数
     *
     * @param field  字段
     * @return        参数格式
     */
    public static String bindParameter(Field field) {
        TableField tableField = field.getAnnotation(TableField.class);
        if (tableField != null&&!Modifier.isStatic(field.getModifiers())&&tableField.exist()){
            String value =  "#{" + field.getName() +",jdbcType="+tableField.jdbcType()+ "}";
            return value;
        }
        return "#{" + field.getName() + "}";
    }

    /**
     * 获取该字段的参数赋值语句,如 user_name = #{userName}
     * @param field  字段
     * @return       参数赋值语句
     */
    public static String assignParameter(Field field) {
        String column = null;
        TableField tableField = field.getAnnotation(TableField.class);
        if (tableField != null&&!Modifier.isStatic(field.getModifiers())&&tableField.exist()){
            column=StringUtils.isEmpty(tableField.value())?field.getName():tableField.value();
        }
        if (StringUtil.isBlank(column)){
            TableId id = field.getAnnotation(TableId.class);
            if (id != null){
                column = StringUtils.isEmpty(id.value())?field.getName():id.value();
            }
        }
        return column + " = " + bindParameter(field);
    }
}

4、Provider

java 复制代码
/****
 * SqlProvider基类 创建表信息
 * @author
 */
public class BaseSqlProviderSupport {
    /**
     * key -> mapper class   value -> tableInfo
     */
    private static Map<Class<?>, TableInfo> tableCache = new ConcurrentHashMap<>(128);

    /**
     * 获取表信息结构
     *
     * @param context  provider context
     * @return  表基本信息
     */
    protected TableInfo tableInfo(ProviderContext context) {

        // 如果不存在则创建-会调用TableInfo的of方法
        return tableCache.computeIfAbsent(context.getMapperType(), TableInfo::of);
    }

}
java 复制代码
/****
 * 根据实体新增数据,为空字段不添加
 * @author
 */
public class InsertSqlProvider extends BaseSqlProviderSupport{
    /**
     * sql
     * @param context context
     * @return  sql
     */
    public String sql(Object entity,ProviderContext context) {
        TableInfo table = tableInfo(context);
        TableInfo.getNoColumnField(entity,table);
        String sql = new SQL()
                .INSERT_INTO(table.getTableName())
                .INTO_COLUMNS(table.getNotNullColumns())
                .INTO_VALUES(Stream.of(table.getNotNullFields()).map(TableInfo::bindParameter).toArray(String[]::new))
                .toString();
        return sql;
    }
}
java 复制代码
/****
 * 根据主键查询数据
 * @author
 */
public class SelectByPrimarySqlProvider  extends BaseSqlProviderSupport{
    /**
     * sql
     * @param context context
     * @return  sql
     */
    public String sql(ProviderContext context) {
        TableInfo table = tableInfo(context);
        //mapper里的参数会直接赋值给#{id}
        String sql = new SQL()
                .SELECT(table.getColumns())
                .FROM(table.getTableName())
                .WHERE(table.getPrimaryKeyWhere())
                .toString();

        return sql;
    }
}
java 复制代码
/****
 * 根据主键查询数据
 * @author
 */
public class SelectListSqlProvider extends BaseSqlProviderSupport{
    /**
     * sql
     * @param context context
     * @return  sql
     */
    public String sql(Object entity,ProviderContext context) {
        TableInfo table = tableInfo(context);
        TableInfo.getNoColumnField(entity,table);
        //mapper里的参数会直接赋值给#{id}
        String sql = new SQL()
                .SELECT(table.getColumns())
                .FROM(table.getTableName())
                .WHERE(Stream.of(table.getNotNullFields())
                        .map(TableInfo::assignParameter)
                        .toArray(String[]::new)).toString();

        return sql;
    }
}

剩下根据自己的要求编写

5、服务接口

java 复制代码
/****
 * 后续有需要扩展的公共方法接口可以放在这里
 * @author
 */
public interface IService<T> {
}
java 复制代码
/****
 * 后续有需要扩展的公共方法接口的实现可以放在这里
 * @author
 */
public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {

    @Resource
    protected M baseMapper;


    public ServiceImpl() {
    }

    public M getBaseMapper() {
        return this.baseMapper;
    }




}

6、使用

java 复制代码
/**
 * @author
 */
@TableName(value = "TableName")
@Data
public class DynamicApiHistory  {


    @TableField("apiId")
    private String apiId;

    @TableId("apiHistoryId")
    private String apiHistoryId;

    @TableField("orgCode")
    private String orgCode;
    @TableField(value = "dynamicApiColumn",jdbcType = JdbcType.CLOB)
    private String dynamicApiColumn;
}
java 复制代码
/**
 * @author
 */
public interface IDynamicApiHistoryService extends IService<DynamicApiHistory> {
    int insert(DynamicApiHistory dynamicApiHistory);
}
java 复制代码
/**
 * @author
 */
@Service
public class DynamicApiHistoryServiceImpl extends ServiceImpl<DynamicApiHistoryMapper, DynamicApiHistory> implements IDynamicApiHistoryService {
    @Resource
    DynamicApiService dynamicApiService;

    @Override
    public int insert(DynamicApiHistory dynamicApiHistory ) {
      return baseMapper.insert(dynamicApiHistory);
    }

}
相关推荐
XiaoLeisj25 分钟前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck26 分钟前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei26 分钟前
java的类加载机制的学习
java·学习
励志成为嵌入式工程师1 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉2 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer2 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq2 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
Yaml42 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~2 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616882 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端