首页 > 编程语言 >Java注解(2):实现自己的ORM

Java注解(2):实现自己的ORM

时间:2022-10-15 09:33:09浏览次数:51  
标签:Java String default ORM 注解 type public name

搞过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,String,default,ORM,注解,type,public,name
From: https://www.cnblogs.com/xiangwang1111/p/16793056.html

相关文章

  • JavaWeb学习3:Tomcat
    1、安装Tomcathttps://tomcat.apache.org/2、Tomcat启动和关闭启动关闭3、Tomcat的配置可以配置启动的端口号Tomcat默认端口号:8080<Connectorport="8080"......
  • JavaWeb学习4:Http
    1、什么是http超文本传输协议(HyperTextTransferProtocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。2、两个时代HTTP/1.0客户端可以与web服务器连接后,只......
  • JavaWeb学习5:Maven
    为什么要学习这个技术?在javaweb开发中,需要使用大量的jar包,这种jar包需要手动的导入如何让一个东西自动导入和配置jar包所以Maven诞生了maven就是一个架构管理工具1......
  • JavaWeb学习6:Servlet
    1、什么是Servletsun公司用于开发动态web的一种技术sun公司在这里API中提供了一个接口,叫做Servlet,如果想开发一个Servlet程序,只需要完成两个步骤:编写一个类,实现Servle......
  • delphi FormatFloat随笔
    用FormatFloat来处理浮点数,是一个很好的选择.我这里只讲一种语法:FormatFloat(格式,数值)第一坑:第二参数为数值类型,别传个文本值进去.第二坑:返回值是一......
  • 如何在 JavaScript中将axios与async/await一起使用?
    Axios是一个基于promise的处理异步HTTP请求的客户端。本指南将演示如何通过async/await处理这些请求。安装和使用要使用Axios,您需要使用npmnpminstallaxios......
  • 肖sir__java_string概述
    string字符串 1、字符串的操作  2、一个登录的账号和密码实时使用字符串账号:字符串密码:字符串publicclassjava2_进阶001{publicstaticvoidmain(Str......
  • 肖sir__java__Java访问控制修饰符详解(public、 private、protected 和 friendly)
    1、  1.private用private修饰的类成员,只能被该类自身的方法访问和修改,而不能被任何其他类(包括该类的子类)访问和引用。因此,private修饰符具有最高的保护级别。例......
  • JavaFx 使用字体图标记录
    原文:JavaFx使用字体图标记录-Stars-One的杂货小窝之前其实也是研究过关于字体图标的使用,还整了个库Tornadofx学习笔记(4)——IconTextFx开源库,整合5000+个字体图标......
  • java: Retirement
    /***版权所有2022涂聚文有限公司*许可信息查看:*描述:*CoreJava,VolumeI:Fundamentals,TwelfthEditionbyCayS.Horstamnn*CoreJava,VolumeII:Adv......