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;
				// 获得每个字段上的注解信息,这里不需要继承的注解
				// 还有其他方法,具体可以去看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);
		
	}

 这是我新学的经验,欢迎大家指正,有更好的方式 希望能留言,这样的方式 感觉不好。

 

你可能感兴趣的:(java,注解,Hibernate,annotation,自动建表)