DBGenerator:獲取PO註解信息生成表sql

        開發過程當中,經常建立了PO以後,還要去數據庫裏建立對應的表,類似的過程,卻要作兩次,有沒有感受很麻煩?使用Hibernate能夠生成表,還要去配置,並且沒法獲得表建立sql,因而 DBGenerator 應運而生了。DBGenerator是一個工具類,能獲取PO類的註解信息,自動生成表建立SQL,節省了不少時間,同時也能保證測試環境和生產環境表的一致性。java

1. jar包依賴

    commons-lang-2.6.jarsql

    hibernate3.jar數據庫

2. 源碼

package com.cg.db;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;

import org.apache.commons.lang.StringUtils;

import com.sun.xml.internal.bind.v2.model.core.ID;

/** 
 *
 * <p>根據PO生成表建立sql<p>
 * <p>根據read方法上的註解,生成數據庫字段信息,沒有read方法的Field跳過<p>
 * @since jdk1.6
 * @date 2016-8-15
 */
public class DBGenerator {

	/**
	 * 
	 * 根據類的註解信息生成表sql
	 * @param clazz
	 * @return
	 */
	public String generate(Class clazz){
		if(!clazz.isAnnotationPresent(Table.class)){
			throw new RuntimeException("No Annotation[Table] founded in class["+clazz.getName()+"]");
		}
		Table table = (Table)clazz.getAnnotation(Table.class);
		String tableName = table.name();
		StringBuilder sb = new StringBuilder("-- Create table\n");
		sb.append("create table " + tableName + "\n");
		sb.append("(\n");
		Field[] fieldArr = clazz.getDeclaredFields();
		int maxLength = getMaxLength(clazz, fieldArr);
		String primaryKey = generateFields(clazz, sb, fieldArr, maxLength);
		sb.append(");\n");
		generatePrimaryKey(sb, tableName, primaryKey);
		return sb.toString();
	}
	 
	/** 
	 * 生成sql字段
	 * @param clazz
	 * @param sb
	 * @param fieldArr
	 * @param primaryKey
	 * @param maxLength
	 * @return  
	 */
	  	
	private String generateFields(Class clazz, StringBuilder sb,
			Field[] fieldArr, int maxLength) {
		String primaryKey = "";
		Field field;
		for(int i=0;i<fieldArr.length;i++){
			field = fieldArr[i];
			int offset;
			try {
				PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
				Method mt = pd.getReadMethod();
				if(null != mt){
					Column col = (Column)mt.getAnnotation(Column.class);
					writeBlankSpace(sb, 2);
					sb.append(col.name());
					offset = maxLength - col.name().length();
					writeBlankSpace(sb, offset);
					writeBlankSpace(sb, 1);
					sb.append(convertJava2Oracle(field, col));
					if(mt.isAnnotationPresent(Id.class)){
						sb.append(" not null");
						primaryKey = col.name();
					}
				}
			} catch (IntrospectionException e) {
				//找不到readMethod,跳過
				//throw new RuntimeException("No " + field.getName() + "'s ReadMethod founded in class["+clazz.getName()+"]");
				continue;
			}
			if(i != (fieldArr.length -1)){
				sb.append(",");
			}
			sb.append("\n");
		}
		return primaryKey;
	}
	 
	/** 
	 * 生成主鍵sql
	 * @param tableName
	 * @param sb
	 * @param primaryKey  
	 */
	  	
	private void generatePrimaryKey(StringBuilder sb, String tableName, String primaryKey) {
		if(StringUtils.isNotBlank(primaryKey)){
			sb.append("alter table " + tableName + "\n");
			sb.append("  add primary key (" + primaryKey + ")\n");
			sb.append("  using index;");
		}
	}
	 
	/** 
	 * 得到Field最大長度
	 * @param clazz
	 * @param fieldArr  
	 */
	  	
	private int getMaxLength(Class clazz, Field[] fieldArr) {
		Field field;
		int maxLength = 0;
		for(int i=0;i<fieldArr.length;i++){
			field = fieldArr[i];
			PropertyDescriptor pd;
			try {
				pd = new PropertyDescriptor(field.getName(), clazz);
				Method mt = pd.getReadMethod();
				if(null != mt){
					if(!mt.isAnnotationPresent(Column.class)){
						throw new RuntimeException("No Annotation[Column] founded in Method["+mt.getName()+"]");
					}
					Column col = (Column)mt.getAnnotation(Column.class);
					int temLength = col.name().length();
					if(temLength > maxLength){
						maxLength = temLength;
					}
				}
			} catch (IntrospectionException e) {
				//找不到readMethod,跳過
				//throw new RuntimeException("No " + field.getName() + "'s ReadMethod founded in class["+clazz.getName()+"]");
				continue;
			}
		}
		return maxLength;
	}
	
	/**
	 * 
	 * 將java類型轉換爲orable類型
	 * @param field
	 * @param col
	 * @return
	 */
	private String convertJava2Oracle(Field field, Column col){
		//TODO 此處可根據本身須要作類型轉換
		String type = "VARCHAR2";
		if(field.getType().equals(String.class)){
			type = "VARCHAR2(" + col.length() + ")";
		}else if(field.getType().equals(java.util.Date.class) || field.getType().equals(java.sql.Date.class)){
			type = "DATE";
		}else if(field.getType().equals(Integer.class)){
			type = "NUMBER";
		}
		return type;
	}
	
	/**
	 * 
	 * 輸出空格
	 * @param sb
	 * @param n
	 */
	private void writeBlankSpace(StringBuilder sb, int n){
		for(int i=0;i<n;i++){
			sb.append(" ");
		}
	}
}

3. 事例

    1.TBankCode類,使用了註解@Table、@Id、@Column標識了表名、主鍵、列信息, DBGenerator能讀取類的註解信息,生成對應sql。(ps:因爲本人習慣將 Column加到get方法上,在開發過程當中限定DBGenerator 只讀取get方法上的註解,此外對應數據庫(oracle)的類型只作了幾個經常使用的轉換,可根據本身須要調整。)apache

package com.cg.db;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;

@Table(name = "T_BANK_CODE")
public class TBankCode implements java.io.Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = -9047055962822128897L;
	/**
	 * 主鍵id
	 */
	private String id;
	/***省名 */
	private String province;
	/*** 省代碼*/
	private String provinceNo;
	/*** 地區名 */
	private String area;
	/*** 地區代碼*/
	private String areaNo;
	/*** 銀行行名稱*/
	private String bankName;
	/*** 銀行號*/
	private String bankNo;
	/*** 分行名稱 */
	private String branchBankName;
	/*** 分行聯行號*/
	private String branchBankCode;
	
	
	@Id
	@Column(name = "ID", unique = true, nullable = false, length = 40)
	public String getId() {
		return id;
	}

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

	@Column(name = "PROVINCE", length = 100)
	public String getProvince() {
		return province;
	}

	public void setProvince(String province) {
		this.province = province;
	}

	@Column(name = "AREA", length = 100)
	public String getArea() {
		return area;
	}

	public void setArea(String area) {
		this.area = area;
	}
	
	@Column(name = "AREA_NO", length = 10)
	public String getAreaNo() {
		return areaNo;
	}

	public void setAreaNo(String areaNo) {
		this.areaNo = areaNo;
	}

	@Column(name = "PROVINCE_NO", length = 10)
	public String getProvinceNo() {
		return provinceNo;
	}

	public void setProvinceNo(String provinceNo) {
		this.provinceNo = provinceNo;
	}

	@Column(name = "BANK_NAME", length = 100)
	public String getBankName() {
		return bankName;
	}

	public void setBankName(String bankName) {
		this.bankName = bankName;
	}

	@Column(name = "BANK_NO", length = 30)
	public String getBankNo() {
		return bankNo;
	}

	public void setBankNo(String bankNo) {
		this.bankNo = bankNo;
	}

	@Column(name = "BRANCH_BANK_NAME", length = 100)
	public String getBranchBankName() {
		return branchBankName;
	}

	public void setBranchBankName(String branchBankName) {
		this.branchBankName = branchBankName;
	}

	@Column(name = "BRANCH_BANK_CODE", length = 30)
	public String getBranchBankCode() {
		return branchBankCode;
	}

	public void setBranchBankCode(String branchBankCode) {
		this.branchBankCode = branchBankCode;
	}
}

    2.實例化 DBGenerator 調用generate方法,傳遞參數TBankCode.classoracle

package com.cg.db;

public class TestRun {

	public static void main(String[] args) {
		String a = new DBGenerator().generate(TBankCode.class);
		System.out.println(a);
	}
}

    3.運行結果app

-- Create table
create table T_BANK_CODE
(
  ID               VARCHAR2(40) not null,
  PROVINCE         VARCHAR2(100),
  PROVINCE_NO      VARCHAR2(10),
  AREA             VARCHAR2(100),
  AREA_NO          VARCHAR2(10),
  BANK_NAME        VARCHAR2(100),
  BANK_NO          VARCHAR2(30),
  BRANCH_BANK_NAME VARCHAR2(100),
  BRANCH_BANK_CODE VARCHAR2(30)
);
alter table T_BANK_CODE
  add primary key (ID)
  using index;
相關文章
相關標籤/搜索