一口一口吃掉Hibernate(三)——Hibernate給表和字段設置先後綴及分隔符

       在《一口一口吃掉Hibernate(一)——使用SchemaExport生成數據表》中介紹瞭如何生成數據表。可是這只是最基本的。Hibernate在生成或者操做數據庫時,會受一些限制。好比一開始設計表的時候,直接寫成了user(id,name,password,createTime)  這種格式的。可是客戶後來要求表名稱要以「t_」開頭,字段名要以「stu_」開頭,能夠是一些數據庫的關鍵字,單詞之間以「_」隔開,方便他們維護.例如:T_User(stu_Id,stu_Name,stu_Create_Time)。html


      對於上面的問題,常規的方法就是去修改Hibernate_cfg.xml中的表,爲每一個表添加「t_」,或者寫table屬性,字段也從新使用column屬性來修改。若是你有100張表,每一個表平均有10個字段,你還會去一個一個修改麼?還有可能漏掉或者改錯。最「可惡」的是,若是客戶再讓你改爲其餘的呢,是否是還要所有修改一次?java


      有沒有一種方法,不修改原先的配置,添加並配置一下表和字段的先後綴及分隔符等等,既能夠完成呢??通過嘗試,終於被我拿下了,如今拿出來與你們分享。node


      針對上述問題,我主要用的是NamingStrategy接口。這個接口頗有意思,能夠做爲業務類規範和數據庫表規範的橋樑,它能夠表和列的映射關係的轉變和處理。例如一個數據對象User,對應數據庫表是T_USER,若是全部映射關係都是這樣的狀況,可使用NamingStrategy作爲一個橋樑銜接,而不用再hbm.xml映射文件中指定class對應的物理table。sql


      先說一下Hibernate讀取映射文件的簡要過程:循環讀取class標籤,判斷class標籤的table屬性值是否爲null,若爲null,則調用NamingStrategy接口的classToTableName方法將class值轉換並處理(按命名策略NamingStrategy處理)的表名。若不爲null,則說明設置了table,那麼調用NamingStrategy接口的tableName方法獲取處理過的表名。循環遍歷property,判斷property標籤的column屬性值是否爲null,若爲null,則首先調用propertyToColumnName方法,將屬性值轉化爲列名,再調用logicalColumnName方法。若不爲null,則直接調用NamingStrategy接口的logicalColumnName方法,再調用columnName方法進行處理(按命名策略NamingStrategy處理)。
數據庫


      瞭解了上面說的這個過程,只要咱們實現NamingStrategy這個接口,就能夠爲所欲爲的修改表映射了。很少說了,直接上代碼吧:session

    【MyNamingStrategy】自定義的命名策略,可對錶、字段進行統一處理。app

package com.tgb.hibernate.neatlyDB;

import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.util.StringHelper;

/**
 * 數據庫命名策略,可定製表、字段等的先後綴
 * 
 * @author Longxuan
 * 
 */
public class MyNamingStrategy implements NamingStrategy {

	/**
	 * 數據庫命名策略單一實例
	 */
	private static MyNamingStrategy instance = null;

	/**
	 * 數據庫配置信息類
	 */
	private static DatabaseConfiguration dbcfg = null;

	/**
	 * 私有化構造方法
	 */
	private MyNamingStrategy() {

	}

	/**
	 * 使用單利模式,獲取數據庫命名策略的惟一實例
	 * 
	 * @return
	 */
	public static synchronized MyNamingStrategy getInstance() {
		// 默認讀取hibernate.cfg.xml文件
		Configuration cfg = new Configuration().configure();
		return getInstance(cfg);
	}

	/**
	 * 使用單利模式,獲取數據庫命名策略的惟一實例,同時使用默認Hibernate.cfg.xml更新命名策略信息
	 * 
	 * @param cfg
	 *            配置文件信息
	 * @return
	 */
	public static synchronized MyNamingStrategy getInstance(Configuration cfg) {
		if (instance == null) {
			instance = new MyNamingStrategy();
		}
		MyNamingStrategy.dbcfg = new DatabaseConfiguration(cfg);
		return instance;
	}

	/**
	 * 使用單利模式,獲取數據庫命名策略的惟一實例,同時更新命名策略信息
	 * 
	 * @param cfg
	 *            配置文件信息
	 * @return
	 */
	public static synchronized MyNamingStrategy getInstance(
			DatabaseConfiguration dbcfg) {
		if (instance == null) {
			instance = new MyNamingStrategy();
		}
		MyNamingStrategy.dbcfg = dbcfg;
		return instance;
	}

	/**
	 * 設置或更新數據庫配置信息
	 * 
	 * @param dbcfg
	 */
	public void setDBConfig(DatabaseConfiguration dbcfg) {
		MyNamingStrategy.dbcfg = dbcfg;
	}

	/**
	 * 轉化爲物理表名
	 * 
	 * @param className hbm.xml中的對應表的class值
	 */
	@Override
	public String classToTableName(String className) {
		
		if(className == null ) return null;
		
		//改變大小寫
		String str =UpdateStyle(className,dbcfg.getTableStyle().name());
			
		//添加先後綴
		str = addPrefixORStuffix(str, dbcfg.getTablePrefix(),dbcfg.getTableSuffix());
		
		//添加分隔符
		str = addSeparator(str,dbcfg.getTableSeparator());
		
		return str;
	}

	@Override
	public String collectionTableName(String ownerEntity,
			String ownerEntityTable, String associatedEntity,
			String associatedEntityTable, String propertyName) {
		return null;
	}

	
	/**
	 * 將讀取到的列名傳遞過來進行加工處理,變爲物理表的字段名
	 * 
	 * @param columnName logicalColumnName方法讀取到的列名
	 */
	@Override
	public String columnName(String columnName) {
		//先調用logicalColumnName方法,拿處處理過的值,
		//再傳遞到該方法中,因此能夠在這兩個方法中任一選擇修改。		
		//return columnName;
		
		if(columnName == null ) return null;
		
		//改變大小寫
		String str =UpdateStyle(columnName,dbcfg.getColumnTyle().name());
			
		//添加先後綴
		str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getColumnPrefix(),dbcfg.getColumnSuffix());
		
		//添加分隔符
		str = addSeparator(str,dbcfg.getColumnSeparator());
		
		return str;
		
	}

	
	/**
	 * 處理外鍵列名
	 * 
	 */
	@Override
	public String foreignKeyColumnName(String propertyName,
			String propertyEntityName, String propertyTableName,
			String referencedColumnName) {
		
		if(referencedColumnName == null ) return null;
		
		//改變大小寫
		String str =UpdateStyle(referencedColumnName,dbcfg.getColumnTyle().name());
			
		//添加先後綴
		str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getColumnPrefix(),dbcfg.getColumnSuffix());
		
		//添加分隔符
		str = addSeparator(str,dbcfg.getColumnSeparator());
		
		return str;
	}

	/**
	 * 關聯鍵的名稱
	 */
	@Override
	public String joinKeyColumnName(String joinedColumn, String joinedTable) {
		
		if(joinedColumn == null ) return null;
		
		//改變大小寫
		String str =UpdateStyle(joinedColumn,dbcfg.getColumnTyle().name());
			
		//添加先後綴
		str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getColumnPrefix(),dbcfg.getColumnSuffix());
		
		//添加分隔符
		str = addSeparator(str,dbcfg.getColumnSeparator());
		
		return str;
	}

	@Override
	public String logicalCollectionColumnName(String columnName,
			String propertyName, String referencedColumn) {
		return null;
	}

	@Override
	public String logicalCollectionTableName(String tableName,
			String ownerEntityTable, String associatedEntityTable,
			String propertyName) {
		return null;
	}

	/**
	 * 處理邏輯列名
	 * <b>若設置了column屬性,會直接調用調用該方法</b>
	 * 
	 * @param columnName	列名
	 * @param propertyName	實體列名
	 */
	@Override
	public String logicalColumnName(String columnName, String propertyName) {
		
		//name值對應propertyName,column值對應columnName
		//判斷columnName是否設置,若設置了,則返回column值,不然返回propertyName值
		return columnName == null || columnName =="" ? propertyName:columnName;
		
	}

	/**
	 * 處理邏輯列名
	 * <b>若未設置column屬性,則先調用該方法,再調用logicalColumnName方法</b>
	 * 
	 * @param propertyName	實體列名
	 */
	@Override
	public String propertyToColumnName(String propertyName) {

		if(propertyName == null ) return null;
		
		//改變大小寫
		String str =UpdateStyle(propertyName,dbcfg.getColumnTyle().name());
			
		//添加先後綴
		str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getColumnPrefix(),dbcfg.getColumnSuffix());
		
		//添加分隔符
		str = addSeparator(str,dbcfg.getColumnSeparator());
		
		return str;
	}

	
	/**
	 * 處理表名
	 * <b>若設置了table屬性,纔會調用該方法</b>
	 */
	@Override
	public String tableName(String tableName) {
		
		if(tableName == null ) return null;
		
		//改變大小寫
		String str =UpdateStyle(tableName,dbcfg.getTableStyle().name());
			
		//添加先後綴
		str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getTablePrefix(),dbcfg.getTableSuffix());
		
		//添加分隔符
		str = addSeparator(str,dbcfg.getTableSeparator());
		
		return str;
	}

	/**
	 * 單詞分隔符
	 * 
	 * @param name
	 * @return
	 */
	private String addSeparator(String str, String flag) {
		StringBuffer buf = new StringBuffer(str.substring(str.lastIndexOf(".")+1));
		for (int i = 1; i < buf.length() - 1; i++) {
			if ('_' != buf.charAt(i - 1)
					&& Character.isUpperCase(buf.charAt(i))
					&& !Character.isUpperCase(buf.charAt(i + 1))) {
				// buf.insert(i++, '_');
				buf.insert(i++, flag);
			}
		}
		return buf.toString();
	}

	/**
	 * 添加先後綴
	 * 
	 * @param str
	 *            字符串
	 * @param prefix
	 *            前綴
	 * @param suffix
	 *            後綴
	 * @return
	 */
	private String addPrefixORStuffix(String str, String prefix, String suffix) {
		StringBuffer buf = new StringBuffer(str.substring(str.lastIndexOf(".")+1));
		buf.insert(buf.length(), suffix).insert(0, prefix);
		return buf.toString();
	}

	/**
	 * 更新樣式
	 * @param str
	 * @param style
	 * @return
	 */
	private String UpdateStyle(String str, String style) {		
		if ("AU".equals(style)) {
			str = str.toUpperCase();
		} else if ("AL".equals(style)) {
			str = str.toLowerCase();
		} else if ("FU".equals(style)) {
			StringBuffer buf = new StringBuffer(str.substring(str.lastIndexOf(".")+1));
			String upper =buf.substring(0,1).toUpperCase();
			buf.delete(0, 1).insert(0, upper);
			str = buf.toString();
		} else if ("FL".equals(style)) {
			StringBuffer buf = new StringBuffer(str.substring(str.lastIndexOf(".")+1));
			String lower =buf.substring(0,1).toLowerCase();
			buf.delete(0, 1).insert(0, lower);
			str = buf.toString();
		}  else{
			
		}		
		return str;
	}
	
	
}


【DatabaseConfiguration】數據庫樣式配置,包括先後綴、分隔符、大小寫等ide

package com.tgb.hibernate.neatlyDB;

import org.hibernate.cfg.Configuration;


/**
 * 數據庫模式配置
 * @author Longxuan
 *
 */
public final class DatabaseConfiguration {


	/**
	 * 列名樣式
	 * AU-all upper case
	 * AL-all lower case
	 * FU-first upper case per word
	 * FL-first lower case ,Other first letter upper case
	 */
	public static enum ColumnTyle {
		AU,AL,FU,FL;		
	}
	
	/**
	 * 表名稱樣式
	 * AU-all upper case
	 * AL-all lower case
	 * FU-first upper case per word
	 * FL-first lower case ,Other first letter upper case
	 */
	public static enum TableStyle{
		AU,AL,FU,FL;
	}

	/**
	 * 列名樣式
	 * AU-all upper case
	 * AL-all lower case
	 * FU-first upper case per word
	 * FL-first lower case ,Other first letter upper case
	 */
	private ColumnTyle columnTyle = ColumnTyle.FL;
	
	/**
	 * 表名稱樣式
	 * AU-all upper case
	 * AL-all lower case
	 * FU-first upper case per word
	 * FL-first lower case ,Other first letter upper case
	 */
	private TableStyle tableStyle = TableStyle.FU;
	
	/**
	 * 表名稱前綴
	 */
	private String tablePrefix = "";
	
	/**
	 * 表名稱後綴
	 */
	private String tableSuffix = "";
	
	/**
	 * 表名稱分隔符
	 */
	private String tableSeparator = "";
	
	/**
	 * 列名前綴
	 */
	private String columnPrefix = "";
	
	/**
	 * 列名後綴
	 */
	private String columnSuffix = "";
	
	/**
	 * 列名分隔符
	 */
	private String columnSeparator = "";
	
	public ColumnTyle getColumnTyle() {
		return columnTyle;
	}

	public void setColumnTyle(ColumnTyle columnTyle) {
		this.columnTyle = columnTyle;
	}

	public TableStyle getTableStyle() {
		return tableStyle;
	}

	public void setTableStyle(TableStyle tableStyle) {
		this.tableStyle = tableStyle;
	}

	public String getTablePrefix() {
		return tablePrefix;
	}

	public void setTablePrefix(String tablePrefix) {
		this.tablePrefix = tablePrefix;
	}

	public String getTableSuffix() {
		return tableSuffix;
	}

	public void setTableSuffix(String tableSuffix) {
		this.tableSuffix = tableSuffix;
	}

	public String getTableSeparator() {
		return tableSeparator;
	}

	public void setTableSeparator(String tableSeparator) {
		this.tableSeparator = tableSeparator;
	}

	public String getColumnPrefix() {
		return columnPrefix;
	}

	public void setColumnPrefix(String columnPrefix) {
		this.columnPrefix = columnPrefix;
	}

	public String getColumnSuffix() {
		return columnSuffix;
	}

	public void setColumnSuffix(String columnSuffix) {
		this.columnSuffix = columnSuffix;
	}

	public String getColumnSeparator() {
		return columnSeparator;
	}

	public void setColumnSeparator(String columnSeparator) {
		this.columnSeparator = columnSeparator;
	}
	

	/**
	 * 初始化,讀取配置參數,默認讀取Hibernate.cfg.xml
	 * @param cfg
	 */
	public DatabaseConfiguration(){
		ReadConfig(new Configuration().configure()); 
	}
	
	/**
	 * 初始化,讀取配置文件
	 * @param cfg
	 */
	public DatabaseConfiguration(Configuration cfg){
		ReadConfig(cfg); 
	}
	

	/**
	 * 自動讀取配置信息
	 * @param cfg
	 */
	private void ReadConfig(Configuration cfg){
		tableStyle = cfg.getProperty("tablestyle")==""?TableStyle.FU:TableStyle.valueOf(cfg.getProperty("tablestyle"));
		tablePrefix = cfg.getProperty("tablePrefix");
		tableSuffix = cfg.getProperty("tablesuffix");
		tableSeparator = cfg.getProperty("tableseparator");
		
		columnTyle = cfg.getProperty("columntyle")==""?ColumnTyle.FL:ColumnTyle.valueOf(cfg.getProperty("columntyle"));
		columnPrefix = cfg.getProperty("columnPrefix");
		columnSuffix = cfg.getProperty("columnsuffix");
		columnSeparator = cfg.getProperty("columnseparator");
		
	}
	
}


【hibernate.cfg.xml】設置數據庫樣式配置信息ui

<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
	<session-factory name="foo">		
<!-- 
	name:		配置的名稱
	style:		類型 枚舉AU-all upper case
					  AL-all lower case
					  FU-first letter upper case per word
					  FL-first letter lower case ,Other first letters upper case
	
	befix:		前綴
	suffix:		後綴
	separator:	分隔符
 -->
    	<property name="tablestyle">FU</property>
		<property name="tablePrefix" >T_</property>
		<property name="tablesuffix" ></property>
		<property name="tableseparator" >_</property>		
    	<property name="columntyle">FU</property>
    	<property name="columnPrefix">[stu_</property>
    	<property name="columnsuffix">]</property>
    	<property name="columnseparator">_</property>
    	
    	
    
		<property name="hibernate.dialect" >org.hibernate.dialect.MySQLDialect</property>
		<property name="hibernate.show_sql">true</property><!-- 設置是否顯示生成sql語句 -->
		<property name="hibernate.format_sql">false</property><!-- 設置是否格式化sql語句-->
		
		<mapping resource="com/bjpowernode/hibernate/User.hbm.xml" />
		
	</session-factory>
	
</hibernate-configuration>

【User.hbm.xml】 映射文件能夠比較隨意的修改或者設定了

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class name="com.bjpowernode.hibernate.User" table="Users">
		<id name="id" column="pid">
			<generator class="uuid" />
		</id>
		<property name="name" column="userName"></property>
		<property name="password" column="pwd"></property>
		<property name="createTime"></property>
		<property name="expireTime"></property>
		
	</class>
</hibernate-mapping>

最後修改一下【ExportDB】,主要是修改必須先設置NamingStrategy,在調用configure方法

package com.bjpowernode.hibernate;

import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;

import com.tgb.hibernate.neatlyDB.DatabaseConfiguration;
import com.tgb.hibernate.neatlyDB.MyNamingStrategy;



/**
 * 將hbm生成ddl
 * @author Longxuan
 *
 */
public class ExportDB {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		//默認讀取hibernate.cfg.xml文件,並按照命名策略修改表、字段的名稱
		//Configuration cfg = new Configuration().configure(); 
		
		//注意,必須先設置NamingStrategy,在調用configure方法
		Configuration cfg = new Configuration().setNamingStrategy(MyNamingStrategy.getInstance()).configure();
						
		SchemaExport export = new SchemaExport(cfg);
		
		//true 在控制檯打印ddl語句,true 導入ddl語句到數據庫,便可執行
		export.create(true, true);
	}

}

      看一下結果圖吧:表名,字段名都已經修改過了。



      上面演示的是生成數據表。在對數據庫的增刪改查時,只要一樣設置NamingStrategy便可。this

      爲了你們更爲方便的使用,已經作成jar包分享給你們了,點這裏下載。

相關文章
相關標籤/搜索