`

Hibernate给表和字段设置前后缀及分隔符

阅读更多

Hibernate在生成或者操作数据库时,会受一些限制。比如一开始设计表的时候,直接写成了user(id,name,password,createTime)  这种格式的。但是客户后来要求表名称要以“t_”开头,字段名要以“stu_”开头,可以是一些数据库的关键字,单词之间以“_”隔开,方便他们维护.例如:T_User(stu_Id,stu_Name,stu_Create_Time)。

 

      对于上面的问题,常规的方法就是去修改Hibernate_cfg.xml中的表,为每个表添加“t_”,或者写table属性,字段也重新使用column属性来修改。如果你有100张表,每个表平均有10个字段,你还会去一个一个修改么?还有可能漏掉或者改错。最“可恶”的是,如果客户再让你改成其他的呢,是不是还要全部修改一次?

 

      有没有一种方法,不修改原先的配置,添加并配置一下表和字段的前后缀及分隔符等等,既可以完成呢??经过尝试,终于被我拿下了,现在拿出来与大家分享。

 

      针对上述问题,我主要用的是NamingStrategy接口。这个接口很有意思,可以作为业务类规范和数据库表规范的桥梁,它可以表和列的映射关系的转变和处理。例如一个数据对象User,对应数据库表是T_USER,如果所有映射关系都是这样的情况,可以使用NamingStrategy做为一个桥梁衔接,而不用再hbm.xml映射文件中指定class对应的物理table。


      先说一下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这个接口,就可以随心所欲的修改表映射了。不多说了,直接上代码吧:

    【MyNamingStrategy】自定义的命名策略,可对表、字段进行统一处理。

 

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】数据库样式配置,包括前后缀、分隔符、大小写等

 

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】设置数据库样式配置信息

 

 

 

<!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即可。

分享到:
评论

相关推荐

    java提取数据库表字段信息的工具类.docx

    `getColumnNames`方法则只返回字段名,同样可以指定字段之间的分隔符。核心方法`getTableColumns`通过执行SQL查询获取了表的第一行数据的元数据,从而得到每个字段的名称和对应的Java类型,存储在一个LinkedHashMap...

    数据库学习

    4. **合并列值**:在MySQL中,可以使用`GROUP_CONCAT(字段名 SEPARATOR 分隔符)`函数将多行数据的某个字段合并成一行显示: ``` SELECT GROUP_CONCAT(字段名 SEPARATOR 分隔符) FROM 表名; ``` 其中默认的分隔符...

    mysql+struts+

    - `parse`方法首先通过`.`分隔符分割字符串,然后对分割后的结果进一步处理,以提取各个字段的值。值得注意的是,这种方式在实际应用中可能会存在问题,因为实际地址数据可能并不总是按照预期的方式格式化。 ### ...

    Ibatis入门教程

    注意在定义存储过程时需要使用特定的分隔符(例如`$$`),以避免语法冲突。 3. **创建实体类**: - 实体类`User`包含了`id`、`userName`和`email`三个属性,以及对应的getter和setter方法。同时,为了方便调试,还...

    面试常遇到的问题

    使用`String.split()`方法可以将字符串按照指定分隔符(这里是逗号)切割成数组。 2. `request.getAttribute()`和`request.getParameter()`的区别是什么? `getAttribute()`用于获取请求范围内的对象,返回的是...

    java面试题广州

    3. **千分位格式化**:将数字转换为含千分隔符的字符串,可以通过正则表达式或自定义逻辑实现,逐位插入分隔符。 ### 面试智力题与逻辑题 1. **逻辑推理题**:例如,通过逻辑分析找出开关对应的灯,或求解斐波那契...

    hql文档详解 相信对初步的朋友有帮助

    HQL还支持更新和删除操作,这在Hibernate 3.0及更高版本中得到了增强。 ```java Transaction trans = session.beginTransaction(); String hql = "update User set age = 20 where age = 18"; Query query...

    常用Sql注入语句.

    - 列出表和字段:使用像`SELECT * FROM information_schema.tables`这样的语句来获取表名,然后列出每个表的字段。 - 数据获取:通过`SELECT * FROM table_name`等语句读取表数据。 - 权限提升:尝试执行修改或...

    java编码规范

    - **索引**:合理创建索引,避免在经常更新的字段上创建索引,主键通常设置为自动增长的整数字段。 - **SQL语句**:编写规范的SQL语句,避免SQL注入,使用参数化查询或存储过程。 以上内容仅为Java编码规范的一...

    J2EE开发规范

    比如,应避免不必要的包导入,确保每个类只负责单一职责,方法签名应简洁明了,避免过长的方法参数列表,以及合理使用访问修饰符来保护类和字段的可见性。 #### 表达式与语句 控制语句和循环语句的编写方式也受到...

    Openbravo技术评测

    - **配置缺省数字格式**:设置数字的显示方式,如小数点分隔符等。 - **解决已知问题**:了解并解决在特定环境下可能出现的一些常见问题。 #### 三、系统使用到的技术 **3.1 Openbravo ERP 涉及的技术** 除了前面...

    程序编码规范java.doc

    4. **Class Fields**: 类字段应有适当的访问修饰符和初始化。 5. **存取方法**: get/set方法应简洁明了。 6. **构造函数**: 应清晰地定义职责。 7. **main方法**: 作为程序入口点,应简洁易懂。 8. **换行和行长度**...

    SQL 注入漏洞 专题资料

    3. **堆叠查询注入**:通过分隔符(如`;`)执行多个独立的SQL查询。 4. **信息泄露**:通过查询数据库元数据,攻击者可能获得关于数据库结构、版本等敏感信息。 5. **权限提升**:通过修改用户权限,攻击者可以执行...

    java实现tcp客户端发送服务端解析程序

    对于数据解析,可以使用各种方法,如正则表达式、JSON解析库(如Jackson或Gson)或者自定义的分隔符策略。例如,如果数据是以逗号分隔的,可以使用`String.split(",")`进行解析。 在服务器接收到数据后,可能需要...

    java程序开发规范

    - **访问修饰符**:合理使用public、private、protected和默认修饰符,确保封装性和安全性。 - **继承与多态**:慎重使用继承,优先考虑组合和接口实现来实现多态性。 - **单元测试**:编写单元测试以验证代码...

    JAVA常用英文

    分隔符,用于区分字符串或其他数据序列中的不同部分,如逗号、空格等。 ### Exception 异常,Java中用于处理错误和非预期情况的机制,通过抛出和捕获异常进行错误处理。 ### entry 入口,常指程序或数据结构的...

    java基础学习词汇

    例如,在CSV文件中,逗号通常作为字段之间的分隔符。 #### Encapsulation (封装) 封装是面向对象编程的一个基本原则,指的是隐藏对象的具体实现细节,只暴露对外提供的接口。这样可以保护数据的安全性,并使代码...

    JAVA+ORALCE面试题汇总

    - **separator**:分割字符串的分隔符。 - **limit**:限制返回数组的最大长度。 #### 15. Oracle数据库的特性 Oracle数据库是业界领先的数据库管理系统之一,其特性包括: - **高性能**:通过内存管理和并发控制...

    面试题及答案.docx

    - 数组相关:`getBytes()`将字符串转换为字节数组,`toCharArray()`转换为字符数组,`split(String)`按指定分隔符切割字符串。 - 判断相关:`equals()`和`equalsIgnoreCase()`比较字符串内容是否相同,`contains()...

    《阿里巴巴Java开发手册》(v1.1.0版)

    - 在操作符前后添加空格,如`a = b + c`。 - 方法调用后紧跟括号,如`foo()`而非`foo ( )`。 - 在逻辑行过长时使用换行来提高可读性。 **4. OOP规约** - **规则概述:** - 面向对象编程原则的遵循,包括但不...

Global site tag (gtag.js) - Google Analytics