我們知道可以通過Hibernate對象自動生成DDL建表語句,通過PowerDesigner工具可以反向工程生成數(shù)據(jù)字典,但是在生成的DDL中一直不能寫上中文的注釋,這就使我們生成的數(shù)據(jù)字典不具有可用性。
這個假期宅在家里調(diào)試代碼,發(fā)現(xiàn)Hibernate的Dialect,Table,Column的映射中已經(jīng)做了comment的處理,只是Hibernate團隊認(rèn)為這個功能的重要性太小,一直沒有時間提供這個需求,于是就自己動手實現(xiàn)這個功能了,這可是使用我們的數(shù)據(jù)對象代碼與數(shù)據(jù)字典文檔同步的關(guān)鍵一環(huán)?。?/p>
通過對Hibernate代碼的跟蹤發(fā)現(xiàn)了處理映射的邏輯是在代碼AnnotationBinder中,我們不需要在運行期間處理comment,只是在用SchemaExport時處理就可以,于是簡單的實現(xiàn)了此功能:
1. 增加一個注解 @Comment("這是表的說明,也可以是字段的說明"),適用在類名和屬性名
2. 復(fù)制org.hibernate.cfg.AnnotationBuilder代碼為org.hibernate.cfg.MyAnnotationBuilder,處理注解@Comment
3. 復(fù)制org.hibernate.cfg.Configuration為org.hibernate.cfg.MyConfiguration,將AnnotationBuilder的調(diào)用換成MyAnnotationBuilder
3. 實現(xiàn)SchemaExportTool類,傳入MyConfiguration處理Hibernate對象的映射關(guān)系,并生成DDL
以上思路在基于Hibernate 4.2.3版本在MySql 5.1上測試成功,因為代碼只是在開發(fā)期運行,不需要良好的結(jié)構(gòu)和優(yōu)化,所以只是簡單實現(xiàn)了,需要此功能的朋友可以自己實現(xiàn)。
以下是處理結(jié)果示例:
- @Entity
- @Table(name = "AuditRecord_")
- @Comment("系統(tǒng)審計表")
- @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("創(chuàng)建時間")
- private Date creationTime;
- }
- @Entity
- @Table(name = "AuditRecord_")
- @Comment("系統(tǒng)審計表")
- @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("創(chuàng)建時間")
- 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 '創(chuàng)建時間',
- description longtext comment '操作簡述',
- user_id bigint comment '操作人',
- primary key (id)
- ) comment='系統(tǒng)審計表';
- create table audit_record_ (
- id bigint not null auto_increment comment 'ID主鍵',
- audit_type varchar(30) comment '審計類型',
- creation_time datetime comment '創(chuàng)建時間',
- description longtext comment '操作簡述',
- user_id bigint comment '操作人',
- primary key (id)
- ) comment='系統(tǒng)審計表';
主要代碼片斷如下:
- 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;
- }
-
- }
- 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.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 "";
- }
- /**
- * $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 "";
- }
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請
點擊舉報。