hibernate 里面通过注解,映射等手段,可以自动生成表,现在模拟实现。随便学学注解如何使用。
首先,我们要定义几个注解:
Table 用于定义表名字,类型使用Type
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Table { // 表名 String name() default ""; }
Types,定义一下常用的类型,这里我写得比较乱,也可以使用 枚举 等其他方法,方便使用
import java.util.HashMap; import java.util.Map; public class Types { // 自己定义的一些基本类型,和数据对应就行了,就是组成字符串 // 这是临时的办法,需要大家从新设计 public static final String VARCHAR = "VARCHAR"; public static final String INT = "INT"; public static final String BOOLEAN = "BOOLEAN"; // 默认长度,和数据库对应 public static final int STRING_LENGTH =32; public static final int INT_LENGTH = 10; // 将类型 已经默认长度,放入集合 public static Map<String,Integer> map = new HashMap(); static{ map.put(VARCHAR, STRING_LENGTH); map.put(INT, INT_LENGTH); map.put(BOOLEAN, 0); } public static String getType(String type,int length){ if(type == null){ throw new RuntimeException("Not recognized the type :"+type); } // 防止boolean 这类型 if( length > 0){ return type+"("+length+")"; } return type; } public static String getString(){ return getStirng(VARCHAR, STRING_LENGTH); } public static String getString(int length){ return getStirng(VARCHAR, length); } public static String getInt(){ return getStirng(INT, INT_LENGTH); } public static String getInt(int length){ return getStirng(INT, length); } public static String getBoolean(){ return BOOLEAN; } private static String getStirng(String str,int length){ return str+"("+length+")"; } }
这是建表的一些约束条件,只写普通的,可以自己添加
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Constraints{ // 是否主键,是否为空 等 boolean primaryKey() default false; boolean allowNull() default true; boolean unique() default false; }
Column 是 对映实体Bean
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Column { // 名字 String name() default ""; // 长度 int length() default 0; // 类型 String type(); // 约束,这里可以使用其他注解类型。 Constraints constraints() default @Constraints; }
下面看我们的实体
@Table(name="TestTable") @SuppressWarnings("unused") public class TestTable { // 指定了列名字,约束为 主键,长度 以及类型 @Column(name="id",constraints=@Constraints(primaryKey=true),length=15, type = Types.INT) private int id; // 列名 类型,如果都没有,只能使用默认的,也可以在后面处理类 里面 定义 @Column(name="name", type = Types.VARCHAR) private String name; @Column(type = Types.BOOLEAN) private Boolean sex; }
基本工作完成了,下面就是如果完成解析,获得我们需要的SQL:
import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; public class CrateTable { public static void main(String[] args) { // 类路径 System.out.println(getCreateSQL("com.annotation.TestTable")); } @SuppressWarnings("unused") public static String getCreateSQL(String className){ try { // 加载类 Class<?> c = Class.forName(className); // 获得指定类型的注解对象 Table table = c.getAnnotation(Table.class); if(table == null){ System.out.println("No Table annotation in class "+ className); return null; } String tableName = table.name(); if(tableName.length() == 0){ // 如果没指定长度, 可以默认以类的名字 命名表名 tableName = c.getName().toUpperCase(); } List<String> columns = new ArrayList<String>(); // 遍历所有字段 for(Field field : c.getDeclaredFields()){ String columnName = null; String columnType = null; // 获得每个字段上的注解信息,这里不需要继承的注解 // 还有其他方法,具体可以去看API Annotation[] anns = field.getDeclaredAnnotations(); if(anns.length == 0){ // 如果该字段没有注解,表示这个字段,不需要生成 continue; }else{ // 获得该字段的注解信息,默认这设置的column注解信息 Column col = (Column) anns[0]; // 获得建表 语句 字符串 String name = col.name(); String type = col.type(); Integer length = col.length(); String constraint = getConstraints(col.constraints()); if(name.length() == 0){ // 获得默认字段名 columnName = field.getName(); }else{ columnName = name; } if(type.length() == 0){ // 获得默认类型 columnType = field.getType().toString(); }else{ columnType = type; } if(length == 0){ // 获取默认长度 length = Types.map.get(type); if(length == null){ throw new RuntimeException("Type cant't be solved :"+type); } } type = Types.getType(type,length); columns.add(columnName + " "+ type+constraint); } } if(columns.size() == 0){ throw new RuntimeException("There is no field in "+className); } StringBuilder createCommand = new StringBuilder("CREATE TABLE "+tableName +" ("); for(String column : columns){ createCommand.append("\n "+column +" ,"); } String createTable = createCommand.substring(0,createCommand.length()-1)+" \n );"; return createTable; } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } /** * 获得约束条件 * @param con * @return */ private static String getConstraints(Constraints con){ String constraints = ""; if(!con.allowNull()){ constraints += " NOT NULL"; } if(con.primaryKey()){ constraints += " PRIMARY KEY"; } if(con.unique()){ constraints += " UNIQUE "; } return constraints; } /** * 获得所需要的字段 * @param fields * @return */ public static List<Field> getNeedField(Field[] fields){ List<Field> allFileds = new ArrayList<Field>(); for(Field field : fields){ // 获得每个字段上的注解信息,这里不需要继承的注解 Annotation[] anns = field.getDeclaredAnnotations(); if(anns.length != 0){ // 如果该字段没有注解,表示这个字段,不需要生成 allFileds.add(field); } } return allFileds; } }
上面用了一下反射的功能,有些比较死板,要灵活构建,需要从写。可以进行测试,获得的SQL,是否可以生成表,当然也可以移动到xml 配置文件里面,这里我暂时不写了,先看测试。
其实只需要打印出SQL,看看是否正确就行了。
下面的方法, 用了JDBC连接。详情请看:http://greemranqq.iteye.com/admin/blogs/1830200
/** * 执行SQL * @param sql */ public static void executeSql(String sql){ conn = ConnectionUtil.getConnection(); try { PreparedStatement ps = conn.prepareStatement(sql); ps.execute(); } catch (SQLException e) { e.printStackTrace(); }finally{ ConnectionUtil.colse(conn); } } public static void main(String[] args) { String sql = CrateTable.getCreateSQL("com.annotation.TestTable"); System.out.println(sql); executeSql(sql); }
这是我新学的经验,欢迎大家指正,有更好的方式 希望能留言,这样的方式 感觉不好。