Annotation 使用筆記(二) 註解生成SQL腳本

簡述:

《Java 編程思想第四版 》 第20章註解使用筆記


目標: 使用註解生成SQL建表文件


步驟及說明:

1. 項目結構:




2. 聲明幾種註解

1)  table

DBTable.java

package com.anialy.test.annotation.dbautomaker;

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


2)  SQLInteger

SQLInteger.java

package com.anialy.test.annotation.dbautomaker;

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 "";
	Constraints constraints() default @Constraints;
}


3)  SQLString

SQLString.java

package com.anialy.test.annotation.dbautomaker;

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 "";
	Constraints constraints() default @Constraints;
}



4) Constraints

Constraints.java

package com.anialy.test.annotation.dbautomaker;

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 unique() default false;
}


3. 綁定Table 實體類Entity

User.java

package com.anialy.test.annotation.dbautomaker.domain;

import com.anialy.test.annotation.dbautomaker.Constraints;
import com.anialy.test.annotation.dbautomaker.DBTable;
import com.anialy.test.annotation.dbautomaker.SQLInteger;
import com.anialy.test.annotation.dbautomaker.SQLString;

@DBTable(name="t_user")
public class User {
	@SQLString(value=36, constraints = @Constraints(primaryKey=true)) 
	private String id; 
	
	// 學號
	@SQLString(value=10, constraints = @Constraints(unique=true))
	private String sn; 
	
	// 姓名
	@SQLString(value=30)
	private String name;
	
	// 年齡
	@SQLInteger 
	private int age;

	public String getId() {
		return id;
	}

	public String getSn() {
		return sn;
	}

	public String getName() {
		return name;
	}

	public int getAge() {
		return age;
	}

	public void setId(String id) {
		this.id = id;
	}

	public void setSn(String sn) {
		this.sn = sn;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setAge(int age) {
		this.age = age;
	}

}


4. SQL Factory 生成sql腳本

SQLFactory.java

package com.anialy.test.annotation.dbautomaker.sqlfactory;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import com.anialy.test.annotation.dbautomaker.Constraints;
import com.anialy.test.annotation.dbautomaker.DBTable;
import com.anialy.test.annotation.dbautomaker.SQLInteger;
import com.anialy.test.annotation.dbautomaker.SQLString;

public class SQLFactory {
	
	
	public SQLFactory(final String className) {
		this.className = className;
	}

	/**
	 * 類名
	 */
	private String className;
	
	/**
	 * 表名
	 */
	private String tableName;
	
	/**
	 * 數據表成員變量的SQL列表
	 */
	private List<String> columnsDefs = new ArrayList<String>();
	
	private String genSQLOfClass() 
			throws ClassNotFoundException{
		Class<?> clazz = Class.forName(className);

		DBTable dbTable = clazz.getAnnotation(DBTable.class);
		
		if(dbTable == null){
			System.out.printf("no such class: %s", className);
			return "";
		}
		
		tableName = dbTable.name();
		
		// If the tableName is empty, then use the class name instead
		if(tableName == null || "".equals(tableName)){
			String fullClassNamePath = clazz.getName().toUpperCase();
			int lastCommaIndex =  fullClassNamePath.lastIndexOf(".");
			tableName = fullClassNamePath.substring(lastCommaIndex + 1);
		}
		
		for(Field field : clazz.getDeclaredFields()){
			String columnName = null;
			Annotation[] anns = field.getDeclaredAnnotations();
			Annotation curAnno = anns[0];
			if(curAnno == null) // no annotation on this field, then continue
				continue;
			else if(curAnno instanceof SQLString){
				SQLString annoString = (SQLString) curAnno;
				columnName = annoString.name();
				if(columnName == null || "".equals(columnName)){
					columnName = field.getName().toUpperCase();
				}
				columnsDefs.add(columnName 
						+ " VARCHAR(" + annoString.value() + ") " 
						+ getConstraints(annoString.constraints())
				);
			}else if(curAnno instanceof SQLInteger){
				SQLInteger annoInt = (SQLInteger)curAnno;
				columnName = annoInt.name();
				if(columnName == null || "".equals(columnName)){
					columnName = field.getName();
				}
				columnsDefs.add(columnName 
						+ " INT "
						+ getConstraints(annoInt.constraints())
				);
			}
		}
		
		
		
		StringBuilder sbd = new StringBuilder();
		sbd.append("CREATE TABLE " + tableName + " (\n");
		for(String columnRow : columnsDefs){
			sbd.append("\t" + columnRow + ",\n");
		}
		// remove trailing comma
		String tbCreate = sbd.substring(0, sbd.length() - 2);
		tbCreate += "\n);\n\n";
		
		return tbCreate;
	}
	
	
	/**
	 * definition of constraints
	 * @param constraints
	 * @return
	 */
	private String getConstraints(Constraints constraints) {
		String constraintsStr = "";
		if(constraints.primaryKey()){
			constraintsStr += "PRIMARY KEY";
		}
		if(constraints.unique()){
			constraintsStr += "UNIQUE";
		}
		return constraintsStr;
	}

	public void outputSQL() throws ClassNotFoundException{
		String createTbSQL = genSQLOfClass();
		if(createTbSQL == null || "".equals(createTbSQL))
			return;
		File file = new File(tableName + ".sql");

		FileOutputStream fos = null;
		
		try {
			fos = new FileOutputStream(file);
			fos.write(createTbSQL.getBytes("utf-8"));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			if(fos != null){
				try {
					fos.flush();
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}





5. 測試類

Test.java

package com.anialy.test.annotation.dbautomaker.test;

import com.anialy.test.annotation.dbautomaker.sqlfactory.SQLFactory;

public class Test {
	
	public static void main(String[] args) throws ClassNotFoundException {
		 new SQLFactory("com.anialy.test.annotation.dbautomaker.domain.User").outputSQL();
	}
}


輸出:






附錄:

如果使用nio輸出,output部分可以這麼寫

	public void outputSQL() throws IOException, ClassNotFoundException{
		String createTbSQL = genSQLOfClass();
		if(createTbSQL == null || "".equals(createTbSQL))
			return;

		FileChannel fc = new RandomAccessFile(tableName + ".sql", "rw")
                           .getChannel();
		byte[] outputBytes = createTbSQL.getBytes();
		int bytesNum = outputBytes.length;
		ByteBuffer bb = fc.map(FileChannel.MapMode.READ_WRITE, 0, bytesNum);
		bb.put(outputBytes);
		fc.close();
	}





















發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章