搞过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的核心——反射 + 注解——就是这么玩的。
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦