注解的意义:使得代码更加的整洁,并且便于维护。
java目前内置了三种注解:override、suppressWarning和Deparecated
- override:覆盖超类的方法。
- suppressWarning:关闭不当的编译器警告信息
- Deparecated:使编译器发出警告
同时Java 还提供了四种元注解,他们用于为注解进行注解。我们将在下面的代码中进行介绍。
注解元素:所有基本类型 、String 、 Class 、 enum、Annotation,及上述类型的数组形式。
默认值:元素不能有不确定的值,也就是说必须要有固定的默认值或者注解是提供元素的值。具体看下述案例
下面以一个实例来阐述 如何构建一套基于注解的java实体生成对应建表语句的小工具
第一步:定义一个表级注解,并了解注解基本参数
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
public String tableName() default "";
}
我们注意到 自定义一个注解的形式类似于声明一个接口,使用public interface 只不过这里的interface前面有一个@。
之后我们来看一下这两个元注解 Target 和 Retention 还有 @Document @Inherited
@Target 表示该注解可以应用在什么位置,他的值是一个枚举
- CONSTRUCTOR 构造器声明
- FIELD 域声明
- LOCAL_VARIABLE 局部变量声明
- METHOD 方法声明
- PACKAGE 包声明
- PARAMETER 参数声明
- TYPE 类 接口 或 enum声明
@Retention 表示需要在什么级别保存该注解信息,说白了就是这个注解转换成代码保留在程序的什么时期
- SOURCE 注解将在编译器编译的时候丢弃
- CLASS 注解在class文件中会保留 但是在jvm运行时会被抛弃
- RUNTIME 注解信息在整个运行期间会保留,因此可以通过反射获取
除此之外还有
@Document 将此注解包含在JavaDoc中
@Inherited 允许子类继承父类中的注解。
第二步:定义一个字段的基类注解
这里所谓的字段的基类注解是用于表述一系列关键信息例如是否主键 是否为空 是否唯一。
由于这三项属性在大部分字段都可以采取默认值,因此将其提出转化成基类。注意注解并不存在继承的概念,所以这里的基类仅仅是表示注解的嵌套(别的注解会嵌套该注解从而获得该注解的属性)。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBColumnConstraints {
boolean primaryKey() default false; //是否主键,默认不是
boolean allowNull() default true;//是否允许空,默认允许
boolean unique() default false;//是否唯一,默认不是唯一
}
请注意这里的ElementType 是 FIELD ,请看上文中对FIELD的定义:域声明。
接下来我们定义所谓的要嵌套这个注解的另外两个注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBIntegerColumn {
public String name () default "";
public int value() default -1;
DBColumnConstraints dbColumnConstraints () default @DBColumnConstraints;
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBVarcharColumn {
public String name () default "";
public String value() default "";
DBColumnConstraints dbColumnConstraints () default @DBColumnConstraints;
}
他们分别表示 字段是Varchar类型的注解 和 字段是Integer类型的注解。可以看到他们都嵌套了 DBColumnConstraints 注解,说明他们具备了DBColumnConstraints的属性。
第三步 编写我们需要注解的实体类
注解我们编写完了 是不是该定义表结构对应的实体类了。
假如我们要生产一个用户表和角色表,那么我们可以先编写出这两个表的实体类,然后产生这两个表的见表语句。首先定义model。
这个是角色实体类
package com.umbrellacore.testannotation;
@DBTable(tableName = "RoleVO")
public class RoleVO {
@DBIntegerColumn(name = "roleId" ,dbColumnConstraints = @DBColumnConstraints(primaryKey = true))
private int roleId;
@DBVarcharColumn(name = "roleName")
private String roleName;
public int getRoleId() {
return roleId;
}
public void setRoleId(int roleId) {
this.roleId = roleId;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
}
可以看出我们在类的开头加了@DBTable,大家可以翻看第一步我们定义的表级注解。这个注解表达了这个table的名字叫 ”RoleVO“
然后字段方面 我们可以看到典型的嵌套注解:
@DBIntegerColumn(name = "roleId" ,dbColumnConstraints = @DBColumnConstraints(primaryKey = true))
这个意思就是 该成员是一个字段,并且他对应的字段名字是roleId ,因为是Id类型的,所以他是主键,由于主键是在字段类型注解里增加的“基类注解”的属性,所以我们要用dbColumnConstraints = @DBColumnConstraints(primaryKey = true)来额外声明一下这里的primaryKey不要用default的false,而是True。
ok 大家看到这里应该基本明白注解的写法了。
同样的步骤 让我们继续编写用户实体类!
package com.umbrellacore.testannotation;
@DBTable(tableName = "UserVO")
public class UserVO {
@DBIntegerColumn(name = "userId" ,dbColumnConstraints = @DBColumnConstraints(primaryKey = true))
private int userId;
@DBVarcharColumn(name = "userName" ,value = "MolEliza")
private String userName;
@DBVarcharColumn(name = "userAddr",value = "Beijing")
private String userAddr;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
第四步 编写注解执行器产生SQL语句
package com.umbrellacore.testannotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
public class TableCreater {
// ===============获得字段类注解是否主键 是否唯一 是否非空的静态方法===========
public static String getDBColumnConstrains(DBColumnConstraints dbColumnConstraints){
String dbConstraints = "";
if(!dbColumnConstraints.allowNull()){
dbConstraints += " not null ";
}
if(dbColumnConstraints.primaryKey()){
dbConstraints += " primary key ";
}
if(dbColumnConstraints.unique()){
dbConstraints += " unique ";
}
return dbConstraints;
}
public static void main(String[] args) {
//================获得需要转换成SQL见表语句的实体类的路径=====================
List<String> classPath = new ArrayList<String>();
classPath.add("com.umbrellacore.testannotation.RoleVO");
classPath.add("com.umbrellacore.testannotation.UserVO");
//==================遍历==================
for(String className : classPath){
Class<?> tableClass = null;
try { //===========通过反射机制,获得类=============//
tableClass = Class.forName(className);
DBTable dbTable = tableClass.getAnnotation(DBTable.class);//===获得类的DBTable注解
String tableName = dbTable.tableName(); //===获得注解的表名
List<String> columns = new ArrayList<String>(); //=====定义存储表中字段的集合
for(Field field : tableClass.getDeclaredFields()){ //=========便利声明为Field的注解
String columnName = null;
Annotation[] anns = field.getDeclaredAnnotations(); //获得注解的内容,由于vo的成员变量只有一个注解,所以我们取anns[0]
if(anns[0] instanceof DBIntegerColumn){ // ================如果是数字类型的,如下做处理,拼写SQL
DBIntegerColumn dbIntegerColumn = (DBIntegerColumn)anns[0];
columns.add(
dbIntegerColumn.name()
+ "Integer"
+ getDBColumnConstrains(dbIntegerColumn.dbColumnConstraints())//=====调用“基注解”方法获取额外属性
);
}
if(anns[0] instanceof DBVarcharColumn){ // ================如果是字符串类型的,如下做处理,拼写SQL
DBVarcharColumn dbVarcharColumn = (DBVarcharColumn)anns[0];
columns.add(
dbVarcharColumn.name()
+ "Varchar"
+ getDBColumnConstrains(dbVarcharColumn.dbColumnConstraints())
);
}
}
StringBuilder createCommand = new StringBuilder("");
createCommand.append("Create Table");//==========拼写SQL语句
createCommand.append(tableName);
createCommand.append("(");
for(String columnName : columns){
createCommand.append(columnName);
createCommand.append(",");
}
createCommand.replace(createCommand.length()-1,createCommand.length(),"");
createCommand.append(");");
System.out.println(createCommand.toString());
}catch(Exception e){
e.printStackTrace();
}
}
}
}
结果:
Create TableRoleVO(roleIdInteger primary key ,roleNameVarchar);
Create TableUserVO(userIdInteger primary key ,userNameVarchar,userAddrVarchar);
Process finished with exit code 0