JAVA 注解(Annotation) ,模拟自动创建表
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;// 获得每个字段上的注解信息,这里不需要继承的注解// 还有其他方法,具体可以去看APIAnnotation[] 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);}
?这是我新学的经验,欢迎大家指正,有更好的方式 希望能留言,这样的方式 感觉不好。
?
type = Types.getType(type);