在关系数据库中,每个表中的各个字段都有特定的含义,并且字段与字段之间存在某种联系。所以我们可以通过对象/关系映射的方式,将JavaBean对象存储在数据库中。下面我们就实现这一功能。

一、首先定义一个注解来标注表名

package annotations.database;

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 DBTable {
    public String name() default ""; //用来指定表名
}

二、对表中的每个字段定义注解

1.首先定义约束注解(用来标注该字段是否为主键、是否为空)

package annotations.database;

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 Contraints {
    boolean primaryKey() default false; //确定该字段是否为主键
    boolean unique() default false;     //确定该字段是否唯一
    boolean allowNull() default false;  //确定该字段是否为空
}

2.定义字符串类型的注解

package annotations.database;

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 SQLString {
    int value() default 0;          //定义字段值  
    String name() default "";       //定义字段名
    Contraints constraints() default @Contraints;   //注解嵌套
}

3.定义整型的注解

package annotations.database;

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 SQLInteger {
    String name() default "";           //字段名
    Contraints contraints() default @Contraints;  //注解嵌套
}

三、对Bean进行注解

package annotations.database;

@DBTable(name = "MEMBER") //定义表名为MEMBER
public class Member {
    @SQLString(30) //该字段的长度为30个字符
    String firstName;
    @SQLString(30)
    String lastName;
    @SQLInteger
    Integer age;
    @SQLString(value = 30, constraints = @Contraints(primaryKey = true))
    String handle;
    static int memberCount;

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public Integer getAge() {
        return age;
    }

    public String getHandle() {
        return handle;
    }

    public String toString() {
        return handle;
    }
}

四、注解处理器的实现

package annotations.database;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class TableCreator {
    public static void main(String[] args) throws ClassNotFoundException {
        if (args.length < 1) {
            System.out.println("参数:使用注解的class文件");
            System.exit(0);
        }
        for (String className : args) {
            Class<?> c1 = Class.forName(className); //将传入的class文件转变为CLASS对象
            DBTable dbTable = c1.getAnnotation(DBTable.class); //获取Member中使用到的DBTable注解
            if (dbTable == null) {
                System.out.println(className + "中没有使用DBTable注解");
                continue;
            }
            String tableName = dbTable.name();  //获取表名
            if (tableName.length() < 1)
                tableName = c1.getName().toUpperCase(); //获取类名,并将其作为表名
            List<String> columnDefs = new ArrayList<String>();
            for (Field field : c1.getDeclaredFields()) { //遍历Member中所有的属性
                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().toUpperCase(); //将属性名作为字段名
                    else {
                        columnName = sInt.name();   //使用注解中指定的字段名
                    }
                    columnDefs.add(columnName + "INT"
                            + getConstraints(sInt.contraints())); //获取字段的约束条件
                }
                if (anns[0] instanceof SQLString) {
                    SQLString sString = (SQLString) anns[0];
                    if (sString.name().length() < 1)
                        columnName = field.getName().toUpperCase();
                    else
                        columnName = sString.name();
                    columnDefs.add(columnName + " VARCHAR(" + sString.value()
                            + ") " + getConstraints(sString.constraints()));
                }
                StringBuilder createCommand = new StringBuilder("CREATE TABLE " //使用StringBuilder来构造SQL语句
                        + tableName + "(");
                for (String columnDef : columnDefs)
                    createCommand.append("\n   " + columnDef + ".");
                String tableCreate = createCommand.substring(0,
                        createCommand.length() - 1)
                        + "\n);\n";
                System.out.println("Table CREATE SQL for " + className
                        + " is : \n" + tableCreate);
            }
        }
    }

    private static String getConstraints(Contraints con) { //对约束注解中的每个字段进行访问
        String constraints = "";
        if (!con.allowNull())
            constraints += "NOT NULL ";
        if (!con.primaryKey())
            constraints += "PRIMARY KEY";
        if (con.unique())
            constraints += "UNIQUE";
        return constraints;
    }
}

以上的代码来自《JAVA编程思想》一书,在此仅仅用于学习交流。

从以上的代码可以看出注解就是一个特殊Bean类,里面可以存储一些元数据。通过处理器来获取这些元数据,实现相应的功能。其主要作用还是为了减少程序员的工作量,提高代码的可用性、可扩张性。