在使用各种框架的时候,我经常会看到各种@,加了这个神奇的符号,我们就可以实现许多神奇的功能,这两天,我按照Thinking in java 的思路实现了一个简易的生成sql数据表的程序
DataTable 注解
package annotation.database;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author: miaoxu
* @Description:
* @Date: Created in 2017/11/14 0014
* @Modified By :
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
public String name() default "";
}
@Target注解用来说明这个注解应用的级别,Type代表应用的是class,接口等,后面出现的Field代表应用的是变量,@Retention表示需要在什么级别保存该注解信息,Running代表在运行期间也要保留注解,因此可以通过反射机制读取注解的信息这个注解的成员只有一个name方法,我们可以在使用注解的时候,给name赋值,如果没有指定值,默认值是空字符串,每个注解前面都会有@符号,代表这是一个注解,实际上,在idea中,直接创建class的时候,就可以选择创建注解。非常方便
constraints 注解
package annotation.database;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author: miaoxu
* @Description:
* @Date: Created in 2017/11/14 0014
* @Modified By :
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
boolean primaryKey() default false;
boolean allowNull() default true;
boolean unique() default false;
}
constrains实现的是数据库中对字段的约束,正如上面所定义的那样,常见的约束有是否是主键,是否允许为空等等,这个注解极大地方便了后面字段注解的实现
SQLString 注解
package annotation.database;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author: miaoxu
* @Description:
* @Date: Created in 2017/11/14 0014
* @Modified By :
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
int value() default 0;
String name() default "";
Constraints constrants() default @Constraints;
}
SQlString的value实际上是为了代表数据库中的varchar长度,name是字段名
package annotation.database;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author: miaoxu
* @Description:
* @Date: Created in 2017/11/14 0014
* @Modified By :
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger {
String name() default "";
Constraints constraints() default @Constraints;
}
Member要生成的表
package annotation.database;
/**
* @Author: miaoxu
* @Description:
* @Date: Created in 2017/11/14 0014
* @Modified By :
*/
@DBTable(name = "member")
public class Member {
@SQLString(30)
String firstname;
@SQLString(50)
String lastname;
@SQLInteger
Integer age;
@SQLString(value = 30, constrants = @Constraints(primaryKey = true))
String handle;
public String getHandle()
{
return handle;
}
public String getFirstname() {
return firstname;
}
public String getLastname() {
return lastname;
}
public Integer getAge() {
return age;
}
@Override
public String toString() {
return handle;
}
}
Member类就是我们要生成的表
TableCreator类
package annotation.database;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: miaoxu
* @Description:
* @Date: Created in 2017/11/14 0014
* @Modified By :
*/
public class TableCreator {
public static void main(String[] args) throws Exception{
if (args.length < 1)
{
System.out.println("arguments: annotated classes");;
}
for (String className: args)
{
Class<?> cl = Class.forName(className);
DBTable dbTable= cl.getAnnotation(DBTable.class);
if (dbTable == null)
{
System.out.println("No DBTable Annoation in class " + className);
continue;
}
String tablename = dbTable.name();
if (tablename.length() < 1)
{
tablename = cl.getName().toUpperCase();
}
List<String> columnDefs = new ArrayList<String>();
for (Field field: cl.getDeclaredFields())
{
String columnName = null;
Annotation[] anns = field.getDeclaredAnnotations();
if (anns.length < 1)
{
continue;
}
if (anns[0] instanceof SQLInteger) {
SQLInteger sInt = (SQLInteger) anns[0];
if (sInt.name().length() < 1)
{
columnName = field.getName().toLowerCase();
}
else
{
columnName = sInt.name();
}
columnDefs.add(columnName + " INT" + getConstraints(sInt.constraints()));;
}
if (anns[0] instanceof SQLString)
{
SQLString sqlString = (SQLString)anns[0];
if (sqlString.name().length() < 1)
{
columnName = field.getName().toUpperCase();
}
else
{
columnName = sqlString.name();
}
columnDefs.add(columnName + " VarChar(" + sqlString.value() + ")" + getConstraints(sqlString.constrants()));
}
}
StringBuilder createCommmand = new StringBuilder("Create table" + tablename + "(");
for (String columnDef: columnDefs)
{
createCommmand.append("\n " + columnDef + ",");
}
String tablecreats = createCommmand.substring(0, createCommmand.length() - 1) + ");";
System.out.println("Table create Sql for" + className + "is:\n" + tablecreats);
}
}
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;
}
}
TableCreator类主要用来对注解进行解析,通过传进的带解析的类名,Class.forName(className) 生成