当前位置: 首页 > article >正文

Mybatis通用接口-基于Provider

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

1、创建实体类注解

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

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

    private FieldStrategy() {
    }
}
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基类

/****
 * 通用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、实体类处理

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

/****
 * 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);
    }

}
/****
 * 根据实体新增数据,为空字段不添加
 * @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;
    }
}
/****
 * 根据主键查询数据
 * @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;
    }
}
/****
 * 根据主键查询数据
 * @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、服务接口

/****
 * 后续有需要扩展的公共方法接口可以放在这里
 * @author
 */
public interface IService<T> {
}
/****
 * 后续有需要扩展的公共方法接口的实现可以放在这里
 * @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、使用

/**
 * @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;
}
/**
 * @author
 */
public interface IDynamicApiHistoryService extends IService<DynamicApiHistory> {
    int insert(DynamicApiHistory dynamicApiHistory);
}
/**
 * @author
 */
@Service
public class DynamicApiHistoryServiceImpl extends ServiceImpl<DynamicApiHistoryMapper, DynamicApiHistory> implements IDynamicApiHistoryService {
    @Resource
    DynamicApiService dynamicApiService;

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

}


http://www.kler.cn/news/305760.html

相关文章:

  • 一维稳态与非稳态导热的详细分析
  • 力扣100题——栈和堆
  • 设计模式 装饰模式(Decorator Pattern)
  • 讨论人机交互研究中大语言模型的整合与伦理问题
  • Mysql----索引与事务
  • NLP基础及其代码-BERT系列
  • Ubuntu 24.04 配置 nginx + php-fpm
  • 异常冲突行为和危险识别系统源码分享
  • Rust使用dotenvy读取环境变量
  • 网络通信流程
  • 树和二叉树基本术语、性质
  • 劳特巴赫ICD调试器CMM调用烧录框架固件研究之C语言版本
  • GitHub每日最火火火项目(9.15)
  • 影刀RPA实战:网页爬虫之CSDN博文作品数据
  • 基于C#+SQL Server2008 开发三层架构(CS界面)图书管理系统
  • SQLmap使用请求包进行sql爆破
  • 鹏哥C语言自定义笔记重点(67-)
  • MySQL练手题--公司和部门平均工资比较(困难)
  • 【前端UI框架】VUE ElementUI 离线文档 可不联网打开
  • 后端面试经典问题汇总
  • MATLAB中的函数编写有哪些最佳实践
  • Python(PyTorch)和MATLAB及Rust和C++结构相似度指数测量导图
  • JS的事件以及常见事件的绑定
  • Win电脑使用Ollama与Open Web UI搭建本地大语言模型运行工具
  • Go 中 Gin 框架的使用指南
  • GIS 中的 3D 分析
  • 数据结构基础详解:哈希表【C语言代码实践篇】开放地址法__拉链法_哈希表的创建_增删查操作详解
  • 详解c++多态---上
  • 移动应用开发与测试赛题2
  • 将 YOLOv10 模型从 PyTorch 转换为 ONNX