搞过Java的码农都知道,在J2EE开发中一个(确切地说,应该是一类)很重要的框架,那就是ORM(Object Relational Mapping,对象关系映射)。它把Java中的类和数据库中的表关联起来,可以像操作对象那样操作数据表,十分方便。给码农们节约了大量的时间去摸鱼。其实它的本质一点都不复杂,而最核心的就是怎么实现对象和表之间的转换。之前对反射和注解有了一点了解,所以就试着来实现咱们自己的缝合怪。

首先,需要建立一个「表格」:

/**
 * 类注解,将类注解成数据库表
 *
 * @author xiangwang
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
   String name() default "";
}

然后,定义需要的数据库数据类型:

/**
 * 字段类型枚举
 *
 * @author xiangwang
 */
public enum Type {
   CHAR,
   STRING,
   BOOLEAN,
   INTEGER,
   LONG,
   FLOAT,
   DOUBLE,
   DATETIME
}
/**
 * 数据库字段类型
 *
 * @author xiangwang
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ColumnType {
   Type value() default Type.INTEGER;
}

再来完善字段相关信息:

/**
 * 字段信息
 *
 * @author xiangwang
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExtraInfo {
   String name() default "";
   int length() default 0;
}
/**
 * 明确字段约束
 *
 * @author xiangwang
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
    boolean primaryKey() default false;
    boolean allowNull() default true;
    boolean unique() default false;
    // 还可以增加默认值
}

把他们拼起来,成为完整的字段描述:

/**
 * 拼装注解,形成完整的字段嵌套注解
 *
 * @author xiangwang
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableColumn {
   ColumnType columntype() default @ColumnType;
   ExtraInfo extrainfo() default @ExtraInfo;
   Constraints constraints() default @Constraints;
}

最后,创建实体类,应用刚才写好的这些注解:

/**
 * 用户实体类
 *
 * @author xiangwang
 */
@DBTable(name = "User")
public class User {
   @TableColumn(
         columntype = @ColumnType(Type.INTEGER),
         extrainfo = @ExtraInfo(name = "id", length = 4),
         constraints = @Constraints(primaryKey = true))
   private String id;

   @TableColumn(
         columntype = @ColumnType(Type.STRING),
         extrainfo = @ExtraInfo(name = "name", length = 32),
         constraints = @Constraints(primaryKey = false, allowNull = false, unique = true))
   private String name;

   @TableColumn(
         columntype = @ColumnType(Type.INTEGER),
         extrainfo = @ExtraInfo(name = "age", length = 4),
         constraints = @Constraints(primaryKey = false))
   private Integer age;

   public String getId() { return id; }
   public void setId(String id) { this.id = id; }

   public String getName() { return name; }
   public void setName(String name) { this.name = name; }

   public Integer getAge() { return age; }
   public void setAge(Integer age) { this.age = age; }

   @Override
   public String toString() {
      return "User [id="   id   ", name="   name   ", age="   age   "]";
   }
}

来看看ORM是怎么工作的吧:

/**
 * 解析类型注解
 */
private static String getColumnType(ColumnType columntype) {
   String type = "";
   switch (columntype.value()) {
      case CHAR:
         type  = "CHAR";
         break;
      case STRING:
         type  = "VARCHAR";
         break;
      case BOOLEAN:
         type  = "BIT";
         break;
      case INTEGER:
         type  = "INT";
         break;
      case LONG:
         type  = "BIGINT";
         break;
      case FLOAT:
         type  = "FLOAT";
         break;
      case DOUBLE:
         type  = "DOUBLE";
         break;
      case DATETIME:
         type  = "DATETIME";
         break;
      default:
         type  = "VARCHAR";
         break;
   }
   return type;
}
/**
 * 解析信息注解
 */
private static String getExtraInfo(ExtraInfo extrainfo) {
   String info = "";
   if (null != extrainfo.name()) {
      info = extrainfo.name();
   } else {
      return null;
   }
   if (0 < extrainfo.length()) {
      info  = " ("   extrainfo.length()   ")";
   } else {
      return null;
   }
   return info;
}
/**
 * 解析约束注解
 */
private static String getConstraints(Constraints con) {
   String constraints = "";
   if (con.primaryKey()) {
      constraints  = " PRIMARY KEY";
   }
   if (!con.allowNull()) {
      constraints  = " NOT NULL";
   }
   if (con.unique()) {
      constraints  = " UNIQUE";
   }

   return constraints;
}

做了那么多的铺垫,终于到了临门一脚了,实现一个缝合怪了:

/**
 * 临门一脚:实现一个缝合怪
 */
private static void createTable(List<String> list) {
   for (String className : list) {
      Class<?> clazz;
      try {
         clazz = Class.forName(className);
         DBTable dbTable = clazz.getAnnotation(DBTable.class);
         if (dbTable == null) {// 无DBTable注解
            continue;
         }
         // 转大写
         String tableName = clazz.getSimpleName().toUpperCase();
         StringBuilder sql = new StringBuilder("CREATE TABLE "   tableName   "(");
         for (Field field : clazz.getDeclaredFields()) {
            // 反射得到注解
            Annotation[] anns = field.getDeclaredAnnotations();
            if (anns.length < 1) {
               continue;
            }
            String columnInfo = "";
            // 类型判断
            if (anns[0] instanceof TableColumn) {
               TableColumn column = (TableColumn) anns[0];
               String type = getColumnType(column.columntype());
               columnInfo = getExtraInfo(column.extrainfo());
               // 代替(
               columnInfo = columnInfo.replace("(", type   "(");
               columnInfo  = getConstraints(column.constraints());
            }
            sql.append("\n "   columnInfo   ",");
         }
         // 删除尾部的逗号
         String tableCreate = sql.substring(0, sql.length() - 1)   "\n);";
         System.out.println(tableCreate);
      } catch (ClassNotFoundException e) {
         e.printStackTrace();
      }
   }
}

验证效果的时候到了:

public static void main(String[] args) {
   Class<?> clazz = User.class;
   List<String> list = new ArrayList<>();
   list.add(clazz.getName());

   createTable(list);
}

当然,实际的运营于生产环境中的ORM框架可要比这个小玩意复杂多了。但千变万变,原理不变,ORM的核心——反射 注解——就是这么玩的。

到此这篇关于Java注解实现自己的ORM的文章就介绍到这了,更多相关Java注解ORM内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

详解Java注解实现自己的ORM的更多相关文章

  1. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  3. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  4. Java实现世界上最快的排序算法Timsort的示例代码

    Timsort 是一个混合、稳定的排序算法,简单来说就是归并排序和二分插入排序算法的混合体,号称世界上最好的排序算法。本文将详解Timsort算法是定义与实现,需要的可以参考一下

  5. Java日期工具类的封装详解

    在日常的开发中,我们难免会对日期格式化,对日期进行计算,对日期进行校验,为了避免重复写这些琐碎的逻辑,我这里封装了一个日期工具类,方便以后使用,直接复制代码到项目中即可使用,需要的可以参考一下

  6. 一种angular的方法级的缓存注解(装饰器)

    本篇文章主要介绍了一种angular的方法级的缓存注解(装饰器),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  7. Java设计模式之模板方法模式Template Method Pattern详解

    在我们实际开发中,如果一个方法极其复杂时,如果我们将所有的逻辑写在一个方法中,那维护起来就很困难,要替换某些步骤时都要重新写,这样代码的扩展性就很差,当遇到这种情况就要考虑今天的主角——模板方法模式

  8. Java 中 Class Path 和 Package的使用详解

    这篇文章主要介绍了Java 中 Class Path和Package的使用详解,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下

  9. java SpringBoot 分布式事务的解决方案(JTA+Atomic+多数据源)

    这篇文章主要介绍了java SpringBoot 分布式事务的解决方案(JTA+Atomic+多数据源),文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下

  10. Java一维数组和二维数组元素默认初始化值的判断方式

    这篇文章主要介绍了Java一维数组和二维数组元素默认初始化值的判断方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

随机推荐

  1. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  3. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  4. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  5. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  6. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  7. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  8. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  9. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Spring JdbcTemplate执行数据库操作详解

    JdbcTemplate是Spring框架自带的对JDBC操作的封装,目的是提供统一的模板方法使对数据库的操作更加方便、友好,效率也不错,这篇文章主要介绍了Spring JdbcTemplate执行数据库操作,需要的朋友可以参考下

返回
顶部