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

相關文章
相關標籤/搜索