zoukankan      html  css  js  c++  java
  • 让Hibernate生成的DDL脚本自动增加注释


    我们知道可以通过Hibernate对象自动生成DDL建表语句,通过PowerDesigner工具可以反向工程生成数据字典,但是在生成的DDL中一直不能写上中文的注释,这就使我们生成的数据字典不具有可用性。

    这个假期宅在家里调试代码,发现Hibernate的Dialect,Table,Column的映射中已经做了comment的处理,只是Hibernate团队认为这个功能的重要性太小,一直没有时间提供这个需求,于是就自己动手实现这个功能了,这可是使用我们的数据对象代码与数据字典文档同步的关键一环啊!

    通过对Hibernate代码的跟踪发现了处理映射的逻辑是在代码AnnotationBinder中,我们不需要在运行期间处理comment,只是在用SchemaExport时处理就可以,于是简单的实现了此功能:

    1. 增加一个注解 @Comment("这是表的说明,也可以是字段的说明"),适用在类名和属性名

    2. 复制org.hibernate.cfg.AnnotationBuilder代码为org.hibernate.cfg.MyAnnotationBuilder,处理注解@Comment

    3. 复制org.hibernate.cfg.Configuration为org.hibernate.cfg.MyConfiguration,将AnnotationBuilder的调用换成MyAnnotationBuilder

    3. 实现SchemaExportTool类,传入MyConfiguration处理Hibernate对象的映射关系,并生成DDL

    以上思路在基于Hibernate 4.2.3版本在MySql 5.1上测试成功,因为代码只是在开发期运行,不需要良好的结构和优化,所以只是简单实现了,需要此功能的朋友可以自己实现。

    以下是处理结果示例:

    @Entity
    @Table(name = "AuditRecord_")
    @Comment("系统审计表")
    @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
    public class AuditRecord implements Serializable {
    
    	private static final long serialVersionUID = 8844543936912679937L;
    	@Id
    	@GeneratedValue
    	@Comment("ID主键")
    	private Long id;
    	@Comment("审计类型")
    	@Column(length = 30)
    	private String auditType;
    	@Comment("操作人")
    	@ManyToOne
    	@JoinColumn(name = "userId")
    	private Passport operator;
    	// 操作简述
    	@Comment("操作简述")
    	@Column(length = 4000)
    	private String description;
    	@Comment("创建时间")
    	private Date creationTime;
    }


    生成的DDL如下:

    create table audit_record_ (
            id bigint not null auto_increment comment 'ID主键',
            audit_type varchar(30) comment '审计类型',
            creation_time datetime comment '创建时间',
            description longtext comment '操作简述',
            user_id bigint comment '操作人',
            primary key (id)
        ) comment='系统审计表';
    


     

    主要代码片断如下:

    import java.io.IOException;
    import java.util.Properties;
    
    import javax.persistence.Embeddable;
    import javax.persistence.Entity;
    import javax.persistence.MappedSuperclass;
    
    import org.hibernate.MappingException;
    import org.hibernate.cfg.MyConfiguration;
    import org.hibernate.tool.hbm2ddl.SchemaExport;
    import org.springframework.core.io.Resource;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.core.io.support.ResourcePatternResolver;
    import org.springframework.core.io.support.ResourcePatternUtils;
    import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
    import org.springframework.core.type.classreading.MetadataReader;
    import org.springframework.core.type.classreading.MetadataReaderFactory;
    import org.springframework.core.type.filter.AnnotationTypeFilter;
    import org.springframework.core.type.filter.TypeFilter;
    import org.springframework.util.ClassUtils;
    
    public class SchemaExportTool extends MyConfiguration {
    
    	private static final long serialVersionUID = 1L;
    
    	private static final String RESOURCE_PATTERN = "/**/*.class";
    
    	private static final String PACKAGE_INFO_SUFFIX = ".package-info";
    
    	private static final TypeFilter[] ENTITY_TYPE_FILTERS = new TypeFilter[] {
    			new AnnotationTypeFilter(Entity.class, false),
    			new AnnotationTypeFilter(Embeddable.class, false),
    			new AnnotationTypeFilter(MappedSuperclass.class, false) };
    	private final ResourcePatternResolver resourcePatternResolver;
    
    	public SchemaExportTool() {
    		this.resourcePatternResolver = ResourcePatternUtils
    				.getResourcePatternResolver(new PathMatchingResourcePatternResolver());
    	}
    
    	public static void main(String[] args) {
    		try {
    			Properties p = new Properties();
    			p.setProperty("hibernate.dialect",
    					"org.hibernate.dialect.MySQLDialect");
    			SchemaExportTool cfg = new SchemaExportTool();
    			cfg.addProperties(p);
    			cfg.setNamingStrategy(new ImprovedMyNamingStrategy());
    			cfg.scanPackage("com.share.passport.domain",
    					"com.share.authority.domain", "com.share.utils.domain");
    
    			SchemaExport se = new SchemaExport(cfg);
    			if (null != args && args.length > 1)
    				if ("-f".equals(args[0]))
    					se.setOutputFile(args[1]);
    				else
    					se.setOutputFile("create_table.sql");
    			else
    				se.setOutputFile("create_table.sql");
    			se.setDelimiter(";");
    			// se.drop(false, false);
    			se.create(false, false);
    
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    
    	}
    
    	private SchemaExportTool scanPackage(String... packagesToScan) {
    		try {
    			for (String pkg : packagesToScan) {
    				String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
    						+ ClassUtils.convertClassNameToResourcePath(pkg)
    						+ RESOURCE_PATTERN;
    				Resource[] resources = this.resourcePatternResolver
    						.getResources(pattern);
    				MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(
    						this.resourcePatternResolver);
    				for (Resource resource : resources) {
    					if (resource.isReadable()) {
    						MetadataReader reader = readerFactory
    								.getMetadataReader(resource);
    						String className = reader.getClassMetadata()
    								.getClassName();
    						if (matchesEntityTypeFilter(reader, readerFactory)) {
    							addAnnotatedClass(this.resourcePatternResolver
    									.getClassLoader().loadClass(className));
    						} else if (className.endsWith(PACKAGE_INFO_SUFFIX)) {
    							addPackage(className.substring(
    									0,
    									className.length()
    											- PACKAGE_INFO_SUFFIX.length()));
    						}
    					}
    				}
    			}
    			return this;
    		} catch (IOException ex) {
    			throw new MappingException(
    					"Failed to scan classpath for unlisted classes", ex);
    		} catch (ClassNotFoundException ex) {
    			throw new MappingException(
    					"Failed to load annotated classes from classpath", ex);
    		}
    	}
    
    	/**
    	 * Check whether any of the configured entity type filters matches the
    	 * current class descriptor contained in the metadata reader.
    	 */
    	private boolean matchesEntityTypeFilter(MetadataReader reader,
    			MetadataReaderFactory readerFactory) throws IOException {
    		for (TypeFilter filter : ENTITY_TYPE_FILTERS) {
    			if (filter.match(reader, readerFactory)) {
    				return true;
    			}
    		}
    		return false;
    	}
    
    }
    
    /**
     * $Id:$
     */
    package com.share.utils.hibernate;
    
    import org.hibernate.annotations.common.reflection.XClass;
    import org.hibernate.annotations.common.reflection.XProperty;
    import org.hibernate.cfg.Ejb3Column;
    import org.hibernate.mapping.PersistentClass;
    
    import com.share.annotations.Comment;
    
    public class CommentBinder {
        public static void bindTableComment(XClass clazzToProcess, PersistentClass persistentClass) {
            if (clazzToProcess.isAnnotationPresent(Comment.class)) {
                String tableComment = clazzToProcess.getAnnotation(Comment.class).value();
                persistentClass.getTable().setComment(tableComment);
    
            }
        }
    
        public static void bindColumnComment(XProperty property, Ejb3Column[] columns) {
            if (null != columns)
    
                if (property.isAnnotationPresent(Comment.class)) {
                    String comment = property.getAnnotation(Comment.class).value();
                    for (Ejb3Column column : columns) {
                        column.getMappingColumn().setComment(comment);
                    }
    
                }
        }
    
        public static void bindColumnComment(XProperty property, Ejb3Column column) {
            if (null != column)
                if (property.isAnnotationPresent(Comment.class)) {
                    String comment = property.getAnnotation(Comment.class).value();
    
                    column.getMappingColumn().setComment(comment);
    
                }
        }
    }
    
    /**
     * $Id:$
     */
    package com.share.annotations;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.TYPE,ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Comment {
        String value() default "";
    }
    



  • 相关阅读:
    JS实现 div拖拽 限制在屏幕内
    国际化配置simple_form
    simple_form模板templates erb haml
    git rolify
    rails模板生成bootstrap格式的simple_form的erb文件
    rails生成器生成自定义controller模板
    ubuntu 终端常用命令(转)
    Ruby for Rails笔记
    Java基础
    javascript ybmiaov
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3358089.html
Copyright © 2011-2022 走看看