Java 注解入门 自动生成SQL语句

引言

    在用hibernate的时候发现idea能自动生成JavaBean,同时带有一些注解,这引发了个人好奇。当在学习Android的时候,我发现XUtils这个工具包中的DBUtils也可以使用相似hibernate的注解。因而乎在java编程思想中找了找有关注解的用法。java

一 注解定义

    注解(也称为元数据)为咱们在代码中添加信息提供了一种形式化的方法,使咱们能够在稍后某个时刻很是方便的使用这些数据。注解来源于C#之类的其余语言。spring

    注解的语法比较简单,除了@符号外,它与java的固有语法一致。javaSE5中内置了三种注解:编程

  •  @Override:定义覆盖超类,当覆写对应不上被覆盖的方法,编译器发出错误提示。数组

  • @Deprecated:当使用了该注解,即表示这个方法已经不推荐被使用。app

  • @SuppressWarnings:关闭不当的编译器警告。ide

二 基本语法

    咱们使用自定义的注解对一个方法进行注解:工具

public class Testable{
    public void execute()
    {
        System.out.println("execute...");
    }
    @WETest
    void taskStart()
    {
        execute();
    }
}

 

    在上边的代码中,咱们对taskStart方法使用了注解,接下来咱们对WETest注解进行定义:学习

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface WETest{}

 

 

三 定义注解

    咱们给上边的注解添加一些内容:ui

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface WETest{
    public int id();
    public String Notes() default "there is no Notes";
}

 

    一样,咱们对Testable类使用最新的注解:this

public class Testable{
    @WETest(id=666)
    public void execute()
    {
        System.out.println("execute...");
    }
    @WETest(id=666,Notes="this is a method")
    void taskStart()
    {
        execute();
    }
}

 

    注解就是这么使用的,当注解内容没有填写时,他会使用默认的值,如execute方法,他没有定义Notes,那么Notes默认值为"there is no Notes"。

 

四 元注解

    咱们看到注解上边有两行内容,它们是元注解,专门对注解的解释。元注解一共有四种,分别是:

  • @Target:表示该注解能够用到哪些地方,ElementType,CONSTRUCTOR构造器声明,FIELD域声明(包括enum实例),LOCAL_VARIABLE局部变量声明,METHOD方法,PACKAGE包,PARAMETER参数,TYPE类、接口或enum。

  • Retention:表示须要在什么级别上使用,RetentionPolicy,SOURCE注解会被编译器丢掉,CLASS在class文件中可用会被VM抛弃,RUNTIME在VM运行期也会保留能够经过反射获取注解信息。

  • Documented:将注解包含在Javadoc中。

  • Inherited:容许子类继承父类中的注解。

 

五 经过注解反射生成SQL语句

    接下来,我用一个例子来解释注解的做用。先编写一些注解定义:

//DBTable.java            用来生成数据表
package annotations;

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 "";
}

//Constraints.java        用来定义约束项
package annotations;

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;
}

//PrimaryKey.java        将Constraints中的primarykey定义为真,表示为主键
package annotations;

import java.lang.annotation.*;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PrimaryKey {
	Constraints constraints() default @Constraints(primarykey = true);
}

//SQLInteger.java         定义列的类型
package annotations;

import java.lang.annotation.*;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger {
	String name() default "";
	Constraints constraints() default @Constraints;
}

//SQLString.java        定义列的类型
package annotations;

import java.lang.annotation.*;


@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
	int value() default 64;
	String name() default "";
	Constraints constraints() default @Constraints;
}

 

   接下来写一个javabean,使用上述注解:

//User.java
import annotations.Constraints;
import annotations.DBTable;
import annotations.SQLInteger;
import annotations.SQLString;

@DBTable(name="user")
public class User {
	@SQLInteger(name="id",constraints = @Constraints(primarykey=true))
	public Integer id;
	@SQLString(value=30)
	public String name;
	@SQLString(name="passwd",constraints=@Constraints(allownull=false))
	public String password;
	
	/*能够不用
	public void setId(Integer id) {
		this.id = id;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public Integer getId() {
		return id;
	}
	public String getName() {
		return name;
	}
	public String getPassword() {
		return password;
	}*/	
}

 

    咱们看到注解中可使用注解,在SQLInteger中咱们使用了Constraints注解。

    接下来咱们写一个注解处理器:

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

import annotations.Constraints;
import annotations.DBTable;
import annotations.SQLInteger;
import annotations.SQLString;

public class Test {
	
	public static String getConstraints(Constraints con)
	{
		String constraints = "";
		if(!con.allownull())
		{
			constraints +=" NOT NULL";
		}
		if(con.primarykey())
		{
			constraints += " PRIMARY KEY";
		}
		return constraints;
	}

	public static void main(String[] args) throws ClassNotFoundException {
		Scanner s = new Scanner(System.in);
		String name = s.next();                                    //从控制台输入一个类名,咱们输入User便可
		Class<?> cl = Class.forName(name);                         //加载类,若是该类不在默认路径底下,会报 java.lang.ClassNotFoundException
		DBTable dbTable = cl.getAnnotation(DBTable.class);         //从User类中获取DBTable注解
		if(dbTable == null){                                       //若是没有DBTable注解,则直接返回,咱们写了,固然有
			return;
		}
		String tableName = (dbTable.name().length()<1)?cl.getName():dbTable.name();//获取表的名字,若是没有在DBTable中定义,则获取类名做为Table的名字
		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];
				columnName = (sInt.name().length()<1)?field.getName():sInt.name();//获取列名称与获取表名同样
				columnDefs.add(columnName+" INT"+getConstraints(sInt.constraints()));//使用一个方法,本身写的getConstraints(Constraints constraints)获取列定义
			}
			if(anns[0] instanceof SQLString)
			{
				SQLString sStr = (SQLString)anns[0];
				columnName = (sStr.name().length()<1)?field.getName().toUpperCase():sStr.name();
				columnDefs.add(columnName + " VARCHAR("+sStr.value()+")"+getConstraints(sStr.constraints()));
			}
		}
		StringBuilder createCommand = new StringBuilder("CREATE TABLE "+tableName+"(");
		for(String columnDef :columnDefs)
		{
			createCommand.append("\n    "+columnDef+",");
		}
		String tableCreate = createCommand.substring(0,createCommand.length()-1)+"\n);";
		System.out.println(tableCreate);                        //打印出来
	}

}

 

    咱们能够采用上述方法动态的处理一些数据,例如建立数据表。

六 总结

    注意:注解不支持继承例如 extends @xxx。注解的default默认值不能够为null

    总结:使用注解能够减小对xml等外部文件的依赖,使得对类的定义能够在一处实现,避免了一个类两处定义的麻烦。spring和hibernate就采用的这样的方法。

 

更多文章:https://blog.gavinzh.com

相关文章
相关标签/搜索